Merge commit '2aeeaaee445f98a39b1da203a266aec063cc02ae'

# Conflicts:
#	Telegram/Telegram-iOS/en.lproj/Localizable.strings
This commit is contained in:
Ali 2023-07-20 13:10:08 +04:00
commit ec472970f2
16 changed files with 297 additions and 160 deletions

View File

@ -9428,10 +9428,6 @@ Sorry for the inconvenience.";
"MediaPicker.AddImage" = "Add Image";
"Premium.Stories" = "Story Posting";
"Premium.StoriesInfo" = "Be one of the first to share your stories with your contacts or an unlimited audience.";
"Premium.Stories.Proceed" = "Unlock Story Posting";
"AutoDownloadSettings.OnForContacts" = "On for contacts";
"AutoDownloadSettings.StoriesSectionHeader" = "AUTO-DOWNLOAD STORIES";
@ -9553,10 +9549,9 @@ Sorry for the inconvenience.";
"Story.ContextDeleteStory" = "Delete Story";
"Story.TooltipPrivacyCloseFriends" = "You are seeing this story because %@ added you\nto their list of Close Friends.";
"Story.TooltipPrivacyContacts" = "Only %@'s contacts can view this story.";
"Story.TooltipPrivacySelectedContacts" = "Only some contacts %@ selected can view this story.";
"Story.TooltipPrivacyCloseFriends" = "You are seeing this story because **%@** added you\nto their list of Close Friends.";
"Story.TooltipPrivacyContacts" = "Only **%@'s** contacts can view this story.";
"Story.TooltipPrivacySelectedContacts" = "Only some contacts **%@** selected can view this story.";
"Story.ToastViewInChat" = "View in Chat";
"Story.ToastReactionSent" = "Reaction Sent.";
@ -9630,8 +9625,7 @@ Sorry for the inconvenience.";
"Story.Editor.ExpirationValue_1" = "1 Hour";
"Story.Editor.ExpirationValue_any" = "%d Hours";
"Story.Editor.TooltipPremiumCustomExpiration" = "Subscribe to **Telegram Premium** to make your stories disappear %@.";
"Story.Editor.TooltipPremiumMore" = "More";
"Story.Editor.TooltipPremiumExpiration" = "Subscribe to **Telegram Premium** to make your stories disappear after 6, 12 or 48 hours.";
"Story.Editor.InputPlaceholderAddCaption" = "Add a caption...";
@ -9699,7 +9693,7 @@ Sorry for the inconvenience.";
"Story.Privacy.CategoryContacts" = "Contacts";
"Story.Privacy.CategoryCloseFriends" = "Close Friends";
"Story.Privacy.CategorySelectedContacts" = "Selected Contacts";
"Story.Privacy.ExcludedPeople" = "ExcludedPeople";
"Story.Privacy.ExcludedPeople" = "Excluded People";
"Story.Privacy.ExcludePeople" = "exclude people";
"Story.Privacy.ExcludePeopleExceptNames" = "except %@";

View File

@ -141,7 +141,7 @@ final class AssetDownloadManager {
} else {
return EmptyDisposable
}
}
} |> runOn(self.queue)
}
}

View File

