Open bots from peer info screen

This commit is contained in:
Isaac 2024-07-12 17:09:26 +04:00
parent 0ae86bd218
commit ed592cc64c
3 changed files with 325 additions and 26 deletions

View File

@ -143,9 +143,11 @@ swift_library(
"//submodules/TelegramUI/Components/TextLoadingEffect", "//submodules/TelegramUI/Components/TextLoadingEffect",
"//submodules/TelegramUI/Components/Settings/BirthdayPickerScreen", "//submodules/TelegramUI/Components/Settings/BirthdayPickerScreen",
"//submodules/TelegramUI/Components/Settings/PeerSelectionScreen", "//submodules/TelegramUI/Components/Settings/PeerSelectionScreen",
"//submodules/TelegramUI/Components/ButtonComponent",
"//submodules/ConfettiEffect", "//submodules/ConfettiEffect",
"//submodules/ContactsPeerItem", "//submodules/ContactsPeerItem",
"//submodules/TelegramUI/Components/PeerManagement/OldChannelsController", "//submodules/TelegramUI/Components/PeerManagement/OldChannelsController",
"//submodules/UrlHandling",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -11,6 +11,9 @@ import ContextUI
import SwiftSignalKit import SwiftSignalKit
import TextLoadingEffect import TextLoadingEffect
import EmojiTextAttachmentView import EmojiTextAttachmentView
import ComponentFlow
import ButtonComponent
import ComponentDisplayAdapters
enum PeerInfoScreenLabeledValueTextColor { enum PeerInfoScreenLabeledValueTextColor {
case primary case primary
@ -49,6 +52,16 @@ private struct TextLinkItemSource: Equatable {
} }
final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem { final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
final class Button {
let title: String
let action: () -> Void
init(title: String, action: @escaping () -> Void) {
self.title = title
self.action = action
}
}
let id: AnyHashable let id: AnyHashable
let context: AccountContext? let context: AccountContext?
let label: String let label: String
@ -62,6 +75,7 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
let longTapAction: ((ASDisplayNode) -> Void)? let longTapAction: ((ASDisplayNode) -> Void)?
let linkItemAction: ((TextLinkItemActionType, TextLinkItem, ASDisplayNode, CGRect?, Promise<Bool>?) -> Void)? let linkItemAction: ((TextLinkItemActionType, TextLinkItem, ASDisplayNode, CGRect?, Promise<Bool>?) -> Void)?
let iconAction: (() -> Void)? let iconAction: (() -> Void)?
let button: Button?
let contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? let contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
let requestLayout: () -> Void let requestLayout: () -> Void
@ -79,6 +93,7 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
longTapAction: ((ASDisplayNode) -> Void)? = nil, longTapAction: ((ASDisplayNode) -> Void)? = nil,
linkItemAction: ((TextLinkItemActionType, TextLinkItem, ASDisplayNode, CGRect?, Promise<Bool>?) -> Void)? = nil, linkItemAction: ((TextLinkItemActionType, TextLinkItem, ASDisplayNode, CGRect?, Promise<Bool>?) -> Void)? = nil,
iconAction: (() -> Void)? = nil, iconAction: (() -> Void)? = nil,
button: Button? = nil,
contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? = nil, contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? = nil,
requestLayout: @escaping () -> Void requestLayout: @escaping () -> Void
) { ) {
@ -95,6 +110,7 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
self.longTapAction = longTapAction self.longTapAction = longTapAction
self.linkItemAction = linkItemAction self.linkItemAction = linkItemAction
self.iconAction = iconAction self.iconAction = iconAction
self.button = button
self.contextAction = contextAction self.contextAction = contextAction
self.requestLayout = requestLayout self.requestLayout = requestLayout
} }
@ -148,6 +164,8 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
private var linkHighlightingNode: LinkHighlightingNode? private var linkHighlightingNode: LinkHighlightingNode?
private var actionButton: ComponentView<Empty>?
private let activateArea: AccessibilityAreaNode private let activateArea: AccessibilityAreaNode
private var validLayout: (width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool)? private var validLayout: (width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool)?
@ -651,6 +669,52 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
height += additionalTextSize.height + 3.0 height += additionalTextSize.height + 3.0
} }
if let button = item.button {
height += 3.0
let actionButton: ComponentView<Empty>
if let current = self.actionButton {
actionButton = current
} else {
actionButton = ComponentView()
self.actionButton = actionButton
}
let actionButtonSize = actionButton.update(
transition: ComponentTransition(transition),
component: AnyComponent(ButtonComponent(
background: ButtonComponent.Background(
color: presentationData.theme.list.itemCheckColors.fillColor,
foreground: presentationData.theme.list.itemCheckColors.foregroundColor,
pressedColor: presentationData.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
),
content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent(Text(text: button.title, font: Font.semibold(17.0), color: presentationData.theme.list.itemCheckColors.foregroundColor))),
isEnabled: true,
allowActionWhenDisabled: false,
displaysProgress: false,
action: {
button.action()
}
)),
environment: {},
containerSize: CGSize(width: width - sideInset * 2.0, height: 50.0)
)
let actionButtonFrame = CGRect(origin: CGPoint(x: sideInset, y: height), size: actionButtonSize)
if let actionButtonView = actionButton.view {
if actionButtonView.superview == nil {
self.contextSourceNode.contentNode.view.addSubview(actionButtonView)
}
transition.updateFrame(view: actionButtonView, frame: actionButtonFrame)
}
height += actionButtonSize.height
height += 16.0
} else {
if let actionButton = self.actionButton {
self.actionButton = nil
actionButton.view?.removeFromSuperview()
}
}
let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel
self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition) self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition)
transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset))) transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset)))

