diff --git a/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift b/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift index c6e303c22d..d5afd29a15 100644 --- a/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift +++ b/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift @@ -105,6 +105,48 @@ public enum PeerInfoAvatarListItem: Equatable { } } + func isSemanticallyEqual(to: PeerInfoAvatarListItem) -> Bool { + if case let .topImage(lhsRepresentations, _, _) = self { + if case let .topImage(rhsRepresentations, _, _) = self { + if let lhsRepresentation = largestImageRepresentation(lhsRepresentations.map { $0.representation }), + let rhsRepresentation = largestImageRepresentation(rhsRepresentations.map { $0.representation }) { + return lhsRepresentation.isSemanticallyEqual(to: rhsRepresentation) + } else { + return false + } + } else if case let .image(_, rhsRepresentations, _, _) = self { + if let lhsRepresentation = largestImageRepresentation(lhsRepresentations.map { $0.representation }), + let rhsRepresentation = largestImageRepresentation(rhsRepresentations.map { $0.representation }) { + return lhsRepresentation.isSemanticallyEqual(to: rhsRepresentation) + } else { + return false + } + } else { + return false + } + } else if case let .image(_, lhsRepresentations, _, _) = self { + if case let .topImage(rhsRepresentations, _, _) = self { + if let lhsRepresentation = largestImageRepresentation(lhsRepresentations.map { $0.representation }), + let rhsRepresentation = largestImageRepresentation(rhsRepresentations.map { $0.representation }) { + return lhsRepresentation.isSemanticallyEqual(to: rhsRepresentation) + } else { + return false + } + } else if case let .image(_, rhsRepresentations, _, _) = self { + if let lhsRepresentation = largestImageRepresentation(lhsRepresentations.map { $0.representation }), + let rhsRepresentation = largestImageRepresentation(rhsRepresentations.map { $0.representation }) { + return lhsRepresentation.isSemanticallyEqual(to: rhsRepresentation) + } else { + return false + } + } else { + return false + } + } else { + return false + } + } + var representations: [ImageRepresentationWithReference] { switch self { case .custom: @@ -344,9 +386,15 @@ public final class PeerInfoAvatarListItemNode: ASDisplayNode { } func setup(item: PeerInfoAvatarListItem, isMain: Bool, progress: Signal? = nil, synchronous: Bool, fullSizeOnly: Bool = false) { + let previousItem = self.item self.item = item self.progress = progress + var fullSizeOnly = fullSizeOnly + if let previousItem = previousItem, previousItem.isSemanticallyEqual(to: item) && self.didSetReady && isMain { + fullSizeOnly = true + } + if let progress = progress { self.loadingProgress.set((progress |> beforeNext { [weak self] next in @@ -1142,7 +1190,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode { var additiveTransitionOffset: CGFloat = 0.0 var itemsAdded = false if self.currentIndex >= 0 && self.currentIndex < self.items.count { - let preloadSpan: Int = 2 + let preloadSpan: Int = 0 for i in max(0, self.currentIndex - preloadSpan) ... min(self.currentIndex + preloadSpan, self.items.count - 1) { if self.items[i].representations.isEmpty { continue diff --git a/submodules/PhotoResources/Sources/PhotoResources.swift b/submodules/PhotoResources/Sources/PhotoResources.swift index 903d223334..2e9b45696c 100644 --- a/submodules/PhotoResources/Sources/PhotoResources.swift +++ b/submodules/PhotoResources/Sources/PhotoResources.swift @@ -2343,7 +2343,7 @@ public func svgIconImageFile(account: Account, fileReference: FileMediaReference } } -private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], immediateThumbnailData: Data?, autoFetchFullSize: Bool = false, attemptSynchronously: Bool = false) -> Signal, NoError> { +private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], immediateThumbnailData: Data?, autoFetchFullSize: Bool = false, attemptSynchronously: Bool = false, skipThumbnail: Bool = false) -> Signal, NoError> { if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.representation })), let largestRepresentation = largestImageRepresentation(representations.map({ $0.representation })), let smallestIndex = representations.firstIndex(where: { $0.representation == smallestRepresentation }), let largestIndex = representations.firstIndex(where: { $0.representation == largestRepresentation }) { let maybeFullSize = account.postbox.mediaBox.resourceData(largestRepresentation.resource, attemptSynchronously: attemptSynchronously) @@ -2403,9 +2403,19 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR } } - return thumbnail |> mapToSignal { thumbnailData in - return fullSizeData |> map { value in - return Tuple(thumbnailData, value._0, value._1) + if skipThumbnail { + return fullSizeData |> mapToSignal { value -> Signal , NoError> in + if value._1 { + return .single(Tuple(nil, value._0, value._1)) + } else { + return .complete() + } + } + } else { + return thumbnail |> mapToSignal { thumbnailData in + return fullSizeData |> map { value in + return Tuple(thumbnailData, value._0, value._1) + } } } } @@ -2418,7 +2428,7 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR } public func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepresentationWithReference], immediateThumbnailData: Data?, autoFetchFullSize: Bool = false, attemptSynchronously: Bool = false, skipThumbnail: Bool = false, skipBlurIfLarge: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { - let signal = avatarGalleryPhotoDatas(account: account, representations: representations, immediateThumbnailData: immediateThumbnailData, autoFetchFullSize: autoFetchFullSize, attemptSynchronously: attemptSynchronously) + let signal = avatarGalleryPhotoDatas(account: account, representations: representations, immediateThumbnailData: immediateThumbnailData, autoFetchFullSize: autoFetchFullSize, attemptSynchronously: attemptSynchronously, skipThumbnail: skipThumbnail) return signal |> map { value in diff --git a/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift index fae0dc6a57..4c6f222d5b 100644 --- a/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift @@ -151,86 +151,90 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode { self.messageDisposable.set((context.account.postbox.messagesAtIds(messageIds) |> deliverOnMainQueue).start(next: { [weak self] messages in if let strongSelf = self { - var authors = "" - var uniquePeerIds = Set() - var title = "" - var text = "" - var sourcePeer: (Bool, String)? - for message in messages { - if let author = message.forwardInfo?.author ?? message.effectiveAuthor, !uniquePeerIds.contains(author.id) { - uniquePeerIds.insert(author.id) - if !authors.isEmpty { - authors.append(", ") - } - if author.id == context.account.peerId { - authors.append(strongSelf.strings.DialogList_You) - } else { - authors.append(EnginePeer(author).compactDisplayTitle) - } - } - if let peer = message.peers[message.id.peerId] { - sourcePeer = (peer.id.namespace == Namespaces.Peer.CloudUser, EnginePeer(peer).displayTitle(strings: strongSelf.strings, displayOrder: strongSelf.nameDisplayOrder)) - } - } - - if messages.count == 1 { - title = strongSelf.strings.Conversation_ForwardOptions_ForwardTitleSingle - let (string, _) = textStringForForwardedMessage(messages[0], strings: strings) - text = "\(authors): \(string)" + if messages.isEmpty { + strongSelf.dismiss?() } else { - title = strongSelf.strings.Conversation_ForwardOptions_ForwardTitle(Int32(messages.count)) - text = strongSelf.strings.Conversation_ForwardFrom(authors).string - } - - strongSelf.messages = messages - strongSelf.sourcePeer = sourcePeer - strongSelf.authors = authors - - strongSelf.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor) - strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: strongSelf.theme.chat.inputPanel.secondaryTextColor) - - let headerString: String - if messages.count == 1 { - headerString = "Forward message" - } else { - headerString = "Forward messages" - } - strongSelf.actionArea.accessibilityLabel = "\(headerString). From: \(authors).\n\(text)" - - if let (size, inset, interfaceState) = strongSelf.validLayout { - strongSelf.updateState(size: size, inset: inset, interfaceState: interfaceState) - } - - let _ = (ApplicationSpecificNotice.getChatForwardOptionsTip(accountManager: strongSelf.context.sharedContext.accountManager) - |> deliverOnMainQueue).start(next: { [weak self] count in - if let strongSelf = self, count < 3 { - Queue.mainQueue().after(3.0) { - if let snapshotView = strongSelf.textNode.view.snapshotContentTree() { - let text: String - if let (size, _, _) = strongSelf.validLayout, size.width > 320.0 { - text = strongSelf.strings.Conversation_ForwardOptions_TapForOptions - } else { - text = strongSelf.strings.Conversation_ForwardOptions_TapForOptionsShort - } - - strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: strongSelf.theme.chat.inputPanel.secondaryTextColor) - - strongSelf.view.addSubview(snapshotView) - - if let (size, inset, interfaceState) = strongSelf.validLayout { - strongSelf.updateState(size: size, inset: inset, interfaceState: interfaceState) - } - - strongSelf.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) - snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in - snapshotView?.removeFromSuperview() - }) + var authors = "" + var uniquePeerIds = Set() + var title = "" + var text = "" + var sourcePeer: (Bool, String)? + for message in messages { + if let author = message.forwardInfo?.author ?? message.effectiveAuthor, !uniquePeerIds.contains(author.id) { + uniquePeerIds.insert(author.id) + if !authors.isEmpty { + authors.append(", ") } - - let _ = ApplicationSpecificNotice.incrementChatForwardOptionsTip(accountManager: strongSelf.context.sharedContext.accountManager).start() + if author.id == context.account.peerId { + authors.append(strongSelf.strings.DialogList_You) + } else { + authors.append(EnginePeer(author).compactDisplayTitle) + } + } + if let peer = message.peers[message.id.peerId] { + sourcePeer = (peer.id.namespace == Namespaces.Peer.CloudUser, EnginePeer(peer).displayTitle(strings: strongSelf.strings, displayOrder: strongSelf.nameDisplayOrder)) } } - }) + + if messages.count == 1 { + title = strongSelf.strings.Conversation_ForwardOptions_ForwardTitleSingle + let (string, _) = textStringForForwardedMessage(messages[0], strings: strings) + text = "\(authors): \(string)" + } else { + title = strongSelf.strings.Conversation_ForwardOptions_ForwardTitle(Int32(messages.count)) + text = strongSelf.strings.Conversation_ForwardFrom(authors).string + } + + strongSelf.messages = messages + strongSelf.sourcePeer = sourcePeer + strongSelf.authors = authors + + strongSelf.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor) + strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: strongSelf.theme.chat.inputPanel.secondaryTextColor) + + let headerString: String + if messages.count == 1 { + headerString = "Forward message" + } else { + headerString = "Forward messages" + } + strongSelf.actionArea.accessibilityLabel = "\(headerString). From: \(authors).\n\(text)" + + if let (size, inset, interfaceState) = strongSelf.validLayout { + strongSelf.updateState(size: size, inset: inset, interfaceState: interfaceState) + } + + let _ = (ApplicationSpecificNotice.getChatForwardOptionsTip(accountManager: strongSelf.context.sharedContext.accountManager) + |> deliverOnMainQueue).start(next: { [weak self] count in + if let strongSelf = self, count < 3 { + Queue.mainQueue().after(3.0) { + if let snapshotView = strongSelf.textNode.view.snapshotContentTree() { + let text: String + if let (size, _, _) = strongSelf.validLayout, size.width > 320.0 { + text = strongSelf.strings.Conversation_ForwardOptions_TapForOptions + } else { + text = strongSelf.strings.Conversation_ForwardOptions_TapForOptionsShort + } + + strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: strongSelf.theme.chat.inputPanel.secondaryTextColor) + + strongSelf.view.addSubview(snapshotView) + + if let (size, inset, interfaceState) = strongSelf.validLayout { + strongSelf.updateState(size: size, inset: inset, interfaceState: interfaceState) + } + + strongSelf.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in + snapshotView?.removeFromSuperview() + }) + } + + let _ = ApplicationSpecificNotice.incrementChatForwardOptionsTip(accountManager: strongSelf.context.sharedContext.accountManager).start() + } + } + }) + } } })) } diff --git a/submodules/WebUI/Sources/WebAppWebView.swift b/submodules/WebUI/Sources/WebAppWebView.swift index c4740fdd36..4adf65fe62 100644 --- a/submodules/WebUI/Sources/WebAppWebView.swift +++ b/submodules/WebUI/Sources/WebAppWebView.swift @@ -65,12 +65,13 @@ final class WebAppWebView: WKWebView { configuration.userContentController = userController configuration.allowsInlineMediaPlayback = true + configuration.allowsPictureInPictureMediaPlayback = false if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { - configuration.mediaTypesRequiringUserActionForPlayback = [] + configuration.mediaTypesRequiringUserActionForPlayback = .all } else if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { - configuration.requiresUserActionForMediaPlayback = false + configuration.requiresUserActionForMediaPlayback = true } else { - configuration.mediaPlaybackRequiresUserAction = false + configuration.mediaPlaybackRequiresUserAction = true } super.init(frame: CGRect(), configuration: configuration)