From 1c817881b5c3e0c26f953641a813148e46356c2e Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 18 Jul 2023 23:22:37 +0200 Subject: [PATCH 1/6] Fix localization --- Telegram/Telegram-iOS/en.lproj/Localizable.strings | 2 +- .../ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 8481a453da..ac2ad35005 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -9698,7 +9698,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 %@"; diff --git a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift index a94bb8f429..534fd87bf8 100644 --- a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift +++ b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift @@ -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: From b06ce15f546419e0d8f88c5b14f451b203831e8e Mon Sep 17 00:00:00 2001 From: Mike Renoir <> Date: Wed, 19 Jul 2023 12:16:20 +0200 Subject: [PATCH 2/6] fix syntax --- submodules/TelegramVoip/Sources/OngoingCallContext.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TelegramVoip/Sources/OngoingCallContext.swift b/submodules/TelegramVoip/Sources/OngoingCallContext.swift index 2bc04aad92..1c1270e8c9 100644 --- a/submodules/TelegramVoip/Sources/OngoingCallContext.swift +++ b/submodules/TelegramVoip/Sources/OngoingCallContext.swift @@ -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 } From a5d5a34d1b1af9dae7a2fedcad3596c53e3112c3 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 19 Jul 2023 16:45:01 +0200 Subject: [PATCH 3/6] Various fixes --- .../MediaPickerUI/Sources/FetchAssets.swift | 2 +- .../Sources/MediaPickerGridItem.swift | 57 ++++++++++--------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/submodules/MediaPickerUI/Sources/FetchAssets.swift b/submodules/MediaPickerUI/Sources/FetchAssets.swift index d9610f1272..95878b87bc 100644 --- a/submodules/MediaPickerUI/Sources/FetchAssets.swift +++ b/submodules/MediaPickerUI/Sources/FetchAssets.swift @@ -141,7 +141,7 @@ final class AssetDownloadManager { } else { return EmptyDisposable } - } + } |> runOn(self.queue) } } diff --git a/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift b/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift index 678469b125..29beed3d71 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift @@ -516,40 +516,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) From f35d5ff3f50b0889606bcc926687b976192d7036 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 19 Jul 2023 20:54:01 +0200 Subject: [PATCH 4/6] Fix bot app launch --- ...StoryItemSetContainerViewSendMessage.swift | 2 +- .../TelegramUI/Sources/ChatController.swift | 108 +++++++++++------- submodules/WebUI/BUILD | 2 + .../Sources/WebAppAlertContentNode.swift | 17 +-- .../WebUI/Sources/WebAppController.swift | 25 +++- ... WebAppLaunchConfirmationController.swift} | 92 +++++++++++++-- 6 files changed, 179 insertions(+), 67 deletions(-) rename submodules/WebUI/Sources/{WebAppOpenConfirmationController.swift => WebAppLaunchConfirmationController.swift} (73%) diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift index 877381838c..794a1f806f 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift @@ -1565,7 +1565,7 @@ final class StoryItemSetContainerSendMessage { let theme = component.theme let updatedPresentationData: (initial: PresentationData, signal: Signal) = (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 } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index b50bdcca37..b1fa575d70 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -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) } diff --git a/submodules/WebUI/BUILD b/submodules/WebUI/BUILD index 8f10d3c0a4..ef88a3e302 100644 --- a/submodules/WebUI/BUILD +++ b/submodules/WebUI/BUILD @@ -30,6 +30,8 @@ swift_library( "//submodules/PhoneNumberFormat:PhoneNumberFormat", "//submodules/QrCodeUI:QrCodeUI", "//submodules/InstantPageUI:InstantPageUI", + "//submodules/CheckNode:CheckNode", + "//submodules/Markdown:Markdown", ], visibility = [ "//visibility:public", diff --git a/submodules/WebUI/Sources/WebAppAlertContentNode.swift b/submodules/WebUI/Sources/WebAppAlertContentNode.swift index a3da723cdd..76c1633354 100644 --- a/submodules/WebUI/Sources/WebAppAlertContentNode.swift +++ b/submodules/WebUI/Sources/WebAppAlertContentNode.swift @@ -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() diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index f6b4df4f4c..8c866d11e1 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -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)? 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)? = 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)? = 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 }) diff --git a/submodules/WebUI/Sources/WebAppOpenConfirmationController.swift b/submodules/WebUI/Sources/WebAppLaunchConfirmationController.swift similarity index 73% rename from submodules/WebUI/Sources/WebAppOpenConfirmationController.swift rename to submodules/WebUI/Sources/WebAppLaunchConfirmationController.swift index 9ff23dd120..85550aadf3 100644 --- a/submodules/WebUI/Sources/WebAppOpenConfirmationController.swift +++ b/submodules/WebUI/Sources/WebAppLaunchConfirmationController.swift @@ -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)?, peer: EnginePeer, commit: @escaping () -> Void, showMore: (() -> Void)?) -> AlertController { +public func webAppLaunchConfirmationController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)?, 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() From 6fdd2ebf0dfe66e79a6448dd06d82ca7f37b12bc Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 19 Jul 2023 22:16:13 +0200 Subject: [PATCH 5/6] Various fixes --- .../Telegram-iOS/en.lproj/Localizable.strings | 9 ++++----- .../Sources/MediaEditorScreen.swift | 13 ++++++------- submodules/TranslateUI/Sources/Translate.swift | 15 ++++++++++++--- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index ac2ad35005..7be547efa2 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -9552,9 +9552,9 @@ Sorry for the inconvenience."; "Story.ContextDeleteStory" = "Delete Story"; -"Story.TooltipPrivacyCloseFriends" = "You are seeing this story because you have\nbeen added to %@'s 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 you have\nbeen added to **%@'s** 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."; @@ -9629,8 +9629,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..."; diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index d799c6d0e5..7624f578ef 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -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) diff --git a/submodules/TranslateUI/Sources/Translate.swift b/submodules/TranslateUI/Sources/Translate.swift index 5a70f375ce..5b52b36413 100644 --- a/submodules/TranslateUI/Sources/Translate.swift +++ b/submodules/TranslateUI/Sources/Translate.swift @@ -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() 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)) From 2aeeaaee445f98a39b1da203a266aec063cc02ae Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 20 Jul 2023 01:08:04 +0200 Subject: [PATCH 6/6] Various improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 4 - .../PremiumUI/Sources/PremiumDemoScreen.swift | 20 +---- .../Sources/PremiumIntroScreen.swift | 2 +- .../Sources/StoryPrivacyIconComponent.swift | 82 +++++++++++++------ 4 files changed, 61 insertions(+), 47 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 7be547efa2..f7e28535f6 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -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"; diff --git a/submodules/PremiumUI/Sources/PremiumDemoScreen.swift b/submodules/PremiumUI/Sources/PremiumDemoScreen.swift index b2afa7ae51..8890b9e757 100644 --- a/submodules/PremiumUI/Sources/PremiumDemoScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumDemoScreen.swift @@ -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 diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index f3bd80a70a..5e66a39116 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -395,7 +395,7 @@ enum PremiumPerk: CaseIterable { case .translation: return strings.Premium_Translation case .stories: - return strings.Premium_Stories + return "" } } diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryPrivacyIconComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryPrivacyIconComponent.swift index fa886bfa5d..025e35588a 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryPrivacyIconComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryPrivacyIconComponent.swift @@ -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, 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))