View File

@ -109,6 +109,7 @@ import PeerNameColorItem
import PeerSelectionScreen import PeerSelectionScreen
import UIKitRuntimeUtils import UIKitRuntimeUtils
import OldChannelsController import OldChannelsController
import UrlHandling
public enum PeerInfoAvatarEditingMode { public enum PeerInfoAvatarEditingMode {
case generic case generic
@ -1203,6 +1204,7 @@ private enum InfoSection: Int, CaseIterable {
case calls case calls
case personalChannel case personalChannel
case peerInfo case peerInfo
case peerInfoTrailing
case peerMembers case peerMembers
} }
@ -1211,6 +1213,8 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
return [] return []
} }
var currentPeerInfoSection: InfoSection = .peerInfo
var items: [InfoSection: [PeerInfoScreenItem]] = [:] var items: [InfoSection: [PeerInfoScreenItem]] = [:]
for section in InfoSection.allCases { for section in InfoSection.allCases {
items[section] = [] items[section] = []
@ -1265,7 +1269,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
} else { } else {
label = presentationData.strings.ContactInfo_PhoneLabelMobile label = presentationData.strings.ContactInfo_PhoneLabelMobile
} }
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: label, text: formattedPhone, textColor: .accent, action: { node, progress in items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: label, text: formattedPhone, textColor: .accent, action: { node, progress in
interaction.openPhone(phone, node, nil, progress) interaction.openPhone(phone, node, nil, progress)
}, longTapAction: nil, contextAction: { node, gesture, _ in }, longTapAction: nil, contextAction: { node, gesture, _ in
interaction.openPhone(phone, node, gesture, nil) interaction.openPhone(phone, node, gesture, nil)
@ -1280,7 +1284,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
additionalUsernames = presentationData.strings.Profile_AdditionalUsernames(String(usernames.map { "@\($0.username)" }.joined(separator: ", "))).string additionalUsernames = presentationData.strings.Profile_AdditionalUsernames(String(usernames.map { "@\($0.username)" }.joined(separator: ", "))).string
} }
items[.peerInfo]!.append( items[currentPeerInfoSection]!.append(
PeerInfoScreenLabeledValueItem( PeerInfoScreenLabeledValueItem(
id: 1, id: 1,
label: presentationData.strings.Profile_Username, label: presentationData.strings.Profile_Username,
@ -1326,30 +1330,70 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
} }
} }
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 400, context: context, label: hasBirthdayToday ? presentationData.strings.UserInfo_BirthdayToday : presentationData.strings.UserInfo_Birthday, text: stringForCompactBirthday(birthday, strings: presentationData.strings, showAge: true), textColor: .primary, leftIcon: hasBirthdayToday ? .birthday : nil, icon: hasBirthdayToday ? .premiumGift : nil, action: birthdayAction, longTapAction: nil, iconAction: { items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: 400, context: context, label: hasBirthdayToday ? presentationData.strings.UserInfo_BirthdayToday : presentationData.strings.UserInfo_Birthday, text: stringForCompactBirthday(birthday, strings: presentationData.strings, showAge: true), textColor: .primary, leftIcon: hasBirthdayToday ? .birthday : nil, icon: hasBirthdayToday ? .premiumGift : nil, action: birthdayAction, longTapAction: nil, iconAction: {
interaction.openPremiumGift() interaction.openPremiumGift()
}, contextAction: birthdayContextAction, requestLayout: { }, contextAction: birthdayContextAction, requestLayout: {
})) }))
} }
if user.isFake { if user.isFake {
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: "", text: user.botInfo != nil ? presentationData.strings.UserInfo_FakeBotWarning : presentationData.strings.UserInfo_FakeUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledPrivateBioEntities : []), action: nil, requestLayout: { items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: "", text: user.botInfo != nil ? presentationData.strings.UserInfo_FakeBotWarning : presentationData.strings.UserInfo_FakeUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledPrivateBioEntities : []), action: nil, requestLayout: {
interaction.requestLayout(false) interaction.requestLayout(false)
})) }))
} else if user.isScam { } else if user.isScam {
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledPrivateBioEntities : []), action: nil, requestLayout: { items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledPrivateBioEntities : []), action: nil, requestLayout: {
interaction.requestLayout(false) interaction.requestLayout(false)
})) }))
} else if let about = cachedData.about, !about.isEmpty { } else if let about = cachedData.about, !about.isEmpty {
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.isPremium ? enabledPublicBioEntities : enabledPrivateBioEntities), action: isMyProfile ? { node, _ in var actionButton: PeerInfoScreenLabeledValueItem.Button?
if let menuButton = cachedData.botInfo?.menuButton, case let .webView(text, url) = menuButton {
//TODO:localize
actionButton = PeerInfoScreenLabeledValueItem.Button(title: "Open App", action: {
guard let parentController = interaction.getController() else {
return
}
openWebApp(
parentController: parentController,
context: context,
peer: .user(user),
buttonText: text,
url: url,
simple: false,
source: .menu
)
})
}
items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.isPremium ? enabledPublicBioEntities : enabledPrivateBioEntities), action: isMyProfile ? { node, _ in
bioContextAction(node, nil, nil) bioContextAction(node, nil, nil)
} : nil, linkItemAction: bioLinkAction, contextAction: bioContextAction, requestLayout: { } : nil, linkItemAction: bioLinkAction, button: actionButton, contextAction: bioContextAction, requestLayout: {
interaction.requestLayout(false) interaction.requestLayout(false)
})) }))
if let botInfo = user.botInfo, botInfo.flags.contains(.canEdit) {
//TODO:localize
items[currentPeerInfoSection]!.append(PeerInfoScreenCommentItem(id: 800, text: "By publishing this mini app, you agree to the [Telegram Terms of Service for Developers](https://telegram.org/privacy).", linkAction: { action in
if case let .tap(url) = action {
context.sharedContext.applicationBindings.openUrl(url)
}
}))
} else if actionButton != nil {
//TODO:localize
items[currentPeerInfoSection]!.append(PeerInfoScreenCommentItem(id: 800, text: "By launching this mini app, you agree to the [Terms of Service for Mini Apps](https://telegram.org/privacy).", linkAction: { action in
if case let .tap(url) = action {
context.sharedContext.applicationBindings.openUrl(url)
}
}))
}
if actionButton != nil {
currentPeerInfoSection = .peerInfoTrailing
}
} }
if let businessHours = cachedData.businessHours { if let businessHours = cachedData.businessHours {
items[.peerInfo]!.append(PeerInfoScreenBusinessHoursItem(id: 300, label: presentationData.strings.PeerInfo_BusinessHours_Label, businessHours: businessHours, requestLayout: { animated in items[currentPeerInfoSection]!.append(PeerInfoScreenBusinessHoursItem(id: 300, label: presentationData.strings.PeerInfo_BusinessHours_Label, businessHours: businessHours, requestLayout: { animated in
interaction.requestLayout(animated) interaction.requestLayout(animated)
}, longTapAction: nil, contextAction: workingHoursContextAction)) }, longTapAction: nil, contextAction: workingHoursContextAction))
} }
@ -1357,7 +1401,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
if let businessLocation = cachedData.businessLocation { if let businessLocation = cachedData.businessLocation {
if let coordinates = businessLocation.coordinates { if let coordinates = businessLocation.coordinates {
let imageSignal = chatMapSnapshotImage(engine: context.engine, resource: MapSnapshotMediaResource(latitude: coordinates.latitude, longitude: coordinates.longitude, width: 90, height: 90)) let imageSignal = chatMapSnapshotImage(engine: context.engine, resource: MapSnapshotMediaResource(latitude: coordinates.latitude, longitude: coordinates.longitude, width: 90, height: 90))
items[.peerInfo]!.append(PeerInfoScreenAddressItem( items[currentPeerInfoSection]!.append(PeerInfoScreenAddressItem(
id: 301, id: 301,
label: presentationData.strings.PeerInfo_Location_Label, label: presentationData.strings.PeerInfo_Location_Label,
text: businessLocation.address, text: businessLocation.address,
@ -1368,7 +1412,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
contextAction: businessLocationContextAction contextAction: businessLocationContextAction
)) ))
} else { } else {
items[.peerInfo]!.append(PeerInfoScreenAddressItem( items[currentPeerInfoSection]!.append(PeerInfoScreenAddressItem(
id: 301, id: 301,
label: presentationData.strings.PeerInfo_Location_Label, label: presentationData.strings.PeerInfo_Location_Label,
text: businessLocation.address, text: businessLocation.address,
@ -1382,25 +1426,25 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
if !isMyProfile { if !isMyProfile {
if let reactionSourceMessageId = reactionSourceMessageId, !data.isContact { if let reactionSourceMessageId = reactionSourceMessageId, !data.isContact {
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 3, text: presentationData.strings.UserInfo_SendMessage, action: { items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: 3, text: presentationData.strings.UserInfo_SendMessage, action: {
interaction.openChat(nil) interaction.openChat(nil)
})) }))
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: presentationData.strings.ReportPeer_BanAndReport, color: .destructive, action: { items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: 4, text: presentationData.strings.ReportPeer_BanAndReport, color: .destructive, action: {
interaction.openReport(.reaction(reactionSourceMessageId)) interaction.openReport(.reaction(reactionSourceMessageId))
})) }))
} else if let _ = nearbyPeerDistance { } else if let _ = nearbyPeerDistance {
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 3, text: presentationData.strings.UserInfo_SendMessage, action: { items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: 3, text: presentationData.strings.UserInfo_SendMessage, action: {
interaction.openChat(nil) interaction.openChat(nil)
})) }))
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: presentationData.strings.ReportPeer_Report, color: .destructive, action: { items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: 4, text: presentationData.strings.ReportPeer_Report, color: .destructive, action: {
interaction.openReport(.user) interaction.openReport(.user)
})) }))
} else { } else {
if !data.isContact { if !data.isContact {
if user.botInfo == nil { if user.botInfo == nil {
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 3, text: presentationData.strings.PeerInfo_AddToContacts, action: { items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: 3, text: presentationData.strings.PeerInfo_AddToContacts, action: {
interaction.openAddContact() interaction.openAddContact()
})) }))
} }
@ -1412,14 +1456,14 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
} }
if isBlocked { if isBlocked {
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? presentationData.strings.Bot_Unblock : presentationData.strings.Conversation_Unblock, action: { items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? presentationData.strings.Bot_Unblock : presentationData.strings.Conversation_Unblock, action: {
interaction.updateBlocked(false) interaction.updateBlocked(false)
})) }))
} else { } else {
if user.flags.contains(.isSupport) || data.isContact { if user.flags.contains(.isSupport) || data.isContact {
} else { } else {
if user.botInfo == nil { if user.botInfo == nil {
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: presentationData.strings.Conversation_BlockUser, color: .destructive, action: { items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: 4, text: presentationData.strings.Conversation_BlockUser, color: .destructive, action: {
interaction.updateBlocked(true) interaction.updateBlocked(true)
})) }))
} }
@ -1427,22 +1471,22 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
} }
if let encryptionKeyFingerprint = data.encryptionKeyFingerprint { if let encryptionKeyFingerprint = data.encryptionKeyFingerprint {
items[.peerInfo]!.append(PeerInfoScreenDisclosureEncryptionKeyItem(id: 5, text: presentationData.strings.Profile_EncryptionKey, fingerprint: encryptionKeyFingerprint, action: { items[currentPeerInfoSection]!.append(PeerInfoScreenDisclosureEncryptionKeyItem(id: 5, text: presentationData.strings.Profile_EncryptionKey, fingerprint: encryptionKeyFingerprint, action: {
interaction.openEncryptionKey() interaction.openEncryptionKey()
})) }))
} }
if user.botInfo != nil { if user.botInfo != nil {
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 6, text: presentationData.strings.ReportPeer_Report, action: { items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: 6, text: presentationData.strings.ReportPeer_Report, action: {
interaction.openReport(.default) interaction.openReport(.default)
})) }))
} }
if let botInfo = user.botInfo, botInfo.flags.contains(.worksWithGroups) { if let botInfo = user.botInfo, botInfo.flags.contains(.worksWithGroups) {
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 7, text: presentationData.strings.Bot_AddToChat, color: .accent, action: { items[currentPeerInfoSection]!.append(PeerInfoScreenActionItem(id: 7, text: presentationData.strings.Bot_AddToChat, color: .accent, action: {
interaction.openAddBotToGroup() interaction.openAddBotToGroup()
})) }))
items[.peerInfo]!.append(PeerInfoScreenCommentItem(id: 8, text: presentationData.strings.Bot_AddToChatInfo)) items[currentPeerInfoSection]!.append(PeerInfoScreenCommentItem(id: 8, text: presentationData.strings.Bot_AddToChatInfo))
} }
} }
} }
@ -1472,7 +1516,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
let linkText = "https://t.me/\(mainUsername)/\(threadId)" let linkText = "https://t.me/\(mainUsername)/\(threadId)"
items[.peerInfo]!.append( items[currentPeerInfoSection]!.append(
PeerInfoScreenLabeledValueItem( PeerInfoScreenLabeledValueItem(
id: ItemUsername, id: ItemUsername,
label: presentationData.strings.Channel_LinkItem, label: presentationData.strings.Channel_LinkItem,
@ -1499,7 +1543,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
if let _ = channel.addressName { if let _ = channel.addressName {
} else { } else {
items[.peerInfo]!.append(PeerInfoScreenCommentItem(id: ItemUsernameInfo, text: presentationData.strings.PeerInfo_PrivateShareLinkInfo)) items[currentPeerInfoSection]!.append(PeerInfoScreenCommentItem(id: ItemUsernameInfo, text: presentationData.strings.PeerInfo_PrivateShareLinkInfo))
} }
} else { } else {
if let location = (data.cachedData as? CachedChannelData)?.peerGeoLocation { if let location = (data.cachedData as? CachedChannelData)?.peerGeoLocation {
@ -1524,7 +1568,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
additionalUsernames = presentationData.strings.Profile_AdditionalUsernames(String(usernames.map { "@\($0.username)" }.joined(separator: ", "))).string additionalUsernames = presentationData.strings.Profile_AdditionalUsernames(String(usernames.map { "@\($0.username)" }.joined(separator: ", "))).string
} }
items[.peerInfo]!.append( items[currentPeerInfoSection]!.append(
PeerInfoScreenLabeledValueItem( PeerInfoScreenLabeledValueItem(
id: ItemUsername, id: ItemUsername,
label: presentationData.strings.Channel_LinkItem, label: presentationData.strings.Channel_LinkItem,
@ -1579,7 +1623,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
if case .group = channel.info { if case .group = channel.info {
enabledEntities = enabledPrivateBioEntities enabledEntities = enabledPrivateBioEntities
} }
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Channel_Info_Description, text: aboutText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledEntities), action: isMyProfile ? { node, _ in items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Channel_Info_Description, text: aboutText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledEntities), action: isMyProfile ? { node, _ in
bioContextAction(node, nil, nil) bioContextAction(node, nil, nil)
} : nil, linkItemAction: bioLinkAction, contextAction: bioContextAction, requestLayout: { } : nil, linkItemAction: bioLinkAction, contextAction: bioContextAction, requestLayout: {
interaction.requestLayout(true) interaction.requestLayout(true)
@ -1631,7 +1675,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
} }
if let aboutText = aboutText { if let aboutText = aboutText {
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Channel_Info_Description, text: aboutText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPrivateBioEntities), action: isMyProfile ? { node, _ in items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Channel_Info_Description, text: aboutText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPrivateBioEntities), action: isMyProfile ? { node, _ in
bioContextAction(node, nil, nil) bioContextAction(node, nil, nil)
} : nil, linkItemAction: bioLinkAction, contextAction: bioContextAction, requestLayout: { } : nil, linkItemAction: bioLinkAction, contextAction: bioContextAction, requestLayout: {
interaction.requestLayout(true) interaction.requestLayout(true)
@ -13685,3 +13729,192 @@ private final class HeaderContextReferenceContentSource: ContextReferenceContent
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds) return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds)
} }
} }
private func openWebApp(parentController: ViewController, context: AccountContext, peer: EnginePeer, buttonText: String, url: String, simple: Bool, source: ChatOpenWebViewSource) {
let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
let botName: String
let botAddress: String
let botVerified: Bool
if case let .inline(bot) = source {
botName = bot.compactDisplayTitle
botAddress = bot.addressName ?? ""
botVerified = bot.isVerified
} else {
botName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
botAddress = peer.addressName ?? ""
botVerified = peer.isVerified
}
let _ = botAddress
let openWebView = { [weak parentController] in
guard let parentController else {
return
}
if source == .menu {
if let navigationController = parentController.navigationController as? NavigationController, let minimizedContainer = navigationController.minimizedContainer {
for controller in minimizedContainer.controllers {
if let controller = controller as? AttachmentController, let mainController = controller.mainController as? WebAppController, mainController.botId == peer.id && mainController.source == .menu {
navigationController.maximizeViewController(controller, animated: true)
return
}
}
}
var fullSize = false
if isTelegramMeLink(url), let internalUrl = parseFullInternalUrl(sharedContext: context.sharedContext, url: url), case .peer(_, .appStart) = internalUrl {
fullSize = !url.contains("?mode=compact")
}
var presentImpl: ((ViewController, Any?) -> Void)?
let params = WebAppParameters(source: .menu, peerId: peer.id, botId: peer.id, botName: botName, botVerified: botVerified, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: fullSize)
//TODO:localize
//updatedPresentationData
let controller = standaloneWebAppController(context: context, updatedPresentationData: nil, params: params, threadId: nil, openUrl: { [weak parentController] url, concealed, commit in
guard let parentController else {
return
}
let _ = parentController
/*ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in
presentImpl?(c, a)
}, commit: commit)*/
}, requestSwitchInline: { [weak parentController] query, chatTypes, completion in
guard let parentController else {
return
}
let _ = parentController
//ChatControllerImpl.botRequestSwitchInline(context: context, controller: self, peerId: peerId, botAddress: botAddress, query: query, chatTypes: chatTypes, completion: completion)
}, getInputContainerNode: {
return nil
}, completion: {
}, willDismiss: {
}, didDismiss: {
}, getNavigationController: { [weak parentController] () -> NavigationController? in
guard let parentController else {
return nil
}
return parentController.navigationController as? NavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController
})
controller.navigationPresentation = .flatModal
parentController.push(controller)
presentImpl = { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a)
}
let _ = presentImpl
} else if simple {
var isInline = false
var botId = peer.id
var botName = botName
var botAddress = ""
var botVerified = false
if case let .inline(bot) = source {
isInline = true
botId = bot.id
botName = bot.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
botAddress = bot.addressName ?? ""
botVerified = bot.isVerified
}
let _ = botAddress
let _ = ((context.engine.messages.requestSimpleWebView(botId: botId, url: url, source: isInline ? .inline : .generic, themeParams: generateWebAppThemeParams(presentationData.theme)))
|> deliverOnMainQueue).startStandalone(next: { [weak parentController] result in
guard let parentController else {
return
}
var presentImpl: ((ViewController, Any?) -> Void)?
let params = WebAppParameters(source: isInline ? .inline : .simple, peerId: peer.id, botId: botId, botName: botName, botVerified: botVerified, url: result.url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: result.flags.contains(.fullSize))
let controller = standaloneWebAppController(context: context, updatedPresentationData: nil, params: params, threadId: nil, openUrl: { [weak parentController] url, concealed, commit in
guard let parentController else {
return
}
let _ = parentController
/*ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in
presentImpl?(c, a)
}, commit: commit)*/
}, requestSwitchInline: { query, chatTypes, completion in
//ChatControllerImpl.botRequestSwitchInline(context: context, controller: self, peerId: peerId, botAddress: botAddress, query: query, chatTypes: chatTypes, completion: completion)
}, getNavigationController: { [weak parentController] in
guard let parentController else {
return nil
}
return parentController.navigationController as? NavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController
})
controller.navigationPresentation = .flatModal
parentController.push(controller)
presentImpl = { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a)
}
let _ = presentImpl
}, error: { [weak parentController] error in
guard let parentController else {
return
}
parentController.present(textAlertController(context: context, updatedPresentationData: nil, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
})]), in: .window(.root))
})
} else {
let _ = ((context.engine.messages.requestWebView(peerId: peer.id, botId: peer.id, url: !url.isEmpty ? url : nil, payload: nil, themeParams: generateWebAppThemeParams(presentationData.theme), fromMenu: false, replyToMessageId: nil, threadId: nil))
|> deliverOnMainQueue).startStandalone(next: { [weak parentController] result in
guard let parentController else {
return
}
var presentImpl: ((ViewController, Any?) -> Void)?
let context = context
let params = WebAppParameters(source: .button, peerId: peer.id, botId: peer.id, botName: botName, botVerified: botVerified, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false, fullSize: result.flags.contains(.fullSize))
let controller = standaloneWebAppController(context: context, updatedPresentationData: nil, params: params, threadId: nil, openUrl: { [weak parentController] url, concealed, commit in
guard let parentController else {
return
}
let _ = parentController
/*ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in
presentImpl?(c, a)
}, commit: commit)*/
}, completion: {
}, getNavigationController: { [weak parentController] in
guard let parentController else {
return nil
}
return parentController.navigationController as? NavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController
})
controller.navigationPresentation = .flatModal
parentController.push(controller)
presentImpl = { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a)
}
let _ = presentImpl
}, error: { [weak parentController] error in
guard let parentController else {
return
}
parentController.present(textAlertController(context: context, updatedPresentationData: nil, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
})]), in: .window(.root))
})
}
}
var botPeer = peer
if case let .inline(bot) = source {
botPeer = bot
}
let _ = (ApplicationSpecificNotice.getBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id)
|> deliverOnMainQueue).startStandalone(next: { [weak parentController] value in
guard let parentController else {
return
}
if value {
openWebView()
} else {
let controller = webAppLaunchConfirmationController(context: context, updatedPresentationData: nil, peer: botPeer, completion: { _ in
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone()
openWebView()
}, showMore: nil)
parentController.present(controller, in: .window(.root))
}
})
}