From b5e8c8960d1f3874d861190e1e90d19b7fe48d83 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 30 Sep 2025 16:13:37 +0800 Subject: [PATCH 1/7] Update --- .../Sources/GlassBackgroundComponent.swift | 14 +++++++++----- .../GlassEdge40x40.imageset/18Glass@2x.png | Bin 0 -> 5434 bytes .../GlassEdge40x40.imageset/18Glass@3x.png | Bin 0 -> 10737 bytes .../GlassEdge40x40.imageset/Contents.json | 14 ++++++++++++-- .../GlassEdge40x40.imageset/iOS 28.pdf | Bin 49799 -> 0 bytes 5 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Item List/GlassEdge40x40.imageset/18Glass@2x.png create mode 100644 submodules/TelegramUI/Images.xcassets/Item List/GlassEdge40x40.imageset/18Glass@3x.png delete mode 100644 submodules/TelegramUI/Images.xcassets/Item List/GlassEdge40x40.imageset/iOS 28.pdf diff --git a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift index 734f6f916a..c53a0e58bb 100644 --- a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift +++ b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift @@ -701,15 +701,19 @@ public extension GlassBackgroundView { let context = ctx.cgContext context.setFillColor(fillColor.cgColor) - context.fill(CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset).insetBy(dx: 0.1, dy: 0.1)) + context.fill(CGRect(origin: CGPoint(), size: size)) if let image = UIImage(bundleImageName: "Item List/GlassEdge40x40") { - if s <= 0.3 && !isDark { - image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset), blendMode: .normal, alpha: 0.7) + let imageInset = (image.size.width - 40.0) * 0.5 + + if s == 0.0 && abs(a - 0.7) < 0.1 && !isDark { + image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .normal, alpha: 1.0) + } else if s <= 0.3 && !isDark { + image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .normal, alpha: 0.7) } else if b >= 0.2 { - image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset), blendMode: .plusLighter, alpha: 0.7) + image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .plusLighter, alpha: 0.7) } else { - image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset), blendMode: .normal, alpha: 0.5) + image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .normal, alpha: 0.5) } } } diff --git a/submodules/TelegramUI/Images.xcassets/Item List/GlassEdge40x40.imageset/18Glass@2x.png b/submodules/TelegramUI/Images.xcassets/Item List/GlassEdge40x40.imageset/18Glass@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a192b6a5783b6bab2fdb34d419b9fc8b8bd71281 GIT binary patch literal 5434 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 O2r5p Date: Tue, 30 Sep 2025 17:41:32 +0800 Subject: [PATCH 2/7] Update --- .../Sources/ComposePollScreen.swift | 2 +- .../Sources/DefaultDayPresentationTheme.swift | 2 +- .../ChatInputMessageAccessoryPanel.swift | 4 +- .../Sources/ChatTextInputPanelNode.swift | 20 ++---- .../Sources/ChatEntityKeyboardInputNode.swift | 7 +- .../Sources/EmojiPagerContentComponent.swift | 64 ++++++++++++++++--- .../Sources/EmojiPagerContentSignals.swift | 6 +- .../Sources/EmojiSearchContent.swift | 2 +- .../Sources/GlassBackgroundComponent.swift | 2 +- .../Sources/MediaEditorScreen.swift | 2 +- .../Sources/ChatControllerNode.swift | 1 + 11 files changed, 78 insertions(+), 34 deletions(-) diff --git a/submodules/ComposePollUI/Sources/ComposePollScreen.swift b/submodules/ComposePollUI/Sources/ComposePollScreen.swift index 8642f6d924..9d8e090b41 100644 --- a/submodules/ComposePollUI/Sources/ComposePollScreen.swift +++ b/submodules/ComposePollUI/Sources/ComposePollScreen.swift @@ -707,7 +707,7 @@ final class ComposePollScreenComponent: Component { hasStickers: false, hasGifs: false, hideBackground: true, - maskEdge: true, + maskEdge: .fade, sendGif: nil ) ) diff --git a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift index 41f7580096..b6c4fb74db 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift @@ -950,7 +950,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio inputStrokeColor: UIColor(rgb: 0x000000, alpha: 0.1), inputPlaceholderColor: UIColor(rgb: 0x000000, alpha: 0.4), inputTextColor: UIColor(rgb: 0x000000), - inputControlColor: UIColor(rgb: 0x000000, alpha: 0.4), + inputControlColor: UIColor(rgb: 0x000000, alpha: 0.5), actionControlFillColor: defaultDayAccentColor, actionControlForegroundColor: UIColor(rgb: 0xffffff), primaryTextColor: UIColor(rgb: 0x000000, alpha: 1.0), diff --git a/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift b/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift index 06fca75090..09b3dd0b3d 100644 --- a/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift +++ b/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift @@ -402,7 +402,7 @@ public final class ChatInputMessageAccessoryPanel: Component { } self.closeButtonIcon.tintColor = environment.theme.chat.inputPanel.inputControlColor - let secondaryTextColor = environment.theme.chat.inputPanel.inputControlColor.withMultipliedBrightnessBy(0.5) + let secondaryTextColor = environment.theme.chat.inputPanel.inputPlaceholderColor var textString: NSAttributedString var isPhoto = false @@ -492,7 +492,7 @@ public final class ChatInputMessageAccessoryPanel: Component { isMedia = false isText = true default: - isMedia = true + isMedia = effectiveMessage.text.isEmpty isText = false } diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift index dc34fa8374..307bd9ca34 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift @@ -1958,7 +1958,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } } - self.updateActionButtons(hasText: inputHasText, hideMicButton: hideMicButton, animated: transition.isAnimated) + self.updateActionButtons(hasText: inputHasText, hideMicButton: hideMicButton, hideMicButtonBackground: mediaRecordingState != nil, animated: transition.isAnimated) var actionButtonsSize = CGSize(width: 40.0, height: 40.0) if let presentationInterfaceState = self.presentationInterfaceState { @@ -1995,8 +1995,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg audioRecordingItemsAlpha = 0.0 } - transition.updateAlpha(layer: self.actionButtons.micButtonBackgroundView.layer, alpha: mediaRecordingState != nil ? 0.01 : 1.0) - if let mediaRecordingState { audioRecordingItemsAlpha = 0.0 @@ -3675,7 +3673,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg self.updateTextHeight(animated: animated) } - private func updateActionButtons(hasText: Bool, hideMicButton: Bool, animated: Bool) { + private func updateActionButtons(hasText: Bool, hideMicButton: Bool, hideMicButtonBackground: Bool, animated: Bool) { var hideMicButton = hideMicButton var mediaInputIsActive = false @@ -3832,19 +3830,15 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } } + let alphaTransition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut) + if hideMicButton { if !self.actionButtons.micButton.alpha.isZero { - self.actionButtons.micButton.alpha = 0.0 - if animated { - self.actionButtons.micButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) - } - - self.actionButtons.micButtonBackgroundView.alpha = 0.0 - if animated { - self.actionButtons.micButtonBackgroundView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) - } + alphaTransition.updateAlpha(layer: self.actionButtons.micButton.layer, alpha: 0.0) } + alphaTransition.updateAlpha(layer: self.actionButtons.micButtonBackgroundView.layer, alpha: 0.0) } else { + alphaTransition.updateAlpha(layer: self.actionButtons.micButtonBackgroundView.layer, alpha: hideMicButtonBackground ? 0.0 : 1.0) let micAlpha: CGFloat = self.actionButtons.micButton.fadeDisabled ? 0.5 : 1.0 if !self.actionButtons.micButton.alpha.isEqual(to: micAlpha) { self.actionButtons.micButton.alpha = micAlpha diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift index 0a98d73031..069339013f 100644 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift +++ b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift @@ -169,7 +169,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { hasStickers: Bool = true, hasGifs: Bool = true, hideBackground: Bool = false, - maskEdge: Bool = false, + maskEdge: EmojiPagerContentComponent.MaskEdgeMode = .none, forceHasPremium: Bool = false, sendGif: ((FileMediaReference, UIView, CGRect, Bool, Bool) -> Bool)? ) -> Signal { @@ -213,7 +213,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { hasEdit: hasEdit, hasAdd: hasEdit, subject: .chatStickers, - hideBackground: hideBackground + hideBackground: hideBackground, + maskEdge: maskEdge ) |> map(Optional.init) } else { @@ -1915,7 +1916,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { externalTopPanelContainer: self.externalTopPanelContainerImpl, externalBottomPanelContainer: nil, externalTintMaskContainer: self.backgroundTintMaskContentView, - displayTopPanelBackground: self.opaqueTopPanelBackground ? .opaque : .blur, + displayTopPanelBackground: self.opaqueTopPanelBackground ? .opaque : .none, topPanelExtensionUpdated: { [weak self] topPanelExtension, transition in guard let strongSelf = self else { return diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift index 68c579f914..f0d3501355 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift @@ -610,6 +610,12 @@ public final class EmojiPagerContentComponent: Component { } } + public enum MaskEdgeMode { + case none + case fade + case clip + } + public let id: AnyHashable public let context: AccountContext public let avatarPeer: EnginePeer? @@ -623,7 +629,7 @@ public final class EmojiPagerContentComponent: Component { public let searchState: SearchState public let warpContentsOnEdges: Bool public let hideBackground: Bool - public let maskEdge: Bool + public let maskEdge: MaskEdgeMode public let displaySearchWithPlaceholder: String? public let searchCategories: EmojiSearchCategories? public let searchInitiallyHidden: Bool @@ -649,7 +655,7 @@ public final class EmojiPagerContentComponent: Component { searchState: SearchState, warpContentsOnEdges: Bool, hideBackground: Bool, - maskEdge: Bool, + maskEdge: MaskEdgeMode, displaySearchWithPlaceholder: String?, searchCategories: EmojiSearchCategories?, searchInitiallyHidden: Bool, @@ -1383,6 +1389,7 @@ public final class EmojiPagerContentComponent: Component { private let backgroundView: BlurredBackgroundView private let backgroundTintView: UIView private var fadingMaskLayer: FadingMaskLayer? + private var tintFadingMaskLayer: FadingMaskLayer? private var vibrancyClippingView: UIView private var vibrancyEffectView: UIView? public private(set) var mirrorContentClippingView: UIView? @@ -4007,6 +4014,9 @@ public final class EmojiPagerContentComponent: Component { if let fadingMaskLayer = self.fadingMaskLayer { fadingMaskLayer.internalAlpha = max(0.0, min(1.0, self.scrollView.contentOffset.y / 30.0)) } + if let tintFadingMaskLayer = self.tintFadingMaskLayer { + tintFadingMaskLayer.internalAlpha = max(0.0, min(1.0, self.scrollView.contentOffset.y / 30.0)) + } } private func updateShimmerIfNeeded() { @@ -4075,18 +4085,31 @@ public final class EmojiPagerContentComponent: Component { if component.hideBackground { self.backgroundView.isHidden = true - if component.maskEdge { + if component.maskEdge != .none { let maskLayer: FadingMaskLayer if let current = self.fadingMaskLayer { maskLayer = current } else { - maskLayer = FadingMaskLayer() + maskLayer = FadingMaskLayer(isHard: component.maskEdge == .clip) self.fadingMaskLayer = maskLayer } + + let tintFadingMaskLayer: FadingMaskLayer + if let current = self.tintFadingMaskLayer { + tintFadingMaskLayer = current + } else { + tintFadingMaskLayer = FadingMaskLayer(isHard: component.maskEdge == .clip) + self.tintFadingMaskLayer = tintFadingMaskLayer + } + if self.layer.mask == nil { self.layer.mask = maskLayer } - maskLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: floorToScreenPixels((topPanelHeight - 34.0) * 0.75)), size: backgroundFrame.size) + if self.mirrorContentClippingView?.layer.mask != tintFadingMaskLayer { + self.mirrorContentClippingView?.layer.mask = tintFadingMaskLayer + } + maskLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: topPanelHeight - 40.0), size: backgroundFrame.size) + tintFadingMaskLayer.frame = maskLayer.frame } } else if component.warpContentsOnEdges { self.backgroundView.isHidden = true @@ -4910,18 +4933,38 @@ private final class FadingMaskLayer: SimpleLayer { let fillLayer = SimpleLayer() let gradientFillLayer = SimpleLayer() + private let isHard: Bool + var internalAlpha: CGFloat = 1.0 { didSet { self.gradientFillLayer.opacity = Float(1.0 - self.internalAlpha) } } + init(isHard: Bool) { + self.isHard = isHard + super.init() + } + + override init(layer: Any) { + self.isHard = false + super.init(layer: layer) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func layoutSublayers() { let gradientHeight: CGFloat = 66.0 if self.gradientLayer.contents == nil { - self.addSublayer(self.gradientLayer) + if !self.isHard { + self.addSublayer(self.gradientLayer) + } self.addSublayer(self.fillLayer) - self.addSublayer(self.gradientFillLayer) + if !self.isHard { + self.addSublayer(self.gradientFillLayer) + } let gradientImage = generateGradientImage(size: CGSize(width: 1.0, height: gradientHeight), colors: [UIColor.white.withAlphaComponent(0.0), UIColor.white.withAlphaComponent(0.0), UIColor.white, UIColor.white], locations: [0.0, 0.4, 0.9, 1.0], direction: .vertical) self.gradientLayer.contents = gradientImage?.cgImage @@ -4932,7 +4975,12 @@ private final class FadingMaskLayer: SimpleLayer { self.gradientLayer.frame = CGRect(origin: .zero, size: CGSize(width: self.bounds.width, height: gradientHeight)) self.gradientFillLayer.frame = self.gradientLayer.frame - self.fillLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: gradientHeight), size: CGSize(width: self.bounds.width, height: self.bounds.height - gradientHeight)) + if self.isHard { + let hardHeight: CGFloat = 40.0 + self.fillLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: hardHeight), size: CGSize(width: self.bounds.width, height: self.bounds.height - hardHeight)) + } else { + self.fillLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: gradientHeight), size: CGSize(width: self.bounds.width, height: self.bounds.height - gradientHeight)) + } } } diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift index c16e3501b5..df4dd2efbb 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift @@ -66,7 +66,7 @@ public extension EmojiPagerContentComponent { forceHasPremium: Bool = false, premiumIfSavedMessages: Bool = true, hideBackground: Bool = false, - maskEdge: Bool = false + maskEdge: EmojiPagerContentComponent.MaskEdgeMode = .none ) -> Signal { let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) let isPremiumDisabled = premiumConfiguration.isPremiumDisabled @@ -1635,7 +1635,7 @@ public extension EmojiPagerContentComponent { searchIsPlaceholderOnly: Bool = true, subject: StickersSubject = .chatStickers, hideBackground: Bool = false, - maskEdge: Bool = false + maskEdge: EmojiPagerContentComponent.MaskEdgeMode = .none ) -> Signal { let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) let isPremiumDisabled = premiumConfiguration.isPremiumDisabled @@ -2202,7 +2202,7 @@ public extension EmojiPagerContentComponent { animationRenderer: MultiAnimationRenderer, hasSearch: Bool, hideBackground: Bool = false, - maskEdge: Bool = false + maskEdge: EmojiPagerContentComponent.MaskEdgeMode = .none ) -> Signal { let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) let isPremiumDisabled = premiumConfiguration.isPremiumDisabled diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift index 1366bfafd4..3967917a8b 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift @@ -469,7 +469,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode searchState: .empty(hasResults: false), warpContentsOnEdges: false, hideBackground: false, - maskEdge: false, + maskEdge: .none, displaySearchWithPlaceholder: self.presentationData.strings.EmojiSearch_SearchEmojiPlaceholder, searchCategories: nil, searchInitiallyHidden: false, diff --git a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift index c53a0e58bb..bf204c6726 100644 --- a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift +++ b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift @@ -696,7 +696,7 @@ public extension GlassBackgroundView { fillColor.getHue(nil, saturation: &s, brightness: &b, alpha: &a) let innerImage: UIImage - if size == CGSize(width: 40.0 + inset * 2.0, height: 40.0 + inset * 2.0) { + if size == CGSize(width: 40.0 + inset * 2.0, height: 40.0 + inset * 2.0), b >= 0.2 { innerImage = UIGraphicsImageRenderer(size: size).image { ctx in let context = ctx.cgContext diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index bc8df56128..e5eed8438c 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -407,7 +407,7 @@ final class MediaEditorScreenComponent: Component { areCustomEmojiEnabled: true, hasSearch: true, hideBackground: true, - maskEdge: true, + maskEdge: .fade, sendGif: nil ) |> map { inputData -> ChatEntityKeyboardInputNode.InputData in return ChatEntityKeyboardInputNode.InputData( diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index bcf11e3564..a5b7eefda2 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -3856,6 +3856,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { areCustomEmojiEnabled: self.chatPresentationInterfaceState.customEmojiAvailable, hasEdit: true, hideBackground: true, + maskEdge: .clip, sendGif: { [weak self] fileReference, sourceView, sourceRect, silentPosting, schedule in if let self { return self.controllerInteraction.sendGif(fileReference, sourceView, sourceRect, silentPosting, schedule) From 3bca9ed1588b25083021f0bbe63eee568e368314 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 30 Sep 2025 17:51:47 +0800 Subject: [PATCH 3/7] Fix input tint on iOS 18 --- .../Sources/AccessoryItemIconButton.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/AccessoryItemIconButton.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/AccessoryItemIconButton.swift index 006482b186..71853ca9bd 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/AccessoryItemIconButton.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/AccessoryItemIconButton.swift @@ -54,6 +54,7 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie switch item { case .input, .botInput, .silentPost: self.iconImageView.isHidden = true + self.iconImageView.tintMask.isHidden = true self.animationView = ComponentView() self.tintMaskAnimationView = UIImageView() default: @@ -211,6 +212,7 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie imageFrame.origin.y += 1.0 } self.iconImageView.frame = imageFrame + self.iconImageView.tintMask.frame = imageFrame if let animationView = self.animationView { let width = AccessoryItemIconButton.calculateWidth(item: item, image: image, text: "", strings: self.strings) From 4746b8d486e02e9c736fb4d4c9aca6ae52def6b7 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 30 Sep 2025 19:09:58 +0800 Subject: [PATCH 4/7] Stickers --- .../Sources/EmojiPagerContentComponent.swift | 60 ++++++++++++++++--- .../Sources/GlassBackgroundComponent.swift | 2 +- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift index f0d3501355..bb3da9d9c9 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift @@ -1390,6 +1390,8 @@ public final class EmojiPagerContentComponent: Component { private let backgroundTintView: UIView private var fadingMaskLayer: FadingMaskLayer? private var tintFadingMaskLayer: FadingMaskLayer? + private var topPanelSeparator: (colorLayer: SimpleLayer, tintLayer: SimpleLayer)? + private var topPanelHeight: CGFloat = 0.0 private var vibrancyClippingView: UIView private var vibrancyEffectView: UIView? public private(set) var mirrorContentClippingView: UIView? @@ -4016,6 +4018,23 @@ public final class EmojiPagerContentComponent: Component { } if let tintFadingMaskLayer = self.tintFadingMaskLayer { tintFadingMaskLayer.internalAlpha = max(0.0, min(1.0, self.scrollView.contentOffset.y / 30.0)) + + self.updateTopPanelSeparator(transition: transition) + } + } + + private func updateTopPanelSeparator(transition: ComponentTransition) { + if let topPanelSeparator = self.topPanelSeparator { + var offset = self.scrollView.contentOffset.y + let startOffset: CGFloat = 40.0 - self.topPanelHeight + let endOffset: CGFloat = startOffset + 10.0 + + offset = min(max(offset, startOffset), endOffset) + offset = (endOffset - offset) / (endOffset - startOffset) + let alpha = 1.0 - offset + + transition.setAlpha(layer: topPanelSeparator.colorLayer, alpha: alpha) + transition.setAlpha(layer: topPanelSeparator.tintLayer, alpha: alpha) } } @@ -4102,14 +4121,41 @@ public final class EmojiPagerContentComponent: Component { self.tintFadingMaskLayer = tintFadingMaskLayer } + if case .clip = component.maskEdge { + let topPanelSeparator: (colorLayer: SimpleLayer, tintLayer: SimpleLayer) + if let current = self.topPanelSeparator { + topPanelSeparator = current + } else { + topPanelSeparator = (SimpleLayer(), SimpleLayer()) + self.topPanelSeparator = topPanelSeparator + self.layer.addSublayer(topPanelSeparator.colorLayer) + if let effectContainerView = externalTintMaskContainer ?? component.inputInteractionHolder.inputInteraction?.externalBackground?.effectContainerView { + effectContainerView.layer.addSublayer(topPanelSeparator.tintLayer) + } + } + + topPanelSeparator.colorLayer.backgroundColor = keyboardChildEnvironment.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5).cgColor + topPanelSeparator.tintLayer.backgroundColor = UIColor(white: 0.0, alpha: 0.7).cgColor + + let separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelHeight - UIScreenPixel), size: CGSize(width: backgroundFrame.width, height: UIScreenPixel)) + transition.setFrame(layer: topPanelSeparator.colorLayer, frame: separatorFrame) + transition.setFrame(layer: topPanelSeparator.tintLayer, frame: separatorFrame) + + self.topPanelHeight = topPanelHeight + self.updateTopPanelSeparator(transition: transition) + } + if self.layer.mask == nil { self.layer.mask = maskLayer } if self.mirrorContentClippingView?.layer.mask != tintFadingMaskLayer { self.mirrorContentClippingView?.layer.mask = tintFadingMaskLayer } - maskLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: topPanelHeight - 40.0), size: backgroundFrame.size) - tintFadingMaskLayer.frame = maskLayer.frame + let maskFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelHeight - 40.0), size: backgroundFrame.size) + transition.setFrame(layer: maskLayer, frame: maskFrame) + transition.setFrame(layer: tintFadingMaskLayer, frame: maskLayer.frame) + maskLayer.update(size: maskFrame.size, transition: transition) + tintFadingMaskLayer.update(size: maskFrame.size, transition: transition) } } else if component.warpContentsOnEdges { self.backgroundView.isHidden = true @@ -4955,7 +5001,7 @@ private final class FadingMaskLayer: SimpleLayer { fatalError("init(coder:) has not been implemented") } - override func layoutSublayers() { + func update(size: CGSize, transition: ComponentTransition) { let gradientHeight: CGFloat = 66.0 if self.gradientLayer.contents == nil { if !self.isHard { @@ -4973,13 +5019,13 @@ private final class FadingMaskLayer: SimpleLayer { self.gradientFillLayer.backgroundColor = UIColor.white.cgColor } - self.gradientLayer.frame = CGRect(origin: .zero, size: CGSize(width: self.bounds.width, height: gradientHeight)) - self.gradientFillLayer.frame = self.gradientLayer.frame + transition.setFrame(layer: self.gradientLayer, frame: CGRect(origin: .zero, size: CGSize(width: size.width, height: gradientHeight))) + transition.setFrame(layer: self.gradientFillLayer, frame: self.gradientLayer.frame) if self.isHard { let hardHeight: CGFloat = 40.0 - self.fillLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: hardHeight), size: CGSize(width: self.bounds.width, height: self.bounds.height - hardHeight)) + transition.setFrame(layer: self.fillLayer, frame: CGRect(origin: CGPoint(x: 0.0, y: hardHeight), size: CGSize(width: size.width, height: size.height - hardHeight))) } else { - self.fillLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: gradientHeight), size: CGSize(width: self.bounds.width, height: self.bounds.height - gradientHeight)) + transition.setFrame(layer: self.fillLayer, frame: CGRect(origin: CGPoint(x: 0.0, y: gradientHeight), size: CGSize(width: size.width, height: size.height - gradientHeight))) } } } diff --git a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift index bf204c6726..cad254df10 100644 --- a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift +++ b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift @@ -711,7 +711,7 @@ public extension GlassBackgroundView { } else if s <= 0.3 && !isDark { image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .normal, alpha: 0.7) } else if b >= 0.2 { - image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .plusLighter, alpha: 0.7) + image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .overlay, alpha: 1.0) } else { image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .normal, alpha: 0.5) } From bdca60c3d00a3d24c327151966be2796d9cbd04e Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 30 Sep 2025 20:54:54 +0800 Subject: [PATCH 5/7] Update --- .../Sources/PagerComponent.swift | 22 ++- .../Sources/AccessoryItemIconButton.swift | 19 +- .../Components/EntityKeyboard/BUILD | 1 + ...tyKeyboardTopContainerPanelComponent.swift | 17 +- .../EntityKeyboardTopPanelComponent.swift | 181 ++++++++++++++---- .../Sources/GlassBackgroundComponent.swift | 2 +- 6 files changed, 189 insertions(+), 53 deletions(-) diff --git a/submodules/Components/PagerComponent/Sources/PagerComponent.swift b/submodules/Components/PagerComponent/Sources/PagerComponent.swift index b4c8c28192..022076b735 100644 --- a/submodules/Components/PagerComponent/Sources/PagerComponent.swift +++ b/submodules/Components/PagerComponent/Sources/PagerComponent.swift @@ -17,6 +17,10 @@ public protocol PagerContentViewWithBackground: UIView { func pagerUpdateBackground(backgroundFrame: CGRect, topPanelHeight: CGFloat, externalTintMaskContainer: UIView?, transition: ComponentTransition) } +public protocol PagerTopPanelView: UIView { + var tintContentMask: UIView { get } +} + public final class PagerComponentChildEnvironment: Equatable { public struct ContentScrollingUpdate { public var relativeOffset: CGFloat @@ -671,6 +675,12 @@ public final class PagerComponent() + let tintContentView = UIView() let visibilityFractionUpdated = ActionSlot<(CGFloat, ComponentTransition)>() var isExpanded: Bool = false } - final class View: UIView { + final class View: UIView, PagerTopPanelView { private var backgroundView: BlurredBackgroundView? private var backgroundSeparatorView: UIView? @@ -88,7 +89,11 @@ final class EntityKeyboardTopContainerPanelComponent: Component { private var visibilityFraction: CGFloat = 1.0 + public let tintContentMask: UIView + override init(frame: CGRect) { + self.tintContentMask = UIView() + super.init(frame: frame) self.disablesInteractiveKeyboardGestureRecognizer = true @@ -150,6 +155,7 @@ final class EntityKeyboardTopContainerPanelComponent: Component { panelView = PanelView() self.panelViews[panel.id] = panelView self.addSubview(panelView.view) + self.tintContentMask.addSubview(panelView.tintContentView) } let panelId = panel.id @@ -172,12 +178,20 @@ final class EntityKeyboardTopContainerPanelComponent: Component { ) if isInBounds { transition.animatePosition(view: panelView.view, from: CGPoint(x: transitionOffsetFraction * availableSize.width, y: 0.0), to: CGPoint(), additive: true, completion: nil) + transition.animatePosition(view: panelView.tintContentView, from: CGPoint(x: transitionOffsetFraction * availableSize.width, y: 0.0), to: CGPoint(), additive: true, completion: nil) } panelTransition.setFrame(view: panelView.view, frame: panelFrame, completion: { [weak self] completed in if isPartOfTransition && completed { self?.state?.updated(transition: .immediate) } }) + panelTransition.setFrame(view: panelView.tintContentView, frame: panelFrame) + if let panelViewImpl = panelView.view.componentView as? PagerTopPanelView { + if panelViewImpl.tintContentMask.superview == nil { + panelView.tintContentView.addSubview(panelViewImpl.tintContentMask) + } + panelTransition.setFrame(view: panelViewImpl.tintContentMask, frame: CGRect(origin: CGPoint(), size: panelFrame.size)) + } } } } @@ -186,6 +200,7 @@ final class EntityKeyboardTopContainerPanelComponent: Component { if !validPanelIds.contains(id) { removedPanelIds.append(id) panelView.view.removeFromSuperview() + panelView.tintContentView.removeFromSuperview() } } for id in removedPanelIds { diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboardTopPanelComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboardTopPanelComponent.swift index 59e9034eb2..d6c9379c2e 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboardTopPanelComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboardTopPanelComponent.swift @@ -13,6 +13,7 @@ import AccountContext import MultilineTextComponent import LottieAnimationComponent import AvatarNode +import GlassBackgroundComponent final class EntityKeyboardAnimationTopPanelComponent: Component { typealias EnvironmentType = EntityKeyboardTopPanelItemEnvironment @@ -324,12 +325,16 @@ final class EntityKeyboardIconTopPanelComponent: Component { } final class View: UIView { - let iconView: UIImageView + let iconView: GlassBackgroundView.ContentImageView + let tintMaskView: UIView + var component: EntityKeyboardIconTopPanelComponent? var titleView: ComponentView? override init(frame: CGRect) { - self.iconView = UIImageView() + self.tintMaskView = UIView() + self.iconView = GlassBackgroundView.ContentImageView() + self.tintMaskView.addSubview(self.iconView.tintMask) super.init(frame: frame) @@ -355,13 +360,13 @@ final class EntityKeyboardIconTopPanelComponent: Component { var image: UIImage? switch component.icon { case .featured: - image = UIImage(bundleImageName: "Chat/Input/Media/PanelFeaturedIcon") + image = UIImage(bundleImageName: "Chat/Input/Media/PanelFeaturedIcon")?.withRenderingMode(.alwaysTemplate) case .trending: - image = UIImage(bundleImageName: "Chat/Input/Media/PanelTrendingIcon") + image = UIImage(bundleImageName: "Chat/Input/Media/PanelTrendingIcon")?.withRenderingMode(.alwaysTemplate) case .recent: - image = UIImage(bundleImageName: "Chat/Input/Media/PanelRecentIcon") + image = UIImage(bundleImageName: "Chat/Input/Media/PanelRecentIcon")?.withRenderingMode(.alwaysTemplate) case .saved: - image = UIImage(bundleImageName: "Chat/Input/Media/PanelSavedIcon") + image = UIImage(bundleImageName: "Chat/Input/Media/PanelSavedIcon")?.withRenderingMode(.alwaysTemplate) case .liked: image = UIImage(bundleImageName: "Chat/Input/Media/PanelHeartIcon")?.withRenderingMode(.alwaysTemplate) case .collectible: @@ -402,10 +407,10 @@ final class EntityKeyboardIconTopPanelComponent: Component { if component.useAccentColor { color = component.theme.list.itemAccentColor } else { - color = component.theme.chat.inputMediaPanel.panelHighlightedIconColor + color = component.theme.chat.inputPanel.inputControlColor } } else { - color = component.theme.chat.inputMediaPanel.panelIconColor + color = component.theme.chat.inputPanel.inputControlColor } } @@ -1278,7 +1283,94 @@ public final class EntityKeyboardTopPanelComponent: Component { } } - public final class View: UIView, UIScrollViewDelegate, ComponentTaggedView { + public final class View: UIView, UIScrollViewDelegate, ComponentTaggedView, PagerTopPanelView { + private final class ContentScrollLayer: CALayer { + public var mirrorLayer: CALayer? + + override public init() { + super.init() + } + + override public init(layer: Any) { + super.init(layer: layer) + } + + required public init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override public var position: CGPoint { + get { + return super.position + } set(value) { + if let mirrorLayer = self.mirrorLayer { + mirrorLayer.position = value + } + super.position = value + } + } + + override public var bounds: CGRect { + get { + return super.bounds + } set(value) { + if let mirrorLayer = self.mirrorLayer { + mirrorLayer.bounds = value + } + super.bounds = value + } + } + + override public func add(_ animation: CAAnimation, forKey key: String?) { + if let mirrorLayer = self.mirrorLayer { + mirrorLayer.add(animation, forKey: key) + } + + super.add(animation, forKey: key) + } + + override public func removeAllAnimations() { + if let mirrorLayer = self.mirrorLayer { + mirrorLayer.removeAllAnimations() + } + + super.removeAllAnimations() + } + + override public func removeAnimation(forKey: String) { + if let mirrorLayer = self.mirrorLayer { + mirrorLayer.removeAnimation(forKey: forKey) + } + + super.removeAnimation(forKey: forKey) + } + } + + private final class ContentScrollView: UIScrollView, PagerExpandableScrollView { + override static var layerClass: AnyClass { + return ContentScrollLayer.self + } + + private let mirrorView: UIView + + init(mirrorView: UIView) { + self.mirrorView = mirrorView + + super.init(frame: CGRect()) + + (self.layer as? ContentScrollLayer)?.mirrorLayer = mirrorView.layer + self.canCancelContentTouches = true + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func touchesShouldCancel(in view: UIView) -> Bool { + return true + } + } + private struct ItemLayout { struct ItemDescription { var isStatic: Bool @@ -1394,9 +1486,11 @@ public final class EntityKeyboardTopPanelComponent: Component { } } - private let scrollView: UIScrollView + private let mirrorContentScrollView: UIView + private let scrollView: ContentScrollView private var itemViews: [AnyHashable: ComponentHostView] = [:] private var highlightedIconBackgroundView: UIView + private var highlightedIconTintBackgroundView: UIView private var temporaryReorderingOrderIndex: (id: AnyHashable, index: Int)? @@ -1429,21 +1523,35 @@ public final class EntityKeyboardTopPanelComponent: Component { private var reorderGestureRecognizer: ReorderGestureRecognizer? + public let tintContentMask: UIView + private var component: EntityKeyboardTopPanelComponent? weak var state: EmptyComponentState? private var environment: EntityKeyboardTopContainerPanelEnvironment? override init(frame: CGRect) { - self.scrollView = UIScrollView() + self.mirrorContentScrollView = UIView() + self.scrollView = ContentScrollView(mirrorView: self.mirrorContentScrollView) self.highlightedIconBackgroundView = UIView() self.highlightedIconBackgroundView.isUserInteractionEnabled = false self.highlightedIconBackgroundView.clipsToBounds = true self.highlightedIconBackgroundView.isHidden = true + self.highlightedIconTintBackgroundView = UIView() + self.highlightedIconTintBackgroundView.isUserInteractionEnabled = false + self.highlightedIconTintBackgroundView.clipsToBounds = true + self.highlightedIconTintBackgroundView.isHidden = true + self.highlightedIconTintBackgroundView.backgroundColor = UIColor(white: 0.0, alpha: 0.1) + + self.tintContentMask = UIView() + self.mirrorContentScrollView.addSubview(self.highlightedIconTintBackgroundView) + self.tintContentMask.addSubview(self.mirrorContentScrollView) + super.init(frame: frame) self.scrollView.layer.anchorPoint = CGPoint() + self.mirrorContentScrollView.layer.anchorPoint = CGPoint() self.scrollView.delaysContentTouches = false self.scrollView.clipsToBounds = false if #available(iOSApplicationExtension 11.0, iOS 11.0, *) { @@ -1849,11 +1957,21 @@ public final class EntityKeyboardTopPanelComponent: Component { }, containerSize: itemOuterFrame.size ) + let itemFrame = CGRect(origin: CGPoint(x: itemOuterFrame.minX + floor((itemOuterFrame.width - itemSize.width) / 2.0), y: itemOuterFrame.minY + floor((itemOuterFrame.height - itemSize.height) / 2.0)), size: itemSize) itemTransition.setFrame(view: itemView, frame: itemFrame) - itemTransition.setSublayerTransform(view: itemView, transform: CATransform3DMakeScale(scale, scale, 1.0)) itemTransition.setAlpha(view: itemView, alpha: self.visibilityFraction) + + if let itemView = itemView.componentView as? EntityKeyboardIconTopPanelComponent.View { + if itemView.tintMaskView.superview == nil { + self.mirrorContentScrollView.addSubview(itemView.tintMaskView) + } + + itemTransition.setFrame(view: itemView.tintMaskView, frame: itemFrame) + itemTransition.setSublayerTransform(view: itemView.tintMaskView, transform: CATransform3DMakeScale(scale, scale, 1.0)) + itemTransition.setAlpha(view: itemView.tintMaskView, alpha: self.visibilityFraction) + } } } var removedIds: [AnyHashable] = [] @@ -1861,6 +1979,9 @@ public final class EntityKeyboardTopPanelComponent: Component { if !validIds.contains(id) { removedIds.append(id) itemView.removeFromSuperview() + if let itemView = itemView.componentView as? EntityKeyboardIconTopPanelComponent.View { + itemView.tintMaskView.removeFromSuperview() + } } } for id in removedIds { @@ -2020,6 +2141,7 @@ public final class EntityKeyboardTopPanelComponent: Component { if let activeContentItemId = self.activeContentItemId, activeContentItemId == self.items[index].id { self.highlightedIconBackgroundView.frame = itemOuterFrame + self.highlightedIconTintBackgroundView.frame = itemOuterFrame } } } @@ -2080,6 +2202,7 @@ public final class EntityKeyboardTopPanelComponent: Component { var highlightTransition = transition if self.highlightedIconBackgroundView.isHidden { self.highlightedIconBackgroundView.isHidden = false + self.highlightedIconTintBackgroundView.isHidden = false highlightTransition = .immediate } @@ -2089,16 +2212,24 @@ public final class EntityKeyboardTopPanelComponent: Component { } else { isRound = false } + highlightTransition.setCornerRadius(layer: self.highlightedIconBackgroundView.layer, cornerRadius: isRound ? min(itemFrame.width / 2.0, itemFrame.height / 2.0) : 10.0) highlightTransition.setPosition(view: self.highlightedIconBackgroundView, position: CGPoint(x: itemFrame.midX, y: itemFrame.midY)) highlightTransition.setBounds(view: self.highlightedIconBackgroundView, bounds: CGRect(origin: CGPoint(), size: itemFrame.size)) + + highlightTransition.setCornerRadius(layer: self.highlightedIconTintBackgroundView.layer, cornerRadius: isRound ? min(itemFrame.width / 2.0, itemFrame.height / 2.0) : 10.0) + highlightTransition.setPosition(view: self.highlightedIconTintBackgroundView, position: CGPoint(x: itemFrame.midX, y: itemFrame.midY)) + highlightTransition.setBounds(view: self.highlightedIconTintBackgroundView, bounds: CGRect(origin: CGPoint(), size: itemFrame.size)) } else { self.highlightedIconBackgroundView.isHidden = true + self.highlightedIconTintBackgroundView.isHidden = true } } else { self.highlightedIconBackgroundView.isHidden = true + self.highlightedIconTintBackgroundView.isHidden = true } transition.setAlpha(view: self.highlightedIconBackgroundView, alpha: isExpanded ? 0.0 : 1.0) + transition.setAlpha(view: self.highlightedIconTintBackgroundView, alpha: isExpanded ? 0.0 : 1.0) panelEnvironment.visibilityFractionUpdated.connect { [weak self] (fraction, transition) in guard let strongSelf = self else { @@ -2130,6 +2261,9 @@ public final class EntityKeyboardTopPanelComponent: Component { transition.setScale(view: self.highlightedIconBackgroundView, scale: scale) transition.setAlpha(view: self.highlightedIconBackgroundView, alpha: self.visibilityFraction) + transition.setScale(view: self.highlightedIconTintBackgroundView, scale: scale) + transition.setAlpha(view: self.highlightedIconTintBackgroundView, alpha: self.visibilityFraction) + for (_, itemView) in self.itemViews { transition.setSublayerTransform(view: itemView, transform: CATransform3DMakeScale(scale, scale, 1.0)) transition.setAlpha(view: itemView, alpha: self.visibilityFraction) @@ -2165,29 +2299,6 @@ public final class EntityKeyboardTopPanelComponent: Component { } } } - - /*var found = false - for i in 0 ..< self.items.count { - if self.items[i].id == itemId { - found = true - self.highlightedIconBackgroundView.isHidden = false - let itemFrame = itemLayout.containerFrame(at: i) - - var highlightTransition = transition - if highlightTransition.animation.isImmediate { - highlightTransition = highlightTransition.withAnimation(.curve(duration: 0.3, curve: .spring)) - } - highlightTransition.setPosition(view: self.highlightedIconBackgroundView, position: CGPoint(x: itemFrame.midX, y: itemFrame.midY)) - highlightTransition.setBounds(view: self.highlightedIconBackgroundView, bounds: CGRect(origin: CGPoint(), size: itemFrame.size)) - - self.scrollView.scrollRectToVisible(itemFrame.insetBy(dx: -6.0, dy: 0.0), animated: true) - - break - } - } - if !found { - self.highlightedIconBackgroundView.isHidden = true - }*/ } override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { diff --git a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift index cad254df10..82d63582b1 100644 --- a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift +++ b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift @@ -711,7 +711,7 @@ public extension GlassBackgroundView { } else if s <= 0.3 && !isDark { image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .normal, alpha: 0.7) } else if b >= 0.2 { - image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .overlay, alpha: 1.0) + image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .overlay, alpha: max(0.5, min(1.0, 0.9 * s))) } else { image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .normal, alpha: 0.5) } From 54d2b58eb3267a3228b7c9de060a96b69f5cb464 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 30 Sep 2025 21:52:21 +0800 Subject: [PATCH 6/7] Updates --- .../Sources/State/PendingMessageManager.swift | 2 +- .../Sources/DefaultDayPresentationTheme.swift | 2 +- .../Sources/GlassBackgroundComponent.swift | 3 ++- .../TelegramUI/Sources/ChatControllerNode.swift | 2 +- .../TelegramUI/Sources/ChatHistoryListNode.swift | 14 ++++++++++++++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift index b97190d5bd..1b4de7dd3c 100644 --- a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift +++ b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift @@ -494,7 +494,7 @@ public final class PendingMessageManager { stateManager: strongSelf.stateManager, accountPeerId: strongSelf.accountPeerId, peerId: message.id.peerId, - title: "Topic #\(message.stableId)", + title: "New Thread", iconColor: 0, iconFileId: nil ).startStrict(next: { [weak strongSelf] topicId in diff --git a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift index b6c4fb74db..aacb1f0111 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift @@ -964,7 +964,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio panelIconColor: UIColor(rgb: 0x858e99), panelHighlightedIconBackgroundColor: UIColor(rgb: 0x858e99, alpha: 0.2), panelHighlightedIconColor: UIColor(rgb: 0x4D5561), - panelContentVibrantOverlayColor: UIColor(white: 0.7, alpha: 0.65), + panelContentVibrantOverlayColor: UIColor(white: 0.6, alpha: 0.65), panelContentControlVibrantOverlayColor: UIColor(white: 0.85, alpha: 0.65), panelContentControlVibrantSelectionColor: UIColor(white: 0.85, alpha: 0.1), panelContentControlOpaqueOverlayColor: UIColor(white: 0.0, alpha: 0.2), diff --git a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift index 82d63582b1..1410cd9da9 100644 --- a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift +++ b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift @@ -711,7 +711,8 @@ public extension GlassBackgroundView { } else if s <= 0.3 && !isDark { image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .normal, alpha: 0.7) } else if b >= 0.2 { - image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .overlay, alpha: max(0.5, min(1.0, 0.9 * s))) + let maxAlpha: CGFloat = isDark ? 0.7 : 0.8 + image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .overlay, alpha: max(0.5, min(1.0, maxAlpha * s))) } else { image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset - imageInset, dy: inset - imageInset), blendMode: .normal, alpha: 0.5) } diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index a5b7eefda2..1419fdcd8d 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -5173,7 +5173,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { } func prepareSwitchToChatLocation(chatLocation: ChatLocation, historyNode: ChatHistoryListNodeImpl, animationDirection: ChatControllerAnimateInnerChatSwitchDirection?) { - self.chatLocation = historyNode.chatLocation + self.chatLocation = chatLocation if historyNode === self.historyNode { historyNode.updateChatLocation(chatLocation: chatLocation) } else { diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 88c4bb2aad..b2b08bdccb 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -1092,6 +1092,17 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto } } + if matches { + for (message, _) in item.content { + if strongSelf.chatLocation.threadId != nil { + if message.id.namespace != Namespaces.Message.Cloud { + matches = false + break + } + } + } + } + if matches { var maxItemIndex: MessageIndex? for (message, _) in item.content { @@ -1236,6 +1247,9 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto } self.chatLocation = chatLocation + self.interactiveReadActionDisposable?.dispose() + self.interactiveReadActionDisposable = nil + self.beginChatHistoryTransitions(resetScrolling: true, switchedToAnotherSource: false) self.beginReadHistoryManagement() } From 5b65b52c6169111d93793e00db9f559e0136d343 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 30 Sep 2025 22:01:43 +0800 Subject: [PATCH 7/7] Update --- .../Sources/ChatTextInputPanelNode.swift | 6 ++++++ submodules/TelegramUI/Sources/ChatController.swift | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift index 307bd9ca34..65482d65f6 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift @@ -338,6 +338,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } } + public var ignoreInputStateUpdates: Bool = false + override public var context: AccountContext? { didSet { self.actionButtons.micButton.statusBarHost = self.context?.sharedContext.mainWindow?.statusBarHost @@ -362,6 +364,10 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } public func updateInputTextState(_ state: ChatTextInputState, keepSendButtonEnabled: Bool, extendedSearchLayout: Bool, accessoryItems: [ChatTextInputAccessoryItem], animated: Bool) { + if self.ignoreInputStateUpdates { + return + } + if let currentState = self.presentationInterfaceState { var updateAccessoryButtons = false if accessoryItems.count == self.accessoryItemButtons.count { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 1648950bdb..4a48ba8fd2 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -10190,6 +10190,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var clearInputState = false if transferInputState { + self.chatDisplayNode.textInputPanelNode?.ignoreInputStateUpdates = true + var peerId: PeerId var currentThreadId: Int64? switch self.chatLocation { @@ -10294,6 +10296,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.currentChatSwitchDirection = nil self.isUpdatingChatLocationThread = false + self.chatDisplayNode.textInputPanelNode?.ignoreInputStateUpdates = false + if clearInputState { //DispatchQueue.main.async { [weak self] in // guard let self else {