Improve media pinch-to-zoom in Instant View

This commit is contained in:
Ilya Laktyushin 2023-03-17 22:52:50 +04:00
parent beedb2ce7e
commit de8aea109f
7 changed files with 48 additions and 27 deletions

View File

@ -20,6 +20,8 @@ final class InstantPageContentNode : ASDisplayNode {
private let longPressMedia: (InstantPageMedia) -> Void private let longPressMedia: (InstantPageMedia) -> Void
private let openPeer: (EnginePeer) -> Void private let openPeer: (EnginePeer) -> Void
private let openUrl: (InstantPageUrlItem) -> Void private let openUrl: (InstantPageUrlItem) -> Void
private let activatePinchPreview: ((PinchSourceContainerNode) -> Void)?
private let pinchPreviewFinished: ((InstantPageNode) -> Void)?
var currentLayoutTiles: [InstantPageTile] = [] var currentLayoutTiles: [InstantPageTile] = []
var currentLayoutItemsWithNodes: [InstantPageItem] = [] var currentLayoutItemsWithNodes: [InstantPageItem] = []
@ -40,7 +42,7 @@ final class InstantPageContentNode : ASDisplayNode {
private var previousVisibleBounds: CGRect? private var previousVisibleBounds: CGRect?
init(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, items: [InstantPageItem], contentSize: CGSize, inOverlayPanel: Bool = false, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void) { init(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, items: [InstantPageItem], contentSize: CGSize, inOverlayPanel: Bool = false, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void) {
self.context = context self.context = context
self.strings = strings self.strings = strings
self.nameDisplayOrder = nameDisplayOrder self.nameDisplayOrder = nameDisplayOrder
@ -49,6 +51,8 @@ final class InstantPageContentNode : ASDisplayNode {
self.openMedia = openMedia self.openMedia = openMedia
self.longPressMedia = longPressMedia self.longPressMedia = longPressMedia
self.activatePinchPreview = activatePinchPreview
self.pinchPreviewFinished = pinchPreviewFinished
self.openPeer = openPeer self.openPeer = openPeer
self.openUrl = openUrl self.openUrl = openUrl
@ -190,19 +194,23 @@ final class InstantPageContentNode : ASDisplayNode {
let detailsIndex = detailsIndex let detailsIndex = detailsIndex
if let newNode = item.node(context: self.context, strings: self.strings, nameDisplayOrder: self.nameDisplayOrder, theme: theme, sourceLocation: self.sourceLocation, openMedia: { [weak self] media in if let newNode = item.node(context: self.context, strings: self.strings, nameDisplayOrder: self.nameDisplayOrder, theme: theme, sourceLocation: self.sourceLocation, openMedia: { [weak self] media in
self?.openMedia(media) self?.openMedia(media)
}, longPressMedia: { [weak self] media in }, longPressMedia: { [weak self] media in
self?.longPressMedia(media) self?.longPressMedia(media)
}, },
activatePinchPreview: nil, activatePinchPreview: { [weak self] node in
pinchPreviewFinished: nil, self?.activatePinchPreview?(node)
openPeer: { [weak self] peerId in },
self?.openPeer(peerId) pinchPreviewFinished: { [weak self] node in
}, openUrl: { [weak self] url in self?.pinchPreviewFinished?(node)
self?.openUrl(url) },
}, updateWebEmbedHeight: { _ in openPeer: { [weak self] peerId in
}, updateDetailsExpanded: { [weak self] expanded in self?.openPeer(peerId)
self?.updateDetailsExpanded(detailsIndex, expanded) }, openUrl: { [weak self] url in
}, currentExpandedDetails: self.currentExpandedDetails) { self?.openUrl(url)
}, updateWebEmbedHeight: { _ in
}, updateDetailsExpanded: { [weak self] expanded in
self?.updateDetailsExpanded(detailsIndex, expanded)
}, currentExpandedDetails: self.currentExpandedDetails) {
newNode.frame = itemFrame newNode.frame = itemFrame
newNode.updateLayout(size: itemFrame.size, transition: transition) newNode.updateLayout(size: itemFrame.size, transition: transition)
if let topNode = topNode { if let topNode = topNode {

View File

@ -166,14 +166,18 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
savedMessages = true savedMessages = true
} else { } else {
if peers.count == 1, let peer = peers.first { if peers.count == 1, let peer = peers.first {
let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) var peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
peerName = peerName.replacingOccurrences(of: "**", with: "")
text = presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string text = presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string
} else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last {
let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) var firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) firstPeerName = firstPeerName.replacingOccurrences(of: "**", with: "")
var secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
secondPeerName = secondPeerName.replacingOccurrences(of: "**", with: "")
text = presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string text = presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string
} else if let peer = peers.first { } else if let peer = peers.first {
let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) var peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
peerName = peerName.replacingOccurrences(of: "**", with: "")
text = presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string text = presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string
} else { } else {
text = "" text = ""
@ -1340,6 +1344,10 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let navigationController = strongSelf.getNavigationController() { if let navigationController = strongSelf.getNavigationController() {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), attachBotStart: attachBotStart)) strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), attachBotStart: attachBotStart))
} }
case let .withBotApp(botAppStart):
if let navigationController = strongSelf.getNavigationController() {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), botAppStart: botAppStart))
}
case .info: case .info:
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peer.id)) let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peer.id))
|> deliverOnMainQueue).start(next: { peer in |> deliverOnMainQueue).start(next: { peer in

View File

@ -45,7 +45,7 @@ final class InstantPageDetailsItem: InstantPageItem {
if let expandedDetails = currentExpandedDetails, let currentlyExpanded = expandedDetails[self.index] { if let expandedDetails = currentExpandedDetails, let currentlyExpanded = expandedDetails[self.index] {
expanded = currentlyExpanded expanded = currentlyExpanded
} }
return InstantPageDetailsNode(context: context, sourceLocation: sourceLocation, strings: strings, nameDisplayOrder: nameDisplayOrder, theme: theme, item: self, openMedia: openMedia, longPressMedia: longPressMedia, openPeer: openPeer, openUrl: openUrl, currentlyExpanded: expanded, updateDetailsExpanded: updateDetailsExpanded) return InstantPageDetailsNode(context: context, sourceLocation: sourceLocation, strings: strings, nameDisplayOrder: nameDisplayOrder, theme: theme, item: self, openMedia: openMedia, longPressMedia: longPressMedia, activatePinchPreview: activatePinchPreview, pinchPreviewFinished: pinchPreviewFinished, openPeer: openPeer, openUrl: openUrl, currentlyExpanded: expanded, updateDetailsExpanded: updateDetailsExpanded)
} }
func matchesAnchor(_ anchor: String) -> Bool { func matchesAnchor(_ anchor: String) -> Bool {

View File

@ -35,7 +35,7 @@ final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
var requestLayoutUpdate: ((Bool) -> Void)? var requestLayoutUpdate: ((Bool) -> Void)?
init(context: AccountContext, sourceLocation: InstantPageSourceLocation, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, item: InstantPageDetailsItem, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, currentlyExpanded: Bool?, updateDetailsExpanded: @escaping (Bool) -> Void) { init(context: AccountContext, sourceLocation: InstantPageSourceLocation, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, item: InstantPageDetailsItem, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, currentlyExpanded: Bool?, updateDetailsExpanded: @escaping (Bool) -> Void) {
self.context = context self.context = context
self.strings = strings self.strings = strings
self.nameDisplayOrder = nameDisplayOrder self.nameDisplayOrder = nameDisplayOrder
@ -65,7 +65,7 @@ final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
self.arrowNode = InstantPageDetailsArrowNode(color: theme.controlColor, open: self.expanded) self.arrowNode = InstantPageDetailsArrowNode(color: theme.controlColor, open: self.expanded)
self.separatorNode = ASDisplayNode() self.separatorNode = ASDisplayNode()
self.contentNode = InstantPageContentNode(context: context, strings: strings, nameDisplayOrder: nameDisplayOrder, sourceLocation: sourceLocation, theme: theme, items: item.items, contentSize: CGSize(width: item.frame.width, height: item.frame.height - item.titleHeight), openMedia: openMedia, longPressMedia: longPressMedia, openPeer: openPeer, openUrl: openUrl) self.contentNode = InstantPageContentNode(context: context, strings: strings, nameDisplayOrder: nameDisplayOrder, sourceLocation: sourceLocation, theme: theme, items: item.items, contentSize: CGSize(width: item.frame.width, height: item.frame.height - item.titleHeight), openMedia: openMedia, longPressMedia: longPressMedia, activatePinchPreview: activatePinchPreview, pinchPreviewFinished: pinchPreviewFinished, openPeer: openPeer, openUrl: openUrl)
super.init() super.init()

View File

@ -204,7 +204,7 @@ class InstantPageReferenceControllerNode: ViewControllerTracingNode, UIScrollVie
let sideInset: CGFloat = 16.0 let sideInset: CGFloat = 16.0
let (_, items, contentSize) = layoutTextItemWithString(self.anchorText, boundingWidth: width - sideInset * 2.0, offset: CGPoint(x: sideInset, y: sideInset), media: media, webpage: self.webPage) let (_, items, contentSize) = layoutTextItemWithString(self.anchorText, boundingWidth: width - sideInset * 2.0, offset: CGPoint(x: sideInset, y: sideInset), media: media, webpage: self.webPage)
let contentNode = InstantPageContentNode(context: self.context, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder, sourceLocation: self.sourceLocation, theme: self.theme, items: items, contentSize: CGSize(width: width, height: contentSize.height), inOverlayPanel: true, openMedia: { _ in }, longPressMedia: { _ in }, openPeer: { _ in }, openUrl: { _ in }) let contentNode = InstantPageContentNode(context: self.context, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder, sourceLocation: self.sourceLocation, theme: self.theme, items: items, contentSize: CGSize(width: width, height: contentSize.height), inOverlayPanel: true, openMedia: { _ in }, longPressMedia: { _ in }, activatePinchPreview: nil, pinchPreviewFinished: nil, openPeer: { _ in }, openUrl: { _ in })
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: titleAreaHeight), size: CGSize(width: width, height: contentSize.height))) transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: titleAreaHeight), size: CGSize(width: width, height: contentSize.height)))
self.contentContainerNode.insertSubnode(contentNode, at: 0) self.contentContainerNode.insertSubnode(contentNode, at: 0)
self.contentNode = contentNode self.contentNode = contentNode