@ -518,40 +518,45 @@ final class MediaPickerGridItemNode: GridItemNode {
self.currentDraftState = nil
}
var typeIcon: UIImage?
var duration: String?
if asset.isFavorite {
self.typeIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Favorite"), color: .white)
if self.typeIconNode.supernode == nil {
self.addSubnode(self.gradientNode)
self.addSubnode(self.typeIconNode)
self.setNeedsLayout()
typeIcon = generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Favorite"), color: .white)
} else if asset.mediaType == .video {
if asset.mediaSubtypes.contains(.videoHighFrameRate) {
typeIcon = UIImage(bundleImageName: "Media Editor/MediaSlomo")
} else if asset.mediaSubtypes.contains(.videoTimelapse) {
typeIcon = UIImage(bundleImageName: "Media Editor/MediaTimelapse")
} else {
typeIcon = UIImage(bundleImageName: "Media Editor/MediaVideo")
}
duration = stringForDuration(Int32(asset.duration))
}
if asset.mediaType == .video {
if !asset.isFavorite {
if asset.mediaSubtypes.contains(.videoHighFrameRate) {
self.typeIconNode.image = UIImage(bundleImageName: "Media Editor/MediaSlomo")
} else if asset.mediaSubtypes.contains(.videoTimelapse) {
self.typeIconNode.image = UIImage(bundleImageName: "Media Editor/MediaTimelapse")
} else {
self.typeIconNode.image = UIImage(bundleImageName: "Media Editor/MediaVideo")
}
}
self.durationNode.attributedText = NSAttributedString(string: stringForDuration(Int32(asset.duration)), font: Font.semibold(12.0), textColor: .white)
if self.durationNode.supernode == nil {
if typeIcon != nil || duration != nil {
if self.gradientNode.supernode == nil {
self.addSubnode(self.gradientNode)
}
} else if self.gradientNode.supernode != nil {
self.gradientNode.removeFromSupernode()
}
if let typeIcon {
self.typeIconNode.image = typeIcon
if self.typeIconNode.supernode == nil {
self.addSubnode(self.typeIconNode)
}
} else if self.typeIconNode.supernode != nil {
self.typeIconNode.removeFromSupernode()
}
if let duration {
self.durationNode.attributedText = NSAttributedString(string: duration, font: Font.semibold(12.0), textColor: .white)
if self.durationNode.supernode == nil {
self.addSubnode(self.durationNode)
self.setNeedsLayout()
}
} else {
if self.typeIconNode.supernode != nil {
self.gradientNode.removeFromSupernode()
self.typeIconNode.removeFromSupernode()
self.durationNode.removeFromSupernode()
}
} else if self.durationNode.supernode != nil {
self.durationNode.removeFromSupernode()
}
self.currentAssetState = (fetchResult, index)

View File

@ -939,24 +939,6 @@ private final class DemoSheetContent: CombinedComponent {
)
)
)
availableItems[.stories] = DemoPagerComponent.Item(
AnyComponentWithIdentity(
id: PremiumDemoScreen.Subject.stories,
component: AnyComponent(
PageComponent(
content: AnyComponent(PhoneDemoComponent(
context: component.context,
position: .top,
videoFile: configuration.videos["voice_to_text"],
decoration: .badgeStars
)),
title: strings.Premium_Stories,
text: strings.Premium_StoriesInfo,
textColor: textColor
)
)
)
)
var items: [DemoPagerComponent.Item] = component.order.compactMap { availableItems[$0] }
let index: Int
@ -1048,7 +1030,7 @@ private final class DemoSheetContent: CombinedComponent {
case .translation:
buttonText = strings.Premium_Translation_Proceed
case .stories:
buttonText = strings.Premium_Stories_Proceed
buttonText = strings.Common_OK
buttonAnimationName = "premium_unlock"
default:
buttonText = strings.Common_OK

View File

@ -395,7 +395,7 @@ enum PremiumPerk: CaseIterable {
case .translation:
return strings.Premium_Translation
case .stories:
return strings.Premium_Stories
return ""
}
}

View File

@ -3454,7 +3454,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
if hasPremium {
updateTimeout(3600 * 6)
} else {
self?.presentTimeoutPremiumSuggestion(3600 * 6)
self?.presentTimeoutPremiumSuggestion()
}
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Story_Editor_ExpirationValue(12), icon: { theme in
@ -3469,7 +3469,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
if hasPremium {
updateTimeout(3600 * 12)
} else {
self?.presentTimeoutPremiumSuggestion(3600 * 12)
self?.presentTimeoutPremiumSuggestion()
}
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Story_Editor_ExpirationValue(24), icon: { theme in
@ -3491,7 +3491,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
if hasPremium {
updateTimeout(86400 * 2)
} else {
self?.presentTimeoutPremiumSuggestion(86400 * 2)
self?.presentTimeoutPremiumSuggestion()
}
})))
@ -3499,14 +3499,13 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
self.present(contextController, in: .window(.root))
}
private func presentTimeoutPremiumSuggestion(_ timeout: Int32) {
private func presentTimeoutPremiumSuggestion() {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let timeoutString = presentationData.strings.MuteExpires_Hours(max(1, timeout / (60 * 60)))
let text = presentationData.strings.Story_Editor_TooltipPremiumCustomExpiration(timeoutString).string
let text = presentationData.strings.Story_Editor_TooltipPremiumExpiration
let context = self.context
let controller = UndoOverlayController(presentationData: presentationData, content: .autoDelete(isOn: true, title: nil, text: text, customUndoText: presentationData.strings.Story_Editor_TooltipPremiumMore), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak self] action in
let controller = UndoOverlayController(presentationData: presentationData, content: .autoDelete(isOn: true, title: nil, text: text, customUndoText: nil), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak self] action in
if case .undo = action, let self {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .settings)
self.push(controller)

View File

@ -1446,7 +1446,7 @@ final class ShareWithPeersScreenComponent: Component {
case .closeFriends:
title = environment.strings.Story_Privacy_CategoryCloseFriends
case .contacts:
title = environment.strings.Story_Privacy_ExcludePeople
title = environment.strings.Story_Privacy_ExcludedPeople
case .nobody:
title = environment.strings.Story_Privacy_CategorySelectedContacts
case .everyone:

View File

@ -1565,7 +1565,7 @@ final class StoryItemSetContainerSendMessage {
let theme = component.theme
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
let controller = WebAppController(context: component.context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: nil)
controller.openUrl = { [weak self] url in
controller.openUrl = { [weak self] url, _, _ in
guard let self else {
return
}

View File

@ -33,14 +33,72 @@ final class StoryPrivacyIconComponent: Component {
}
final class View: UIImageView {
private let iconView = UIImageView()
private var component: StoryPrivacyIconComponent?
private weak var state: EmptyComponentState?
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(self.iconView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(component: StoryPrivacyIconComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
let previousPrivacy = self.component?.privacy
self.component = component
self.state = state
let colors: [CGColor]
var icon: UIImage?
if let previousPrivacy, previousPrivacy != component.privacy {
let disappearingBackgroundView = UIImageView(image: self.image)
disappearingBackgroundView.frame = self.bounds
self.insertSubview(disappearingBackgroundView, at: 0)
disappearingBackgroundView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak disappearingBackgroundView] _ in
disappearingBackgroundView?.removeFromSuperview()
})
let disappearingIconView = UIImageView(image: self.iconView.image)
disappearingIconView.frame = self.iconView.frame
self.insertSubview(disappearingIconView, belowSubview: self.iconView)
disappearingIconView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak disappearingIconView] _ in
disappearingIconView?.removeFromSuperview()
})
disappearingIconView.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
self.iconView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.iconView.layer.animateScale(from: 0.01, to: 1.0, duration: 0.2)
}
switch component.privacy {
case .everyone:
colors = [UIColor(rgb: 0x4faaff).cgColor, UIColor(rgb: 0x017aff).cgColor]
icon = UIImage(bundleImageName: "Stories/PrivacyEveryone")
case .closeFriends:
colors = [UIColor(rgb: 0x87d93a).cgColor, UIColor(rgb: 0x31b73b).cgColor]
icon = UIImage(bundleImageName: "Stories/PrivacyCloseFriends")
case .contacts:
colors = [UIColor(rgb: 0xc36eff).cgColor, UIColor(rgb: 0x8c61fa).cgColor]
icon = UIImage(bundleImageName: "Stories/PrivacyContacts")
case .selectedContacts:
colors = [UIColor(rgb: 0xffb643).cgColor, UIColor(rgb: 0xf69a36).cgColor]
icon = UIImage(bundleImageName: "Stories/PrivacySelectedContacts")
}
let size = CGSize(width: component.isEditable ? 40.0 : 24.0, height: 24.0)
let iconFrame = CGRect(origin: CGPoint(x: component.isEditable ? 1.0 : 0.0, y: 0.0), size: CGSize(width: size.height, height: size.height))
self.iconView.image = icon
self.iconView.bounds = CGRect(origin: .zero, size: iconFrame.size)
self.iconView.center = iconFrame.center
self.image = generateImage(size, contextGenerator: { size, context in
let bounds = CGRect(origin: .zero, size: size)
context.clear(bounds)
@ -56,32 +114,10 @@ final class StoryPrivacyIconComponent: Component {
context.clip()
var locations: [CGFloat] = [1.0, 0.0]
let colors: [CGColor]
var icon: UIImage?
switch component.privacy {
case .everyone:
colors = [UIColor(rgb: 0x4faaff).cgColor, UIColor(rgb: 0x017aff).cgColor]
icon = UIImage(bundleImageName: "Stories/PrivacyEveryone")
case .closeFriends:
colors = [UIColor(rgb: 0x87d93a).cgColor, UIColor(rgb: 0x31b73b).cgColor]
icon = UIImage(bundleImageName: "Stories/PrivacyCloseFriends")
case .contacts:
colors = [UIColor(rgb: 0xc36eff).cgColor, UIColor(rgb: 0x8c61fa).cgColor]
icon = UIImage(bundleImageName: "Stories/PrivacyContacts")
case .selectedContacts:
colors = [UIColor(rgb: 0xffb643).cgColor, UIColor(rgb: 0xf69a36).cgColor]
icon = UIImage(bundleImageName: "Stories/PrivacySelectedContacts")
}
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
if let icon, let cgImage = icon.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(x: component.isEditable ? 1.0 : 0.0, y: 0.0), size: icon.size))
}
if component.isEditable {
if let arrowIcon = UIImage(bundleImageName: "Stories/PrivacyDownArrow"), let cgImage = arrowIcon.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(x: size.width - arrowIcon.size.width - 6.0, y: floorToScreenPixels((size.height - arrowIcon.size.height) / 2.0)), size: arrowIcon.size))

View File

@ -4214,8 +4214,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: true, fromAttachMenu: false, isInline: false, isSimple: false)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
self?.openUrl(url, concealed: true, forceExternal: true)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
}, getInputContainerNode: { [weak self] in
if let strongSelf = self, let layout = strongSelf.validLayout, case .compact = layout.metrics.widthClass {
return (strongSelf.chatDisplayNode.getWindowInputAccessoryHeight(), strongSelf.chatDisplayNode.inputPanelContainerNode, {
@ -4269,8 +4269,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
let params = WebAppParameters(peerId: peerId, botId: botId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: isInline, isSimple: true)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
self?.openUrl(url, concealed: true, forceExternal: true)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
if let strongSelf = self {
if let chatTypes {
@ -4309,8 +4309,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: false)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
self?.openUrl(url, concealed: true, forceExternal: true)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
}, completion: { [weak self] in
self?.chatDisplayNode.historyNode.scrollToEndOfHistory()
}, getNavigationController: { [weak self] in
@ -4341,7 +4341,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if value {
openWebView()
} else {
let controller = webAppLaunchConfirmationController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: botPeer, commit: {
let controller = webAppLaunchConfirmationController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: botPeer, completion: { _ in
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: botPeer.id).start()
openWebView()
}, showMore: nil)
@ -8837,7 +8837,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] searchResult in
if let strongSelf = self, let (searchResult, searchState, searchLocation) = searchResult {
let controller = ChatSearchResultsController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, location: searchLocation, searchQuery: searchData.query, searchResult: searchResult, searchState: searchState, navigateToMessageIndex: { index in
guard let strongSelf = self else {
return
@ -12948,7 +12947,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.presentAttachmentMenu(subject: .bot(id: botId, payload: payload, justInstalled: justInstalled))
}
public func presentBotApp(botApp: BotApp, botPeer: EnginePeer, payload: String?, concealed: Bool = false) {
public func presentBotApp(botApp: BotApp, botPeer: EnginePeer, payload: String?, concealed: Bool = false, commit: @escaping () -> Void = {}) {
guard let peerId = self.chatLocation.peerId else {
return
}
@ -12958,6 +12957,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self else {
return
}
commit()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
return $0.updatedTitlePanelContext {
if !$0.contains(where: {
@ -13010,8 +13011,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botApp.title, url: url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: false)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
self?.openUrl(url, concealed: true, forceExternal: true)
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
if let strongSelf = self {
if let chatTypes {
@ -13043,19 +13044,29 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}))
}
if concealed || botApp.flags.contains(.notActivated) {
let controller = webAppLaunchConfirmationController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: botPeer, commit: {
let _ = (ApplicationSpecificNotice.getBotGameNotice(accountManager: self.context.sharedContext.accountManager, peerId: botPeer.id)
|> deliverOnMainQueue).start(next: { [weak self] value in
guard let self else {
return
}
if !value || concealed || botApp.flags.contains(.notActivated) {
let context = self.context
let controller = webAppLaunchConfirmationController(context: context, updatedPresentationData: self.updatedPresentationData, peer: botPeer, requestWriteAccess: !botApp.flags.contains(.notActivated) && botApp.flags.contains(.requiresWriteAccess), completion: { allowWrite in
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).start()
openBotApp(allowWrite)
}, showMore: { [weak self] in
if let self {
self.openResolved(result: .peer(botPeer._asPeer(), .info), sourceMessageId: nil)
}
})
self.present(controller, in: .window(.root))
} else {
openBotApp(false)
}, showMore: { [weak self] in
if let strongSelf = self {
strongSelf.openResolved(result: .peer(botPeer._asPeer(), .info), sourceMessageId: nil)
}
})
self.present(controller, in: .window(.root))
} else {
openBotApp(false)
}
}
})
}
private func presentAttachmentPremiumGift() {
@ -13572,8 +13583,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: fromAttachMenu, isInline: false, isSimple: false)
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageId, threadId: strongSelf.chatLocation.threadId)
controller.openUrl = { [weak self] url in
self?.openUrl(url, concealed: true, forceExternal: true)
controller.openUrl = { [weak self] url, concealed, commit in
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
}
controller.getNavigationController = { [weak self] in
return self?.effectiveNavigationController
@ -17400,7 +17411,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}))
}
private func openResolved(result: ResolvedUrl, sourceMessageId: MessageId?, forceExternal: Bool = false, concealed: Bool = false) {
private func openResolved(result: ResolvedUrl, sourceMessageId: MessageId?, forceExternal: Bool = false, concealed: Bool = false, commit: @escaping () -> Void = {}) {
guard let peerId = self.chatLocation.peerId else {
return
}
@ -17409,16 +17420,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
if let currentWebAppController = strongSelf.currentWebAppController {
strongSelf.currentWebAppController = nil
currentWebAppController.dismiss(animated: true, completion: nil)
} else if let currentWebAppController = strongSelf.currentMenuWebAppController {
strongSelf.currentMenuWebAppController = nil
currentWebAppController.dismiss(animated: true, completion: nil)
let dismissWebAppContollers: () -> Void = {
if let currentWebAppController = strongSelf.currentWebAppController {
strongSelf.currentWebAppController = nil
currentWebAppController.dismiss(animated: true, completion: nil)
} else if let currentWebAppController = strongSelf.currentMenuWebAppController {
strongSelf.currentMenuWebAppController = nil
currentWebAppController.dismiss(animated: true, completion: nil)
}
}
switch navigation {
case let .chat(_, subject, peekData):
dismissWebAppContollers()
if case .peer(peerId.id) = strongSelf.chatLocation {
if let subject = subject, case let .message(messageSubject, _, timecode) = subject {
if case let .id(messageId) = messageSubject {
@ -17434,31 +17448,41 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject, keepStack: .always, peekData: peekData))
}
}
commit()
case .info:
dismissWebAppContollers()
strongSelf.navigationActionDisposable.set((strongSelf.context.account.postbox.loadedPeerWithId(peerId.id)
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] peer in
if let strongSelf = self, peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil {
if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
strongSelf.effectiveNavigationController?.pushViewController(infoController)
}
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] peer in
if let strongSelf = self, peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil {
if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
strongSelf.effectiveNavigationController?.pushViewController(infoController)
}
}))
}
}))
commit()
case let .withBotStartPayload(startPayload):
dismissWebAppContollers()
if case .peer(peerId.id) = strongSelf.chatLocation {
strongSelf.startBot(startPayload.payload)
} else if let navigationController = strongSelf.effectiveNavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), botStart: startPayload, keepStack: .always))
}
commit()
case let .withAttachBot(attachBotStart):
dismissWebAppContollers()
if let navigationController = strongSelf.effectiveNavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), attachBotStart: attachBotStart))
}
commit()
case let .withBotApp(botAppStart):
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId.id))
|> deliverOnMainQueue).start(next: { [weak self] peer in
if let strongSelf = self, let peer {
strongSelf.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, concealed: concealed)
strongSelf.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, concealed: concealed, commit: {
dismissWebAppContollers()
commit()
})
}
})
default:
@ -17483,14 +17507,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}, contentContext: nil)
}
private func openUrl(_ url: String, concealed: Bool, forceExternal: Bool = false, skipUrlAuth: Bool = false, skipConcealedAlert: Bool = false, message: Message? = nil) {
private func openUrl(_ url: String, concealed: Bool, forceExternal: Bool = false, skipUrlAuth: Bool = false, skipConcealedAlert: Bool = false, message: Message? = nil, commit: @escaping () -> Void = {}) {
self.commitPurposefulAction()
let _ = self.presentVoiceMessageDiscardAlert(action: {
openUserGeneratedUrl(context: self.context, peerId: self.peerView?.peerId, url: url, concealed: concealed, skipUrlAuth: skipUrlAuth, skipConcealedAlert: skipConcealedAlert, present: { [weak self] c in
self?.present(c, in: .window(.root))
}, openResolved: { [weak self] resolved in
self?.openResolved(result: resolved, sourceMessageId: message?.id, forceExternal: forceExternal, concealed: concealed)
self?.openResolved(result: resolved, sourceMessageId: message?.id, forceExternal: forceExternal, concealed: concealed, commit: commit)
})
}, performAction: true)
}

View File

@ -1420,7 +1420,7 @@ private final class CallDirectConnectionImpl: NSObject, OngoingCallDirectConnect
self.connection?.receiveMessage(completion: { [weak self] data, _, _, error in
assert(queue.isCurrent())
guard let self else {
guard let `self` = self else {
return
}

View File

@ -148,11 +148,20 @@ public func canTranslateText(context: AccountContext, text: String, showTranslat
return (true, nil)
}
var dontTranslateLanguages: [String] = []
var baseLang = context.sharedContext.currentPresentationData.with { $0 }.strings.baseLanguageCode
let rawSuffix = "-raw"
if baseLang.hasSuffix(rawSuffix) {
baseLang = String(baseLang.dropLast(rawSuffix.count))
}
var dontTranslateLanguages = Set<String>()
if let ignoredLanguages = ignoredLanguages {
dontTranslateLanguages = ignoredLanguages
dontTranslateLanguages = Set(ignoredLanguages)
} else {
dontTranslateLanguages = [context.sharedContext.currentPresentationData.with { $0 }.strings.baseLanguageCode]
dontTranslateLanguages.insert(baseLang)
for language in systemLanguageCodes() {
dontTranslateLanguages.insert(language)
}
}
let text = String(text.prefix(64))

View File

@ -30,6 +30,8 @@ swift_library(
"//submodules/PhoneNumberFormat:PhoneNumberFormat",
"//submodules/QrCodeUI:QrCodeUI",
"//submodules/InstantPageUI:InstantPageUI",
"//submodules/CheckNode:CheckNode",
"//submodules/Markdown:Markdown",
],
visibility = [
"//visibility:public",

View File

@ -20,7 +20,6 @@ private func formattedText(_ text: String, color: UIColor, textAlignment: NSText
return parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: color), bold: MarkdownAttributeSet(font: boldTextFont, textColor: color), link: MarkdownAttributeSet(font: textFont, textColor: color), linkAttribute: { _ in return nil}), textAlignment: textAlignment)
}
private final class WebAppAlertContentNode: AlertContentNode {
private let strings: PresentationStrings
private let peerName: String
@ -312,22 +311,24 @@ public func addWebAppToAttachmentController(context: AccountContext, peerName: S
let strings = presentationData.strings
var dismissImpl: ((Bool) -> Void)?
var contentNode: WebAppAlertContentNode?
var getContentNodeImpl: (() -> WebAppAlertContentNode?)?
let actions: [TextAlertAction] = [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
dismissImpl?(true)
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.WebApp_AddToAttachmentAdd, action: { [weak contentNode] in
dismissImpl?(true)
if requestWriteAccess, let allowWriteAccess = contentNode?.allowWriteAccess {
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.WebApp_AddToAttachmentAdd, action: {
if requestWriteAccess, let allowWriteAccess = getContentNodeImpl?()?.allowWriteAccess {
completion(allowWriteAccess)
} else {
completion(false)
}
dismissImpl?(true)
})]
contentNode = WebAppAlertContentNode(account: context.account, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, peerName: peerName, icons: icons, requestWriteAccess: requestWriteAccess, actions: actions)
let contentNode = WebAppAlertContentNode(account: context.account, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, peerName: peerName, icons: icons, requestWriteAccess: requestWriteAccess, actions: actions)
getContentNodeImpl = { [weak contentNode] in
return contentNode
}
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode!)
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
dismissImpl = { [weak controller] animated in
if animated {
controller?.dismissAnimated()

View File

@ -458,7 +458,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
if let url = navigationAction.request.url?.absoluteString {
if isTelegramMeLink(url) || isTelegraPhLink(url) {
decisionHandler(.cancel)
self.controller?.openUrl(url)
self.controller?.openUrl(url, true, {})
} else {
decisionHandler(.allow)
}
@ -469,7 +469,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil, let url = navigationAction.request.url {
self.controller?.openUrl(url.absoluteString)
self.controller?.openUrl(url.absoluteString, true, {})
}
return nil
}
@ -714,8 +714,9 @@ public final class WebAppController: ViewController, AttachmentContainable {
controller.dismiss()
case "web_app_open_tg_link":
if let json = json, let path = json["path_full"] as? String {
controller.openUrl("https://t.me\(path)")
controller.dismiss()
controller.openUrl("https://t.me\(path)", false, { [weak controller] in
controller?.dismiss()
})
}
case "web_app_open_invoice":
if let json = json, let slug = json["slug"] as? String {
@ -1095,7 +1096,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
fileprivate let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
private var presentationDataDisposable: Disposable?
public var openUrl: (String) -> Void = { _ in }
public var openUrl: (String, Bool, @escaping () -> Void) -> Void = { _, _, _ in }
public var getNavigationController: () -> NavigationController? = { return nil }
public var completion: () -> Void = {}
public var requestSwitchInline: (String, [ReplyMarkupButtonRequestPeerType]?, @escaping () -> Void) -> Void = { _, _, _ in }
@ -1394,7 +1395,19 @@ private final class WebAppContextReferenceContentSource: ContextReferenceContent
}
}
public func standaloneWebAppController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, params: WebAppParameters, threadId: Int64?, openUrl: @escaping (String) -> Void, requestSwitchInline: @escaping (String, [ReplyMarkupButtonRequestPeerType]?, @escaping () -> Void) -> Void = { _, _, _ in }, getInputContainerNode: @escaping () -> (CGFloat, ASDisplayNode, () -> AttachmentController.InputPanelTransition?)? = { return nil }, completion: @escaping () -> Void = {}, willDismiss: @escaping () -> Void = {}, didDismiss: @escaping () -> Void = {}, getNavigationController: @escaping () -> NavigationController? = { return nil }, getSourceRect: (() -> CGRect?)? = nil) -> ViewController {
public func standaloneWebAppController(
context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
params: WebAppParameters,
threadId: Int64?,
openUrl: @escaping (String, Bool, @escaping () -> Void) -> Void,
requestSwitchInline: @escaping (String, [ReplyMarkupButtonRequestPeerType]?, @escaping () -> Void) -> Void = { _, _, _ in },
getInputContainerNode: @escaping () -> (CGFloat, ASDisplayNode, () -> AttachmentController.InputPanelTransition?)? = { return nil },
completion: @escaping () -> Void = {},
willDismiss: @escaping () -> Void = {},
didDismiss: @escaping () -> Void = {},
getNavigationController: @escaping () -> NavigationController? = { return nil },
getSourceRect: (() -> CGRect?)? = nil) -> ViewController {
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: .peer(id: params.peerId), buttons: [.standalone], initialButton: .standalone, fromMenu: params.fromMenu, hasTextInput: false, makeEntityInputView: {
return nil
})

View File

@ -10,9 +10,19 @@ import TelegramUIPreferences
import AccountContext
import AppBundle
import AvatarNode
import CheckNode
import Markdown
private let textFont = Font.regular(13.0)
private let boldTextFont = Font.semibold(13.0)
private func formattedText(_ text: String, color: UIColor, textAlignment: NSTextAlignment = .natural) -> NSAttributedString {
return parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: color), bold: MarkdownAttributeSet(font: boldTextFont, textColor: color), link: MarkdownAttributeSet(font: textFont, textColor: color), linkAttribute: { _ in return nil}), textAlignment: textAlignment)
}
private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
private let strings: PresentationStrings
private let peer: EnginePeer
private let title: String
private let text: String
private let showMore: Bool
@ -24,6 +34,9 @@ private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
private let moreButton: HighlightableButtonNode
private let arrowNode: ASImageNode
private let allowWriteCheckNode: InteractiveCheckNode
private let allowWriteLabelNode: ASTextNode
private let actionNodesSeparator: ASDisplayNode
private let actionNodes: [TextAlertContentActionNode]
private let actionVerticalSeparators: [ASDisplayNode]
@ -36,8 +49,15 @@ private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
return self.isUserInteractionEnabled
}
init(context: AccountContext, theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, peer: EnginePeer, title: String, text: String, showMore: Bool, actions: [TextAlertAction], morePressed: @escaping () -> Void) {
var allowWriteAccess: Bool = true {
didSet {
self.allowWriteCheckNode.setSelected(self.allowWriteAccess, animated: true)
}
}
init(context: AccountContext, theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, peer: EnginePeer, title: String, text: String, showMore: Bool, requestWriteAccess: Bool, actions: [TextAlertAction], morePressed: @escaping () -> Void) {
self.strings = strings
self.peer = peer
self.title = title
self.text = text
self.showMore = showMore
@ -62,6 +82,12 @@ private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
self.arrowNode.isHidden = !showMore
self.arrowNode.contentMode = .scaleAspectFit
self.allowWriteCheckNode = InteractiveCheckNode(theme: CheckNodeTheme(backgroundColor: theme.accentColor, strokeColor: theme.contrastColor, borderColor: theme.controlBorderColor, overlayBorder: false, hasInset: false, hasShadow: false))
self.allowWriteCheckNode.setSelected(true, animated: false)
self.allowWriteLabelNode = ASTextNode()
self.allowWriteLabelNode.maximumNumberOfLines = 4
self.allowWriteLabelNode.isUserInteractionEnabled = true
self.actionNodesSeparator = ASDisplayNode()
self.actionNodesSeparator.isLayerBacked = true
@ -86,6 +112,11 @@ private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
self.addSubnode(self.avatarNode)
self.addSubnode(self.moreButton)
self.moreButton.addSubnode(self.arrowNode)
if requestWriteAccess {
self.addSubnode(self.allowWriteCheckNode)
self.addSubnode(self.allowWriteLabelNode)
}
self.addSubnode(self.actionNodesSeparator)
@ -97,6 +128,12 @@ private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
self.addSubnode(separatorNode)
}
self.allowWriteCheckNode.valueChanged = { [weak self] value in
if let strongSelf = self {
strongSelf.allowWriteAccess = !strongSelf.allowWriteAccess
}
}
self.updateTheme(theme)
self.avatarNode.setPeer(context: context, theme: ptheme, peer: peer)
@ -104,6 +141,18 @@ private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
self.moreButton.addTarget(self, action: #selector(self.moreButtonPressed), forControlEvents: .touchUpInside)
}
override func didLoad() {
super.didLoad()
self.allowWriteLabelNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.allowWriteTap(_:))))
}
@objc private func allowWriteTap(_ gestureRecognizer: UITapGestureRecognizer) {
if self.allowWriteCheckNode.isUserInteractionEnabled {
self.allowWriteAccess = !self.allowWriteAccess
}
}
@objc private func moreButtonPressed() {
self.morePressed()
}
@ -115,6 +164,8 @@ private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
self.moreButton.setAttributedTitle(NSAttributedString(string: self.strings.WebApp_LaunchMoreInfo, font: Font.regular(13.0), textColor: theme.accentColor), for: .normal)
self.arrowNode.image = generateTintedImage(image: UIImage(bundleImageName: "Peer Info/AlertArrow"), color: theme.accentColor)
self.allowWriteLabelNode.attributedText = formattedText(strings.WebApp_AddToAttachmentAllowMessages(self.peer.compactDisplayTitle).string, color: theme.primaryColor)
self.actionNodesSeparator.backgroundColor = theme.separatorColor
for actionNode in self.actionNodes {
actionNode.updateTheme(theme)
@ -153,15 +204,32 @@ private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: origin.y), size: titleSize))
origin.y += titleSize.height + 6.0
var entriesHeight: CGFloat = 0.0
if self.showMore {
let moreButtonSize = self.moreButton.measure(CGSize(width: size.width - 32.0, height: size.height))
transition.updateFrame(node: self.moreButton, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - moreButtonSize.width) / 2.0) - 5.0, y: origin.y), size: moreButtonSize))
transition.updateFrame(node: self.arrowNode, frame: CGRect(origin: CGPoint(x: moreButtonSize.width + 3.0, y: 4.0), size: CGSize(width: 9.0, height: 9.0)))
origin.y += moreButtonSize.height + 22.0
entriesHeight += 37.0
}
let textSize = self.textNode.measure(CGSize(width: size.width - 32.0, height: size.height))
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize))
origin.y += textSize.height
if self.allowWriteLabelNode.supernode != nil {
origin.y += 16.0
entriesHeight += 16.0
let checkSize = CGSize(width: 22.0, height: 22.0)
let condensedSize = CGSize(width: size.width - 76.0, height: size.height)
let allowWriteSize = self.allowWriteLabelNode.measure(condensedSize)
transition.updateFrame(node: self.allowWriteLabelNode, frame: CGRect(origin: CGPoint(x: 46.0, y: origin.y), size: allowWriteSize))
transition.updateFrame(node: self.allowWriteCheckNode, frame: CGRect(origin: CGPoint(x: 12.0, y: origin.y - 2.0), size: checkSize))
origin.y += allowWriteSize.height
entriesHeight += allowWriteSize.height
}
let actionButtonHeight: CGFloat = 44.0
var minActionsWidth: CGFloat = 0.0
@ -194,10 +262,7 @@ private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count)
}
var resultSize = CGSize(width: contentWidth, height: avatarSize.height + titleSize.height + textSize.height + actionsHeight + 25.0 + insets.top + insets.bottom)
if self.showMore {
resultSize.height += 37.0
}
let resultSize = CGSize(width: contentWidth, height: avatarSize.height + titleSize.height + textSize.height + entriesHeight + actionsHeight + 25.0 + insets.top + insets.bottom)
transition.updateFrame(node: self.actionNodesSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
@ -248,7 +313,7 @@ private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
}
}
public func webAppLaunchConfirmationController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peer: EnginePeer, commit: @escaping () -> Void, showMore: (() -> Void)?) -> AlertController {
public func webAppLaunchConfirmationController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peer: EnginePeer, requestWriteAccess: Bool = false, completion: @escaping (Bool) -> Void, showMore: (() -> Void)?) -> AlertController {
let theme = defaultDarkColorPresentationTheme
let presentationData: PresentationData
if let updatedPresentationData {
@ -259,10 +324,14 @@ public func webAppLaunchConfirmationController(context: AccountContext, updatedP
let strings = presentationData.strings
var dismissImpl: ((Bool) -> Void)?
var contentNode: WebAppLaunchConfirmationAlertContentNode?
var getContentNodeImpl: (() -> WebAppLaunchConfirmationAlertContentNode?)?
let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: presentationData.strings.WebApp_LaunchOpenApp, action: {
if requestWriteAccess, let allowWriteAccess = getContentNodeImpl?()?.allowWriteAccess {
completion(allowWriteAccess)
} else {
completion(false)
}
dismissImpl?(true)
commit()
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
dismissImpl?(true)
})]
@ -270,12 +339,15 @@ public func webAppLaunchConfirmationController(context: AccountContext, updatedP
let title = peer.compactDisplayTitle
let text = presentationData.strings.WebApp_LaunchConfirmation
contentNode = WebAppLaunchConfirmationAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, peer: peer, title: title, text: text, showMore: showMore != nil, actions: actions, morePressed: {
let contentNode = WebAppLaunchConfirmationAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, peer: peer, title: title, text: text, showMore: showMore != nil, requestWriteAccess: requestWriteAccess, actions: actions, morePressed: {
dismissImpl?(true)
showMore?()
})
getContentNodeImpl = { [weak contentNode] in
return contentNode
}
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode!)
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
dismissImpl = { [weak controller] animated in
if animated {
controller?.dismissAnimated()