From 1e800125d5d692e12a01d5b3e911ebf1c76a59e2 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 28 Aug 2025 04:16:09 +0400 Subject: [PATCH] Various improvements --- submodules/Display/Source/ListView.swift | 6 ++ .../Sources/MakePresentationTheme.swift | 2 +- .../Sources/ChatThemeScreen.swift | 54 +++++++++++++++++- .../GiftThemeTransferAlertController.swift | 2 +- .../Settings/Refresh.imageset/Contents.json | 12 ++++ .../Settings/Refresh.imageset/rotate_18.pdf | Bin 0 -> 4473 bytes .../OverlayAudioPlayerControllerNode.swift | 14 +++-- 7 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Refresh.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Refresh.imageset/rotate_18.pdf diff --git a/submodules/Display/Source/ListView.swift b/submodules/Display/Source/ListView.swift index 26d7997e92..a800abaed0 100644 --- a/submodules/Display/Source/ListView.swift +++ b/submodules/Display/Source/ListView.swift @@ -349,6 +349,8 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel public final var beganInteractiveDragging: (CGPoint) -> Void = { _ in } public final var endedInteractiveDragging: (CGPoint) -> Void = { _ in } public final var didEndScrolling: ((Bool) -> Void)? + public final var didEndScrollingWithOverscroll: (() -> Void)? + private var currentGeneralScrollDirection: GeneralScrollDirection? public final var generalScrollDirectionUpdated: (GeneralScrollDirection) -> Void = { _ in } @@ -891,6 +893,10 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel self.resetScrollIndicatorFlashTimer(start: false) self.isAuxiliaryDisplayLinkEnabled = true + + if scrollView.contentOffset.y < -48.0 { + self.didEndScrollingWithOverscroll?() + } } else { self.isDeceleratingAfterTracking = false self.resetHeaderItemsFlashTimer(start: true) diff --git a/submodules/TelegramPresentationData/Sources/MakePresentationTheme.swift b/submodules/TelegramPresentationData/Sources/MakePresentationTheme.swift index 360bbd44b3..3f0398e984 100644 --- a/submodules/TelegramPresentationData/Sources/MakePresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/MakePresentationTheme.swift @@ -70,7 +70,7 @@ public func makePresentationTheme(chatTheme: ChatTheme, dark: Bool = false) -> P return nil } let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), serviceBackgroundColor: nil, preview: false) - let theme = customizePresentationTheme(defaultTheme, editing: true, accentColor: UIColor(rgb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(rgb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper) + let theme = customizePresentationTheme(defaultTheme, editing: false, accentColor: UIColor(rgb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(rgb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper) if case let .gift(starGiftValue, _) = chatTheme { theme.starGift = starGiftValue } diff --git a/submodules/TelegramUI/Components/ChatThemeScreen/Sources/ChatThemeScreen.swift b/submodules/TelegramUI/Components/ChatThemeScreen/Sources/ChatThemeScreen.swift index cc06dc3451..202d5d05ab 100644 --- a/submodules/TelegramUI/Components/ChatThemeScreen/Sources/ChatThemeScreen.swift +++ b/submodules/TelegramUI/Components/ChatThemeScreen/Sources/ChatThemeScreen.swift @@ -258,7 +258,9 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { private let emojiImageNode: TransformImageNode private var animatedStickerNode: AnimatedStickerNode? private var placeholderNode: StickerShimmerEffectNode + private var bubbleNode: ASImageNode? private var avatarNode: AvatarNode? + private var replaceNode: ASImageNode? var snapshotView: UIView? var item: ThemeSettingsThemeIconItem? @@ -509,6 +511,37 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { animatedStickerNode.updateLayout(size: emojiFrame.size) } + if let _ = item.peer { + let bubbleNode: ASImageNode + if let current = strongSelf.bubbleNode { + bubbleNode = current + } else { + bubbleNode = ASImageNode() + strongSelf.insertSubnode(bubbleNode, belowSubnode: strongSelf.emojiContainerNode) + strongSelf.bubbleNode = bubbleNode + + var bubbleColor: UIColor? + if let theme = item.chatTheme, case let .gift(_, themeSettings) = theme { + if item.nightMode { + if let theme = themeSettings.first(where: { $0.baseTheme == .night || $0.baseTheme == .tinted }) { + bubbleColor = UIColor(rgb: UInt32(bitPattern: theme.accentColor)) + } + } else { + if let theme = themeSettings.first(where: { $0.baseTheme == .classic || $0.baseTheme == .day }) { + bubbleColor = UIColor(rgb: UInt32(bitPattern: theme.accentColor)) + } + } + } + if let bubbleColor { + bubbleNode.image = generateFilledRoundedRectImage(size: CGSize(width: 24.0, height: 48.0), cornerRadius: 12.0, color: bubbleColor) + } + } + bubbleNode.frame = CGRect(origin: CGPoint(x: 50.0, y: 12.0), size: CGSize(width: 24.0, height: 48.0)) + } else if let bubbleNode = strongSelf.bubbleNode { + strongSelf.bubbleNode = nil + bubbleNode.removeFromSupernode() + } + if let peer = item.peer { let avatarNode: AvatarNode if let current = strongSelf.avatarNode { @@ -525,6 +558,25 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { strongSelf.avatarNode = nil avatarNode.removeFromSupernode() } + + if let _ = item.peer { + let replaceNode: ASImageNode + if let current = strongSelf.replaceNode { + replaceNode = current + } else { + replaceNode = ASImageNode() + strongSelf.insertSubnode(replaceNode, belowSubnode: strongSelf.emojiContainerNode) + strongSelf.replaceNode = replaceNode + replaceNode.image = generateTintedImage(image: UIImage(bundleImageName: "Settings/Refresh"), color: .white) + } + replaceNode.transform = CATransform3DMakeRotation(.pi / 2.0, 0.0, 0.0, 1.0) + if let image = replaceNode.image { + replaceNode.frame = CGRect(origin: CGPoint(x: 53.0, y: 37.0), size: image.size) + } + } else if let replaceNode = strongSelf.replaceNode { + strongSelf.replaceNode = nil + replaceNode.removeFromSupernode() + } } }) } @@ -996,7 +1048,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega emojiFile = file } } - if let themePeerId = uniqueGift.themePeerId { + if let themePeerId = uniqueGift.themePeerId, theme.id != initiallySelectedTheme?.id { peer = peers[themePeerId] } } diff --git a/submodules/TelegramUI/Components/ChatThemeScreen/Sources/GiftThemeTransferAlertController.swift b/submodules/TelegramUI/Components/ChatThemeScreen/Sources/GiftThemeTransferAlertController.swift index 8153c510b8..03ea78002f 100644 --- a/submodules/TelegramUI/Components/ChatThemeScreen/Sources/GiftThemeTransferAlertController.swift +++ b/submodules/TelegramUI/Components/ChatThemeScreen/Sources/GiftThemeTransferAlertController.swift @@ -127,7 +127,7 @@ private final class GiftThemeTransferAlertContentNode: AlertContentNode { return ("URL", url) } ), textAlignment: .center) - self.arrowNode.image = generateTintedImage(image: UIImage(bundleImageName: "Media Editor/CutoutUndo"), color: theme.controlBorderColor) + self.arrowNode.image = generateTintedImage(image: UIImage(bundleImageName: "Media Editor/CutoutUndo"), color: theme.secondaryColor.withAlphaComponent(0.9)) self.actionNodesSeparator.backgroundColor = theme.separatorColor for actionNode in self.actionNodes { diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Refresh.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Settings/Refresh.imageset/Contents.json new file mode 100644 index 0000000000..3bd65d39c2 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Refresh.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "rotate_18.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Refresh.imageset/rotate_18.pdf b/submodules/TelegramUI/Images.xcassets/Settings/Refresh.imageset/rotate_18.pdf new file mode 100644 index 0000000000000000000000000000000000000000..34df5f002f48412aa13643f0bd469731770beed1 GIT binary patch literal 4473 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 XMZJk=0`X@`<)KgnNK{nwqSpTb04<;d literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index b5ea9e80bc..8311472202 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -456,11 +456,11 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu panRecognizer.delaysTouchesBegan = false panRecognizer.cancelsTouchesInView = true panRecognizer.shouldBegin = { [weak self] point in - guard let strongSelf = self else { + guard let self else { return false } - if strongSelf.controlsNode.bounds.contains(strongSelf.view.convert(point, to: strongSelf.controlsNode.view)) { - if strongSelf.controlsNode.frame.maxY <= strongSelf.historyNode.frame.minY { + if self.controlsNode.bounds.contains(self.view.convert(point, to: self.controlsNode.view)) { + if self.controlsNode.frame.maxY <= self.historyNode.frame.minY { return true } } @@ -512,6 +512,12 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu } }) self.historyNode.autoScrollWhenReordering = false + self.historyNode.didEndScrollingWithOverscroll = { [weak self] in + guard let self else { + return + } + self.requestDismiss() + } } @@ -751,7 +757,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu self.requestDismiss() } } - + override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if let recognizer = gestureRecognizer as? UIPanGestureRecognizer { let location = recognizer.location(in: self.view)