View File

@ -22,7 +22,7 @@ final class InstantPageSlideshowItem: InstantPageItem {
} }
func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? { func node(context: AccountContext, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, theme: InstantPageTheme, sourceLocation: InstantPageSourceLocation, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, openPeer: @escaping (EnginePeer) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void, currentExpandedDetails: [Int : Bool]?) -> InstantPageNode? {
return InstantPageSlideshowNode(context: context, sourceLocation: sourceLocation, theme: theme, webPage: webPage, medias: self.medias, openMedia: openMedia, longPressMedia: longPressMedia) return InstantPageSlideshowNode(context: context, sourceLocation: sourceLocation, theme: theme, webPage: webPage, medias: self.medias, openMedia: openMedia, longPressMedia: longPressMedia, activatePinchPreview: activatePinchPreview, pinchPreviewFinished: pinchPreviewFinished)
} }
func matchesAnchor(_ anchor: String) -> Bool { func matchesAnchor(_ anchor: String) -> Bool {

View File

@ -6,6 +6,7 @@ import Display
import TelegramPresentationData import TelegramPresentationData
import AccountContext import AccountContext
import TelegramUIPreferences import TelegramUIPreferences
import ContextUI
private final class InstantPageSlideshowItemNode: ASDisplayNode { private final class InstantPageSlideshowItemNode: ASDisplayNode {
private var _index: Int? private var _index: Int?
@ -69,6 +70,8 @@ private final class InstantPageSlideshowPagerNode: ASDisplayNode, UIScrollViewDe
private let webPage: TelegramMediaWebpage private let webPage: TelegramMediaWebpage
private let openMedia: (InstantPageMedia) -> Void private let openMedia: (InstantPageMedia) -> Void
private let longPressMedia: (InstantPageMedia) -> Void private let longPressMedia: (InstantPageMedia) -> Void
private let activatePinchPreview: ((PinchSourceContainerNode) -> Void)?
private let pinchPreviewFinished: ((InstantPageNode) -> Void)?
private let pageGap: CGFloat private let pageGap: CGFloat
private let scrollView: UIScrollView private let scrollView: UIScrollView
@ -98,13 +101,15 @@ private final class InstantPageSlideshowPagerNode: ASDisplayNode, UIScrollViewDe
} }
} }
init(context: AccountContext, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, webPage: TelegramMediaWebpage, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, pageGap: CGFloat = 0.0) { init(context: AccountContext, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, webPage: TelegramMediaWebpage, openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?, pageGap: CGFloat = 0.0) {
self.context = context self.context = context
self.sourceLocation = sourceLocation self.sourceLocation = sourceLocation
self.theme = theme self.theme = theme
self.webPage = webPage self.webPage = webPage
self.openMedia = openMedia self.openMedia = openMedia
self.longPressMedia = longPressMedia self.longPressMedia = longPressMedia
self.activatePinchPreview = activatePinchPreview
self.pinchPreviewFinished = pinchPreviewFinished
self.pageGap = pageGap self.pageGap = pageGap
self.scrollView = UIScrollView() self.scrollView = UIScrollView()
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) { if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
@ -182,7 +187,7 @@ private final class InstantPageSlideshowPagerNode: ASDisplayNode, UIScrollViewDe
let media = self.items[index] let media = self.items[index]
let contentNode: ASDisplayNode let contentNode: ASDisplayNode
if let _ = media.media as? TelegramMediaImage { if let _ = media.media as? TelegramMediaImage {
contentNode = InstantPageImageNode(context: self.context, sourceLocation: self.sourceLocation, theme: self.theme, webPage: self.webPage, media: media, attributes: [], interactive: true, roundCorners: false, fit: false, openMedia: self.openMedia, longPressMedia: self.longPressMedia, activatePinchPreview: nil, pinchPreviewFinished: nil) contentNode = InstantPageImageNode(context: self.context, sourceLocation: self.sourceLocation, theme: self.theme, webPage: self.webPage, media: media, attributes: [], interactive: true, roundCorners: false, fit: false, openMedia: self.openMedia, longPressMedia: self.longPressMedia, activatePinchPreview: self.activatePinchPreview, pinchPreviewFinished: self.pinchPreviewFinished)
} else if let _ = media.media as? TelegramMediaFile { } else if let _ = media.media as? TelegramMediaFile {
contentNode = ASDisplayNode() contentNode = ASDisplayNode()
} else { } else {
@ -381,10 +386,10 @@ final class InstantPageSlideshowNode: ASDisplayNode, InstantPageNode {
private let pagerNode: InstantPageSlideshowPagerNode private let pagerNode: InstantPageSlideshowPagerNode
private let pageControlNode: PageControlNode private let pageControlNode: PageControlNode
init(context: AccountContext, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, webPage: TelegramMediaWebpage, medias: [InstantPageMedia], openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void) { init(context: AccountContext, sourceLocation: InstantPageSourceLocation, theme: InstantPageTheme, webPage: TelegramMediaWebpage, medias: [InstantPageMedia], openMedia: @escaping (InstantPageMedia) -> Void, longPressMedia: @escaping (InstantPageMedia) -> Void, activatePinchPreview: ((PinchSourceContainerNode) -> Void)?, pinchPreviewFinished: ((InstantPageNode) -> Void)?) {
self.medias = medias self.medias = medias
self.pagerNode = InstantPageSlideshowPagerNode(context: context, sourceLocation: sourceLocation, theme: theme, webPage: webPage, openMedia: openMedia, longPressMedia: longPressMedia) self.pagerNode = InstantPageSlideshowPagerNode(context: context, sourceLocation: sourceLocation, theme: theme, webPage: webPage, openMedia: openMedia, longPressMedia: longPressMedia, activatePinchPreview: activatePinchPreview, pinchPreviewFinished: pinchPreviewFinished)
self.pagerNode.replaceItems(medias, centralItemIndex: nil) self.pagerNode.replaceItems(medias, centralItemIndex: nil)
self.pageControlNode = PageControlNode(dotColor: .white, inactiveDotColor: UIColor(white: 1.0, alpha: 0.5)) self.pageControlNode = PageControlNode(dotColor: .white, inactiveDotColor: UIColor(white: 1.0, alpha: 0.5))