diff --git a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift index 96eb178e95..e42428259f 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift @@ -347,7 +347,7 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState, } } - result.append(.PeerEntry(index: ChatListIndex.absoluteUpperBound.predecessor, presentationData: state.presentationData, messages: [], readState: nil, isRemovedFromTotalUnreadCount: false, embeddedInterfaceState: nil, peer: RenderedPeer(peerId: savedMessagesPeer.id, peers: SimpleDictionary([savedMessagesPeer.id: savedMessagesPeer])), presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), editing: state.editing, hasActiveRevealControls: false, selected: false, inputActivities: nil, promoInfo: nil, hasFailedMessages: false, isContact: false)) + result.append(.PeerEntry(index: ChatListIndex.absoluteUpperBound.predecessor, presentationData: state.presentationData, messages: [], readState: nil, isRemovedFromTotalUnreadCount: false, embeddedInterfaceState: nil, peer: RenderedPeer(peerId: savedMessagesPeer.id, peers: SimpleDictionary([savedMessagesPeer.id: savedMessagesPeer])), presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), editing: state.editing, hasActiveRevealControls: false, selected: state.selectedPeerIds.contains(savedMessagesPeer.id), inputActivities: nil, promoInfo: nil, hasFailedMessages: false, isContact: false)) } else { if !filteredAdditionalItemEntries.isEmpty { for item in filteredAdditionalItemEntries.reversed() { diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index d7ae82a8aa..b2e443b830 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -166,7 +166,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll private var seekRate: Double = 1.0 var performAction: ((GalleryControllerInteractionTapAction) -> Void)? - var openActionOptions: ((GalleryControllerInteractionTapAction) -> Void)? + var openActionOptions: ((GalleryControllerInteractionTapAction, Message) -> Void)? var content: ChatItemGalleryFooterContent = .info { didSet { @@ -363,8 +363,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } } self.textNode.longTapAttributeAction = { [weak self] attributes, index in - if let strongSelf = self, let action = strongSelf.actionForAttributes(attributes, index) { - strongSelf.openActionOptions?(action) + if let strongSelf = self, let action = strongSelf.actionForAttributes(attributes, index), let message = strongSelf.currentMessage { + strongSelf.openActionOptions?(action, message) } } diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index 3d32dc868e..cb1bce5c5b 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -145,7 +145,7 @@ private func galleryMessageCaptionText(_ message: Message) -> String { return message.text } -public func galleryItemForEntry(context: AccountContext, presentationData: PresentationData, entry: MessageHistoryEntry, isCentral: Bool = false, streamVideos: Bool, loopVideos: Bool = false, hideControls: Bool = false, fromPlayingVideo: Bool = false, isSecret: Bool = false, landscape: Bool = false, timecode: Double? = nil, playbackRate: Double = 1.0, displayInfoOnTop: Bool = false, configuration: GalleryConfiguration? = nil, tempFilePath: String? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }, storeMediaPlaybackState: @escaping (MessageId, Double?, Double) -> Void = { _, _, _ in }, present: @escaping (ViewController, Any?) -> Void) -> GalleryItem? { +public func galleryItemForEntry(context: AccountContext, presentationData: PresentationData, entry: MessageHistoryEntry, isCentral: Bool = false, streamVideos: Bool, loopVideos: Bool = false, hideControls: Bool = false, fromPlayingVideo: Bool = false, isSecret: Bool = false, landscape: Bool = false, timecode: Double? = nil, playbackRate: Double = 1.0, displayInfoOnTop: Bool = false, configuration: GalleryConfiguration? = nil, tempFilePath: String? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }, openActionOptions: @escaping (GalleryControllerInteractionTapAction, Message) -> Void = { _, _ in }, storeMediaPlaybackState: @escaping (MessageId, Double?, Double) -> Void = { _, _, _ in }, present: @escaping (ViewController, Any?) -> Void) -> GalleryItem? { let message = entry.message let location = entry.location if let (media, mediaImage) = mediaForMessage(message: message) { @@ -379,7 +379,7 @@ public class GalleryController: ViewController, StandalonePresentableController private let actionInteraction: GalleryControllerActionInteraction? private var performAction: (GalleryControllerInteractionTapAction) -> Void - private var openActionOptions: (GalleryControllerInteractionTapAction) -> Void + private var openActionOptions: (GalleryControllerInteractionTapAction, Message) -> Void private let updateVisibleDisposable = MetaDisposable() @@ -409,9 +409,9 @@ public class GalleryController: ViewController, StandalonePresentableController performActionImpl?(action) } - var openActionOptionsImpl: ((GalleryControllerInteractionTapAction) -> Void)? - self.openActionOptions = { action in - openActionOptionsImpl?(action) + var openActionOptionsImpl: ((GalleryControllerInteractionTapAction, Message) -> Void)? + self.openActionOptions = { action, message in + openActionOptionsImpl?(action, message) } super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: GalleryController.darkNavigationTheme, strings: NavigationBarStrings(presentationStrings: self.presentationData.strings))) @@ -669,7 +669,7 @@ public class GalleryController: ViewController, StandalonePresentableController } } - openActionOptionsImpl = { [weak self] action in + openActionOptionsImpl = { [weak self] action, message in if let strongSelf = self { var presentationData = strongSelf.presentationData if !presentationData.theme.overallDarkAppearance { @@ -849,6 +849,13 @@ public class GalleryController: ViewController, StandalonePresentableController ]) strongSelf.present(actionSheet, in: .window(.root)) case let .timecode(timecode, text): + 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 + } + let actionSheet = ActionSheetController(presentationData: presentationData) actionSheet.setItemGroups([ActionSheetItemGroup(items: [ ActionSheetTextItem(title: text), @@ -859,12 +866,50 @@ public class GalleryController: ViewController, StandalonePresentableController strongSelf.galleryNode.pager.centralItemNode()?.processAction(.timecode(timecode)) } }), - ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in + ActionSheetButtonItem(title: isCopyLink ? strongSelf.presentationData.strings.Conversation_ContextMenuCopyLink : strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in actionSheet?.dismissAnimated() - UIPasteboard.general.string = text + 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 _ = (context.engine.messages.exportMessageLink(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 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: .window(.root)) + }) + } 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: .window(.root)) + 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: .window(.root)) + } }) ]), ActionSheetItemGroup(items: [ ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in diff --git a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift index 4ffe741eb3..8699695bb8 100644 --- a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift @@ -106,10 +106,10 @@ class ChatImageGalleryItem: GalleryItem { let location: MessageHistoryEntryLocation? let displayInfoOnTop: Bool let performAction: (GalleryControllerInteractionTapAction) -> Void - let openActionOptions: (GalleryControllerInteractionTapAction) -> Void + let openActionOptions: (GalleryControllerInteractionTapAction, Message) -> Void let present: (ViewController, Any?) -> Void - init(context: AccountContext, presentationData: PresentationData, message: Message, location: MessageHistoryEntryLocation?, displayInfoOnTop: Bool, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void, present: @escaping (ViewController, Any?) -> Void) { + init(context: AccountContext, presentationData: PresentationData, message: Message, location: MessageHistoryEntryLocation?, displayInfoOnTop: Bool, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction, Message) -> Void, present: @escaping (ViewController, Any?) -> Void) { self.context = context self.presentationData = presentationData self.message = message @@ -206,7 +206,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { private let dataDisposable = MetaDisposable() private var status: MediaResourceStatus? - init(context: AccountContext, presentationData: PresentationData, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void, present: @escaping (ViewController, Any?) -> Void) { + init(context: AccountContext, presentationData: PresentationData, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction, Message) -> Void, present: @escaping (ViewController, Any?) -> Void) { self.context = context self.imageNode = TransformImageNode() diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index cbb6aa948a..0758cffc8e 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -49,11 +49,11 @@ public class UniversalVideoGalleryItem: GalleryItem { let configuration: GalleryConfiguration? let playbackCompleted: () -> Void let performAction: (GalleryControllerInteractionTapAction) -> Void - let openActionOptions: (GalleryControllerInteractionTapAction) -> Void + let openActionOptions: (GalleryControllerInteractionTapAction, Message) -> Void let storeMediaPlaybackState: (MessageId, Double?, Double) -> Void let present: (ViewController, Any?) -> Void - public init(context: AccountContext, presentationData: PresentationData, content: UniversalVideoContent, originData: GalleryItemOriginData?, indexData: GalleryItemIndexData?, contentInfo: UniversalVideoGalleryItemContentInfo?, caption: NSAttributedString, credit: NSAttributedString? = nil, displayInfoOnTop: Bool = false, hideControls: Bool = false, fromPlayingVideo: Bool = false, isSecret: Bool = false, landscape: Bool = false, timecode: Double? = nil, playbackRate: Double = 1.0, configuration: GalleryConfiguration? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void, storeMediaPlaybackState: @escaping (MessageId, Double?, Double) -> Void, present: @escaping (ViewController, Any?) -> Void) { + public init(context: AccountContext, presentationData: PresentationData, content: UniversalVideoContent, originData: GalleryItemOriginData?, indexData: GalleryItemIndexData?, contentInfo: UniversalVideoGalleryItemContentInfo?, caption: NSAttributedString, credit: NSAttributedString? = nil, displayInfoOnTop: Bool = false, hideControls: Bool = false, fromPlayingVideo: Bool = false, isSecret: Bool = false, landscape: Bool = false, timecode: Double? = nil, playbackRate: Double = 1.0, configuration: GalleryConfiguration? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction, Message) -> Void, storeMediaPlaybackState: @escaping (MessageId, Double?, Double) -> Void, present: @escaping (ViewController, Any?) -> Void) { self.context = context self.presentationData = presentationData self.content = content @@ -518,7 +518,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { private var customUnembedWhenPortrait: ((OverlayMediaItemNode) -> Bool)? - init(context: AccountContext, presentationData: PresentationData, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void, present: @escaping (ViewController, Any?) -> Void) { + init(context: AccountContext, presentationData: PresentationData, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction, Message) -> Void, present: @escaping (ViewController, Any?) -> Void) { self.context = context self.presentationData = presentationData self.scrubberView = ChatVideoGalleryItemScrubberView() diff --git a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift index a0732db93e..5f9ec94ef5 100644 --- a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift +++ b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift @@ -113,7 +113,7 @@ public struct InstantPageGalleryEntry: Equatable { nativeId = .instantPage(self.pageId, file.fileId) } - return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: NativeVideoContent(id: nativeId, fileReference: .webPage(webPage: WebpageReference(webPage), media: file), streamVideo: isMediaStreamable(media: file) ? .conservative : .none), originData: nil, indexData: indexData, contentInfo: .webPage(webPage, file, nil), caption: caption, credit: credit, fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in }, storeMediaPlaybackState: { _, _, _ in }, present: { _, _ in }) + return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: NativeVideoContent(id: nativeId, fileReference: .webPage(webPage: WebpageReference(webPage), media: file), streamVideo: isMediaStreamable(media: file) ? .conservative : .none), originData: nil, indexData: indexData, contentInfo: .webPage(webPage, file, nil), caption: caption, credit: credit, fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _, _ in }, storeMediaPlaybackState: { _, _, _ in }, present: { _, _ in }) } else { var representations: [TelegramMediaImageRepresentation] = [] representations.append(contentsOf: file.previewRepresentations) @@ -135,12 +135,12 @@ public struct InstantPageGalleryEntry: Equatable { present(gallery, InstantPageGalleryControllerPresentationArguments(transitionArguments: { entry -> GalleryTransitionArguments? in return makeArguments() })) - }), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in }, storeMediaPlaybackState: { _, _, _ in }, present: { _, _ in }) + }), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _, _ in }, storeMediaPlaybackState: { _, _, _ in }, present: { _, _ in }) } else { if let content = WebEmbedVideoContent(webPage: embedWebpage, webpageContent: webpageContent, openUrl: { url in }) { - return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: nil, indexData: nil, contentInfo: .webPage(webPage, embedWebpage, nil), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in }, storeMediaPlaybackState: { _, _, _ in }, present: { _, _ in }) + return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: nil, indexData: nil, contentInfo: .webPage(webPage, embedWebpage, nil), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _, _ in }, storeMediaPlaybackState: { _, _, _ in }, present: { _, _ in }) } else { preconditionFailure() } diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index a246100830..259c5d5e0b 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -868,7 +868,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer, panGestureRecognizer === self.seekRecognizer { let velocity = panGestureRecognizer.velocity(in: self.interactiveVideoNode.view) - return velocity.x > velocity.y + return abs(velocity.x) > abs(velocity.y) } return true }