diff --git a/TelegramUI/ChatController.swift b/TelegramUI/ChatController.swift index cd5fff260f..3834461440 100644 --- a/TelegramUI/ChatController.swift +++ b/TelegramUI/ChatController.swift @@ -369,7 +369,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin break } } - let _ = contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: strongSelf.presentationInterfaceState, account: strongSelf.account, messages: updatedMessages, interfaceInteraction: strongSelf.interfaceInteraction, debugStreamSingleVideo: { id in + let _ = contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: strongSelf.presentationInterfaceState, account: strongSelf.account, messages: updatedMessages, controllerInteraction: strongSelf.controllerInteraction, interfaceInteraction: strongSelf.interfaceInteraction, debugStreamSingleVideo: { id in self?.debugStreamSingleVideo(id) }).start(next: { actions in guard let strongSelf = self, !actions.isEmpty else { @@ -738,7 +738,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin case let .url(url): var cleanUrl = url var canAddToReadingList = true - let canOpenIn = true + let canOpenIn = !availableOpenInOptions(applicationContext: strongSelf.account.telegramApplicationContext, item: .url(url: url)).isEmpty let mailtoString = "mailto:" let telString = "tel:" var openText = strongSelf.presentationData.strings.Conversation_LinkDialogOpen @@ -1389,7 +1389,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin var pinnedMessageId: MessageId? var peerIsBlocked: Bool = false var canReport: Bool = false - var callsAvailable: Bool = false + var callsAvailable: Bool = true var callsPrivate: Bool = false if let cachedData = combinedInitialData.cachedData as? CachedChannelData { pinnedMessageId = cachedData.pinnedMessageId diff --git a/TelegramUI/ChatInterfaceStateContextMenus.swift b/TelegramUI/ChatInterfaceStateContextMenus.swift index 3f02a444d4..66332dda67 100644 --- a/TelegramUI/ChatInterfaceStateContextMenus.swift +++ b/TelegramUI/ChatInterfaceStateContextMenus.swift @@ -149,8 +149,8 @@ func updatedChatEditInterfaceMessagetState(state: ChatPresentationInterfaceState return updated } -func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: ChatPresentationInterfaceState, account: Account, messages: [Message], interfaceInteraction: ChatPanelInterfaceInteraction?, debugStreamSingleVideo: @escaping (MessageId) -> Void) -> Signal<[ChatMessageContextMenuAction], NoError> { - guard let interfaceInteraction = interfaceInteraction else { +func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: ChatPresentationInterfaceState, account: Account, messages: [Message], controllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?, debugStreamSingleVideo: @escaping (MessageId) -> Void) -> Signal<[ChatMessageContextMenuAction], NoError> { + guard let interfaceInteraction = interfaceInteraction, let controllerInteraction = controllerInteraction else { return .single([]) } @@ -440,6 +440,12 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: }))) } + if data.messageActions.options.contains(.viewStickerPack) { + actions.append(.sheet(ChatMessageContextMenuSheetAction(color: .accent, title: chatPresentationInterfaceState.strings.StickerPack_ViewPack, action: { + let _ = controllerInteraction.openMessage(message) + }))) + } + if data.messageActions.options.contains(.forward) { actions.append(.sheet(ChatMessageContextMenuSheetAction(color: .accent, title: chatPresentationInterfaceState.strings.Conversation_ContextMenuForward, action: { interfaceInteraction.forwardMessages(messages) @@ -477,6 +483,7 @@ struct ChatAvailableMessageActionOptions: OptionSet { static let deleteGlobally = ChatAvailableMessageActionOptions(rawValue: 1 << 1) static let forward = ChatAvailableMessageActionOptions(rawValue: 1 << 2) static let report = ChatAvailableMessageActionOptions(rawValue: 1 << 3) + static let viewStickerPack = ChatAvailableMessageActionOptions(rawValue: 1 << 4) } struct ChatAvailableMessageActions { @@ -508,91 +515,103 @@ func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messag if optionsMap[id] == nil { optionsMap[id] = [] } - if id.peerId == accountPeerId { - optionsMap[id]!.insert(.forward) - optionsMap[id]!.insert(.deleteLocally) - } else if let peer = transaction.getPeer(id.peerId), let message = transaction.getMessage(id) { - var isAction = false + if let message = transaction.getMessage(id) { for media in message.media { - if media is TelegramMediaAction { - isAction = true + if let file = media as? TelegramMediaFile, file.isSticker { + for case let .Sticker(sticker) in file.attributes { + if let _ = sticker.packReference { + optionsMap[id]!.insert(.viewStickerPack) + } + break + } } } - if let channel = peer as? TelegramChannel { - if message.flags.contains(.Incoming), channel.adminRights == nil, !channel.flags.contains(.isCreator) { - optionsMap[id]!.insert(.report) + if id.peerId == accountPeerId { + optionsMap[id]!.insert(.forward) + optionsMap[id]!.insert(.deleteLocally) + } else if let peer = transaction.getPeer(id.peerId) { + var isAction = false + for media in message.media { + if media is TelegramMediaAction { + isAction = true + } } - if channel.hasAdminRights(.canBanUsers), case .group = channel.info { - if message.flags.contains(.Incoming) { - if !hadBanPeerId { + if let channel = peer as? TelegramChannel { + if message.flags.contains(.Incoming), channel.adminRights == nil, !channel.flags.contains(.isCreator) { + optionsMap[id]!.insert(.report) + } + if channel.hasAdminRights(.canBanUsers), case .group = channel.info { + if message.flags.contains(.Incoming) { + if !hadBanPeerId { + hadBanPeerId = true + banPeer = message.author + } else if banPeer?.id != message.author?.id { + banPeer = nil + } + } else { hadBanPeerId = true - banPeer = message.author - } else if banPeer?.id != message.author?.id { banPeer = nil } - } else { - hadBanPeerId = true - banPeer = nil } - } - if message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia && !isAction { - optionsMap[id]!.insert(.forward) - } - if !message.flags.contains(.Incoming) { - optionsMap[id]!.insert(.deleteGlobally) - } else { - if channel.hasAdminRights([.canDeleteMessages]) { - optionsMap[id]!.insert(.deleteGlobally) - } - } - } else if let group = peer as? TelegramGroup { - if message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia { - if !isAction { + if message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia && !isAction { optionsMap[id]!.insert(.forward) } - } - optionsMap[id]!.insert(.deleteLocally) - if !message.flags.contains(.Incoming) { - optionsMap[id]!.insert(.deleteGlobally) - } else { - switch group.role { - case .creator, .admin: - optionsMap[id]!.insert(.deleteGlobally) - case .member: - break - } - } - } else if let _ = peer as? TelegramUser { - if message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia && !isAction { - optionsMap[id]!.insert(.forward) - } - optionsMap[id]!.insert(.deleteLocally) - if !message.flags.contains(.Incoming) { - if canPerformEditingActions(limits: limitsConfiguration, accountPeerId: accountPeerId, message: message) { + if !message.flags.contains(.Incoming) { optionsMap[id]!.insert(.deleteGlobally) + } else { + if channel.hasAdminRights([.canDeleteMessages]) { + optionsMap[id]!.insert(.deleteGlobally) + } } - } - } else if let _ = peer as? TelegramSecretChat { - var isNonRemovableServiceAction = false - for media in message.media { - if let action = media as? TelegramMediaAction { - switch action.action { - case .historyScreenshot: - isNonRemovableServiceAction = true - default: + } else if let group = peer as? TelegramGroup { + if message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia { + if !isAction { + optionsMap[id]!.insert(.forward) + } + } + optionsMap[id]!.insert(.deleteLocally) + if !message.flags.contains(.Incoming) { + optionsMap[id]!.insert(.deleteGlobally) + } else { + switch group.role { + case .creator, .admin: + optionsMap[id]!.insert(.deleteGlobally) + case .member: break } } - } - - if !isNonRemovableServiceAction { - optionsMap[id]!.insert(.deleteGlobally) + } else if let _ = peer as? TelegramUser { + if message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia && !isAction { + optionsMap[id]!.insert(.forward) + } + optionsMap[id]!.insert(.deleteLocally) + if !message.flags.contains(.Incoming) { + if canPerformEditingActions(limits: limitsConfiguration, accountPeerId: accountPeerId, message: message) { + optionsMap[id]!.insert(.deleteGlobally) + } + } + } else if let _ = peer as? TelegramSecretChat { + var isNonRemovableServiceAction = false + for media in message.media { + if let action = media as? TelegramMediaAction { + switch action.action { + case .historyScreenshot: + isNonRemovableServiceAction = true + default: + break + } + } + } + + if !isNonRemovableServiceAction { + optionsMap[id]!.insert(.deleteGlobally) + } + } else { + assertionFailure() } } else { - assertionFailure() + optionsMap[id]!.insert(.deleteLocally) } - } else { - optionsMap[id]!.insert(.deleteLocally) } } diff --git a/TelegramUI/ChatItemGalleryFooterContentNode.swift b/TelegramUI/ChatItemGalleryFooterContentNode.swift index c4dfdc01f4..ba409fc6fa 100644 --- a/TelegramUI/ChatItemGalleryFooterContentNode.swift +++ b/TelegramUI/ChatItemGalleryFooterContentNode.swift @@ -511,15 +511,20 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { break } } - + if messages.count == 1 { var subject: ShareControllerSubject = ShareControllerSubject.messages(messages) for m in messages[0].media { if let image = m as? TelegramMediaImage { subject = .image(image.representations) - } else if let webpage = m as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, let image = content.image { - subject = .media(.webPage(webPage: WebpageReference(webpage), media: image)) - preferredAction = .saveToCameraRoll + } else if let webpage = m as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content { + if let file = content.file { + subject = .media(.webPage(webPage: WebpageReference(webpage), media: file)) + preferredAction = .saveToCameraRoll + } else if let image = content.image { + subject = .media(.webPage(webPage: WebpageReference(webpage), media: image)) + preferredAction = .saveToCameraRoll + } } else if let file = m as? TelegramMediaFile { subject = .media(.message(message: MessageReference(messages[0]), media: file)) if file.isAnimated { diff --git a/TelegramUI/ChatRecentActionsControllerNode.swift b/TelegramUI/ChatRecentActionsControllerNode.swift index db680dbf4d..7b60c846e6 100644 --- a/TelegramUI/ChatRecentActionsControllerNode.swift +++ b/TelegramUI/ChatRecentActionsControllerNode.swift @@ -219,7 +219,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { switch action { case let .url(url): var cleanUrl = url - let canOpenIn = true + let canOpenIn = !availableOpenInOptions(applicationContext: strongSelf.account.telegramApplicationContext, item: .url(url: url)).isEmpty var canAddToReadingList = true let mailtoString = "mailto:" let telString = "tel:" diff --git a/TelegramUI/GroupInfoController.swift b/TelegramUI/GroupInfoController.swift index f1b97acab2..7301878b14 100644 --- a/TelegramUI/GroupInfoController.swift +++ b/TelegramUI/GroupInfoController.swift @@ -926,9 +926,6 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa var peers: [PeerId: Peer] = view.peers var disabledPeerIds = state.removingParticipantIds - - - if !state.temporaryParticipants.isEmpty { for participant in state.temporaryParticipants { if !existingParticipantIds.contains(participant.peer.id) { @@ -1935,9 +1932,8 @@ func handlePeerInfoAboutTextAction(account: Account, peerId: PeerId, navigateDis case .longTap: switch itemLink { case let .url(url): - let canOpenIn = true + let canOpenIn = !availableOpenInOptions(applicationContext: account.telegramApplicationContext, item: .url(url: url)).isEmpty let openText = canOpenIn ? presentationData.strings.Conversation_FileOpenIn : presentationData.strings.Conversation_LinkDialogOpen - let actionSheet = ActionSheetController(presentationTheme: presentationData.theme) actionSheet.setItemGroups([ActionSheetItemGroup(items: [ ActionSheetTextItem(title: url), @@ -1979,7 +1975,7 @@ func handlePeerInfoAboutTextAction(account: Account, peerId: PeerId, navigateDis }) ])]) controller.present(actionSheet, in: .window(.root)) - case let .hashtag(peerName, hashtag): + case let .hashtag(_, hashtag): let actionSheet = ActionSheetController(presentationTheme: presentationData.theme) actionSheet.setItemGroups([ActionSheetItemGroup(items: [ ActionSheetTextItem(title: hashtag), diff --git a/TelegramUI/InstantPageControllerNode.swift b/TelegramUI/InstantPageControllerNode.swift index cc18af5a84..e441cdc7e6 100644 --- a/TelegramUI/InstantPageControllerNode.swift +++ b/TelegramUI/InstantPageControllerNode.swift @@ -611,9 +611,8 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { } case .longTap: if let url = self.urlForTapLocation(location) { - let canOpenIn = true + let canOpenIn = !availableOpenInOptions(applicationContext: self.account.telegramApplicationContext, item: .url(url: url.url)).isEmpty let openText = canOpenIn ? self.strings.Conversation_FileOpenIn : self.strings.Conversation_LinkDialogOpen - let actionSheet = ActionSheetController(presentationTheme: self.presentationTheme) actionSheet.setItemGroups([ActionSheetItemGroup(items: [ ActionSheetTextItem(title: url.url), diff --git a/TelegramUI/PeerMediaCollectionController.swift b/TelegramUI/PeerMediaCollectionController.swift index 1eacf445b4..e927fcc9db 100644 --- a/TelegramUI/PeerMediaCollectionController.swift +++ b/TelegramUI/PeerMediaCollectionController.swift @@ -190,9 +190,8 @@ public class PeerMediaCollectionController: TelegramController { if let strongSelf = self { switch content { case let .url(url): - let canOpenIn = true + let canOpenIn = !availableOpenInOptions(applicationContext: strongSelf.account.telegramApplicationContext, item: .url(url: url)).isEmpty let openText = canOpenIn ? strongSelf.presentationData.strings.Conversation_FileOpenIn : strongSelf.presentationData.strings.Conversation_LinkDialogOpen - let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme) actionSheet.setItemGroups([ActionSheetItemGroup(items: [ ActionSheetTextItem(title: url), diff --git a/TelegramUI/SecureIdAuthController.swift b/TelegramUI/SecureIdAuthController.swift index 54dfed144e..51983b504a 100644 --- a/TelegramUI/SecureIdAuthController.swift +++ b/TelegramUI/SecureIdAuthController.swift @@ -99,7 +99,14 @@ final class SecureIdAuthController: ViewController { self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style self.title = self.presentationData.strings.Passport_Title - self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed)) + let leftButtonTitle: String + switch mode { + case .form: + leftButtonTitle = self.presentationData.strings.Common_Cancel + case .list: + leftButtonTitle = self.presentationData.strings.Common_Done + } + self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: leftButtonTitle, style: .plain, target: self, action: #selector(self.cancelPressed)) self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationInfoIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.infoPressed)) self.challengeDisposable.set((twoStepAuthData(account.network) diff --git a/TelegramUI/SecureIdAuthControllerNode.swift b/TelegramUI/SecureIdAuthControllerNode.swift index b8ab3aefcf..99035e2259 100644 --- a/TelegramUI/SecureIdAuthControllerNode.swift +++ b/TelegramUI/SecureIdAuthControllerNode.swift @@ -352,6 +352,9 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { case let .passwordChallenge(hint, challengeState, _): if let current = self.contentNode as? SecureIdAuthPasswordOptionContentNode { current.updateIsChecking(challengeState == .checking) + if case .invalid = challengeState { + current.updateIsInvalid() + } contentNode = current } else { let current = SecureIdAuthPasswordOptionContentNode(theme: presentationData.theme, strings: presentationData.strings, hint: hint, checkPassword: { [weak self] password in @@ -360,6 +363,9 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { self?.interaction.openPasswordHelp() }) current.updateIsChecking(challengeState == .checking) + if case .invalid = challengeState { + current.updateIsInvalid() + } contentNode = current } case .noChallenge: @@ -582,7 +588,7 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { } } else if addressDetails { self.interaction.present(SecureIdDocumentFormController(account: self.account, context: context, requestedData: .address(details: addressDetails, document: nil, translations: false), primaryLanguageByCountry: encryptedFormData.primaryLanguageByCountry, values: formData.values, updatedValues: { values in - updatedValues([.personalDetails], values) + updatedValues([.address], values) }), nil) return } @@ -616,20 +622,20 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { let controller = SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: requestedData, primaryLanguageByCountry: encryptedFormData.primaryLanguageByCountry, values: formData.values, updatedValues: { values in var keys: [SecureIdValueKey] = [] switch requestedData { - case let .identity(details, document, _, _): - if details != nil { - keys.append(.personalDetails) - } - if let document = document { - keys.append(document.valueKey) - } - case let .address(details, document, _): - if details { - keys.append(.address) - } - if let document = document { - keys.append(document.valueKey) - } + case let .identity(details, document, _, _): + if details != nil { + keys.append(.personalDetails) + } + if let document = document { + keys.append(document.valueKey) + } + case let .address(details, document, _): + if details { + keys.append(.address) + } + if let document = document { + keys.append(document.valueKey) + } } updatedValues(keys, values) }) diff --git a/TelegramUI/SecureIdAuthFormFieldNode.swift b/TelegramUI/SecureIdAuthFormFieldNode.swift index 36cc2cde98..4ac8284902 100644 --- a/TelegramUI/SecureIdAuthFormFieldNode.swift +++ b/TelegramUI/SecureIdAuthFormFieldNode.swift @@ -697,8 +697,10 @@ private func fieldErrorText(field: SecureIdParsedRequestedFormField, values: [Se if let _ = personalDetails, let value = findValue(values, key: .personalDetails)?.1 { if let error = value.errors[.value(.personalDetails)] { return error - } else if let error = value.errors.first?.value { - return error + } else if let error = value.errors.first { + if case .value = error.key {} else { + return error.value + } } } if let document = document { @@ -731,8 +733,10 @@ private func fieldErrorText(field: SecureIdParsedRequestedFormField, values: [Se if addressDetails, let value = findValue(values, key: .address)?.1 { if let error = value.errors[.value(.address)] { return error - } else if let error = value.errors.first?.value { - return error + } else if let error = value.errors.first { + if case .value = error.key {} else { + return error.value + } } } if let document = document { diff --git a/TelegramUI/SecureIdPlaintextFormControllerNode.swift b/TelegramUI/SecureIdPlaintextFormControllerNode.swift index cf8962867a..0068549d96 100644 --- a/TelegramUI/SecureIdPlaintextFormControllerNode.swift +++ b/TelegramUI/SecureIdPlaintextFormControllerNode.swift @@ -925,35 +925,5 @@ final class SecureIdPlaintextFormControllerNode: FormControllerNode deliverOnMainQueue).start(next: { [weak self] result in - if let strongSelf = self { - strongSelf.completedWithValue?(nil) - } - }, error: { [weak self] error in - if let strongSelf = self { - guard var innerState = strongSelf.innerState else { - return - } - guard case .deleting = innerState.actionState else { - return - } - innerState.actionState = .none - strongSelf.updateInnerState(transition: .immediate, with: innerState) - } - })) - } } diff --git a/TelegramUI/ShareSearchContainerNode.swift b/TelegramUI/ShareSearchContainerNode.swift index 7597e99ec1..e10c3b371c 100644 --- a/TelegramUI/ShareSearchContainerNode.swift +++ b/TelegramUI/ShareSearchContainerNode.swift @@ -333,7 +333,7 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { recentItemList.append(.topPeers(theme, strings)) var index = 0 for peer in recentPeers { - if let mainPeer = peer.peers[peer.peerId] { + if let mainPeer = peer.peers[peer.peerId], canSendMessagesToPeer(mainPeer) { recentItemList.append(.peer(index: index, theme: theme, peer: mainPeer, associatedPeer: mainPeer.associatedPeerId.flatMap { peer.peers[$0] }, strings)) index += 1 }