From 517df89e9a01ae1706f9b4a530c783cea1e63e46 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 7 Apr 2022 12:19:21 +0400 Subject: [PATCH 1/9] Web app improvements --- .../Sources/AttachmentPanel.swift | 15 +++++++----- .../Sources/AnimatedStickerComponent.swift | 14 +++++++---- .../ContextControllerActionsStackNode.swift | 2 +- .../Context Menu/Shadow.imageset/Shadow.png | Bin 8137 -> 6680 bytes .../Sources/ChatTextInputPanelNode.swift | 22 +++++++++--------- .../WebUI/Sources/WebAppController.swift | 3 ++- 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index c05e10b035..cec0635799 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -221,9 +221,9 @@ private final class AttachButtonComponent: CombinedComponent { animation: AnimatedStickerComponent.Animation( source: .file(media: animationFile), scale: UIScreenScale, - loop: false, - tintColor: tintColor + loop: false ), + tintColor: tintColor, isAnimating: component.isSelected, size: CGSize(width: iconSize.width, height: iconSize.height) ), @@ -361,23 +361,26 @@ public struct AttachmentMainButtonState { let textColor: UIColor let isVisible: Bool let isLoading: Bool + let isEnabled: Bool public init( text: String?, backgroundColor: UIColor, textColor: UIColor, isVisible: Bool, - isLoading: Bool + isLoading: Bool, + isEnabled: Bool ) { self.text = text self.backgroundColor = backgroundColor self.textColor = textColor self.isVisible = isVisible self.isLoading = isLoading + self.isEnabled = isEnabled } static var initial: AttachmentMainButtonState { - return AttachmentMainButtonState(text: nil, backgroundColor: .clear, textColor: .clear, isVisible: false, isLoading: false) + return AttachmentMainButtonState(text: nil, backgroundColor: .clear, textColor: .clear, isVisible: false, isLoading: false, isEnabled: false) } } @@ -401,7 +404,7 @@ private final class MainButtonNode: HighlightTrackingButtonNode { self.addSubnode(self.statusNode) self.highligthedChanged = { [weak self] highlighted in - if let strongSelf = self { + if let strongSelf = self, strongSelf.state.isEnabled { if highlighted { strongSelf.layer.removeAnimation(forKey: "opacity") strongSelf.alpha = 0.65 @@ -899,7 +902,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { func updateMainButtonState(_ mainButtonState: AttachmentMainButtonState?) { var currentButtonState = self.mainButtonState if mainButtonState == nil { - currentButtonState = AttachmentMainButtonState(text: currentButtonState.text, backgroundColor: currentButtonState.backgroundColor, textColor: currentButtonState.textColor, isVisible: false, isLoading: false) + currentButtonState = AttachmentMainButtonState(text: currentButtonState.text, backgroundColor: currentButtonState.backgroundColor, textColor: currentButtonState.textColor, isVisible: false, isLoading: false, isEnabled: currentButtonState.isEnabled) } self.mainButtonState = mainButtonState ?? currentButtonState } diff --git a/submodules/Components/AnimatedStickerComponent/Sources/AnimatedStickerComponent.swift b/submodules/Components/AnimatedStickerComponent/Sources/AnimatedStickerComponent.swift index 2207c317cd..7d02c4498b 100644 --- a/submodules/Components/AnimatedStickerComponent/Sources/AnimatedStickerComponent.swift +++ b/submodules/Components/AnimatedStickerComponent/Sources/AnimatedStickerComponent.swift @@ -16,24 +16,24 @@ public final class AnimatedStickerComponent: Component { public var source: Source public var scale: CGFloat public var loop: Bool - public var tintColor: UIColor? - public init(source: Source, scale: CGFloat = 2.0, loop: Bool, tintColor: UIColor? = nil) { + public init(source: Source, scale: CGFloat = 2.0, loop: Bool) { self.source = source self.scale = scale self.loop = loop - self.tintColor = tintColor } } public let account: Account public let animation: Animation + public var tintColor: UIColor? public let isAnimating: Bool public let size: CGSize - public init(account: Account, animation: Animation, isAnimating: Bool = true, size: CGSize) { + public init(account: Account, animation: Animation, tintColor: UIColor? = nil, isAnimating: Bool = true, size: CGSize) { self.account = account self.animation = animation + self.tintColor = tintColor self.isAnimating = isAnimating self.size = size } @@ -45,6 +45,9 @@ public final class AnimatedStickerComponent: Component { if lhs.animation != rhs.animation { return false } + if lhs.tintColor != rhs.tintColor { + return false + } if lhs.isAnimating != rhs.isAnimating { return false } @@ -100,7 +103,6 @@ public final class AnimatedStickerComponent: Component { case let .file(media): source = AnimatedStickerResourceSource(account: component.account, resource: media.resource, fitzModifier: nil, isVideo: false) } - animationNode.setOverlayColor(component.animation.tintColor, replace: true, animated: false) var playbackMode: AnimatedStickerPlaybackMode = .still(.start) if component.animation.loop { @@ -115,6 +117,8 @@ public final class AnimatedStickerComponent: Component { self.addSubnode(animationNode) } + self.animationNode?.setOverlayColor(component.tintColor, replace: true, animated: false) + if !component.animation.loop && component.isAnimating != self.component?.isAnimating { if component.isAnimating { let _ = self.animationNode?.playIfNeeded() diff --git a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift index 2b9d504e72..49a5be128b 100644 --- a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift @@ -714,7 +714,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode { override init() { self.backgroundNode = NavigationBackgroundNode(color: .clear, enableBlur: false) self.parentShadowNode = ASImageNode() - self.parentShadowNode.image = UIImage(bundleImageName: "Components/Context Menu/Shadow")?.stretchableImage(withLeftCapWidth: 60, topCapHeight: 60) + self.parentShadowNode.image = UIImage(bundleImageName: "Components/Context Menu/Shadow")?.stretchableImage(withLeftCapWidth: 60, topCapHeight: 48) super.init() diff --git a/submodules/TelegramUI/Images.xcassets/Components/Context Menu/Shadow.imageset/Shadow.png b/submodules/TelegramUI/Images.xcassets/Components/Context Menu/Shadow.imageset/Shadow.png index e050a86db72462089e950b46ca0ff84db58a93f5..94b4bd34f8678fcd37945da4089cc02b77f0da68 100644 GIT binary patch literal 6680 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 Date: Thu, 7 Apr 2022 14:40:31 +0400 Subject: [PATCH 2/9] Web app improvements --- submodules/WebUI/Sources/WebAppController.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 15494b2a82..cb98702589 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -308,7 +308,14 @@ public final class WebAppController: ViewController, AttachmentContainable { if let webView = self.webView { let frame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: navigationBarHeight), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - navigationBarHeight - layout.intrinsicInsets.bottom))) let viewportFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: navigationBarHeight), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - navigationBarHeight - layout.intrinsicInsets.bottom - layout.additionalInsets.bottom))) - transition.updateFrame(view: webView, frame: frame) + + if previousLayout != nil && previousLayout?.inputHeight == nil, let inputHeight = layout.inputHeight, inputHeight > 44.0, transition.isAnimated { + Queue.mainQueue().after(0.4, { + transition.updateFrame(view: webView, frame: frame) + }) + } else { + transition.updateFrame(view: webView, frame: frame) + } webView.updateFrame(frame: viewportFrame, transition: transition) } From b92746d3570bbc163b6cc67ba66392cecc4f86c7 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 7 Apr 2022 16:15:07 +0400 Subject: [PATCH 3/9] Web app improvements --- .../Sources/AttachmentController.swift | 6 +- .../Sources/AttachmentPanel.swift | 2 +- .../Sources/PhotoResources.swift | 9 ++- submodules/Svg/Sources/Svg.m | 4 ++ .../Messages/AttachMenuBots.swift | 3 + .../TelegramUI/Sources/ChatController.swift | 7 ++ .../WebUI/Sources/WebAppController.swift | 71 +++++++++---------- 7 files changed, 60 insertions(+), 42 deletions(-) diff --git a/submodules/AttachmentUI/Sources/AttachmentController.swift b/submodules/AttachmentUI/Sources/AttachmentController.swift index 117b8fe25b..3ab0948331 100644 --- a/submodules/AttachmentUI/Sources/AttachmentController.swift +++ b/submodules/AttachmentUI/Sources/AttachmentController.swift @@ -829,8 +829,12 @@ public class AttachmentController: ViewController { super.dismiss(animated: false, completion: {}) } + public var ensureUnfocused = true + public override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) { - self.view.endEditing(true) + if self.ensureUnfocused { + self.view.endEditing(true) + } if flag { if !self.didDismiss { self.didDismiss = true diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index cec0635799..d62e050117 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -806,7 +806,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { let type = self.buttons[i] if case let .app(peer, _, iconFiles) = type { for (name, file) in iconFiles { - if [.default, .iOSAnimated].contains(name) { + if [.default, .iOSAnimated, .placeholder].contains(name) { if self.iconDisposables[file.fileId] == nil, let peer = PeerReference(peer) { self.iconDisposables[file.fileId] = freeMediaFileInteractiveFetched(account: self.context.account, fileReference: .attachBot(peer: peer, media: file)).start() } diff --git a/submodules/PhotoResources/Sources/PhotoResources.swift b/submodules/PhotoResources/Sources/PhotoResources.swift index f9231de7af..a4bcb99285 100644 --- a/submodules/PhotoResources/Sources/PhotoResources.swift +++ b/submodules/PhotoResources/Sources/PhotoResources.swift @@ -2283,7 +2283,7 @@ public func instantPageImageFile(account: Account, fileReference: FileMediaRefer } } -public func svgIconImageFile(account: Account, fileReference: FileMediaReference, fetched: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { +public func svgIconImageFile(account: Account, fileReference: FileMediaReference, stickToTop: Bool = false, fetched: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { return chatMessageFileDatas(account: account, fileReference: fileReference, progressive: false, fetched: false) |> map { value in let fullSizePath = value._1 @@ -2300,11 +2300,14 @@ public func svgIconImageFile(account: Account, fileReference: FileMediaReference if let fullSizePath = fullSizePath { if fullSizeComplete, let data = try? Data(contentsOf: URL(fileURLWithPath: fullSizePath)) { - fullSizeImage = drawSvgImage(data, CGSize(width: 90.0, height: 90.0), .clear, .black, false) + fullSizeImage = drawSvgImage(data, CGSize.zero, .clear, .black, false) } } - let fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x + (drawingRect.size.width - fittedSize.width) / 2.0, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize) + var fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x + (drawingRect.size.width - fittedSize.width) / 2.0, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize) + if stickToTop { + fittedRect.origin.y = 0.0 + } context.withFlippedContext { c in if let fullSizeImage = fullSizeImage?.cgImage { diff --git a/submodules/Svg/Sources/Svg.m b/submodules/Svg/Sources/Svg.m index df48b16ee9..080e3f0db3 100755 --- a/submodules/Svg/Sources/Svg.m +++ b/submodules/Svg/Sources/Svg.m @@ -111,6 +111,10 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *b return nil; } + if (CGSizeEqualToSize(size, CGSizeZero)) { + size = CGSizeMake(image->width, image->height); + } + double deltaTime = -1.0f * [startTime timeIntervalSinceNow]; printf("parseTime = %f\n", deltaTime); diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift index 7980e44625..17cbfdb114 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift @@ -16,6 +16,7 @@ public final class AttachMenuBots: Equatable, Codable { case iOSStatic case iOSAnimated case macOSAnimated + case placeholder init?(string: String) { switch string { @@ -27,6 +28,8 @@ public final class AttachMenuBots: Equatable, Codable { self = .iOSAnimated case "macos_animated": self = .macOSAnimated + case "placeholder_static": + self = .placeholder default: return nil } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index b29bac09b9..8990b285c6 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3377,7 +3377,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self?.interfaceInteraction?.updateShowWebView { _ in return false } + let isFocused = strongSelf.chatDisplayNode.textInputPanelNode?.isFocused ?? false strongSelf.chatDisplayNode.insertSubnode(strongSelf.chatDisplayNode.inputPanelContainerNode, aboveSubnode: strongSelf.chatDisplayNode.historyNodeContainer) + if isFocused { + strongSelf.chatDisplayNode.textInputPanelNode?.ensureFocused() + } }) strongSelf.present(controller, in: .window(.root)) strongSelf.currentMenuWebAppController = controller @@ -9772,6 +9776,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let currentMenuWebAppController = self.currentMenuWebAppController, !self.presentationInterfaceState.showWebView { self.currentMenuWebAppController = nil + if let currentMenuWebAppController = currentMenuWebAppController as? AttachmentController { + currentMenuWebAppController.ensureUnfocused = false + } currentMenuWebAppController.dismiss(animated: true, completion: nil) } diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index cb98702589..10f933fa9c 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -75,7 +75,7 @@ public final class WebAppController: ViewController, AttachmentContainable { private weak var controller: WebAppController? fileprivate var webView: WebAppWebView? - private var placeholderIcon: UIImage? + private var placeholderIcon: (UIImage, Bool)? private var placeholderNode: ShimmerEffectNode? fileprivate let loadingProgressPromise = Promise(nil) @@ -124,22 +124,31 @@ public final class WebAppController: ViewController, AttachmentContainable { guard let strongSelf = self else { return } - var iconFile: TelegramMediaFile? - if let file = bot.icons[.iOSStatic] { - iconFile = file + var imageFile: TelegramMediaFile? + var isPlaceholder = false + if let file = bot.icons[.placeholder] { + imageFile = file + isPlaceholder = true + } else if let file = bot.icons[.iOSStatic] { + imageFile = file } else if let file = bot.icons[.default] { - iconFile = file + imageFile = file } - if let iconFile = iconFile, let peer = PeerReference(bot.peer) { - let _ = freeMediaFileInteractiveFetched(account: strongSelf.context.account, fileReference: .attachBot(peer: peer, media: iconFile)).start() - strongSelf.iconDisposable = (svgIconImageFile(account: strongSelf.context.account, fileReference: .attachBot(peer: peer, media: iconFile)) + if let imageFile = imageFile, let peer = PeerReference(bot.peer) { + let _ = freeMediaFileInteractiveFetched(account: strongSelf.context.account, fileReference: .attachBot(peer: peer, media: imageFile)).start() + strongSelf.iconDisposable = (svgIconImageFile(account: strongSelf.context.account, fileReference: .attachBot(peer: peer, media: imageFile), stickToTop: isPlaceholder) |> deliverOnMainQueue).start(next: { [weak self] transform in if let strongSelf = self { - let imageSize = CGSize(width: 75.0, height: 75.0) + let imageSize: CGSize + if isPlaceholder, let (layout, _) = strongSelf.validLayout { + imageSize = layout.size + } else { + imageSize = CGSize(width: 75.0, height: 75.0) + } let arguments = TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()) let drawingContext = transform(arguments) if let image = drawingContext?.generateImage()?.withRenderingMode(.alwaysTemplate) { - strongSelf.placeholderIcon = image + strongSelf.placeholderIcon = (image, isPlaceholder) if let (layout, navigationBarHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) } @@ -213,31 +222,15 @@ public final class WebAppController: ViewController, AttachmentContainable { self.webView?.sendEvent(name: "main_button_pressed", data: nil) } - private func updatePlaceholder(grid: Bool, layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) -> CGSize { + private func updatePlaceholder(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) -> CGSize { var shapes: [ShimmerEffect.ShimmerEffectNode.Shape] = [] var placeholderSize: CGSize = CGSize() - if grid { - let spacing: CGFloat = 8.0 - let cols: Int = min(4, Int(floor(layout.size.width / 118.0))) - let itemSize: CGSize = CGSize(width: cols == 4 ? 111.0 : 118.0, height: 150.0) - let rows: Int = 4 - - let sideInset = floorToScreenPixels((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - itemSize.width * CGFloat(cols) - spacing * CGFloat(cols - 1)) / 2.0) - - for row in 0 ..< rows { - for col in 0 ..< cols { - shapes.append(.roundedRect(rect: CGRect(x: layout.safeInsets.left + sideInset + CGFloat(col) * (itemSize.width + spacing), y: navigationBarHeight + CGFloat(row) * (itemSize.height + spacing), width: itemSize.width, height: itemSize.height), cornerRadius: 10.0)) - } - } - - placeholderSize = layout.size - } else { - if let icon = self.placeholderIcon { - shapes = [.image(image: icon, rect: CGRect(origin: CGPoint(), size: icon.size))] - placeholderSize = icon.size - } - } + if let (image, _) = self.placeholderIcon { + shapes = [.image(image: image, rect: CGRect(origin: CGPoint(), size: image.size))] + placeholderSize = image.size + } + let theme = self.presentationData.theme self.placeholderNode?.update(backgroundColor: self.backgroundColor ?? .clear, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, horizontal: true, size: placeholderSize) @@ -294,7 +287,7 @@ public final class WebAppController: ViewController, AttachmentContainable { func webView(_ webView: WKWebView, requestMediaCapturePermissionFor origin: WKSecurityOrigin, initiatedByFrame frame: WKFrameInfo, type: WKMediaCaptureType, decisionHandler: @escaping (WKPermissionDecision) -> Void) { decisionHandler(.prompt) } - + func scrollViewDidScroll(_ scrollView: UIScrollView) { let contentOffset = scrollView.contentOffset.y self.controller?.navigationBar?.updateBackgroundAlpha(min(30.0, contentOffset) / 30.0, transition: .immediate) @@ -309,7 +302,7 @@ public final class WebAppController: ViewController, AttachmentContainable { let frame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: navigationBarHeight), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - navigationBarHeight - layout.intrinsicInsets.bottom))) let viewportFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: navigationBarHeight), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - navigationBarHeight - layout.intrinsicInsets.bottom - layout.additionalInsets.bottom))) - if previousLayout != nil && previousLayout?.inputHeight == nil, let inputHeight = layout.inputHeight, inputHeight > 44.0, transition.isAnimated { + if previousLayout != nil && (previousLayout?.inputHeight ?? 0.0).isZero, let inputHeight = layout.inputHeight, inputHeight > 44.0, transition.isAnimated { Queue.mainQueue().after(0.4, { transition.updateFrame(view: webView, frame: frame) }) @@ -328,9 +321,13 @@ public final class WebAppController: ViewController, AttachmentContainable { height = layout.size.height - layout.intrinsicInsets.bottom } - let grid = self.controller?.botId.id._internalGetInt64Value() == 2200339955 - let placeholderSize = self.updatePlaceholder(grid: grid, layout: layout, navigationBarHeight: navigationBarHeight, transition: transition) - let placeholderY: CGFloat = grid ? 0.0 : floorToScreenPixels((height - placeholderSize.height) / 2.0) + let placeholderSize = self.updatePlaceholder(layout: layout, navigationBarHeight: navigationBarHeight, transition: transition) + let placeholderY: CGFloat + if let (_, isPlaceholder) = self.placeholderIcon, isPlaceholder { + placeholderY = navigationBarHeight + } else { + placeholderY = floorToScreenPixels((height - placeholderSize.height) / 2.0) + } let placeholderFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - placeholderSize.width) / 2.0), y: placeholderY), size: placeholderSize) transition.updateFrame(node: placeholderNode, frame: placeholderFrame) placeholderNode.updateAbsoluteRect(placeholderFrame, within: layout.size) From 29d11093db8d3c5fd4adda6abe5ffbfe5936e039 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 7 Apr 2022 16:34:27 +0400 Subject: [PATCH 4/9] Web app improvements --- submodules/AttachmentUI/Sources/AttachmentPanel.swift | 8 ++++---- submodules/PhotoResources/Sources/PhotoResources.swift | 7 +++++-- submodules/WebUI/Sources/WebAppController.swift | 3 ++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index d62e050117..a1d60ed570 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -778,10 +778,10 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { var leftNodeOriginX = (layout.size.width - internalWidth) / 2.0 var buttonWidth = buttonSize.width - if self.buttons.count > 6 { + if self.buttons.count > 6 && layout.size.width < layout.size.height { buttonWidth = smallButtonWidth distanceBetweenNodes = buttonWidth - leftNodeOriginX = sideInset + buttonWidth / 2.0 + leftNodeOriginX = layout.safeInsets.left + sideInset + buttonWidth / 2.0 } for i in 0 ..< self.buttons.count { @@ -851,9 +851,9 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { var contentSize = CGSize(width: layout.size.width, height: buttonSize.height) var buttonWidth = buttonSize.width - if self.buttons.count > 6 { + if self.buttons.count > 6 && layout.size.width < layout.size.height { buttonWidth = smallButtonWidth - contentSize = CGSize(width: sideInset * 2.0 + CGFloat(self.buttons.count) * buttonWidth, height: buttonSize.height) + contentSize.width = layout.safeInsets.left + layout.safeInsets.right + sideInset * 2.0 + CGFloat(self.buttons.count) * buttonWidth } self.scrollLayout = (layout.size.width, contentSize) diff --git a/submodules/PhotoResources/Sources/PhotoResources.swift b/submodules/PhotoResources/Sources/PhotoResources.swift index a4bcb99285..635fae95b2 100644 --- a/submodules/PhotoResources/Sources/PhotoResources.swift +++ b/submodules/PhotoResources/Sources/PhotoResources.swift @@ -2293,7 +2293,7 @@ public func svgIconImageFile(account: Account, fileReference: FileMediaReference let context = DrawingContext(size: arguments.drawingSize, clear: true) let drawingRect = arguments.drawingRect - let fittedSize = arguments.imageSize.aspectFilled(arguments.boundingSize).fitted(arguments.imageSize) + var fittedSize = arguments.imageSize.aspectFilled(arguments.boundingSize).fitted(arguments.imageSize) var fullSizeImage: UIImage? let imageOrientation: UIImage.Orientation = .up @@ -2301,12 +2301,15 @@ public func svgIconImageFile(account: Account, fileReference: FileMediaReference if let fullSizePath = fullSizePath { if fullSizeComplete, let data = try? Data(contentsOf: URL(fileURLWithPath: fullSizePath)) { fullSizeImage = drawSvgImage(data, CGSize.zero, .clear, .black, false) + if let image = fullSizeImage { + fittedSize = image.size.aspectFitted(arguments.boundingSize) + } } } var fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x + (drawingRect.size.width - fittedSize.width) / 2.0, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize) if stickToTop { - fittedRect.origin.y = 0.0 + fittedRect.origin.y = drawingRect.size.height - fittedSize.height } context.withFlippedContext { c in diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 10f933fa9c..99f73c3dbd 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -141,7 +141,8 @@ public final class WebAppController: ViewController, AttachmentContainable { if let strongSelf = self { let imageSize: CGSize if isPlaceholder, let (layout, _) = strongSelf.validLayout { - imageSize = layout.size + let minSize = min(layout.size.width, layout.size.height) + imageSize = CGSize(width: minSize, height: minSize * 3.0) } else { imageSize = CGSize(width: 75.0, height: 75.0) } From 29321aefbf3b93ac6db663743380fba4b7aa98ac Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 7 Apr 2022 17:04:16 +0400 Subject: [PATCH 5/9] Fix attach bot payload passing --- submodules/TelegramUI/Sources/ChatController.swift | 8 ++++---- submodules/WebUI/Sources/WebAppController.swift | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 8990b285c6..887fd3f6c2 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3360,7 +3360,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let openWebView = { if fromMenu { - let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: true) + let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: true) let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, openUrl: { [weak self] url in self?.openUrl(url, concealed: true, forceExternal: true) }, getInputContainerNode: { [weak self] in @@ -3394,7 +3394,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self else { return } - let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: false) + let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: false) let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, openUrl: { [weak self] url in self?.openUrl(url, concealed: true, forceExternal: true) }) @@ -3414,7 +3414,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self else { return } - let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, fromMenu: false) + let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, fromMenu: false) let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, openUrl: { [weak self] url in self?.openUrl(url, concealed: true, forceExternal: true) }, completion: { [weak self] in @@ -10948,7 +10948,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G completion(controller, nil) strongSelf.controllerNavigationDisposable.set(nil) case let .app(bot, botName, _): - let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, buttonText: nil, keepAliveSignal: nil, fromMenu: false) + let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: botPayload, buttonText: nil, keepAliveSignal: nil, fromMenu: false) let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageId) controller.openUrl = { [weak self] url in diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 99f73c3dbd..1bc32f8c78 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -24,6 +24,7 @@ public struct WebAppParameters { let botName: String let url: String? let queryId: Int64? + let payload: String? let buttonText: String? let keepAliveSignal: Signal? let fromMenu: Bool @@ -34,6 +35,7 @@ public struct WebAppParameters { botName: String, url: String?, queryId: Int64?, + payload: String?, buttonText: String?, keepAliveSignal: Signal?, fromMenu: Bool @@ -43,6 +45,7 @@ public struct WebAppParameters { self.botName = botName self.url = url self.queryId = queryId + self.payload = payload self.buttonText = buttonText self.keepAliveSignal = keepAliveSignal self.fromMenu = fromMenu @@ -178,7 +181,7 @@ public final class WebAppController: ViewController, AttachmentContainable { }) } } else { - let _ = (context.engine.messages.requestWebView(peerId: controller.peerId, botId: controller.botId, url: controller.url, payload: nil, themeParams: generateWebAppThemeParams(presentationData.theme), fromMenu: controller.fromMenu, replyToMessageId: controller.replyToMessageId) + let _ = (context.engine.messages.requestWebView(peerId: controller.peerId, botId: controller.botId, url: controller.url, payload: controller.payload, themeParams: generateWebAppThemeParams(presentationData.theme), fromMenu: controller.fromMenu, replyToMessageId: controller.replyToMessageId) |> deliverOnMainQueue).start(next: { [weak self] result in guard let strongSelf = self else { return @@ -454,6 +457,7 @@ public final class WebAppController: ViewController, AttachmentContainable { private let botId: PeerId private let url: String? private let queryId: Int64? + private let payload: String? private let buttonText: String? private let fromMenu: Bool private let keepAliveSignal: Signal? @@ -473,6 +477,7 @@ public final class WebAppController: ViewController, AttachmentContainable { self.botId = params.botId self.url = params.url self.queryId = params.queryId + self.payload = params.payload self.buttonText = params.buttonText self.fromMenu = params.fromMenu self.keepAliveSignal = params.keepAliveSignal From e4cfa809810bf1a5ce149033cab54ff52fd41790 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 7 Apr 2022 18:40:51 +0400 Subject: [PATCH 6/9] Web app improvements --- .../Sources/AttachmentPanel.swift | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index a1d60ed570..527530a692 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -958,9 +958,9 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { self.view.addSubview(inputNodeSnapshotView) let targetInputPosition = CGPoint(x: inputNodeSnapshotView.center.x + inputNodeSnapshotView.frame.width, y: self.mainButtonNode.position.y) - transition.updatePosition(layer: inputNodeSnapshotView.layer, position: targetInputPosition, completion: { [weak inputNodeSnapshotView] _ in + transition.updatePosition(layer: inputNodeSnapshotView.layer, position: targetInputPosition, completion: { [weak inputNodeSnapshotView, weak self] _ in inputNodeSnapshotView?.removeFromSuperview() - self.animatingTransition = false + self?.animatingTransition = false }) } @@ -977,7 +977,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { self.dismissed = dismissed let action = { - guard let menuIconSnapshotView = inputTransition.menuIconNode.view.snapshotView(afterScreenUpdates: true), let menuTextSnapshotView = inputTransition.menuTextNode.view.snapshotView(afterScreenUpdates: false) else { + guard let menuIconSnapshotView = inputTransition.menuIconNode.view.snapshotView(afterScreenUpdates: false), let menuTextSnapshotView = inputTransition.menuTextNode.view.snapshotView(afterScreenUpdates: false) else { return } @@ -1014,19 +1014,19 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { let targetInputFrame = CGRect(x: inputTransition.menuButtonNode.frame.maxX, y: 0.0, width: inputNodeSnapshotView.frame.width - inputTransition.menuButtonNode.frame.maxX, height: inputNodeSnapshotView.frame.height) inputNodeSnapshotView.frame = targetInputFrame.offsetBy(dx: targetInputFrame.width, dy: self.mainButtonNode.position.y - inputNodeSnapshotView.frame.height / 2.0) self.view.addSubview(inputNodeSnapshotView) - transition.updateFrame(layer: inputNodeSnapshotView.layer, frame: targetInputFrame, completion: { [weak inputNodeSnapshotView, weak menuIconSnapshotView, weak menuTextSnapshotView] _ in + transition.updateFrame(layer: inputNodeSnapshotView.layer, frame: targetInputFrame, completion: { [weak inputNodeSnapshotView, weak menuIconSnapshotView, weak menuTextSnapshotView, weak self] _ in inputNodeSnapshotView?.removeFromSuperview() - self.animatingTransition = false + self?.animatingTransition = false if !dismissed { menuIconSnapshotView?.removeFromSuperview() menuTextSnapshotView?.removeFromSuperview() - self.mainButtonNode.backgroundColor = sourceButtonColor - self.mainButtonNode.frame = sourceButtonFrame - self.mainButtonNode.textNode.position = sourceButtonTextPosition - self.mainButtonNode.textNode.layer.removeAllAnimations() - self.mainButtonNode.cornerRadius = sourceButtonCornerRadius + self?.mainButtonNode.backgroundColor = sourceButtonColor + self?.mainButtonNode.frame = sourceButtonFrame + self?.mainButtonNode.textNode.position = sourceButtonTextPosition + self?.mainButtonNode.textNode.layer.removeAllAnimations() + self?.mainButtonNode.cornerRadius = sourceButtonCornerRadius } }) } From c0bb57c8504ec64cf6a6baa8bcd87917172d3ea8 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 7 Apr 2022 20:44:45 +0400 Subject: [PATCH 7/9] Web app improvements --- .../Sources/AttachmentController.swift | 34 +++++++++++++++---- .../Sources/AttachmentPanel.swift | 10 +++++- .../Sources/AnimatedStickerComponent.swift | 2 ++ .../Sources/PhotoResources.swift | 2 +- .../TelegramUI/Sources/ChatController.swift | 4 ++- .../Sources/PlayPauseIconComponent.swift | 9 ++++- .../TranslateUI/Sources/TranslateScreen.swift | 17 ++++++---- 7 files changed, 60 insertions(+), 18 deletions(-) diff --git a/submodules/AttachmentUI/Sources/AttachmentController.swift b/submodules/AttachmentUI/Sources/AttachmentController.swift index 3ab0948331..f86d6a4f96 100644 --- a/submodules/AttachmentUI/Sources/AttachmentController.swift +++ b/submodules/AttachmentUI/Sources/AttachmentController.swift @@ -268,6 +268,7 @@ public class AttachmentController: ViewController { self.container.canHaveKeyboardFocus = true self.panel = AttachmentPanel(context: controller.context, chatLocation: controller.chatLocation, updatedPresentationData: controller.updatedPresentationData) self.panel.fromMenu = controller.fromMenu + self.panel.isStandalone = controller.isStandalone super.init() @@ -636,7 +637,10 @@ public class AttachmentController: ViewController { var containerLayout = layout let containerRect: CGRect + var isCompact = true if case .regular = layout.metrics.widthClass { + isCompact = false + let availableHeight = layout.size.height - (layout.inputHeight ?? 0.0) - 60.0 let size = CGSize(width: 390.0, height: min(620.0, availableHeight)) @@ -645,17 +649,28 @@ public class AttachmentController: ViewController { let masterWidth = min(max(320.0, floor(layout.size.width / 3.0)), floor(layout.size.width / 2.0)) let position: CGPoint = CGPoint(x: masterWidth - 174.0, y: layout.size.height - size.height - insets.bottom - 40.0) - containerRect = CGRect(origin: position, size: size) + if controller.isStandalone { + var containerY = floorToScreenPixels((layout.size.height - size.height) / 2.0) + if let inputHeight = layout.inputHeight, inputHeight > 88.0 { + containerY = layout.size.height - inputHeight - size.height - 80.0 + } + containerRect = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - size.width) / 2.0), y: containerY), size: size) + } else { + containerRect = CGRect(origin: position, size: size) + } containerLayout.size = containerRect.size containerLayout.intrinsicInsets.bottom = 12.0 containerLayout.inputHeight = nil - if self.wrapperNode.view.mask == nil { + if controller.isStandalone { + self.wrapperNode.cornerRadius = 10.0 + } else if self.wrapperNode.view.mask == nil { let maskView = UIImageView() maskView.image = generateMaskImage() maskView.contentMode = .scaleToFill self.wrapperNode.view.mask = maskView } + if let maskView = self.wrapperNode.view.mask { transition.updateFrame(view: maskView, frame: CGRect(origin: CGPoint(), size: size)) } @@ -697,7 +712,7 @@ public class AttachmentController: ViewController { if fromMenu && !hasButton, let inputContainerHeight = self.inputContainerHeight { panelHeight = inputContainerHeight } - if hasPanel || hasButton || fromMenu { + if hasPanel || hasButton || (fromMenu && isCompact) { containerInsets.bottom = panelHeight } @@ -716,13 +731,13 @@ public class AttachmentController: ViewController { panelTransition = .animated(duration: 0.25, curve: .easeInOut) } var panelY = containerRect.height - panelHeight - if fromMenu { + if fromMenu && isCompact { panelY = layout.size.height - panelHeight } else if !hasPanel && !hasButton { panelY = containerRect.height } - if fromMenu { + if fromMenu && isCompact { if hasButton { self.panel.isHidden = false self.inputContainerNode?.isHidden = true @@ -735,7 +750,7 @@ public class AttachmentController: ViewController { } panelTransition.updateFrame(node: self.panel, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY), size: CGSize(width: containerRect.width, height: panelHeight)), completion: { [weak self] finished in - if transitioning && finished { + if transitioning && finished, isCompact { self?.panel.isHidden = !hasButton self?.inputContainerNode?.isHidden = hasButton } @@ -765,7 +780,8 @@ public class AttachmentController: ViewController { if self.container.supernode == nil, !controllers.isEmpty && self.container.isReady { self.wrapperNode.addSubnode(self.container) - if controller.fromMenu { + + if fromMenu, let _ = controller.getInputContainerNode() { self.addSubnode(self.panel) } else { self.container.addSubnode(self.panel) @@ -814,6 +830,10 @@ public class AttachmentController: ViewController { fatalError("init(coder:) has not been implemented") } + fileprivate var isStandalone: Bool { + return self.buttons.contains(.standalone) + } + private var node: Node { return self.displayNode as! Node } diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index 527530a692..e1d52d5c87 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -482,6 +482,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { private var scrollLayout: (width: CGFloat, contentSize: CGSize)? var fromMenu: Bool = false + var isStandalone: Bool = false var selectionChanged: (AttachmentButtonType) -> Bool = { _ in return false } var beganTextEditing: () -> Void = {} @@ -1090,9 +1091,16 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { let containerTransition: ContainedViewLayoutTransition let containerFrame: CGRect if isButtonVisible { - let height: CGFloat + var height: CGFloat if layout.intrinsicInsets.bottom > 0.0 && (layout.inputHeight ?? 0.0).isZero { height = bounds.height + 9.0 + if case .regular = layout.metrics.widthClass { + if self.isStandalone { + height -= 3.0 + } else { + height += 6.0 + } + } } else { height = bounds.height + 9.0 + 8.0 } diff --git a/submodules/Components/AnimatedStickerComponent/Sources/AnimatedStickerComponent.swift b/submodules/Components/AnimatedStickerComponent/Sources/AnimatedStickerComponent.swift index 7d02c4498b..1d46928659 100644 --- a/submodules/Components/AnimatedStickerComponent/Sources/AnimatedStickerComponent.swift +++ b/submodules/Components/AnimatedStickerComponent/Sources/AnimatedStickerComponent.swift @@ -109,6 +109,8 @@ public final class AnimatedStickerComponent: Component { playbackMode = .loop } else if component.isAnimating { playbackMode = .once + } else { + animationNode.autoplay = true } animationNode.setup(source: source, width: Int(component.size.width * component.animation.scale), height: Int(component.size.height * component.animation.scale), playbackMode: playbackMode, mode: .direct(cachePathPrefix: nil)) animationNode.visibility = self.isInHierarchy diff --git a/submodules/PhotoResources/Sources/PhotoResources.swift b/submodules/PhotoResources/Sources/PhotoResources.swift index 635fae95b2..1d88ec047e 100644 --- a/submodules/PhotoResources/Sources/PhotoResources.swift +++ b/submodules/PhotoResources/Sources/PhotoResources.swift @@ -2300,7 +2300,7 @@ public func svgIconImageFile(account: Account, fileReference: FileMediaReference if let fullSizePath = fullSizePath { if fullSizeComplete, let data = try? Data(contentsOf: URL(fileURLWithPath: fullSizePath)) { - fullSizeImage = drawSvgImage(data, CGSize.zero, .clear, .black, false) + fullSizeImage = drawSvgImage(data, stickToTop ? CGSize.zero : CGSize(width: 90.0, height: 90.0), .clear, .black, false) if let image = fullSizeImage { fittedSize = image.size.aspectFitted(arguments.boundingSize) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 887fd3f6c2..1f4329ddee 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -2931,6 +2931,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G case .speak: let _ = speakText(text.string) case .translate: + strongSelf.chatDisplayNode.dismissInput() + let _ = (context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings]) |> take(1) |> deliverOnMainQueue).start(next: { sharedData in @@ -3364,7 +3366,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, openUrl: { [weak self] url in self?.openUrl(url, concealed: true, forceExternal: true) }, getInputContainerNode: { [weak self] in - if let strongSelf = self { + if let strongSelf = self, let layout = strongSelf.validLayout, case .compact = layout.metrics.widthClass { return (strongSelf.chatDisplayNode.getWindowInputAccessoryHeight(), strongSelf.chatDisplayNode.inputPanelContainerNode, { return strongSelf.chatDisplayNode.textInputPanelNode?.makeAttachmentMenuTransition(accessoryPanelNode: nil) }) diff --git a/submodules/TranslateUI/Sources/PlayPauseIconComponent.swift b/submodules/TranslateUI/Sources/PlayPauseIconComponent.swift index dec0969495..ba94aa2efc 100644 --- a/submodules/TranslateUI/Sources/PlayPauseIconComponent.swift +++ b/submodules/TranslateUI/Sources/PlayPauseIconComponent.swift @@ -55,10 +55,12 @@ private final class PlayPauseIconNode: ManagedAnimationNode { final class PlayPauseIconComponent: Component { let state: PlayPauseIconNodeState + let tintColor: UIColor? let size: CGSize - init(state: PlayPauseIconNodeState, size: CGSize) { + init(state: PlayPauseIconNodeState, tintColor: UIColor?, size: CGSize) { self.state = state + self.tintColor = tintColor self.size = size } @@ -66,6 +68,9 @@ final class PlayPauseIconComponent: Component { if lhs.state != rhs.state { return false } + if lhs.tintColor != rhs.tintColor { + return false + } if lhs.size != rhs.size { return false } @@ -94,6 +99,8 @@ final class PlayPauseIconComponent: Component { self.animationNode.enqueueState(component.state, animated: true) } + + self.animationNode.customColor = component.tintColor let animationSize = component.size let size = CGSize(width: min(animationSize.width, availableSize.width), height: min(animationSize.height, availableSize.height)) diff --git a/submodules/TranslateUI/Sources/TranslateScreen.swift b/submodules/TranslateUI/Sources/TranslateScreen.swift index 775681717b..a500a2dcc5 100644 --- a/submodules/TranslateUI/Sources/TranslateScreen.swift +++ b/submodules/TranslateUI/Sources/TranslateScreen.swift @@ -15,11 +15,10 @@ import MultilineTextComponent import BundleIconComponent import UndoUI -private func generateExpandBackground(size: CGSize) -> UIImage { +private func generateExpandBackground(size: CGSize, color: UIColor) -> UIImage { return generateImage(size, rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) - let color = UIColor.white var locations: [CGFloat] = [0.0, 1.0] let colors: [CGColor] = [color.withAlphaComponent(0.0).cgColor, color.cgColor] @@ -88,7 +87,7 @@ private final class TranslateScreenComponent: CombinedComponent { private var speechHolder: SpeechSynthesizerHolder? fileprivate var availableSpeakLanguages: Set - fileprivate var moreBackgroundImage: (CGSize, UIImage)? + fileprivate var moreBackgroundImage: (CGSize, UIImage, UIColor)? init(context: AccountContext, fromLanguage: String?, text: String, toLanguage: String, expand: @escaping () -> Void) { self.context = context @@ -115,6 +114,7 @@ private final class TranslateScreenComponent: CombinedComponent { } deinit { + self.speechHolder?.stop() self.translationDisposable.dispose() } @@ -346,6 +346,7 @@ private final class TranslateScreenComponent: CombinedComponent { ))), AnyComponentWithIdentity(id: "a", component: AnyComponent(PlayPauseIconComponent( state: state.isSpeakingOriginalText ? .pause : .play, + tintColor: theme.list.itemCheckColors.foregroundColor, size: CGSize(width: 18.0, height: 18.0) ))), ])), @@ -381,14 +382,15 @@ private final class TranslateScreenComponent: CombinedComponent { let originalMoreBackgroundSize = CGSize(width: originalMoreButton.size.width + 50.0, height: originalMoreButton.size.height) let originalMoreBackgroundImage: UIImage - if let (size, image) = state.moreBackgroundImage, size == originalMoreBackgroundSize { + let backgroundColor = theme.list.itemBlocksBackgroundColor + if let (size, image, color) = state.moreBackgroundImage, size == originalMoreBackgroundSize && color == backgroundColor { originalMoreBackgroundImage = image } else { - originalMoreBackgroundImage = generateExpandBackground(size: originalMoreBackgroundSize) - state.moreBackgroundImage = (originalMoreBackgroundSize, originalMoreBackgroundImage) + originalMoreBackgroundImage = generateExpandBackground(size: originalMoreBackgroundSize, color: backgroundColor) + state.moreBackgroundImage = (originalMoreBackgroundSize, originalMoreBackgroundImage, backgroundColor) } let originalMoreBackground = originalMoreBackground.update( - component: Image(image: originalMoreBackgroundImage, tintColor: theme.list.itemBlocksBackgroundColor), + component: Image(image: originalMoreBackgroundImage, tintColor: backgroundColor), availableSize: originalMoreBackgroundSize, transition: .immediate ) @@ -426,6 +428,7 @@ private final class TranslateScreenComponent: CombinedComponent { ))), AnyComponentWithIdentity(id: "a", component: AnyComponent(PlayPauseIconComponent( state: state.isSpeakingTranslatedText ? .pause : .play, + tintColor: theme.list.itemCheckColors.foregroundColor, size: CGSize(width: 18.0, height: 18.0) ))), ])), From 7f7cb498bbc6b604a1f423997a803252506da0bd Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 7 Apr 2022 22:30:48 +0400 Subject: [PATCH 8/9] Web app improvements --- submodules/AttachmentUI/BUILD | 1 + .../Sources/AttachmentPanel.swift | 25 +++++++++++++++++-- .../CachedResourceRepresentations.swift | 20 +++++++++++++++ .../Sources/PhotoResources.swift | 23 +++++++++-------- submodules/Svg/PublicHeaders/Svg/Svg.h | 2 +- submodules/Svg/Sources/Svg.m | 24 ++++++++++++------ .../TelegramUI/Sources/ChatController.swift | 21 ++++++++++++++++ .../Sources/FetchCachedRepresentations.swift | 23 +++++++++++++++++ .../TranslateUI/Sources/TranslateScreen.swift | 7 +++++- .../Sources/WallpaperResources.swift | 2 +- 10 files changed, 125 insertions(+), 23 deletions(-) diff --git a/submodules/AttachmentUI/BUILD b/submodules/AttachmentUI/BUILD index 655fdaa421..2d66c0b2f6 100644 --- a/submodules/AttachmentUI/BUILD +++ b/submodules/AttachmentUI/BUILD @@ -30,6 +30,7 @@ swift_library( "//submodules/ContextUI:ContextUI", "//submodules/ManagedAnimationNode:ManagedAnimationNode", "//submodules/PhotoResources:PhotoResources", + "//submodules/MediaResources:MediaResources", "//submodules/SemanticStatusNode:SemanticStatusNode", "//submodules/Components/AnimatedStickerComponent:AnimatedStickerComponent", ], diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index e1d52d5c87..0fdbcf5f5c 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -15,6 +15,7 @@ import ChatTextLinkEditUI import PhotoResources import AnimatedStickerComponent import SemanticStatusNode +import MediaResources private let buttonSize = CGSize(width: 88.0, height: 49.0) private let smallButtonWidth: CGFloat = 69.0 @@ -79,7 +80,7 @@ private final class IconComponent: Component { self.image = nil } - self.disposable = (svgIconImageFile(account: component.account, fileReference: fileReference, fetched: true) + self.disposable = (svgIconImageFile(account: component.account, fileReference: fileReference) |> runOn(Queue.concurrentDefaultQueue()) |> deliverOnMainQueue).start(next: { [weak self] transform in let arguments = TransformImageArguments(corners: ImageCorners(), imageSize: availableSize, boundingSize: availableSize, intrinsicInsets: UIEdgeInsets()) @@ -809,7 +810,27 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { for (name, file) in iconFiles { if [.default, .iOSAnimated, .placeholder].contains(name) { if self.iconDisposables[file.fileId] == nil, let peer = PeerReference(peer) { - self.iconDisposables[file.fileId] = freeMediaFileInteractiveFetched(account: self.context.account, fileReference: .attachBot(peer: peer, media: file)).start() + if case .placeholder = name { + let account = self.context.account + let path = account.postbox.mediaBox.cachedRepresentationCompletePath(file.resource.id, representation: CachedPreparedSvgRepresentation()) + if !FileManager.default.fileExists(atPath: path) { + let accountFullSizeData = Signal<(Data?, Bool), NoError> { subscriber in + let accountResource = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedPreparedSvgRepresentation(), complete: false, fetch: true) + + let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .media(media: .attachBot(peer: peer, media: file), resource: file.resource)) + let fetchedFullSizeDisposable = fetchedFullSize.start() + let fullSizeDisposable = accountResource.start() + + return ActionDisposable { + fetchedFullSizeDisposable.dispose() + fullSizeDisposable.dispose() + } + } + self.iconDisposables[file.fileId] = accountFullSizeData.start() + } + } else { + self.iconDisposables[file.fileId] = freeMediaFileInteractiveFetched(account: self.context.account, fileReference: .attachBot(peer: peer, media: file)).start() + } } } } diff --git a/submodules/MediaResources/Sources/CachedResourceRepresentations.swift b/submodules/MediaResources/Sources/CachedResourceRepresentations.swift index 6b92e55531..bb6baa9a89 100644 --- a/submodules/MediaResources/Sources/CachedResourceRepresentations.swift +++ b/submodules/MediaResources/Sources/CachedResourceRepresentations.swift @@ -344,3 +344,23 @@ public final class CachedPreparedPatternWallpaperRepresentation: CachedMediaReso } } } + + +public final class CachedPreparedSvgRepresentation: CachedMediaResourceRepresentation { + public let keepDuration: CachedMediaRepresentationKeepDuration = .general + + public var uniqueId: String { + return "prepared-svg" + } + + public init() { + } + + public func isEqual(to: CachedMediaResourceRepresentation) -> Bool { + if to is CachedPreparedSvgRepresentation { + return true + } else { + return false + } + } +} diff --git a/submodules/PhotoResources/Sources/PhotoResources.swift b/submodules/PhotoResources/Sources/PhotoResources.swift index 1d88ec047e..b4438bcc84 100644 --- a/submodules/PhotoResources/Sources/PhotoResources.swift +++ b/submodules/PhotoResources/Sources/PhotoResources.swift @@ -2283,13 +2283,14 @@ public func instantPageImageFile(account: Account, fileReference: FileMediaRefer } } -public func svgIconImageFile(account: Account, fileReference: FileMediaReference, stickToTop: Bool = false, fetched: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { - return chatMessageFileDatas(account: account, fileReference: fileReference, progressive: false, fetched: false) +public func svgIconImageFile(account: Account, fileReference: FileMediaReference, stickToTop: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { + let data = account.postbox.mediaBox.cachedResourceRepresentation(fileReference.media.resource, representation: CachedPreparedSvgRepresentation(), complete: false, fetch: true) + + return data |> map { value in - let fullSizePath = value._1 - let fullSizeComplete = value._2 + let fullSizePath = value.path + let fullSizeComplete = value.complete return { arguments in -// assertNotOnMainThread() let context = DrawingContext(size: arguments.drawingSize, clear: true) let drawingRect = arguments.drawingRect @@ -2298,12 +2299,12 @@ public func svgIconImageFile(account: Account, fileReference: FileMediaReference var fullSizeImage: UIImage? let imageOrientation: UIImage.Orientation = .up - if let fullSizePath = fullSizePath { - if fullSizeComplete, let data = try? Data(contentsOf: URL(fileURLWithPath: fullSizePath)) { - fullSizeImage = drawSvgImage(data, stickToTop ? CGSize.zero : CGSize(width: 90.0, height: 90.0), .clear, .black, false) - if let image = fullSizeImage { - fittedSize = image.size.aspectFitted(arguments.boundingSize) - } + if fullSizeComplete, let data = try? Data(contentsOf: URL(fileURLWithPath: fullSizePath)) { + fullSizeImage = renderPreparedImage(data, CGSize.zero, .clear, UIScreenScale) + +// fullSizeImage = drawSvgImage(data, stickToTop ? CGSize.zero : CGSize(width: 90.0, height: 90.0), .clear, .black, false) + if let image = fullSizeImage { + fittedSize = image.size.aspectFitted(arguments.boundingSize) } } diff --git a/submodules/Svg/PublicHeaders/Svg/Svg.h b/submodules/Svg/PublicHeaders/Svg/Svg.h index 48e51ef4ff..0c05521c13 100755 --- a/submodules/Svg/PublicHeaders/Svg/Svg.h +++ b/submodules/Svg/PublicHeaders/Svg/Svg.h @@ -5,7 +5,7 @@ #import NSData * _Nullable prepareSvgImage(NSData * _Nonnull data); -UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size); +UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIColor * _Nonnull backgroundColor, CGFloat scale); UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor * _Nullable backgroundColor, UIColor * _Nullable foregroundColor, bool opaque); diff --git a/submodules/Svg/Sources/Svg.m b/submodules/Svg/Sources/Svg.m index 080e3f0db3..06835a760d 100755 --- a/submodules/Svg/Sources/Svg.m +++ b/submodules/Svg/Sources/Svg.m @@ -358,11 +358,11 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *b @end -UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size) { +UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIColor *backgroundColor, CGFloat scale) { NSDate *startTime = [NSDate date]; UIColor *foregroundColor = [UIColor whiteColor]; - UIColor *backgroundColor = [UIColor blackColor]; + int32_t ptr = 0; int32_t width; @@ -377,17 +377,27 @@ UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size) { [data getBytes:&height range:NSMakeRange(ptr, sizeof(height))]; ptr += sizeof(height); - UIGraphicsBeginImageContextWithOptions(size, true, 1.0); + if (CGSizeEqualToSize(size, CGSizeZero)) { + size = CGSizeMake(width, height); + } + + bool isTransparent = [backgroundColor isEqual:[UIColor clearColor]]; + + UIGraphicsBeginImageContextWithOptions(size, !isTransparent, scale); CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, backgroundColor.CGColor); - CGContextFillRect(context, CGRectMake(0.0f, 0.0f, size.width, size.height)); + if (isTransparent) { + CGContextClearRect(context, CGRectMake(0.0f, 0.0f, size.width, size.height)); + } else { + CGContextSetFillColorWithColor(context, backgroundColor.CGColor); + CGContextFillRect(context, CGRectMake(0.0f, 0.0f, size.width, size.height)); + } CGSize svgSize = CGSizeMake(width, height); CGSize drawingSize = aspectFillSize(svgSize, size); - CGFloat scale = MAX(size.width / MAX(1.0, svgSize.width), size.height / MAX(1.0, svgSize.height)); + CGFloat renderScale = MAX(size.width / MAX(1.0, svgSize.width), size.height / MAX(1.0, svgSize.height)); - CGContextScaleCTM(context, scale, scale); + CGContextScaleCTM(context, renderScale, renderScale); CGContextTranslateCTM(context, (size.width - drawingSize.width) / 2.0, (size.height - drawingSize.height) / 2.0); while (ptr < data.length) { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 1f4329ddee..b42fa801d5 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -279,6 +279,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private var bankCardDisposable: MetaDisposable? private var hasActiveGroupCallDisposable: Disposable? private var sendAsPeersDisposable: Disposable? + private let preloadAttachBotIconsDisposables = DisposableSet() private let editingMessage = ValuePromise(nil, ignoreRepeated: true) private let startingBot = ValuePromise(false, ignoreRepeated: true) @@ -4828,6 +4829,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.nextChannelToReadDisposable?.dispose() self.inviteRequestsDisposable.dispose() self.sendAsPeersDisposable?.dispose() + self.preloadAttachBotIconsDisposables.dispose() } public func updatePresentationMode(_ mode: ChatControllerPresentationMode) { @@ -9053,6 +9055,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }).start()) } } + + self.preloadAttachBotIcons() } if let _ = self.focusOnSearchAfterAppearance { @@ -15711,6 +15715,23 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return false } } + + func preloadAttachBotIcons() { + let _ = (self.context.engine.messages.attachMenuBots() + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] bots in + guard let strongSelf = self else { + return + } + for bot in bots { + for (name, file) in bot.icons { + if [.iOSAnimated].contains(name), let peer = PeerReference(bot.peer) { + strongSelf.preloadAttachBotIconsDisposables.add(freeMediaFileInteractiveFetched(account: strongSelf.context.account, fileReference: .attachBot(peer: peer, media: file)).start()) + } + } + } + }) + } } private final class ContextControllerContentSourceImpl: ContextControllerContentSource { diff --git a/submodules/TelegramUI/Sources/FetchCachedRepresentations.swift b/submodules/TelegramUI/Sources/FetchCachedRepresentations.swift index e7aa5763fd..b417cc205d 100644 --- a/submodules/TelegramUI/Sources/FetchCachedRepresentations.swift +++ b/submodules/TelegramUI/Sources/FetchCachedRepresentations.swift @@ -137,6 +137,14 @@ public func fetchCachedResourceRepresentation(account: Account, resource: MediaR } return fetchPreparedPatternWallpaperRepresentation(resource: resource, resourceData: data, representation: representation) } + } else if let representation = representation as? CachedPreparedSvgRepresentation { + return account.postbox.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false)) + |> mapToSignal { data -> Signal in + if !data.complete { + return .complete() + } + return fetchPreparedSvgRepresentation(resource: resource, resourceData: data, representation: representation) + } } return .never() } @@ -755,3 +763,18 @@ private func fetchPreparedPatternWallpaperRepresentation(resource: MediaResource return EmptyDisposable }) |> runOn(Queue.concurrentDefaultQueue()) } + +private func fetchPreparedSvgRepresentation(resource: MediaResource, resourceData: MediaResourceData, representation: CachedPreparedSvgRepresentation) -> Signal { + return Signal({ subscriber in + if let data = try? Data(contentsOf: URL(fileURLWithPath: resourceData.path), options: [.mappedIfSafe]) { + if let data = prepareSvgImage(data) { + let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))" + let url = URL(fileURLWithPath: path) + let _ = try? data.write(to: url) + subscriber.putNext(.temporaryPath(path)) + subscriber.putCompletion() + } + } + return EmptyDisposable + }) |> runOn(Queue.concurrentDefaultQueue()) +} diff --git a/submodules/TranslateUI/Sources/TranslateScreen.swift b/submodules/TranslateUI/Sources/TranslateScreen.swift index a500a2dcc5..1abaa4ef56 100644 --- a/submodules/TranslateUI/Sources/TranslateScreen.swift +++ b/submodules/TranslateUI/Sources/TranslateScreen.swift @@ -337,6 +337,11 @@ private final class TranslateScreenComponent: CombinedComponent { if state.textExpanded { if let fromLanguage = state.fromLanguage, state.availableSpeakLanguages.contains(fromLanguage) { + var checkColor = theme.list.itemCheckColors.foregroundColor + if checkColor.rgb == theme.list.itemPrimaryTextColor.rgb { + checkColor = theme.list.plainBackgroundColor + } + let originalSpeakButton = originalSpeakButton.update( component: Button( content: AnyComponent(ZStack([ @@ -346,7 +351,7 @@ private final class TranslateScreenComponent: CombinedComponent { ))), AnyComponentWithIdentity(id: "a", component: AnyComponent(PlayPauseIconComponent( state: state.isSpeakingOriginalText ? .pause : .play, - tintColor: theme.list.itemCheckColors.foregroundColor, + tintColor: checkColor, size: CGSize(width: 18.0, height: 18.0) ))), ])), diff --git a/submodules/WallpaperResources/Sources/WallpaperResources.swift b/submodules/WallpaperResources/Sources/WallpaperResources.swift index ebcabbb882..f3b2a3cc15 100644 --- a/submodules/WallpaperResources/Sources/WallpaperResources.swift +++ b/submodules/WallpaperResources/Sources/WallpaperResources.swift @@ -531,7 +531,7 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete var image: UIImage? if let fullSizeData = fullSizeData { if mode == .screen { - image = renderPreparedImage(fullSizeData, CGSize(width: size.width * context.scale, height: size.height * context.scale)) + image = renderPreparedImage(fullSizeData, CGSize(width: size.width * context.scale, height: size.height * context.scale), .black, 1.0) } else { image = UIImage(data: fullSizeData) } From 30d5f9ddef061fc8e91aec95e561db5494a2e690 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 8 Apr 2022 00:01:01 +0400 Subject: [PATCH 9/9] Web app improvements --- .../Sources/AttachmentController.swift | 14 ++++--- .../Sources/DebugController.swift | 31 +++++++++----- .../TelegramUI/Sources/ChatController.swift | 25 +++++++----- .../WebUI/Sources/WebAppController.swift | 40 ++++++++----------- 4 files changed, 60 insertions(+), 50 deletions(-) diff --git a/submodules/AttachmentUI/Sources/AttachmentController.swift b/submodules/AttachmentUI/Sources/AttachmentController.swift index f86d6a4f96..42dceef3c2 100644 --- a/submodules/AttachmentUI/Sources/AttachmentController.swift +++ b/submodules/AttachmentUI/Sources/AttachmentController.swift @@ -161,7 +161,8 @@ public class AttachmentController: ViewController { private let initialButton: AttachmentButtonType private let fromMenu: Bool - public var dismissed: () -> Void = {} + public var willDismiss: () -> Void = {} + public var didDismiss: () -> Void = {} public var mediaPickerContext: AttachmentMediaPickerContext? { get { @@ -843,9 +844,8 @@ public class AttachmentController: ViewController { self.displayNodeDidLoad() } - private var didDismiss = false + private var dismissedFlag = false public func _dismiss() { - self.dismissed() super.dismiss(animated: false, completion: {}) } @@ -856,15 +856,17 @@ public class AttachmentController: ViewController { self.view.endEditing(true) } if flag { - if !self.didDismiss { - self.didDismiss = true - self.dismissed() + if !self.dismissedFlag { + self.dismissedFlag = true + self.willDismiss() self.node.animateOut(completion: { [weak self] in + self?.didDismiss() self?._dismiss() completion?() }) } } else { + self.didDismiss() self._dismiss() completion?() } diff --git a/submodules/DebugSettingsUI/Sources/DebugController.swift b/submodules/DebugSettingsUI/Sources/DebugController.swift index 9636006ae3..6e73ee816e 100644 --- a/submodules/DebugSettingsUI/Sources/DebugController.swift +++ b/submodules/DebugSettingsUI/Sources/DebugController.swift @@ -14,6 +14,7 @@ import OverlayStatusController import AccountContext import AppBundle import ZipArchive +import WebKit @objc private final class DebugControllerMailComposeDelegate: NSObject, MFMailComposeViewControllerDelegate { public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { @@ -74,6 +75,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { case resetHoles(PresentationTheme) case reindexUnread(PresentationTheme) case resetBiometricsData(PresentationTheme) + case resetWebViewCache(PresentationTheme) case optimizeDatabase(PresentationTheme) case photoPreview(PresentationTheme, Bool) case knockoutWallpaper(PresentationTheme, Bool) @@ -103,7 +105,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { return DebugControllerSection.logging.rawValue case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries: return DebugControllerSection.experiments.rawValue - case .clearTips, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .experimentalBackground, .snow: + case .clearTips, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .resetWebViewCache, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .experimentalBackground, .snow: return DebugControllerSection.experiments.rawValue case .preferredVideoCodec: return DebugControllerSection.videoExperiments.rawValue @@ -160,30 +162,32 @@ private enum DebugControllerEntry: ItemListNodeEntry { return 20 case .resetBiometricsData: return 21 - case .optimizeDatabase: + case .resetWebViewCache: return 22 - case .photoPreview: + case .optimizeDatabase: return 23 - case .knockoutWallpaper: + case .photoPreview: return 24 + case .knockoutWallpaper: + return 25 case .experimentalCompatibility: return 26 case .enableDebugDataDisplay: return 27 case .acceleratedStickers: - return 29 + return 28 case .experimentalBackground: - return 30 + return 29 case .snow: - return 31 + return 30 case .playerEmbedding: - return 32 + return 31 case .playlistPlayback: - return 33 + return 32 case .voiceConference: - return 34 + return 33 case let .preferredVideoCodec(index, _, _, _): - return 35 + index + return 34 + index case .disableVideoAspectScaling: return 100 case .enableVoipTcp: @@ -777,6 +781,10 @@ private enum DebugControllerEntry: ItemListNodeEntry { return settings.withUpdatedBiometricsDomainState(nil).withUpdatedShareBiometricsDomainState(nil) }).start() }) + case .resetWebViewCache: + return ItemListActionItem(presentationData: presentationData, title: "Clear Web View Cache", kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: { + WKWebsiteDataStore.default().removeData(ofTypes: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache], modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{ }) + }) case .optimizeDatabase: return ItemListActionItem(presentationData: presentationData, title: "Optimize Database", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { guard let context = arguments.context else { @@ -968,6 +976,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present entries.append(.resetHoles(presentationData.theme)) if isMainApp { entries.append(.reindexUnread(presentationData.theme)) + entries.append(.resetWebViewCache(presentationData.theme)) } entries.append(.optimizeDatabase(presentationData.theme)) if isMainApp { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index b42fa801d5..523b0df863 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3376,14 +3376,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } }, completion: { [weak self] in self?.chatDisplayNode.historyNode.scrollToEndOfHistory() - }, dismissed: { [weak self] in + }, willDismiss: { [weak self] in self?.interfaceInteraction?.updateShowWebView { _ in return false } - let isFocused = strongSelf.chatDisplayNode.textInputPanelNode?.isFocused ?? false - strongSelf.chatDisplayNode.insertSubnode(strongSelf.chatDisplayNode.inputPanelContainerNode, aboveSubnode: strongSelf.chatDisplayNode.historyNodeContainer) - if isFocused { - strongSelf.chatDisplayNode.textInputPanelNode?.ensureFocused() + }, didDismiss: { [weak self] in + if let strongSelf = self { + let isFocused = strongSelf.chatDisplayNode.textInputPanelNode?.isFocused ?? false + strongSelf.chatDisplayNode.insertSubnode(strongSelf.chatDisplayNode.inputPanelContainerNode, aboveSubnode: strongSelf.chatDisplayNode.historyNodeContainer) + if isFocused { + strongSelf.chatDisplayNode.textInputPanelNode?.ensureFocused() + } } }) strongSelf.present(controller, in: .window(.root)) @@ -6792,7 +6795,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return value }) }) - if updatedInputMode == .text { + var dismissWebView = false + switch updatedInputMode { + case .text, .media, .inputButtons: + dismissWebView = true + default: + break + } + if dismissWebView { updated = updated.updatedShowWebView(false) } return updated @@ -6802,9 +6812,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self else { return } - strongSelf.interfaceInteraction?.updateShowWebView { _ in - return false - } strongSelf.chatDisplayNode.openStickers() strongSelf.mediaRecordingModeTooltipController?.dismissImmediately() }, editMessage: { [weak self] in diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 1bc32f8c78..b1fc7dab20 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -260,31 +260,22 @@ public final class WebAppController: ViewController, AttachmentContainable { } return nil } + + func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { + Queue.mainQueue().after(0.65, { + let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .linear) + transition.updateAlpha(layer: webView.layer, alpha: 1.0) + if let placeholderNode = self.placeholderNode { + self.placeholderNode = nil + transition.updateAlpha(node: placeholderNode, alpha: 0.0, completion: { [weak placeholderNode] _ in + placeholderNode?.removeFromSupernode() + }) + } - private var loadCount = 0 - func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - self.loadCount += 1 - } - - func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - self.loadCount -= 1 - - Queue.mainQueue().after(0.1, { - if self.loadCount == 0, let webView = self.webView { - let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .linear) - transition.updateAlpha(layer: webView.layer, alpha: 1.0) - if let placeholderNode = self.placeholderNode { - self.placeholderNode = nil - transition.updateAlpha(node: placeholderNode, alpha: 0.0, completion: { [weak placeholderNode] _ in - placeholderNode?.removeFromSupernode() - }) - } + if let (layout, navigationBarHeight) = self.validLayout { + self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) } }) - - if let (layout, navigationBarHeight) = self.validLayout { - self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) - } } @available(iOSApplicationExtension 15.0, iOS 15.0, *) @@ -677,7 +668,7 @@ private final class WebAppContextReferenceContentSource: ContextReferenceContent } } -public func standaloneWebAppController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, params: WebAppParameters, openUrl: @escaping (String) -> Void, getInputContainerNode: @escaping () -> (CGFloat, ASDisplayNode, () -> AttachmentController.InputPanelTransition?)? = { return nil }, completion: @escaping () -> Void = {}, dismissed: @escaping () -> Void = {}) -> ViewController { +public func standaloneWebAppController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, params: WebAppParameters, openUrl: @escaping (String) -> Void, getInputContainerNode: @escaping () -> (CGFloat, ASDisplayNode, () -> AttachmentController.InputPanelTransition?)? = { return nil }, completion: @escaping () -> Void = {}, willDismiss: @escaping () -> Void = {}, didDismiss: @escaping () -> Void = {}) -> ViewController { let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: .peer(id: params.peerId), buttons: [.standalone], initialButton: .standalone, fromMenu: params.fromMenu) controller.getInputContainerNode = getInputContainerNode controller.requestController = { _, present in @@ -686,6 +677,7 @@ public func standaloneWebAppController(context: AccountContext, updatedPresentat webAppController.completion = completion present(webAppController, webAppController.mediaPickerContext) } - controller.dismissed = dismissed + controller.willDismiss = willDismiss + controller.didDismiss = didDismiss return controller }