From ad731bf23760d222ae789860d0bf7058cb854c36 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Sat, 31 Jan 2026 00:37:35 +0800 Subject: [PATCH] Various improvements --- .../Source/Base/Transition.swift | 6 +- .../Sources/ChatTitleComponent.swift | 11 ++- ...UpdateChatPresentationInterfaceState.swift | 37 +++++----- .../UIViewController+Navigation.h | 15 ++++ .../UIViewController+Navigation.m | 68 ++++++++++++++++--- 5 files changed, 107 insertions(+), 30 deletions(-) diff --git a/submodules/ComponentFlow/Source/Base/Transition.swift b/submodules/ComponentFlow/Source/Base/Transition.swift index 92999c1ea9..93886bc1a0 100644 --- a/submodules/ComponentFlow/Source/Base/Transition.swift +++ b/submodules/ComponentFlow/Source/Base/Transition.swift @@ -114,12 +114,14 @@ public extension ComponentTransition { options.insert(.allowUserInteraction) } switch curve { - case .spring, .bounce: + case .spring, .bounce, .custom: var parameters: CALayerSpringParametersOverrideParameters? var dampingValue: CGFloat = 500.0 if case let .bounce(stiffness, damping) = curve { dampingValue = damping - parameters = CALayerSpringParametersOverrideParameters(stiffness: stiffness, damping: damping, duration: duration) + parameters = CALayerSpringParametersOverrideParametersSpring(stiffness: stiffness, damping: damping, duration: duration) + } else if case let .custom(a, b, c, d) = curve { + parameters = CALayerSpringParametersOverrideParametersCustomCurve(cp1: CGPoint(x: CGFloat(a), y: CGFloat(b)), cp2: CGPoint(x: CGFloat(c), y: CGFloat(d))) } CALayer.push(CALayerSpringParametersOverride(parameters: parameters)) UIView.animate(withDuration: duration, delay: delay, usingSpringWithDamping: dampingValue, initialSpringVelocity: 0.0, options: options, animations: { diff --git a/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift b/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift index 65370c7753..be38d26f7b 100644 --- a/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift +++ b/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift @@ -45,7 +45,9 @@ public final class ChatNavigationBarTitleView: UIView, NavigationBarTitleView { private var activities: ChatTitleComponent.Activities? private var networkState: AccountNetworkState? + private var ignoreParentTransitionRequests: Bool = false public var requestUpdate: ((ContainedViewLayoutTransition) -> Void)? + public var tapAction: (() -> Void)? public var longTapAction: (() -> Void)? @@ -82,8 +84,10 @@ public final class ChatNavigationBarTitleView: UIView, NavigationBarTitleView { dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, content: ChatTitleContent, - transition: ComponentTransition + transition: ComponentTransition, + ignoreParentTransitionRequests: Bool = false ) { + self.ignoreParentTransitionRequests = ignoreParentTransitionRequests self.contentData = ContentData( context: context, theme: theme, @@ -95,6 +99,7 @@ public final class ChatNavigationBarTitleView: UIView, NavigationBarTitleView { content: content ) self.update(transition: transition) + self.ignoreParentTransitionRequests = false } public func updateActivities(activities: ChatTitleComponent.Activities?, transition: ComponentTransition) { @@ -112,7 +117,9 @@ public final class ChatNavigationBarTitleView: UIView, NavigationBarTitleView { } private func update(transition: ComponentTransition) { - self.requestUpdate?(transition.containedViewLayoutTransition) + if !self.ignoreParentTransitionRequests { + self.requestUpdate?(transition.containedViewLayoutTransition) + } } public func updateLayout(availableSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize { diff --git a/submodules/TelegramUI/Sources/Chat/UpdateChatPresentationInterfaceState.swift b/submodules/TelegramUI/Sources/Chat/UpdateChatPresentationInterfaceState.swift index 3a288cf7c9..c1ba97148d 100644 --- a/submodules/TelegramUI/Sources/Chat/UpdateChatPresentationInterfaceState.swift +++ b/submodules/TelegramUI/Sources/Chat/UpdateChatPresentationInterfaceState.swift @@ -456,6 +456,25 @@ func updateChatPresentationInterfaceStateImpl( selfController.tempHideAccessoryPanels = selfController.presentationInterfaceState.search != nil + if let chatTitleContent = selfController.contentData?.state.chatTitleContent { + var titleTransition = ComponentTransition(transition) + if case .messageOptions = selfController.subject { + titleTransition = titleTransition.withAnimation(.none) + } + selfController.chatTitleView?.update( + context: selfController.context, + theme: selfController.presentationData.theme, + preferClearGlass: selfController.presentationInterfaceState.preferredGlassType == .clear, + wallpaper: selfController.presentationInterfaceState.chatWallpaper, + strings: selfController.presentationData.strings, + dateTimeFormat: selfController.presentationData.dateTimeFormat, + nameDisplayOrder: selfController.presentationData.nameDisplayOrder, + content: chatTitleContent, + transition: titleTransition, + ignoreParentTransitionRequests: true + ) + } + if selfController.isNodeLoaded { selfController.chatDisplayNode.updateChatPresentationInterfaceState(updatedChatPresentationInterfaceState, transition: transition, interactive: interactive, completion: completion) } else { @@ -609,23 +628,5 @@ func updateChatPresentationInterfaceStateImpl( } } - if let chatTitleContent = selfController.contentData?.state.chatTitleContent { - var titleTransition = ComponentTransition(transition) - if case .messageOptions = selfController.subject { - titleTransition = titleTransition.withAnimation(.none) - } - selfController.chatTitleView?.update( - context: selfController.context, - theme: selfController.presentationData.theme, - preferClearGlass: selfController.presentationInterfaceState.preferredGlassType == .clear, - wallpaper: selfController.presentationInterfaceState.chatWallpaper, - strings: selfController.presentationData.strings, - dateTimeFormat: selfController.presentationData.dateTimeFormat, - nameDisplayOrder: selfController.presentationData.nameDisplayOrder, - content: chatTitleContent, - transition: titleTransition - ) - } - selfController.stateUpdated?(transition) } diff --git a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.h b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.h index 782a77ad67..928aa420c9 100644 --- a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.h +++ b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.h @@ -28,6 +28,12 @@ typedef NS_OPTIONS(NSUInteger, UIResponderDisableAutomaticKeyboardHandling) { @interface CALayerSpringParametersOverrideParameters : NSObject +- (instancetype _Nonnull)init; + +@end + +@interface CALayerSpringParametersOverrideParametersSpring : CALayerSpringParametersOverrideParameters + @property (nonatomic, readonly) CGFloat stiffness; @property (nonatomic, readonly) CGFloat damping; @property (nonatomic, readonly) double duration; @@ -36,6 +42,15 @@ typedef NS_OPTIONS(NSUInteger, UIResponderDisableAutomaticKeyboardHandling) { @end +@interface CALayerSpringParametersOverrideParametersCustomCurve : CALayerSpringParametersOverrideParameters + +@property (nonatomic, readonly) CGPoint cp1; +@property (nonatomic, readonly) CGPoint cp2; + +- (instancetype _Nonnull)initWithCp1:(CGPoint)cp1 cp2:(CGPoint)cp2; + +@end + @interface CALayerSpringParametersOverride : NSObject @property (nonatomic, strong, readonly) CALayerSpringParametersOverrideParameters * _Nullable parameters; diff --git a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.m b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.m index da76d8763c..1c475ce8e3 100644 --- a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.m +++ b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.m @@ -115,18 +115,42 @@ static bool notyfyingShiftState = false; @implementation CALayerSpringParametersOverrideParameters -- (instancetype _Nonnull)initWithStiffness:(CGFloat)stiffness damping:(CGFloat)damping duration:(double)duration; { +- (instancetype _Nonnull)init { self = [super init]; if (self != nil) { - _stiffness = stiffness; - _damping = damping; - _duration = duration; } return self; } @end +@implementation CALayerSpringParametersOverrideParametersSpring + +- (instancetype _Nonnull)initWithStiffness:(CGFloat)stiffness damping:(CGFloat)damping duration:(double)duration { + self = [super init]; + if (self != nil) { + _stiffness = stiffness; + _damping = damping; + } + return self; +} + +@end + +@implementation CALayerSpringParametersOverrideParametersCustomCurve + +- (instancetype _Nonnull)initWithCp1:(CGPoint)cp1 cp2:(CGPoint)cp2 { + self = [super init]; + if (self != nil) { + _cp1 = cp1; + _cp2 = cp2; + } + return self; +} + +@end + + @implementation CALayerSpringParametersOverride - (instancetype _Nonnull)initWithParameters:(CALayerSpringParametersOverrideParameters * _Nullable)parameters { @@ -167,12 +191,13 @@ static NSMutableArray *currentSpringParameter if (currentSpringParametersOverrideStack().count != 0 && [anim isKindOfClass:[CASpringAnimation class]]) { CALayerSpringParametersOverride *overrideData = [currentSpringParametersOverrideStack() lastObject]; if (overrideData) { - if (overrideData.parameters) { + if ([overrideData.parameters isKindOfClass:[CALayerSpringParametersOverrideParametersSpring class]]) { + CALayerSpringParametersOverrideParametersSpring *parameters = (CALayerSpringParametersOverrideParametersSpring *)overrideData.parameters; CABasicAnimation *sourceAnimation = (CABasicAnimation *)anim; - CASpringAnimation *animation = makeSpringBounceAnimationImpl(sourceAnimation.keyPath, 0.0, overrideData.parameters.damping); + CASpringAnimation *animation = makeSpringBounceAnimationImpl(sourceAnimation.keyPath, 0.0, parameters.damping); - animation.stiffness = overrideData.parameters.stiffness; + animation.stiffness = parameters.stiffness; animation.fromValue = sourceAnimation.fromValue; animation.toValue = sourceAnimation.toValue; animation.byValue = sourceAnimation.byValue; @@ -189,7 +214,34 @@ static NSMutableArray *currentSpringParameter if (k != 0.0 && k != 1.0) { speed = 1.0f / k; } - animation.speed = sourceAnimation.speed * (float)(animation.duration / overrideData.parameters.duration); + animation.speed = sourceAnimation.speed * (float)(animation.duration / parameters.duration); + + updatedAnimation = animation; + } else if ([overrideData.parameters isKindOfClass:[CALayerSpringParametersOverrideParametersCustomCurve class]]) { + CALayerSpringParametersOverrideParametersCustomCurve *parameters = (CALayerSpringParametersOverrideParametersCustomCurve *)overrideData.parameters; + CABasicAnimation *sourceAnimation = (CABasicAnimation *)anim; + + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:sourceAnimation.keyPath]; + animation.fromValue = sourceAnimation.fromValue; + animation.toValue = sourceAnimation.toValue; + animation.byValue = sourceAnimation.byValue; + animation.additive = sourceAnimation.additive; + animation.duration = sourceAnimation.duration; + animation.timingFunction = [[CAMediaTimingFunction alloc] initWithControlPoints:parameters.cp1.x :parameters.cp1.y :parameters.cp2.x :parameters.cp2.y]; + animation.removedOnCompletion = sourceAnimation.isRemovedOnCompletion; + animation.fillMode = sourceAnimation.fillMode; + animation.speed = sourceAnimation.speed; + animation.beginTime = sourceAnimation.beginTime; + animation.timeOffset = sourceAnimation.timeOffset; + animation.repeatCount = sourceAnimation.repeatCount; + animation.autoreverses = sourceAnimation.autoreverses; + + float k = animationDurationFactorImpl(); + float speed = 1.0f; + if (k != 0.0 && k != 1.0) { + speed = 1.0f / k; + } + animation.speed = speed * sourceAnimation.speed; updatedAnimation = animation; } else {