diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 56aa5b7adf..abbaafa7c3 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -171,7 +171,7 @@ public enum ResolvedUrl { case inaccessiblePeer case botStart(peerId: PeerId, payload: String) case groupBotStart(peerId: PeerId, payload: String) - case channelMessage(peerId: PeerId, messageId: MessageId) + case channelMessage(peerId: PeerId, messageId: MessageId, timecode: Double?) case replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage, messageId: MessageId) case stickerPack(name: String) case instantView(TelegramMediaWebpage, String?) diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index 1ddd5bbe7f..a6d2dfe764 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -339,7 +339,7 @@ public struct ChatTextInputStateText: PostboxCoding, Equatable { } public enum ChatControllerSubject: Equatable { - case message(id: MessageId, highlight: Bool) + case message(id: MessageId, highlight: Bool, timecode: Double?) case scheduledMessages case pinnedMessages(id: MessageId?) } diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 07c1764a1f..03b430ec14 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -692,7 +692,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass { scrollToEndIfExists = true } - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: .message(id: messageId, highlight: true), purposefulAction: { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: .message(id: messageId, highlight: true, timecode: nil), purposefulAction: { if deactivateOnAction { self?.deactivateSearch(animated: false) } @@ -862,7 +862,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } else { var subject: ChatControllerSubject? if case let .search(messageId) = source, let id = messageId { - subject = .message(id: id, highlight: false) + subject = .message(id: id, highlight: false, timecode: nil) } let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.id), subject: subject, botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index 88115f21a8..d86eef5c66 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -965,7 +965,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { let resolvedMessage = .single(nil) |> then(context.sharedContext.resolveUrl(context: context, peerId: nil, url: finalQuery, skipUrlAuth: true) |> mapToSignal { resolvedUrl -> Signal in - if case let .channelMessage(_, messageId) = resolvedUrl { + if case let .channelMessage(_, messageId, _) = resolvedUrl { return context.engine.messages.downloadMessage(messageId: messageId) } else { return .single(nil) diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift index 034972000f..5be46fde59 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift @@ -57,7 +57,7 @@ public final class HashtagSearchController: TelegramBaseController { if let strongSelf = self { strongSelf.openMessageFromSearchDisposable.set((storedMessageFromSearchPeer(account: strongSelf.context.account, peer: peer) |> deliverOnMainQueue).start(next: { actualPeerId in if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: message.id.peerId == actualPeerId ? .message(id: message.id, highlight: true) : nil, keepStack: .always)) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: message.id.peerId == actualPeerId ? .message(id: message.id, highlight: true, timecode: nil) : nil, keepStack: .always)) } })) strongSelf.controllerNode.listNode.clearHighlightAnimated(true) diff --git a/submodules/StatisticsUI/Sources/ChannelStatsController.swift b/submodules/StatisticsUI/Sources/ChannelStatsController.swift index 2bae41250a..649297977a 100644 --- a/submodules/StatisticsUI/Sources/ChannelStatsController.swift +++ b/submodules/StatisticsUI/Sources/ChannelStatsController.swift @@ -518,7 +518,7 @@ public func channelStatsController(context: AccountContext, peerId: PeerId, cach items.append(.action(ContextMenuActionItem(text: presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak controller] c, _ in c.dismiss(completion: { if let navigationController = controller?.navigationController as? NavigationController { - context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true))) + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true, timecode: nil))) } }) }))) diff --git a/submodules/StatisticsUI/Sources/MessageStatsController.swift b/submodules/StatisticsUI/Sources/MessageStatsController.swift index cd36e64526..3eebe518d1 100644 --- a/submodules/StatisticsUI/Sources/MessageStatsController.swift +++ b/submodules/StatisticsUI/Sources/MessageStatsController.swift @@ -264,7 +264,7 @@ public func messageStatsController(context: AccountContext, messageId: MessageId } navigateToMessageImpl = { [weak controller] messageId in if let navigationController = controller?.navigationController as? NavigationController { - context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true), keepStack: .always, useExisting: false, purposefulAction: {}, peekData: nil)) + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true, timecode: nil), keepStack: .always, useExisting: false, purposefulAction: {}, peekData: nil)) } } return controller diff --git a/submodules/TelegramUI/Sources/ApplicationContext.swift b/submodules/TelegramUI/Sources/ApplicationContext.swift index 3b5106cb76..20adc4ffc6 100644 --- a/submodules/TelegramUI/Sources/ApplicationContext.swift +++ b/submodules/TelegramUI/Sources/ApplicationContext.swift @@ -759,7 +759,7 @@ final class AuthorizedApplicationContext { } let navigateToMessage = { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: strongSelf.rootController, context: strongSelf.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true))) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: strongSelf.rootController, context: strongSelf.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true, timecode: nil))) } if chatIsVisible { @@ -838,7 +838,7 @@ final class AuthorizedApplicationContext { if visiblePeerId != peerId || messageId != nil { if self.rootController.rootTabController != nil { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: self.rootController, context: self.context, chatLocation: .peer(peerId), subject: messageId.flatMap { .message(id: $0, highlight: true) }, activateInput: activateInput)) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: self.rootController, context: self.context, chatLocation: .peer(peerId), subject: messageId.flatMap { .message(id: $0, highlight: true, timecode: nil) }, activateInput: activateInput)) } else { self.scheduledOpenChatWithPeerId = (peerId, messageId, activateInput) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 2f7d3a8833..2d47ddd783 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -107,13 +107,13 @@ private enum ChatRecordingActivity { } public enum NavigateToMessageLocation { - case id(MessageId) + case id(MessageId, Double?) case index(MessageIndex) case upperBound(PeerId) var messageId: MessageId? { switch self { - case let .id(id): + case let .id(id, _): return id case let .index(index): return index.id @@ -124,7 +124,7 @@ public enum NavigateToMessageLocation { var peerId: PeerId { switch self { - case let .id(id): + case let .id(id, _): return id.peerId case let .index(index): return index.id.peerId @@ -572,7 +572,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G case .pinnedMessageUpdated: for attribute in message.attributes { if let attribute = attribute as? ReplyMessageAttribute { - strongSelf.navigateToMessage(from: message.id, to: .id(attribute.messageId)) + strongSelf.navigateToMessage(from: message.id, to: .id(attribute.messageId, nil)) break } } @@ -581,7 +581,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G case .gameScore: for attribute in message.attributes { if let attribute = attribute as? ReplyMessageAttribute { - strongSelf.navigateToMessage(from: message.id, to: .id(attribute.messageId)) + strongSelf.navigateToMessage(from: message.id, to: .id(attribute.messageId, nil)) break } } @@ -997,9 +997,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }, openMessageContextActions: { message, node, rect, gesture in gesture?.cancel() }, navigateToMessage: { [weak self] fromId, id in - self?.navigateToMessage(from: fromId, to: .id(id), forceInCurrentChat: fromId.peerId == id.peerId) + self?.navigateToMessage(from: fromId, to: .id(id, nil), forceInCurrentChat: fromId.peerId == id.peerId) }, navigateToMessageStandalone: { [weak self] id in - self?.navigateToMessage(from: nil, to: .id(id), forceInCurrentChat: false) + self?.navigateToMessage(from: nil, to: .id(id, nil), forceInCurrentChat: false) }, tapMessage: nil, clickThroughMessage: { [weak self] in self?.chatDisplayNode.dismissInput() }, toggleMessagesSelection: { [weak self] ids, value in @@ -1876,7 +1876,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let message = message else { return } + let context = strongSelf.context + let chatPresentationInterfaceState = strongSelf.presentationInterfaceState let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) + + let isCopyLink: Bool + if message.id.namespace == Namespaces.Message.Cloud, let _ = message.peers[message.id.peerId] as? TelegramChannel, !(message.media.first is TelegramMediaAction) { + isCopyLink = true + } else { + isCopyLink = false + } + actionSheet.setItemGroups([ActionSheetItemGroup(items: [ ActionSheetTextItem(title: text), ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in @@ -1885,12 +1895,52 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.controllerInteraction?.seekToTimecode(message, timecode, true) } }), - ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in + ActionSheetButtonItem(title: isCopyLink ? strongSelf.presentationData.strings.Conversation_ContextMenuCopyLink : strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() - UIPasteboard.general.string = text - - let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied) - self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current) + if isCopyLink, let channel = message.peers[message.id.peerId] as? TelegramChannel { + var threadMessageId: MessageId? + + if case let .replyThread(replyThreadMessage) = chatPresentationInterfaceState.chatLocation { + threadMessageId = replyThreadMessage.messageId + } + let _ = (exportMessageLink(account: context.account, peerId: message.id.peerId, messageId: message.id, isThread: threadMessageId != nil) + |> map { result -> String? in + return result + } + |> deliverOnMainQueue).start(next: { link in + if let link = link { + UIPasteboard.general.string = link + "?t=\(Int32(timecode))" + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + + var warnAboutPrivate = false + if case .peer = chatPresentationInterfaceState.chatLocation { + if channel.addressName == nil { + warnAboutPrivate = true + } + } + Queue.mainQueue().after(0.2, { + let content: UndoOverlayContent + if warnAboutPrivate { + content = .linkCopied(text: presentationData.strings.Conversation_PrivateMessageLinkCopiedLong) + } else { + content = .linkCopied(text: presentationData.strings.Conversation_LinkCopied) + } + self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current) + }) + } else { + UIPasteboard.general.string = text + + let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied) + self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current) + } + }) + } else { + UIPasteboard.general.string = text + + let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied) + self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current) + } }) ]), ActionSheetItemGroup(items: [ ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in @@ -2664,7 +2714,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.openMessageReplies(messageId: threadMessageId, displayProgressInMessage: message.id, isChannelPost: true, atMessage: attribute.messageId, displayModalProgress: false) } } else { - strongSelf.navigateToMessage(from: nil, to: .id(attribute.messageId)) + strongSelf.navigateToMessage(from: nil, to: .id(attribute.messageId, nil)) } break } @@ -4558,7 +4608,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.historyNode.scrolledToIndex = { [weak self] toIndex, initial in if let strongSelf = self, case let .message(index) = toIndex { - if case let .message(messageId, _) = strongSelf.subject, initial, messageId != index.id { + if case let .message(messageId, _, _) = strongSelf.subject, initial, messageId != index.id { strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .info(text: strongSelf.presentationData.strings.Conversation_MessageDoesntExist), elevatedLayout: false, action: { _ in return true }), in: .current) } else if let controllerInteraction = strongSelf.controllerInteraction { if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(index.id) { @@ -4575,6 +4625,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } })) + + if case let .message(_, _, timecode) = strongSelf.subject, let timecode = timecode, initial { + Queue.mainQueue().after(0.2) { + strongSelf.controllerInteraction?.openMessage(message, .timecode(timecode)) + } + } } } } @@ -4859,7 +4915,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.navigateButtons.downPressed = { [weak self] in if let strongSelf = self, strongSelf.isNodeLoaded { if let messageId = strongSelf.historyNavigationStack.removeLast() { - strongSelf.navigateToMessage(from: nil, to: .id(messageId.id), rememberInStack: false) + strongSelf.navigateToMessage(from: nil, to: .id(messageId.id, nil), rememberInStack: false) } else { if case .known = strongSelf.chatDisplayNode.historyNode.visibleContentOffset() { strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory() @@ -4882,7 +4938,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G switch result { case let .result(messageId): if let messageId = messageId { - strongSelf.navigateToMessage(from: nil, to: .id(messageId)) + strongSelf.navigateToMessage(from: nil, to: .id(messageId, nil)) } case .loading: break @@ -5445,7 +5501,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let strongSelf = self { strongSelf.loadingMessage.set(.single(nil)) if let messageId = messageId { - strongSelf.navigateToMessage(from: nil, to: .id(messageId), forceInCurrentChat: true) + strongSelf.navigateToMessage(from: nil, to: .id(messageId, nil), forceInCurrentChat: true) } } })) @@ -5473,7 +5529,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.updateItemNodesSearchTextHighlightStates() } }, navigateToMessage: { [weak self] messageId, dropStack, forceInCurrentChat, statusSubject in - self?.navigateToMessage(from: nil, to: .id(messageId), forceInCurrentChat: forceInCurrentChat, dropStack: dropStack, statusSubject: statusSubject) + self?.navigateToMessage(from: nil, to: .id(messageId, nil), forceInCurrentChat: forceInCurrentChat, dropStack: dropStack, statusSubject: statusSubject) }, navigateToChat: { [weak self] peerId in guard let strongSelf = self else { return @@ -6621,7 +6677,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if let navigationController = strongSelf.effectiveNavigationController { - let subject: ChatControllerSubject? = sourceMessageId.flatMap { ChatControllerSubject.message(id: $0, highlight: true) } + let subject: ChatControllerSubject? = sourceMessageId.flatMap { ChatControllerSubject.message(id: $0, highlight: true, timecode: nil) } strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .replyThread(replyThreadResult), subject: subject, keepStack: .always)) } }, activatePinnedListPreview: { [weak self] node, gesture in @@ -7084,7 +7140,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if let currentItem = currentItem?.id as? PeerMessagesMediaPlaylistItemId, let previousItem = previousItem?.id as? PeerMessagesMediaPlaylistItemId, previousItem.messageId.peerId == peerId, currentItem.messageId.peerId == peerId, currentItem.messageId != previousItem.messageId { if strongSelf.chatDisplayNode.historyNode.isMessageVisibleOnScreen(currentItem.messageId) { - strongSelf.navigateToMessage(from: nil, to: .id(currentItem.messageId), scrollPosition: .center(.bottom), rememberInStack: false, animated: true, completion: nil) + strongSelf.navigateToMessage(from: nil, to: .id(currentItem.messageId, nil), scrollPosition: .center(.bottom), rememberInStack: false, animated: true, completion: nil) } } } @@ -10560,9 +10616,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let subject: ChatControllerSubject? if let atMessageId = atMessageId { - subject = .message(id: atMessageId, highlight: true) + subject = .message(id: atMessageId, highlight: true, timecode: nil) } else if let index = result.scrollToLowerBoundMessage { - subject = .message(id: index.id, highlight: false) + subject = .message(id: index.id, highlight: false, timecode: nil) } else { subject = nil } @@ -10626,11 +10682,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if isPinnedMessages, let messageId = messageLocation.messageId { if let navigationController = self.effectiveNavigationController { self.dismiss() - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true), keepStack: .always)) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true, timecode: nil), keepStack: .always)) } } else if case let .peer(peerId) = self.chatLocation, let messageId = messageLocation.messageId, (messageId.peerId != peerId && !forceInCurrentChat) || (isScheduledMessages && messageId.id != 0 && !Namespaces.Message.allScheduled.contains(messageId.namespace)) { if let navigationController = self.effectiveNavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true), keepStack: .always)) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true, timecode: nil), keepStack: .always)) } } else if forceInCurrentChat { if let _ = fromId, let fromIndex = fromIndex, rememberInStack { @@ -10652,13 +10708,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.messageIndexDisposable.set(nil) self.chatDisplayNode.historyNode.scrollToMessage(from: scrollFromIndex, to: message.index, animated: animated, scrollPosition: scrollPosition) completion?() + + if case let .id(_, timecode) = messageLocation, let timecode = timecode { + self.controllerInteraction?.openMessage(message, .timecode(timecode)) + } } else if case let .index(index) = messageLocation, index.id.id == 0, index.timestamp > 0, case .scheduledMessages = self.presentationInterfaceState.subject { self.chatDisplayNode.historyNode.scrollToMessage(from: scrollFromIndex, to: index, animated: animated, scrollPosition: scrollPosition) } else { self.loadingMessage.set(.single(statusSubject) |> delay(0.1, queue: .mainQueue())) let searchLocation: ChatHistoryInitialSearchLocation switch messageLocation { - case let .id(id): + case let .id(id, _): searchLocation = .id(id) case let .index(index): searchLocation = .index(index) @@ -10751,7 +10811,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let fromIndex = fromIndex { let searchLocation: ChatHistoryInitialSearchLocation switch messageLocation { - case let .id(id): + case let .id(id, _): searchLocation = .id(id) case let .index(index): searchLocation = .index(index) @@ -10785,7 +10845,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G completion?() } else { if let navigationController = strongSelf.effectiveNavigationController { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message(id: $0, highlight: true) })) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message(id: $0, highlight: true, timecode: nil) })) } completion?() } @@ -10797,7 +10857,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G })) } else { if let navigationController = self.effectiveNavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message(id: $0, highlight: true) })) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message(id: $0, highlight: true, timecode: nil) })) } completion?() } @@ -11555,8 +11615,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G switch navigation { case let .chat(_, subject, peekData): if case .peer(peerId) = strongSelf.chatLocation { - if let subject = subject, case let .message(messageId, _) = subject { - strongSelf.navigateToMessage(from: nil, to: .id(messageId)) + if let subject = subject, case let .message(messageId, _, timecode) = subject { + strongSelf.navigateToMessage(from: nil, to: .id(messageId, timecode)) } } else if let navigationController = strongSelf.effectiveNavigationController { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject, keepStack: .always, peekData: peekData)) diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 2954278e19..74d8839abb 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -910,7 +910,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount, highlight: false), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0) } else { - if let subject = subject, case let .message(messageId, highlight) = subject { + if let subject = subject, case let .message(messageId, highlight, _) = subject { strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: highlight), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0) } else if let subject = subject, case let .pinnedMessages(maybeMessageId) = subject, let messageId = maybeMessageId { strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: true), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0) @@ -1088,7 +1088,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { } }) - if let subject = subject, case let .message(messageId, highlight) = subject { + if let subject = subject, case let .message(messageId, highlight, _) = subject { self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: highlight), id: 0) } else if let subject = subject, case let .pinnedMessages(maybeMessageId) = subject, let messageId = maybeMessageId { self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: true), id: 0) diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 7ac4decd62..dcc9ab4721 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1278,7 +1278,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { openPeerId = attribute.messageId.peerId - navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true), peekData: nil) + navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true, timecode: nil), peekData: nil) } } diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 09274cb45b..c7a6e5cd57 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -3012,7 +3012,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { openPeerId = attribute.messageId.peerId - navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true), peekData: nil) + navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true, timecode: nil), peekData: nil) } } diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index 8fc9243c32..473d47fe08 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -731,7 +731,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView { for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { openPeerId = attribute.messageId.peerId - navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true), peekData: nil) + navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true, timecode: nil), peekData: nil) } } diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index e7e794379c..43b041813b 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -884,7 +884,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { openPeerId = attribute.messageId.peerId - navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true), peekData: nil) + navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true, timecode: nil), peekData: nil) } } diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index de97874f89..5b3fb9b56d 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -905,13 +905,13 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { break case .groupBotStart: break - case let .channelMessage(peerId, messageId): + case let .channelMessage(peerId, messageId, timecode): if let navigationController = strongSelf.getNavigationController() { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true))) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true, timecode: timecode))) } case let .replyThreadMessage(replyThreadMessage, messageId): if let navigationController = strongSelf.getNavigationController() { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .replyThread(replyThreadMessage), subject: .message(id: messageId, highlight: true))) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .replyThread(replyThreadMessage), subject: .message(id: messageId, highlight: true, timecode: nil))) } case let .stickerPack(name): let packReference: StickerPackReference = .name(name) diff --git a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift index a5aafc5f90..cbe30e00d4 100644 --- a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift +++ b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift @@ -205,7 +205,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe switch item.content { case let .peer(peer): if let message = peer.messages.first { - let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peer.peerId), subject: .message(id: message.id, highlight: true), botStart: nil, mode: .standard(previewing: true)) + let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peer.peerId), subject: .message(id: message.id, highlight: true, timecode: nil), botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single([]), reactionItems: [], gesture: gesture) presentInGlobalOverlay(contextController) diff --git a/submodules/TelegramUI/Sources/NavigateToChatController.swift b/submodules/TelegramUI/Sources/NavigateToChatController.swift index fe5d204ab5..f464fc7811 100644 --- a/submodules/TelegramUI/Sources/NavigateToChatController.swift +++ b/submodules/TelegramUI/Sources/NavigateToChatController.swift @@ -20,10 +20,10 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam if let updateTextInputState = params.updateTextInputState { controller.updateTextInputState(updateTextInputState) } - if let subject = params.subject, case let .message(messageId, _) = subject { + if let subject = params.subject, case let .message(messageId, _, timecode) = subject { let navigationController = params.navigationController let animated = params.animated - controller.navigateToMessage(messageLocation: .id(messageId), animated: isFirst, completion: { [weak navigationController, weak controller] in + controller.navigateToMessage(messageLocation: .id(messageId, timecode), animated: isFirst, completion: { [weak navigationController, weak controller] in if let navigationController = navigationController, let controller = controller { let _ = navigationController.popToViewController(controller, animated: animated) } diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index c191bab96e..3193c0d365 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -97,8 +97,8 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur } dismissInput() navigationController?.pushViewController(controller) - case let .channelMessage(peerId, messageId): - openPeer(peerId, .chat(textInputState: nil, subject: .message(id: messageId, highlight: true), peekData: nil)) + case let .channelMessage(peerId, messageId, timecode): + openPeer(peerId, .chat(textInputState: nil, subject: .message(id: messageId, highlight: true, timecode: timecode), peekData: nil)) case let .replyThreadMessage(replyThreadMessage, messageId): if let navigationController = navigationController { let _ = ChatControllerImpl.openMessageReplies(context: context, navigationController: navigationController, present: { c, a in diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index 6d5e5b4a98..594c76b429 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -187,7 +187,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu self.isGlobalSearch = false } - self.historyNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: source, subject: .message(id: initialMessageId, highlight: true), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) + self.historyNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: source, subject: .message(id: initialMessageId, highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) super.init() @@ -528,7 +528,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu } let chatLocationContextHolder = Atomic(value: nil) - let historyNode = ChatHistoryListNode(context: self.context, chatLocation: .peer(self.peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: messageId, highlight: true), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) + let historyNode = ChatHistoryListNode(context: self.context, chatLocation: .peer(self.peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: messageId, highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) historyNode.preloadPages = true historyNode.stackFromBottom = true historyNode.updateFloatingHeaderOffset = { [weak self] offset, _ in diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 841fd452d0..35e87efa7c 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -1738,7 +1738,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD c.dismiss(completion: { if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController { let currentPeerId = strongSelf.peerId - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(currentPeerId), subject: .message(id: message.id, highlight: true), keepStack: .always, useExisting: false, purposefulAction: { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(currentPeerId), subject: .message(id: message.id, highlight: true, timecode: nil), keepStack: .always, useExisting: false, purposefulAction: { var viewControllers = navigationController.viewControllers var indexesToRemove = Set() var keptCurrentChatController = false @@ -1884,7 +1884,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD c.dismiss(completion: { if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController { let currentPeerId = strongSelf.peerId - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(currentPeerId), subject: .message(id: message.id, highlight: true), keepStack: .always, useExisting: false, purposefulAction: { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(currentPeerId), subject: .message(id: message.id, highlight: true, timecode: nil), keepStack: .always, useExisting: false, purposefulAction: { var viewControllers = navigationController.viewControllers var indexesToRemove = Set() var keptCurrentChatController = false @@ -2775,7 +2775,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD if copyUsername, let username = user.username, !username.isEmpty { actions.append(ContextMenuAction(content: .text(title: strongSelf.presentationData.strings.Settings_CopyUsername, accessibilityLabel: strongSelf.presentationData.strings.Settings_CopyUsername), action: { [weak self] in - UIPasteboard.general.string = username + UIPasteboard.general.string = "@\(username)" if let strongSelf = self { let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } diff --git a/submodules/TelegramUI/Sources/TextLinkHandling.swift b/submodules/TelegramUI/Sources/TextLinkHandling.swift index f9bc83d904..3ae0393bb1 100644 --- a/submodules/TelegramUI/Sources/TextLinkHandling.swift +++ b/submodules/TelegramUI/Sources/TextLinkHandling.swift @@ -58,9 +58,9 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate context.sharedContext.applicationBindings.openUrl(url) case let .peer(peerId, navigation): openResolvedPeerImpl(peerId, navigation) - case let .channelMessage(peerId, messageId): + case let .channelMessage(peerId, messageId, timecode): if let navigationController = controller.navigationController as? NavigationController { - context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true))) + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true, timecode: timecode))) } case let .replyThreadMessage(replyThreadMessage, messageId): if let navigationController = controller.navigationController as? NavigationController { diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index fe14cff19f..a1287f3b6c 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -16,7 +16,7 @@ private let baseTelegraPhPaths = ["telegra.ph/", "te.legra.ph/", "graph.org/", " public enum ParsedInternalPeerUrlParameter { case botStart(String) case groupBotStart(String) - case channelMessage(Int32) + case channelMessage(Int32, Double?) case replyThread(Int32, Int32) case voiceChat(String?) } @@ -24,7 +24,7 @@ public enum ParsedInternalPeerUrlParameter { public enum ParsedInternalUrl { case peerName(String, ParsedInternalPeerUrlParameter?) case peerId(PeerId) - case privateMessage(messageId: MessageId, threadId: Int32?) + case privateMessage(messageId: MessageId, threadId: Int32?, timecode: Double?) case stickerPack(String) case join(String) case localization(String) @@ -281,37 +281,44 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? { } else if pathComponents.count == 3 && pathComponents[0] == "c" { if let channelId = Int32(pathComponents[1]), let messageId = Int32(pathComponents[2]) { var threadId: Int32? + var timecode: Double? if let queryItems = components.queryItems { for queryItem in queryItems { if let value = queryItem.value { if queryItem.name == "thread" { if let intValue = Int32(value) { threadId = intValue - break + } + } else if queryItem.name == "t" { + if let doubleValue = Double(value) { + timecode = doubleValue } } } } } - return .privateMessage(messageId: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt32Value(channelId)), namespace: Namespaces.Message.Cloud, id: messageId), threadId: threadId) + return .privateMessage(messageId: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt32Value(channelId)), namespace: Namespaces.Message.Cloud, id: messageId), threadId: threadId, timecode: timecode) } else { return nil } } else if let value = Int32(pathComponents[1]) { var threadId: Int32? var commentId: Int32? + var timecode: Double? if let queryItems = components.queryItems { for queryItem in queryItems { if let value = queryItem.value { if queryItem.name == "thread" { if let intValue = Int32(value) { threadId = intValue - break } } else if queryItem.name == "comment" { if let intValue = Int32(value) { commentId = intValue - break + } + } else if queryItem.name == "t" { + if let doubleValue = Double(value) { + timecode = doubleValue } } } @@ -322,7 +329,7 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? { } else if let commentId = commentId { return .peerName(peerName, .replyThread(value, commentId)) } else { - return .peerName(peerName, .channelMessage(value)) + return .peerName(peerName, .channelMessage(value, timecode)) } } else { return nil @@ -357,8 +364,8 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) return .single(.botStart(peerId: peer.id, payload: payload)) case let .groupBotStart(payload): return .single(.groupBotStart(peerId: peer.id, payload: payload)) - case let .channelMessage(id): - return .single(.channelMessage(peerId: peer.id, messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id))) + case let .channelMessage(id, timecode): + return .single(.channelMessage(peerId: peer.id, messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id), timecode: timecode)) case let .replyThread(id, replyId): let replyThreadMessageId = MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id) return fetchChannelReplyThreadMessage(account: context.account, messageId: replyThreadMessageId, atMessageId: nil) @@ -368,7 +375,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) } |> map { result -> ResolvedUrl? in guard let result = result else { - return .channelMessage(peerId: peer.id, messageId: replyThreadMessageId) + return .channelMessage(peerId: peer.id, messageId: replyThreadMessageId, timecode: nil) } return .replyThreadMessage(replyThreadMessage: result, messageId: MessageId(peerId: result.messageId.peerId, namespace: Namespaces.Message.Cloud, id: replyId)) } @@ -397,7 +404,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) return .single(.inaccessiblePeer) } } - case let .privateMessage(messageId, threadId): + case let .privateMessage(messageId, threadId, timecode): return context.account.postbox.transaction { transaction -> Peer? in return transaction.getPeer(messageId.peerId) } @@ -420,12 +427,12 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) } |> map { result -> ResolvedUrl? in guard let result = result else { - return .channelMessage(peerId: foundPeer.id, messageId: replyThreadMessageId) + return .channelMessage(peerId: foundPeer.id, messageId: replyThreadMessageId, timecode: timecode) } return .replyThreadMessage(replyThreadMessage: result, messageId: messageId) } } else { - return .single(.peer(foundPeer.id, .chat(textInputState: nil, subject: .message(id: messageId, highlight: true), peekData: nil))) + return .single(.peer(foundPeer.id, .chat(textInputState: nil, subject: .message(id: messageId, highlight: true, timecode: timecode), peekData: nil))) } } else { return .single(.inaccessiblePeer) diff --git a/submodules/UrlWhitelist/Sources/UrlWhitelist.swift b/submodules/UrlWhitelist/Sources/UrlWhitelist.swift index fac3604964..7f7c8ef7f3 100644 --- a/submodules/UrlWhitelist/Sources/UrlWhitelist.swift +++ b/submodules/UrlWhitelist/Sources/UrlWhitelist.swift @@ -31,7 +31,7 @@ public func parseUrl(url: String, wasConcealed: Bool) -> (string: String, concea latin.insert(charactersIn: "a"..."z") latin.insert(charactersIn: "0"..."9") var punctuation = CharacterSet() - punctuation.insert(charactersIn: ".-/+_") + punctuation.insert(charactersIn: ".-/+_?=") var hasLatin = false var hasNonLatin = false for c in rawHost {