diff --git a/submodules/ChatListUI/Sources/ChatContextMenus.swift b/submodules/ChatListUI/Sources/ChatContextMenus.swift index 6c2a6cea0e..f4449a4f4b 100644 --- a/submodules/ChatListUI/Sources/ChatContextMenus.swift +++ b/submodules/ChatListUI/Sources/ChatContextMenus.swift @@ -735,27 +735,29 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId: } }))) - var canOpenClose = false - if channel.flags.contains(.isCreator) { - canOpenClose = true - } else if channel.hasPermission(.manageTopics) { - canOpenClose = true - } else if threadData.isOwnedByMe { - canOpenClose = true - } - if canOpenClose { - items.append(.action(ContextMenuActionItem(text: threadData.isClosed ? presentationData.strings.ChatList_Context_ReopenTopic : presentationData.strings.ChatList_Context_CloseTopic, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: threadData.isClosed ? "Chat/Context Menu/Play": "Chat/Context Menu/Pause"), color: theme.contextMenu.primaryColor) }, action: { _, f in - f(.default) - - let _ = context.engine.peers.setForumChannelTopicClosed(id: peerId, threadId: threadId, isClosed: !threadData.isClosed).start() - }))) - } - if channel.hasPermission(.deleteAllMessages) { - items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak chatListController] _, f in - f(.default) - - chatListController?.deletePeerThread(peerId: peerId, threadId: threadId) - }))) + if threadId != 1 { + var canOpenClose = false + if channel.flags.contains(.isCreator) { + canOpenClose = true + } else if channel.hasPermission(.manageTopics) { + canOpenClose = true + } else if threadData.isOwnedByMe { + canOpenClose = true + } + if canOpenClose { + items.append(.action(ContextMenuActionItem(text: threadData.isClosed ? presentationData.strings.ChatList_Context_ReopenTopic : presentationData.strings.ChatList_Context_CloseTopic, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: threadData.isClosed ? "Chat/Context Menu/Play": "Chat/Context Menu/Pause"), color: theme.contextMenu.primaryColor) }, action: { _, f in + f(.default) + + let _ = context.engine.peers.setForumChannelTopicClosed(id: peerId, threadId: threadId, isClosed: !threadData.isClosed).start() + }))) + } + if channel.hasPermission(.deleteAllMessages) { + items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak chatListController] _, f in + f(.default) + + chatListController?.deletePeerThread(peerId: peerId, threadId: threadId) + }))) + } } items.append(.separator) diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 680261df3b..c8bf77ef63 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -333,7 +333,30 @@ private func groupReferenceRevealOptions(strings: PresentationStrings, theme: Pr return options } -private func forumRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isMuted: Bool?, isClosed: Bool, isPinned: Bool, isEditing: Bool, canPin: Bool, canOpenClose: Bool, canDelete: Bool) -> [ItemListRevealOption] { +private func forumGeneralRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isMuted: Bool?, isEditing: Bool, canHide: Bool, hiddenByDefault: Bool) -> [ItemListRevealOption] { + var options: [ItemListRevealOption] = [] + if !isEditing { + if let isMuted = isMuted { + if isMuted { + options.append(ItemListRevealOption(key: RevealOptionKey.unmute.rawValue, title: strings.ChatList_Unmute, icon: unmuteIcon, color: theme.list.itemDisclosureActions.neutral2.fillColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor)) + } else { + options.append(ItemListRevealOption(key: RevealOptionKey.mute.rawValue, title: strings.ChatList_Mute, icon: muteIcon, color: theme.list.itemDisclosureActions.neutral2.fillColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor)) + } + } + } + if canHide { + if !isEditing { + if hiddenByDefault { + options.append(ItemListRevealOption(key: RevealOptionKey.unhide.rawValue, title: strings.ChatList_UnhideAction, icon: unhideIcon, color: theme.list.itemDisclosureActions.constructive.fillColor, textColor: theme.list.itemDisclosureActions.constructive.foregroundColor)) + } else { + options.append(ItemListRevealOption(key: RevealOptionKey.hide.rawValue, title: strings.ChatList_HideAction, icon: hideIcon, color: theme.list.itemDisclosureActions.inactive.fillColor, textColor: theme.list.itemDisclosureActions.neutral1.foregroundColor)) + } + } + } + return options +} + +private func forumThreadRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isMuted: Bool?, isClosed: Bool, isEditing: Bool, canOpenClose: Bool, canDelete: Bool) -> [ItemListRevealOption] { var options: [ItemListRevealOption] = [] if !isEditing { if let isMuted = isMuted { @@ -2178,20 +2201,24 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { if item.enableContextActions { if case .forum = item.chatListLocation { if case let .chat(itemPeer) = contentPeer, case let .channel(channel) = itemPeer.peer { - var canOpenClose = false - if channel.flags.contains(.isCreator) { - canOpenClose = true - } else if channel.hasPermission(.manageTopics) { - canOpenClose = true - } else if let threadInfo = threadInfo, threadInfo.isOwnedByMe { - canOpenClose = true + if let threadInfo, threadInfo.id == 1 { + peerRevealOptions = forumGeneralRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isMuted: (currentMutedIconImage != nil), isEditing: item.editing, canHide: channel.flags.contains(.isCreator) || channel.hasPermission(.pinMessages), hiddenByDefault: false) + } else { + var canOpenClose = false + if channel.flags.contains(.isCreator) { + canOpenClose = true + } else if channel.hasPermission(.manageTopics) { + canOpenClose = true + } else if let threadInfo = threadInfo, threadInfo.isOwnedByMe { + canOpenClose = true + } + let canDelete = channel.hasPermission(.deleteAllMessages) + var isClosed = false + if let threadInfo { + isClosed = threadInfo.isClosed + } + peerRevealOptions = forumThreadRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isMuted: (currentMutedIconImage != nil), isClosed: isClosed, isEditing: item.editing, canOpenClose: canOpenClose, canDelete: canDelete) } - let canDelete = channel.hasPermission(.deleteAllMessages) - var isClosed = false - if let threadInfo { - isClosed = threadInfo.isClosed - } - peerRevealOptions = forumRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isMuted: (currentMutedIconImage != nil), isClosed: isClosed, isPinned: isPinned, isEditing: item.editing, canPin: channel.flags.contains(.isCreator) || channel.hasPermission(.pinMessages), canOpenClose: canOpenClose, canDelete: canDelete) peerLeftRevealOptions = [] } else { peerRevealOptions = [] diff --git a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift index 79addadc0c..63beac8e35 100644 --- a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift @@ -1130,7 +1130,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { let (canTranslate, language) = canTranslateText(context: context, text: text, showTranslate: translationSettings.showTranslate, showTranslateIfTopical: false, ignoredLanguages: translationSettings.ignoredLanguages) if canTranslate { actions.append(ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuTranslate, accessibilityLabel: strings.Conversation_ContextMenuTranslate), action: { [weak self] in - let controller = TranslateScreen(context: context, text: text, fromLanguage: language) + let controller = TranslateScreen(context: context, text: text, canCopy: true, fromLanguage: language) controller.pushController = { [weak self] c in (self?.controller?.navigationController as? NavigationController)?._keepModalDismissProgress = true self?.controller?.push(c) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/AppStore.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/AppStore.swift index 2da50b9aef..2038043834 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/AppStore.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/AppStore.swift @@ -90,7 +90,7 @@ func _internal_canPurchasePremium(account: Account, purpose: AppStoreTransaction } } |> `catch` { _ -> Signal in - return.single(false) + return .single(false) } } } diff --git a/submodules/TelegramUI/Components/AudioTranscriptionButtonComponent/Sources/AudioTranscriptionButtonComponent.swift b/submodules/TelegramUI/Components/AudioTranscriptionButtonComponent/Sources/AudioTranscriptionButtonComponent.swift index a5bdc906ea..ad955e5fb7 100644 --- a/submodules/TelegramUI/Components/AudioTranscriptionButtonComponent/Sources/AudioTranscriptionButtonComponent.swift +++ b/submodules/TelegramUI/Components/AudioTranscriptionButtonComponent/Sources/AudioTranscriptionButtonComponent.swift @@ -16,8 +16,8 @@ public final class AudioTranscriptionButtonComponent: Component { } else { return false } - case let .freeform(lhsFreeform): - if case let .freeform(rhsFreeform) = rhs, lhsFreeform == rhsFreeform { + case let .freeform(lhsFreeform, lhsForeground): + if case let .freeform(rhsFreeform, rhsForeground) = rhs, lhsFreeform == rhsFreeform, lhsForeground == rhsForeground { return true } else { return false @@ -26,7 +26,7 @@ public final class AudioTranscriptionButtonComponent: Component { } case bubble(PresentationThemePartedColors) - case freeform((UIColor, Bool)) + case freeform((UIColor, Bool), UIColor) } public enum TranscriptionState { @@ -103,8 +103,8 @@ public final class AudioTranscriptionButtonComponent: Component { case let .bubble(theme): foregroundColor = theme.bubble.withWallpaper.reactionActiveBackground backgroundColor = theme.bubble.withWallpaper.reactionInactiveBackground - case let .freeform(colorAndBlur): - foregroundColor = UIColor.white + case let .freeform(colorAndBlur, color): + foregroundColor = color backgroundColor = .clear if self.blurredBackgroundNode.view.superview == nil { self.insertSubview(self.blurredBackgroundNode.view, at: 0) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 760511f172..08118cd00f 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3441,7 +3441,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) }, delay: true) } - }, performTextSelectionAction: { [weak self] _, text, action in + }, performTextSelectionAction: { [weak self] canCopy, text, action in guard let strongSelf = self else { return } @@ -3493,7 +3493,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let (_, language) = canTranslateText(context: context, text: text.string, showTranslate: translationSettings.showTranslate, showTranslateIfTopical: showTranslateIfTopical, ignoredLanguages: translationSettings.ignoredLanguages) - let controller = TranslateScreen(context: context, text: text.string, fromLanguage: language) + let controller = TranslateScreen(context: context, text: text.string, canCopy: canCopy, fromLanguage: language) controller.pushController = { [weak self] c in self?.effectiveNavigationController?._keepModalDismissProgress = true self?.push(c) diff --git a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift index e67a55c530..1d91664249 100644 --- a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift @@ -117,7 +117,7 @@ public final class ChatControllerInteraction { let scheduleCurrentMessage: () -> Void let sendScheduledMessagesNow: ([MessageId]) -> Void let editScheduledMessagesTime: ([MessageId]) -> Void - let performTextSelectionAction: (UInt32, NSAttributedString, TextSelectionAction) -> Void + let performTextSelectionAction: (Bool, NSAttributedString, TextSelectionAction) -> Void let displayImportedMessageTooltip: (ASDisplayNode) -> Void let displaySwipeToReplyHint: () -> Void let dismissReplyMarkupMessage: (Message) -> Void @@ -226,7 +226,7 @@ public final class ChatControllerInteraction { scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, - performTextSelectionAction: @escaping (UInt32, NSAttributedString, TextSelectionAction) -> Void, + performTextSelectionAction: @escaping (Bool, NSAttributedString, TextSelectionAction) -> Void, displayImportedMessageTooltip: @escaping (ASDisplayNode) -> Void, displaySwipeToReplyHint: @escaping () -> Void, dismissReplyMarkupMessage: @escaping (Message) -> Void, diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 12944a3aa2..4b75f4403a 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -1059,7 +1059,8 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState } } - if (!messageText.isEmpty || resourceAvailable || diceEmoji != nil) && !chatPresentationInterfaceState.copyProtectionEnabled && !message.isCopyProtected() { + if !messageText.isEmpty || resourceAvailable || diceEmoji != nil { + let isCopyProtected = chatPresentationInterfaceState.copyProtectionEnabled || message.isCopyProtected() let message = messages[0] var isExpired = false for media in message.media { @@ -1069,39 +1070,40 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState } if !isExpired { if !isPoll { - actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopy, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor) - }, action: { _, f in - if let diceEmoji = diceEmoji { - UIPasteboard.general.string = diceEmoji - } else { - let copyTextWithEntities = { - var messageEntities: [MessageTextEntity]? - var restrictedText: String? - for attribute in message.attributes { - if let attribute = attribute as? TextEntitiesMessageAttribute { - messageEntities = attribute.entities + if !isCopyProtected { + actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopy, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor) + }, action: { _, f in + if let diceEmoji = diceEmoji { + UIPasteboard.general.string = diceEmoji + } else { + let copyTextWithEntities = { + var messageEntities: [MessageTextEntity]? + var restrictedText: String? + for attribute in message.attributes { + if let attribute = attribute as? TextEntitiesMessageAttribute { + messageEntities = attribute.entities + } + if let attribute = attribute as? RestrictedContentMessageAttribute { + restrictedText = attribute.platformText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) ?? "" + } } - if let attribute = attribute as? RestrictedContentMessageAttribute { - restrictedText = attribute.platformText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) ?? "" + + if let restrictedText = restrictedText { + storeMessageTextInPasteboard(restrictedText, entities: nil) + } else { + storeMessageTextInPasteboard(messageText, entities: messageEntities) } + + Queue.mainQueue().after(0.2, { + let content: UndoOverlayContent = .copy(text: chatPresentationInterfaceState.strings.Conversation_MessageCopied) + controllerInteraction.displayUndo(content) + }) } - - if let restrictedText = restrictedText { - storeMessageTextInPasteboard(restrictedText, entities: nil) - } else { - storeMessageTextInPasteboard(messageText, entities: messageEntities) - } - - Queue.mainQueue().after(0.2, { - let content: UndoOverlayContent = .copy(text: chatPresentationInterfaceState.strings.Conversation_MessageCopied) - controllerInteraction.displayUndo(content) - }) - } - if resourceAvailable { - for media in message.media { - if let image = media as? TelegramMediaImage, let largest = largestImageRepresentation(image.representations) { - let _ = (context.account.postbox.mediaBox.resourceData(largest.resource, option: .incremental(waitUntilFetchStatus: false)) + if resourceAvailable { + for media in message.media { + if let image = media as? TelegramMediaImage, let largest = largestImageRepresentation(image.representations) { + let _ = (context.account.postbox.mediaBox.resourceData(largest.resource, option: .incremental(waitUntilFetchStatus: false)) |> take(1) |> deliverOnMainQueue).start(next: { data in if data.complete, let imageData = try? Data(contentsOf: URL(fileURLWithPath: data.path)) { @@ -1123,18 +1125,19 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState copyTextWithEntities() } }) - break - } else { - copyTextWithEntities() - break + break + } else { + copyTextWithEntities() + break + } } + } else { + copyTextWithEntities() } - } else { - copyTextWithEntities() } - } - f(.default) - }))) + f(.default) + }))) + } } var showTranslateIfTopical = false @@ -1147,7 +1150,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuTranslate, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Translate"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in - controllerInteraction.performTextSelectionAction(0, NSAttributedString(string: messageText), .translate) + controllerInteraction.performTextSelectionAction(!isCopyProtected, NSAttributedString(string: messageText), .translate) f(.default) }))) } @@ -1156,7 +1159,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuSpeak, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Message"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in - controllerInteraction.performTextSelectionAction(0, NSAttributedString(string: messageText), .speak) + controllerInteraction.performTextSelectionAction(!isCopyProtected, NSAttributedString(string: messageText), .speak) f(.default) }))) } diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift index 0e1c948392..4e86f3447a 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift @@ -1768,7 +1768,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { guard let strongSelf = self, let item = strongSelf.arguments else { return } - item.controllerInteraction.performTextSelectionAction(item.message.stableId, text, action) + item.controllerInteraction.performTextSelectionAction(true, text, action) }) self.textSelectionNode = textSelectionNode self.textClippingNode.addSubnode(textSelectionNode) diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift index 801af4bd22..40bfcab65c 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift @@ -765,7 +765,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { let audioTranscriptionButtonSize = audioTranscriptionButton.update( transition: animation.isAnimated ? .easeInOut(duration: 0.3) : .immediate, component: AnyComponent(AudioTranscriptionButtonComponent( - theme: .freeform(durationBlurColor), + theme: .freeform(durationBlurColor, durationTextColor), transcriptionState: effectiveAudioTranscriptionState, pressed: { guard let strongSelf = self else { diff --git a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift index 31bec7a08e..020d1bd160 100644 --- a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift @@ -749,7 +749,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { guard let strongSelf = self, let item = strongSelf.item else { return } - item.controllerInteraction.performTextSelectionAction(item.message.stableId, text, action) + item.controllerInteraction.performTextSelectionAction(true, text, action) }) textSelectionNode.updateRange = { [weak self] selectionRange in if let strongSelf = self, let dustNode = strongSelf.dustNode, !dustNode.isRevealed, let textLayout = strongSelf.textNode.textNode.cachedLayout, !textLayout.spoilers.isEmpty, let selectionRange = selectionRange { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 6747a5f4b7..43c6577b88 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -6328,7 +6328,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate if canTranslate { actions.append(ContextMenuAction(content: .text(title: presentationData.strings.Conversation_ContextMenuTranslate, accessibilityLabel: presentationData.strings.Conversation_ContextMenuTranslate), action: { [weak self] in - let controller = TranslateScreen(context: context, text: text, fromLanguage: language) + let controller = TranslateScreen(context: context, text: text, canCopy: true, fromLanguage: language) controller.pushController = { [weak self] c in (self?.controller?.navigationController as? NavigationController)?._keepModalDismissProgress = true self?.controller?.push(c) diff --git a/submodules/TranslateUI/Sources/TranslateScreen.swift b/submodules/TranslateUI/Sources/TranslateScreen.swift index d51fc4f99b..b6ad520879 100644 --- a/submodules/TranslateUI/Sources/TranslateScreen.swift +++ b/submodules/TranslateUI/Sources/TranslateScreen.swift @@ -38,11 +38,11 @@ private final class TranslateScreenComponent: CombinedComponent { let text: String let fromLanguage: String? let toLanguage: String - let copyTranslation: (String) -> Void + let copyTranslation: ((String) -> Void)? let changeLanguage: (String, String, @escaping (String, String) -> Void) -> Void let expand: () -> Void - init(context: AccountContext, text: String, fromLanguage: String?, toLanguage: String, copyTranslation: @escaping (String) -> Void, changeLanguage: @escaping (String, String, @escaping (String, String) -> Void) -> Void, expand: @escaping () -> Void) { + init(context: AccountContext, text: String, fromLanguage: String?, toLanguage: String, copyTranslation: ((String) -> Void)?, changeLanguage: @escaping (String, String, @escaping (String, String) -> Void) -> Void, expand: @escaping () -> Void) { self.context = context self.text = text self.fromLanguage = fromLanguage @@ -458,20 +458,31 @@ private final class TranslateScreenComponent: CombinedComponent { ) } + let buttonsSpacing: CGFloat = 24.0 + let smallSectionSpacing: CGFloat = 8.0 + + var buttonsHeight: CGFloat = 0.0 + let component = context.component - let copyButton = copyButton.update( - component: TranslateButtonComponent( - theme: theme, - title: strings.Translate_CopyTranslation, - icon: "Chat/Context Menu/Copy", - isEnabled: state.translatedText != nil, - action: { [weak component] in - component?.copyTranslation(state.translatedText ?? "") - } - ), - availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: itemHeight), - transition: context.transition - ) + if component.copyTranslation != nil { + let copyButton = copyButton.update( + component: TranslateButtonComponent( + theme: theme, + title: strings.Translate_CopyTranslation, + icon: "Chat/Context Menu/Copy", + isEnabled: state.translatedText != nil, + action: { [weak component] in + component?.copyTranslation?(state.translatedText ?? "") + } + ), + availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: itemHeight), + transition: context.transition + ) + context.add(copyButton + .position(CGPoint(x: context.availableSize.width / 2.0, y: textBackgroundOrigin.y + textTopInset + originalTitle.size.height + textSpacing + originalText.size.height + itemSpacing + textTopInset + translationTitle.size.height + textSpacing + translationTextHeight + itemSpacing + buttonsSpacing + copyButton.size.height / 2.0)) + ) + buttonsHeight += copyButton.size.height + smallSectionSpacing + } let changeLanguageButton = changeLanguageButton.update( component: TranslateButtonComponent( @@ -489,18 +500,12 @@ private final class TranslateScreenComponent: CombinedComponent { transition: context.transition ) - let buttonsSpacing: CGFloat = 24.0 - let smallSectionSpacing: CGFloat = 8.0 - - context.add(copyButton - .position(CGPoint(x: context.availableSize.width / 2.0, y: textBackgroundOrigin.y + textTopInset + originalTitle.size.height + textSpacing + originalText.size.height + itemSpacing + textTopInset + translationTitle.size.height + textSpacing + translationTextHeight + itemSpacing + buttonsSpacing + copyButton.size.height / 2.0)) - ) - context.add(changeLanguageButton - .position(CGPoint(x: context.availableSize.width / 2.0, y: textBackgroundOrigin.y + textTopInset + originalTitle.size.height + textSpacing + originalText.size.height + itemSpacing + textTopInset + translationTitle.size.height + textSpacing + translationTextHeight + itemSpacing + buttonsSpacing + copyButton.size.height + smallSectionSpacing + changeLanguageButton.size.height / 2.0)) + .position(CGPoint(x: context.availableSize.width / 2.0, y: textBackgroundOrigin.y + textTopInset + originalTitle.size.height + textSpacing + originalText.size.height + itemSpacing + textTopInset + translationTitle.size.height + textSpacing + translationTextHeight + itemSpacing + buttonsSpacing + buttonsHeight + changeLanguageButton.size.height / 2.0)) ) + buttonsHeight += changeLanguageButton.size.height - let contentSize = CGSize(width: context.availableSize.width, height: textBackgroundOrigin.y + textTopInset + originalTitle.size.height + textSpacing + originalText.size.height + itemSpacing + textTopInset + translationTitle.size.height + textSpacing + translationTextHeight + itemSpacing + buttonsSpacing + copyButton.size.height + smallSectionSpacing + changeLanguageButton.size.height + environment.safeInsets.bottom + 44.0) + let contentSize = CGSize(width: context.availableSize.width, height: textBackgroundOrigin.y + textTopInset + originalTitle.size.height + textSpacing + originalText.size.height + itemSpacing + textTopInset + translationTitle.size.height + textSpacing + translationTextHeight + itemSpacing + buttonsSpacing + buttonsHeight + environment.safeInsets.bottom + 44.0) return contentSize } @@ -992,7 +997,7 @@ public class TranslateScreen: ViewController { public var pushController: (ViewController) -> Void = { _ in } public var presentController: (ViewController) -> Void = { _ in } - public convenience init(context: AccountContext, text: String, fromLanguage: String?, toLanguage: String? = nil, isExpanded: Bool = false) { + public convenience init(context: AccountContext, text: String, canCopy: Bool, fromLanguage: String?, toLanguage: String? = nil, isExpanded: Bool = false) { let presentationData = context.sharedContext.currentPresentationData.with { $0 } var baseLanguageCode = presentationData.strings.baseLanguageCode @@ -1010,7 +1015,7 @@ public class TranslateScreen: ViewController { var copyTranslationImpl: ((String) -> Void)? var changeLanguageImpl: ((String, String, @escaping (String, String) -> Void) -> Void)? var expandImpl: (() -> Void)? - self.init(context: context, component: TranslateScreenComponent(context: context, text: text, fromLanguage: fromLanguage, toLanguage: toLanguage, copyTranslation: { text in + self.init(context: context, component: TranslateScreenComponent(context: context, text: text, fromLanguage: fromLanguage, toLanguage: toLanguage, copyTranslation: !canCopy ? nil : { text in copyTranslationImpl?(text) }, changeLanguage: { fromLang, toLang, completion in changeLanguageImpl?(fromLang, toLang, completion) @@ -1037,7 +1042,7 @@ public class TranslateScreen: ViewController { let pushController = self?.pushController let presentController = self?.presentController let controller = languageSelectionController(context: context, fromLanguage: fromLang, toLanguage: toLang, completion: { fromLang, toLang in - let controller = TranslateScreen(context: context, text: text, fromLanguage: fromLang, toLanguage: toLang, isExpanded: true) + let controller = TranslateScreen(context: context, text: text, canCopy: canCopy, fromLanguage: fromLang, toLanguage: toLang, isExpanded: true) controller.pushController = pushController ?? { _ in } controller.presentController = presentController ?? { _ in } presentController?(controller)