From 98f30de9fbbeb685e455006947900098729574a9 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 19 Apr 2022 17:18:01 +0400 Subject: [PATCH 1/4] Various fixes --- Telegram/Telegram-iOS/Resources/ShareDone.tgs | Bin 0 -> 13616 bytes .../Telegram-iOS/Resources/ShareProgress.tgs | Bin 0 -> 13320 bytes .../Telegram-iOS/en.lproj/Localizable.strings | 3 + .../Sources/MediaPlayerScrubbingNode.swift | 4 +- .../StorageUsageController.swift | 2 +- submodules/ShareController/BUILD | 2 + .../Sources/ShareControllerNode.swift | 19 +- .../Sources/ShareLoadingContainerNode.swift | 235 +++++++++++++++++- .../TranslateUI/Sources/Translate.swift | 2 +- 9 files changed, 256 insertions(+), 11 deletions(-) create mode 100644 Telegram/Telegram-iOS/Resources/ShareDone.tgs create mode 100644 Telegram/Telegram-iOS/Resources/ShareProgress.tgs diff --git a/Telegram/Telegram-iOS/Resources/ShareDone.tgs b/Telegram/Telegram-iOS/Resources/ShareDone.tgs new file mode 100644 index 0000000000000000000000000000000000000000..1a69eec93bebf01dc120b7b8626fc1456a534a8e GIT binary patch literal 13616 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�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 Cbe+%u literal 0 HcmV?d00001 diff --git a/Telegram/Telegram-iOS/Resources/ShareProgress.tgs b/Telegram/Telegram-iOS/Resources/ShareProgress.tgs new file mode 100644 index 0000000000000000000000000000000000000000..78fd296aac34b3feb3d9327f6203acf9c7c1f3ec GIT binary patch literal 13320 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 Void = { [weak self] shouldDelay in let minDelay: Double = shouldDelay ? 0.9 : 0.6 - let delay = max(minDelay, (timestamp + minDelay) - CACurrentMediaTime()) + let delay: Double + if let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareProlongedLoadingContainerNode { + delay = contentNode.completionDuration + } else { + delay = max(minDelay, (timestamp + minDelay) - CACurrentMediaTime()) + } Queue.mainQueue().after(delay, { self?.animateOut(shared: true, completion: { self?.dismiss?(true) @@ -658,7 +663,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate }) } if self.fromForeignApp { - self.transitionToContentNode(ShareLoadingContainerNode(theme: self.presentationData.theme, forceNativeAppearance: true), fastOut: true) + self.transitionToContentNode(ShareProlongedLoadingContainerNode(theme: self.presentationData.theme, strings: self.presentationData.strings, forceNativeAppearance: true), fastOut: true) } else { self.animateOut(shared: true, completion: { }) @@ -683,7 +688,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate return } - guard let contentNode = strongSelf.contentNode as? ShareLoadingContainerNode else { + guard let contentNode = strongSelf.contentNode as? ShareLoadingContainer else { return } @@ -988,7 +993,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate transition.updateAlpha(node: self.actionSeparatorNode, alpha: 0.0) transition.updateAlpha(node: self.actionsBackgroundNode, alpha: 0.0) - self.transitionToContentNode(ShareLoadingContainerNode(theme: self.presentationData.theme, forceNativeAppearance: true), fastOut: true) + self.transitionToContentNode(ShareProlongedLoadingContainerNode(theme: self.presentationData.theme, strings: self.presentationData.strings, forceNativeAppearance: true), fastOut: true) let timestamp = CACurrentMediaTime() self.shareDisposable.set(signal.start(completed: { [weak self] in let minDelay = 0.6 @@ -1041,14 +1046,14 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate } self.shareDisposable.set((signal |> deliverOnMainQueue).start(next: { [weak self] status in - guard let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareLoadingContainerNode else { + guard let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareLoadingContainer else { return } if let status = status { contentNode.state = .progress(status) } }, completed: { [weak self] in - guard let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareLoadingContainerNode else { + guard let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareLoadingContainer else { return } contentNode.state = .done diff --git a/submodules/ShareController/Sources/ShareLoadingContainerNode.swift b/submodules/ShareController/Sources/ShareLoadingContainerNode.swift index 6fc827b501..7cd36680a8 100644 --- a/submodules/ShareController/Sources/ShareLoadingContainerNode.swift +++ b/submodules/ShareController/Sources/ShareLoadingContainerNode.swift @@ -1,11 +1,14 @@ import Foundation import UIKit import AsyncDisplayKit +import SwiftSignalKit import Display import Postbox import TelegramPresentationData import ActivityIndicator import RadialStatusNode +import AnimatedStickerNode +import TelegramAnimatedStickerNode public enum ShareLoadingState { case preparing @@ -13,7 +16,11 @@ public enum ShareLoadingState { case done } -public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContainerNode { +protocol ShareLoadingContainer: ASDisplayNode { + var state: ShareLoadingState { get set } +} + +public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContainerNode, ShareLoadingContainer { private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)? private let theme: PresentationTheme @@ -83,3 +90,229 @@ public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContain public func updateSelectedPeers() { } } + +public final class ShareProlongedLoadingContainerNode: ASDisplayNode, ShareContentContainerNode, ShareLoadingContainer { + private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)? + + private let theme: PresentationTheme + private let strings: PresentationStrings + + private let animationNode: AnimatedStickerNode + private let doneAnimationNode: AnimatedStickerNode + private let progressTextNode: ImmediateTextNode + + private let progressBackgroundNode: ASDisplayNode + private let progressForegroundNode: ASDisplayNode + + private let animationStatusDisposable = MetaDisposable() + + private var progressValue: CGFloat = 0.0 + + private var randomCompletionStart: CGFloat = .random(in: 0.94...0.97) + private var completionProgress: Double = 0.0 + private var isDone: Bool = false + + private var startTimestamp: Double? + + public var state: ShareLoadingState = .preparing { + didSet { + switch self.state { + case .preparing: + break + case let .progress(value): + let currentTimestamp = CACurrentMediaTime() + if self.startTimestamp == nil { + self.startTimestamp = currentTimestamp + } else if let startTimestamp = self.startTimestamp, currentTimestamp - startTimestamp < 1.0, value > 0.5 && value < 0.9 { + self.randomCompletionStart = 0.8 + } + + if let (size, isLandscape, bottomInset) = self.validLayout { + self.updateLayout(size: size, isLandscape: isLandscape, bottomInset: bottomInset, transition: .animated(duration: 0.3, curve: .easeInOut)) + } + case .done: + if let (size, isLandscape, bottomInset) = self.validLayout { + self.updateLayout(size: size, isLandscape: isLandscape, bottomInset: bottomInset, transition: .animated(duration: 0.2, curve: .easeInOut)) + } + self.animationNode.stopAtNearestLoop = true + self.animationNode.completed = { [weak self] _ in + if let strongSelf = self { + strongSelf.animationNode.visibility = false + strongSelf.doneAnimationNode.visibility = true + strongSelf.doneAnimationNode.isHidden = false + } + } + self.animationNode.frameUpdated = { [weak self] index, total in + if let strongSelf = self { + let progress = min(1.0, CGFloat(index) / CGFloat(total)) + if abs(progress - strongSelf.completionProgress) >= 0.05 || progress == 1.0 { + strongSelf.completionProgress = 0.5 * progress + + if let (size, isLandscape, bottomInset) = strongSelf.validLayout { + strongSelf.updateLayout(size: size, isLandscape: isLandscape, bottomInset: bottomInset, transition: .animated(duration: 0.2, curve: .easeInOut)) + } + } + } + } + self.doneAnimationNode.frameUpdated = { [weak self] index, total in + if let strongSelf = self { + let progress = 0.5 + min(1.0, CGFloat(index) / CGFloat(total) * 2.1) * 0.5 + if abs(progress - strongSelf.completionProgress) >= 0.05 || progress == 1.0 { + strongSelf.completionProgress = progress + + if progress == 1.0, !strongSelf.isDone { + strongSelf.isDone = true + + if let snapshotView = strongSelf.progressTextNode.view.snapshotContentTree() { + snapshotView.frame = strongSelf.progressTextNode.frame + strongSelf.view.addSubview(snapshotView) + + snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in + snapshotView?.removeFromSuperview() + }) + snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -20.0), duration: 0.25, removeOnCompletion: false, additive: true) + + strongSelf.progressTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + strongSelf.progressTextNode.layer.animatePosition(from: CGPoint(x: 0.0, y: 20.0), to: CGPoint(), duration: 0.25, additive: true) + } + } + + if let (size, isLandscape, bottomInset) = strongSelf.validLayout { + strongSelf.updateLayout(size: size, isLandscape: isLandscape, bottomInset: bottomInset, transition: .animated(duration: 0.2, curve: .easeInOut)) + } + } + } + } + self.doneAnimationNode.started = { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.animationNode.isHidden = true + } + } + } + } + + private var elapsedTime: Double = 0.0 + public var completionDuration: Double { + return self.elapsedTime + 3.0 + 0.15 + } + + public init(theme: PresentationTheme, strings: PresentationStrings, forceNativeAppearance: Bool) { + self.theme = theme + self.strings = strings + + self.animationNode = AnimatedStickerNode() + self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "ShareProgress"), width: 256, height: 256, playbackMode: .loop, mode: .direct(cachePathPrefix: nil)) + self.animationNode.visibility = true + + self.doneAnimationNode = AnimatedStickerNode() + self.doneAnimationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "ShareDone"), width: 256, height: 256, playbackMode: .once, mode: .direct(cachePathPrefix: nil)) + self.doneAnimationNode.visibility = false + self.doneAnimationNode.isHidden = true + + self.progressTextNode = ImmediateTextNode() + self.progressTextNode.textAlignment = .center + + self.progressBackgroundNode = ASDisplayNode() + self.progressBackgroundNode.backgroundColor = theme.actionSheet.controlAccentColor.withMultipliedAlpha(0.2) + self.progressBackgroundNode.cornerRadius = 3.0 + + self.progressForegroundNode = ASDisplayNode() + self.progressForegroundNode.backgroundColor = theme.actionSheet.controlAccentColor + self.progressForegroundNode.cornerRadius = 3.0 + + super.init() + + self.addSubnode(self.animationNode) + self.addSubnode(self.doneAnimationNode) + + self.addSubnode(self.progressTextNode) + + self.addSubnode(self.progressBackgroundNode) + self.addSubnode(self.progressForegroundNode) + + self.animationStatusDisposable.set((self.animationNode.status + |> deliverOnMainQueue).start(next: { [weak self] status in + if let strongSelf = self { + strongSelf.elapsedTime = status.duration - status.timestamp + } + })) + } + + deinit { + self.animationStatusDisposable.dispose() + } + + public func activate() { + } + + public func deactivate() { + } + + public func setEnsurePeerVisibleOnLayout(_ peerId: PeerId?) { + } + + public func setContentOffsetUpdated(_ f: ((CGFloat, ContainedViewLayoutTransition) -> Void)?) { + self.contentOffsetUpdated = f + } + + private var validLayout: (CGSize, Bool, CGFloat)? + public func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { + self.validLayout = (size, isLandscape, bottomInset) + + let nodeHeight: CGFloat = 400.0 + + let inset: CGFloat = 24.0 + let progressHeight: CGFloat = 6.0 + let spacing: CGFloat = 16.0 + + var progress: CGFloat + switch self.state { + case .preparing: + progress = 0.0 + case let .progress(value): + progress = CGFloat(value) * self.randomCompletionStart + case .done: + progress = self.randomCompletionStart + (1.0 - self.randomCompletionStart) * self.completionProgress + } + self.progressValue = max(self.progressValue, progress) + progress = self.progressValue + + let progressFrame = CGRect(x: inset, y: size.height - inset - progressHeight, width: size.width - inset * 2.0, height: progressHeight) + self.progressBackgroundNode.frame = progressFrame + let progressForegroundFrame = CGRect(x: progressFrame.minX, y: progressFrame.minY, width: floorToScreenPixels(progressFrame.width * progress), height: progressHeight) + if !self.progressForegroundNode.frame.width.isZero { + transition.updateFrame(node: self.progressForegroundNode, frame: progressForegroundFrame) + } else { + self.progressForegroundNode.frame = progressForegroundFrame + } + + let progressText: String + if self.isDone { + progressText = self.strings.Share_UploadDone + } else { + progressText = self.strings.Share_UploadProgress(Int(progress * 100.0)).string + } + + self.progressTextNode.attributedText = NSAttributedString(string: progressText, font: Font.with(size: 17.0, design: .regular, weight: .semibold, traits: [.monospacedNumbers]), textColor: self.theme.actionSheet.primaryTextColor) + let progressTextSize = self.progressTextNode.updateLayout(size) + let progressTextFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - progressTextSize.width) / 2.0), y: progressFrame.minY - spacing - 9.0 - progressTextSize.height), size: progressTextSize) + self.progressTextNode.frame = progressTextFrame + + let imageSide: CGFloat = 160.0 + let imageSize = CGSize(width: imageSide, height: imageSide) + + let animationFrame = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: (progressTextFrame.minY - imageSize.height - 20.0)), size: imageSize) + self.animationNode.frame = animationFrame + self.animationNode.updateLayout(size: imageSize) + + self.doneAnimationNode.frame = animationFrame + self.doneAnimationNode.updateLayout(size: imageSize) + + self.contentOffsetUpdated?(-size.height + nodeHeight * 0.5, transition) + } + + public func updateSelectedPeers() { + } +} diff --git a/submodules/TranslateUI/Sources/Translate.swift b/submodules/TranslateUI/Sources/Translate.swift index 7d385dbb01..99cea256b3 100644 --- a/submodules/TranslateUI/Sources/Translate.swift +++ b/submodules/TranslateUI/Sources/Translate.swift @@ -146,7 +146,7 @@ public func canTranslateText(context: AccountContext, text: String, showTranslat return (false, nil) } - if #available(iOS 15.0, *) { + if #available(iOS 12.0, *) { var dontTranslateLanguages: [String] = [] if let ignoredLanguages = ignoredLanguages { dontTranslateLanguages = ignoredLanguages From d99dbbffb7d3efbc3bdc3e4deb1931c0901c67d9 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 19 Apr 2022 18:41:19 +0400 Subject: [PATCH 2/4] Various Fixes --- .../Sources/ChatMessageBackground.swift | 18 +++++++ .../Sources/ChatMessageBubbleItemNode.swift | 48 +++++++++++-------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/submodules/ChatMessageBackground/Sources/ChatMessageBackground.swift b/submodules/ChatMessageBackground/Sources/ChatMessageBackground.swift index e800808d51..e212ae23f5 100644 --- a/submodules/ChatMessageBackground/Sources/ChatMessageBackground.swift +++ b/submodules/ChatMessageBackground/Sources/ChatMessageBackground.swift @@ -542,6 +542,24 @@ public final class ChatMessageBubbleBackdrop: ASDisplayNode { self.backgroundContent?.offsetSpring(value: value, duration: duration, damping: damping) } + public func updateFrame(_ value: CGRect, animator: ControlledTransitionAnimator, completion: @escaping () -> Void = {}) { + if let maskView = self.maskView { + animator.updateFrame(layer: maskView.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset), completion: nil) + } + if let backgroundContent = self.backgroundContent { + animator.updateFrame(layer: backgroundContent.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)), completion: nil) + if let (rect, containerSize) = self.absolutePosition { + var backgroundFrame = backgroundContent.frame + backgroundFrame.origin.x += rect.minX + backgroundFrame.origin.y += rect.minY + backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .animated(duration: animator.duration, curve: .spring)) + } + } + animator.updateFrame(layer: self.layer, frame: value, completion: { _ in + completion() + }) + } + public func updateFrame(_ value: CGRect, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void = {}) { if let maskView = self.maskView { transition.updateFrame(view: maskView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset)) diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 2495e2d16e..9f7f6ac185 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -2764,31 +2764,37 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode shareButtonNode.removeFromSupernode() } - if case .System = animation/*, !strongSelf.mainContextSourceNode.isExtractedToContextPreview*/ { + if case let .System(duration, _) = animation/*, !strongSelf.mainContextSourceNode.isExtractedToContextPreview*/ { if !strongSelf.backgroundNode.frame.equalTo(backgroundFrame) { - animation.animator.updateFrame(layer: strongSelf.backgroundNode.layer, frame: backgroundFrame, completion: nil) - animation.animator.updatePosition(layer: strongSelf.clippingNode.layer, position: backgroundFrame.center, completion: nil) - strongSelf.clippingNode.clipsToBounds = true - animation.animator.updateBounds(layer: strongSelf.clippingNode.layer, bounds: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size), completion: { [weak strongSelf] _ in - let _ = strongSelf - //strongSelf?.clippingNode.clipsToBounds = false - }) + if useDisplayLinkAnimations { + let backgroundAnimation = ListViewAnimation(from: strongSelf.backgroundNode.frame, to: backgroundFrame, duration: duration * UIView.animationDurationFactor(), curve: strongSelf.preferredAnimationCurve, beginAt: beginAt, update: { [weak strongSelf] _, frame in + if let strongSelf = strongSelf { + strongSelf.backgroundNode.frame = frame + strongSelf.clippingNode.position = CGPoint(x: frame.midX, y: frame.midY) + strongSelf.clippingNode.bounds = CGRect(origin: CGPoint(x: frame.minX, y: frame.minY), size: frame.size) + + strongSelf.backgroundNode.updateLayout(size: frame.size, transition: .immediate) + strongSelf.backgroundWallpaperNode.updateFrame(frame, transition: .immediate) + strongSelf.shadowNode.updateLayout(backgroundFrame: frame, transition: .immediate) + } + }) + strongSelf.setAnimationForKey("backgroundNodeFrame", animation: backgroundAnimation) + } else { + animation.animator.updateFrame(layer: strongSelf.backgroundNode.layer, frame: backgroundFrame, completion: nil) + animation.animator.updatePosition(layer: strongSelf.clippingNode.layer, position: backgroundFrame.center, completion: nil) + strongSelf.clippingNode.clipsToBounds = true + animation.animator.updateBounds(layer: strongSelf.clippingNode.layer, bounds: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size), completion: { [weak strongSelf] _ in + let _ = strongSelf + //strongSelf?.clippingNode.clipsToBounds = false + }) - strongSelf.backgroundNode.updateLayout(size: backgroundFrame.size, transition: animation) - animation.animator.updateFrame(layer: strongSelf.backgroundWallpaperNode.layer, frame: backgroundFrame, completion: nil) - strongSelf.shadowNode.updateLayout(backgroundFrame: backgroundFrame, transition: animation.transition) - strongSelf.backgroundWallpaperNode.updateFrame(backgroundFrame, transition: animation.transition) + strongSelf.backgroundNode.updateLayout(size: backgroundFrame.size, transition: animation) + animation.animator.updateFrame(layer: strongSelf.backgroundWallpaperNode.layer, frame: backgroundFrame, completion: nil) + strongSelf.shadowNode.updateLayout(backgroundFrame: backgroundFrame, transition: animation.transition) + strongSelf.backgroundWallpaperNode.updateFrame(backgroundFrame, transition: animation.transition) + } if let _ = strongSelf.backgroundNode.type { - /*var incomingOffset: CGFloat = 0.0 - switch type { - case .incoming: - incomingOffset = 5.0 - default: - break - }*/ - //strongSelf.mainContextSourceNode.contentRect = backgroundFrame.offsetBy(dx: incomingOffset, dy: 0.0) - //strongSelf.mainContainerNode.targetNodeForActivationProgressContentRect = strongSelf.mainContextSourceNode.contentRect if !strongSelf.mainContextSourceNode.isExtractedToContextPreview { if let (rect, size) = strongSelf.absoluteRect { strongSelf.updateAbsoluteRect(rect, within: size) From aa00ef9d90587957f680e97fc60c32fcb8d451c3 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 19 Apr 2022 19:42:30 +0400 Subject: [PATCH 3/4] Various fixes --- .../AttachmentUI/Sources/MoreButtonNode.swift | 4 +-- .../Sources/MediaPickerScreen.swift | 2 +- .../Sources/PeerInfo/PeerInfoHeaderNode.swift | 27 ++++++++++++++++++- .../WebUI/Sources/WebAppController.swift | 2 +- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/submodules/AttachmentUI/Sources/MoreButtonNode.swift b/submodules/AttachmentUI/Sources/MoreButtonNode.swift index 3317af62bf..1c14ba94cc 100644 --- a/submodules/AttachmentUI/Sources/MoreButtonNode.swift +++ b/submodules/AttachmentUI/Sources/MoreButtonNode.swift @@ -111,13 +111,13 @@ public final class MoreButtonNode: ASDisplayNode { } } - @objc private func buttonPressed() { + @objc public func buttonPressed() { self.action?(self.contextSourceNode, nil) if case .more = self.iconNode.iconState { self.iconNode.play() } } - + override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { let animationSize = CGSize(width: 30.0, height: 30.0) let inset: CGFloat = 0.0 diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index 61ed98cb27..8fd7a75e13 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -1339,7 +1339,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { } @objc private func rightButtonPressed() { - self.moreButtonNode.action?(self.moreButtonNode.contextSourceNode, nil) + self.moreButtonNode.buttonPressed() } public func resetForReuse() { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index 7236e683f6..6081c9d4a5 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -1984,6 +1984,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { let subtitleNodeRawContainer: ASDisplayNode let subtitleNode: MultiScaleTextNode let panelSubtitleNode: MultiScaleTextNode + let nextPanelSubtitleNode: MultiScaleTextNode let usernameNodeContainer: ASDisplayNode let usernameNodeRawContainer: ASDisplayNode let usernameNode: MultiScaleTextNode @@ -2045,6 +2046,9 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.panelSubtitleNode = MultiScaleTextNode(stateKeys: [TitleNodeStateRegular, TitleNodeStateExpanded]) self.panelSubtitleNode.displaysAsynchronously = false + self.nextPanelSubtitleNode = MultiScaleTextNode(stateKeys: [TitleNodeStateRegular, TitleNodeStateExpanded]) + self.nextPanelSubtitleNode.displaysAsynchronously = false + self.usernameNodeContainer = ASDisplayNode() self.usernameNodeRawContainer = ASDisplayNode() self.usernameNode = MultiScaleTextNode(stateKeys: [TitleNodeStateRegular, TitleNodeStateExpanded]) @@ -2101,6 +2105,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.titleNodeContainer.addSubnode(self.titleNode) self.subtitleNodeContainer.addSubnode(self.subtitleNode) self.subtitleNodeContainer.addSubnode(self.panelSubtitleNode) +// self.subtitleNodeContainer.addSubnode(self.nextPanelSubtitleNode) self.usernameNodeContainer.addSubnode(self.usernameNode) self.regularContentNode.addSubnode(self.avatarListNode) @@ -2367,6 +2372,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { let smallSubtitleString: NSAttributedString let subtitleString: NSAttributedString var panelSubtitleString: NSAttributedString? + var nextPanelSubtitleString: NSAttributedString? let usernameString: NSAttributedString if let peer = peer { isVerified = peer.isVerified @@ -2415,7 +2421,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { subtitleString = NSAttributedString(string: statusData.text, font: Font.regular(17.0), textColor: subtitleColor) usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) - let (maybePanelStatusData, _, _) = panelStatusData + let (maybePanelStatusData, maybeNextPanelStatusData, _) = panelStatusData if let panelStatusData = maybePanelStatusData { let subtitleColor: UIColor if panelStatusData.isActivity { @@ -2425,6 +2431,9 @@ final class PeerInfoHeaderNode: ASDisplayNode { } panelSubtitleString = NSAttributedString(string: panelStatusData.text, font: Font.regular(17.0), textColor: subtitleColor) } + if let nextPanelStatusData = maybeNextPanelStatusData { + nextPanelSubtitleString = NSAttributedString(string: nextPanelStatusData.text, font: Font.regular(17.0), textColor: presentationData.theme.list.itemSecondaryTextColor) + } } else { subtitleString = NSAttributedString(string: " ", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) smallSubtitleString = subtitleString @@ -2477,6 +2486,14 @@ final class PeerInfoHeaderNode: ASDisplayNode { ], mainState: TitleNodeStateRegular) self.panelSubtitleNode.accessibilityLabel = (panelSubtitleString ?? subtitleString).string + let nextPanelSubtitleNodeLayout = self.nextPanelSubtitleNode.updateLayout(states: [ + TitleNodeStateRegular: MultiScaleTextState(attributedText: nextPanelSubtitleString ?? subtitleString, constrainedSize: titleConstrainedSize), + TitleNodeStateExpanded: MultiScaleTextState(attributedText: nextPanelSubtitleString ?? subtitleString, constrainedSize: titleConstrainedSize) + ], mainState: TitleNodeStateRegular) + if let _ = nextPanelSubtitleString { + self.nextPanelSubtitleNode.isHidden = false + } + let usernameNodeLayout = self.usernameNode.updateLayout(states: [ TitleNodeStateRegular: MultiScaleTextState(attributedText: usernameString, constrainedSize: CGSize(width: titleConstrainedSize.width, height: titleConstrainedSize.height)), TitleNodeStateExpanded: MultiScaleTextState(attributedText: usernameString, constrainedSize: CGSize(width: width - titleNodeLayout[TitleNodeStateExpanded]!.size.width - 8.0, height: titleConstrainedSize.height)) @@ -2490,6 +2507,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { let titleExpandedSize = titleNodeLayout[TitleNodeStateExpanded]!.size let subtitleSize = subtitleNodeLayout[TitleNodeStateRegular]!.size let _ = panelSubtitleNodeLayout[TitleNodeStateRegular]!.size + let _ = nextPanelSubtitleNodeLayout[TitleNodeStateRegular]!.size let usernameSize = usernameNodeLayout[TitleNodeStateRegular]!.size if let image = self.titleCredibilityIconNode.image { @@ -2596,6 +2614,11 @@ final class PeerInfoHeaderNode: ASDisplayNode { TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0 ], alpha: panelSubtitleAlpha, transition: transition) + self.nextPanelSubtitleNode.update(stateFractions: [ + TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0, + TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0 + ], alpha: panelSubtitleAlpha, transition: transition) + self.usernameNode.update(stateFractions: [ TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0, TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0 @@ -2747,6 +2770,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: CGRect(origin: rawSubtitleFrame.center, size: CGSize())) transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: subtitleOffset), size: CGSize())) transition.updateFrame(node: self.panelSubtitleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelSubtitleOffset), size: CGSize())) + transition.updateFrame(node: self.nextPanelSubtitleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelSubtitleOffset), size: CGSize())) transition.updateFrame(node: self.usernameNode, frame: CGRect(origin: CGPoint(), size: CGSize())) transition.updateSublayerTransformScale(node: self.titleNodeContainer, scale: titleScale) transition.updateSublayerTransformScale(node: self.subtitleNodeContainer, scale: subtitleScale) @@ -2789,6 +2813,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { } transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: subtitleOffset), size: CGSize())) transition.updateFrame(node: self.panelSubtitleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelSubtitleOffset), size: CGSize())) + transition.updateFrame(node: self.nextPanelSubtitleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelSubtitleOffset), size: CGSize())) transition.updateFrame(node: self.usernameNode, frame: CGRect(origin: CGPoint(), size: CGSize())) transition.updateSublayerTransformScaleAdditive(node: self.titleNodeContainer, scale: titleScale) transition.updateSublayerTransformScaleAdditive(node: self.subtitleNodeContainer, scale: subtitleScale) diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 34df4b4d8a..ce125e577e 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -624,7 +624,7 @@ public final class WebAppController: ViewController, AttachmentContainable { } @objc private func moreButtonPressed() { - self.moreButtonNode.action?(self.moreButtonNode.contextSourceNode, nil) + self.moreButtonNode.buttonPressed() } @objc private func morePressed(node: ContextReferenceContentNode, gesture: ContextGesture?) { From 78cc7c543a17a7806f0202516a65951f15f86dd0 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 19 Apr 2022 20:27:45 +0400 Subject: [PATCH 4/4] Various fixes --- .../Sources/MediaPickerScreen.swift | 6 ++++-- .../TelegramUI/Sources/ChatController.swift | 16 +++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index 8fd7a75e13..09a9a7f715 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -113,6 +113,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { private let chatLocation: ChatLocation? private let bannedSendMedia: (Int32, Bool)? private let collection: PHAssetCollection? + private let saveEditedPhotos: Bool private let titleView: MediaPickerTitleView private let moreButtonNode: MoreButtonNode @@ -687,7 +688,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { } let proceed: (Bool) -> Void = { convertToJpeg in - guard let signals = TGMediaAssetsController.resultSignals(for: controller.interaction?.selectionState, editingContext: controller.interaction?.editingState, intent: asFile ? TGMediaAssetsControllerSendFileIntent : TGMediaAssetsControllerSendMediaIntent, currentItem: nil, storeAssets: true, convertToJpeg: convertToJpeg, descriptionGenerator: legacyAssetPickerItemGenerator(), saveEditedPhotos: true) else { + guard let signals = TGMediaAssetsController.resultSignals(for: controller.interaction?.selectionState, editingContext: controller.interaction?.editingState, intent: asFile ? TGMediaAssetsControllerSendFileIntent : TGMediaAssetsControllerSendMediaIntent, currentItem: nil, storeAssets: true, convertToJpeg: convertToJpeg, descriptionGenerator: legacyAssetPickerItemGenerator(), saveEditedPhotos: controller.saveEditedPhotos) else { return } controller.completed = true @@ -1066,7 +1067,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { private var isDismissing = false - public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peer: EnginePeer?, chatLocation: ChatLocation?, bannedSendMedia: (Int32, Bool)?, collection: PHAssetCollection? = nil, editingContext: TGMediaEditingContext? = nil, selectionContext: TGMediaSelectionContext? = nil) { + public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peer: EnginePeer?, chatLocation: ChatLocation?, bannedSendMedia: (Int32, Bool)?, collection: PHAssetCollection? = nil, editingContext: TGMediaEditingContext? = nil, selectionContext: TGMediaSelectionContext? = nil, saveEditedPhotos: Bool = false) { self.context = context let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 } @@ -1076,6 +1077,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { self.chatLocation = chatLocation self.bannedSendMedia = bannedSendMedia self.collection = collection + self.saveEditedPhotos = saveEditedPhotos self.titleView = MediaPickerTitleView(theme: self.presentationData.theme, segments: [self.presentationData.strings.Attachment_AllMedia, self.presentationData.strings.Attachment_SelectedMedia(1)], selectedIndex: 0) self.titleView.title = collection?.localizedTitle ?? presentationData.strings.Attachment_Gallery diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index ac4c31bb2e..64a7a36c93 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -10703,13 +10703,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else { buttons = .single((availableButtons, .gallery)) } + + let dataSettings = self.context.sharedContext.accountManager.transaction { transaction -> GeneratedMediaStoreSettings in + let entry = transaction.getSharedData(ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings)?.get(GeneratedMediaStoreSettings.self) + return entry ?? GeneratedMediaStoreSettings.defaultSettings + } - let _ = (buttons - |> deliverOnMainQueue).start(next: { [weak self] buttons, initialButton in + let _ = combineLatest(queue: Queue.mainQueue(), buttons, dataSettings).start(next: { [weak self] buttonsAndInitialButton, dataSettings in guard let strongSelf = self else { return } + let (buttons, initialButton) = buttonsAndInitialButton + guard let initialButton = initialButton else { if let botId = botId { let _ = (context.engine.messages.getAttachMenuBot(botId: botId) @@ -10751,7 +10757,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G controller.prepareForReuse() return } - strongSelf.presentMediaPicker(bannedSendMedia: bannedSendMedia, present: { controller, mediaPickerContext in + strongSelf.presentMediaPicker(saveEditedPhotos: dataSettings.storeEditedPhotos, bannedSendMedia: bannedSendMedia, present: { controller, mediaPickerContext in let _ = currentMediaController.swap(controller) if !inputText.string.isEmpty { mediaPickerContext?.setCaption(inputText) @@ -11435,11 +11441,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.present(actionSheet, in: .window(.root)) } - private func presentMediaPicker(bannedSendMedia: (Int32, Bool)?, present: @escaping (MediaPickerScreen, AttachmentMediaPickerContext?) -> Void, updateMediaPickerContext: @escaping (AttachmentMediaPickerContext?) -> Void, completion: @escaping ([Any], Bool, Int32?, @escaping (String) -> UIView?, @escaping () -> Void) -> Void) { + private func presentMediaPicker(saveEditedPhotos: Bool, bannedSendMedia: (Int32, Bool)?, present: @escaping (MediaPickerScreen, AttachmentMediaPickerContext?) -> Void, updateMediaPickerContext: @escaping (AttachmentMediaPickerContext?) -> Void, completion: @escaping ([Any], Bool, Int32?, @escaping (String) -> UIView?, @escaping () -> Void) -> Void) { guard let peer = self.presentationInterfaceState.renderedPeer?.peer else { return } - let controller = MediaPickerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: EnginePeer(peer), chatLocation: self.chatLocation, bannedSendMedia: bannedSendMedia) + let controller = MediaPickerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: EnginePeer(peer), chatLocation: self.chatLocation, bannedSendMedia: bannedSendMedia, saveEditedPhotos: saveEditedPhotos) let mediaPickerContext = controller.mediaPickerContext controller.openCamera = { [weak self] cameraView in self?.openCamera(cameraView: cameraView)