From 3cc52311851a796edf8fdcaf5f6de9672f18f90d Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 8 Apr 2025 20:36:32 +0400 Subject: [PATCH] Various fixes --- .../TelegramUI/Components/CameraScreen/BUILD | 1 + .../Sources/ShutterBlobView.swift | 120 +---------------- .../Sources/GiftSetupScreen.swift | 1 - .../Sources/FlipButtonContentComponent.swift | 2 +- .../Sources/PeerInfoScreen.swift | 4 +- .../Stories/StoryPeerListComponent/BUILD | 1 + .../MetalResources/storyBlob.metal | 2 +- .../Sources/StoryComposeLayer.swift | 119 +---------------- .../Components/Utils/AnimatableProperty/BUILD | 19 +++ .../Sources/AnimatableProperty.swift | 123 ++++++++++++++++++ 10 files changed, 150 insertions(+), 242 deletions(-) create mode 100644 submodules/TelegramUI/Components/Utils/AnimatableProperty/BUILD create mode 100644 submodules/TelegramUI/Components/Utils/AnimatableProperty/Sources/AnimatableProperty.swift diff --git a/submodules/TelegramUI/Components/CameraScreen/BUILD b/submodules/TelegramUI/Components/CameraScreen/BUILD index 33964a446c..be81f37a3d 100644 --- a/submodules/TelegramUI/Components/CameraScreen/BUILD +++ b/submodules/TelegramUI/Components/CameraScreen/BUILD @@ -86,6 +86,7 @@ swift_library( "//submodules/UndoUI", "//submodules/ContextUI", "//submodules/AvatarNode", + "//submodules/TelegramUI/Components/Utils/AnimatableProperty", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/CameraScreen/Sources/ShutterBlobView.swift b/submodules/TelegramUI/Components/CameraScreen/Sources/ShutterBlobView.swift index f0f68e80b7..f04b2c3925 100644 --- a/submodules/TelegramUI/Components/CameraScreen/Sources/ShutterBlobView.swift +++ b/submodules/TelegramUI/Components/CameraScreen/Sources/ShutterBlobView.swift @@ -4,125 +4,7 @@ import MetalKit import ComponentFlow import Display import MetalImageView - -private final class PropertyAnimation { - let from: T - let to: T - let animation: ComponentTransition.Animation - let startTimestamp: Double - private let interpolator: (Interpolatable, Interpolatable, CGFloat) -> Interpolatable - - init(fromValue: T, toValue: T, animation: ComponentTransition.Animation, startTimestamp: Double) { - self.from = fromValue - self.to = toValue - self.animation = animation - self.startTimestamp = startTimestamp - self.interpolator = T.interpolator() - } - - func valueAt(_ t: CGFloat) -> Interpolatable { - if t <= 0.0 { - return self.from - } else if t >= 1.0 { - return self.to - } else { - return self.interpolator(self.from, self.to, t) - } - } -} - -private final class AnimatableProperty { - var presentationValue: T - var value: T - private var animation: PropertyAnimation? - - init(value: T) { - self.value = value - self.presentationValue = value - } - - func update(value: T, transition: ComponentTransition = .immediate) { - let currentTimestamp = CACurrentMediaTime() - if case .none = transition.animation { - if let animation = self.animation, case let .curve(duration, curve) = animation.animation { - self.value = value - let elapsed = duration - (currentTimestamp - animation.startTimestamp) - if let presentationValue = self.presentationValue as? CGFloat, let newValue = value as? CGFloat, abs(presentationValue - newValue) > 0.56 { - self.animation = PropertyAnimation(fromValue: self.presentationValue, toValue: value, animation: .curve(duration: elapsed * 0.8, curve: curve), startTimestamp: currentTimestamp) - } else { - self.animation = PropertyAnimation(fromValue: self.presentationValue, toValue: value, animation: .curve(duration: elapsed, curve: curve), startTimestamp: currentTimestamp) - } - } else { - self.value = value - self.presentationValue = value - self.animation = nil - } - } else { - self.value = value - self.animation = PropertyAnimation(fromValue: self.presentationValue, toValue: value, animation: transition.animation, startTimestamp: currentTimestamp) - } - } - - func tick(timestamp: Double) -> Bool { - guard let animation = self.animation, case let .curve(duration, curve) = animation.animation else { - return false - } - - let timeFromStart = timestamp - animation.startTimestamp - var t = max(0.0, timeFromStart / duration) - switch curve { - case .linear: - break - case .easeInOut: - t = listViewAnimationCurveEaseInOut(t) - case .spring: - t = lookupSpringValue(t) - case let .custom(x1, y1, x2, y2): - t = bezierPoint(CGFloat(x1), CGFloat(y1), CGFloat(x2), CGFloat(y2), t) - } - self.presentationValue = animation.valueAt(t) as! T - - if timeFromStart <= duration { - return true - } - self.animation = nil - return false - } -} - -private func lookupSpringValue(_ t: CGFloat) -> CGFloat { - let table: [(CGFloat, CGFloat)] = [ - (0.0, 0.0), - (0.0625, 0.1123005598783493), - (0.125, 0.31598418951034546), - (0.1875, 0.5103585720062256), - (0.25, 0.6650152802467346), - (0.3125, 0.777747631072998), - (0.375, 0.8557760119438171), - (0.4375, 0.9079672694206238), - (0.5, 0.942038357257843), - (0.5625, 0.9638798832893372), - (0.625, 0.9776856303215027), - (0.6875, 0.9863143563270569), - (0.75, 0.991658091545105), - (0.8125, 0.9949421286582947), - (0.875, 0.9969474077224731), - (0.9375, 0.9981651306152344), - (1.0, 1.0) - ] - - for i in 0 ..< table.count - 2 { - let lhs = table[i] - let rhs = table[i + 1] - - if t >= lhs.0 && t <= rhs.0 { - let fraction = (t - lhs.0) / (rhs.0 - lhs.0) - let value = lhs.1 + fraction * (rhs.1 - lhs.1) - return value - } - } - return 1.0 -} +import AnimatableProperty private class ShutterBlobLayer: MetalImageLayer { override public init() { diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift index 04e03cab3a..76e2d6e3fa 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift @@ -504,7 +504,6 @@ final class GiftSetupScreenComponent: Component { self.state?.updated() starsContext.add(balance: StarsAmount(value: stars, nanos: 0)) - let _ = (starsContext.onUpdate |> deliverOnMainQueue).start(next: { proceed() diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/FlipButtonContentComponent.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/FlipButtonContentComponent.swift index 3947ddd1b1..20286a1546 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/FlipButtonContentComponent.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/FlipButtonContentComponent.swift @@ -32,7 +32,7 @@ final class FlipButtonContentComponent: Component { private let icon = SimpleLayer() init() { - self.backgroundView = BlurredBackgroundView(color: UIColor(white: 0.0, alpha: 0.5), enableBlur: true) + self.backgroundView = BlurredBackgroundView(color: UIColor(white: 0.2, alpha: 0.45), enableBlur: true) super.init(frame: CGRect()) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index c48f21a471..ebd3998789 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -1001,9 +1001,9 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p })) } if let starsState = data.starsState { - if !isPremiumDisabled || starsState.balance > StarsAmount.zero { + if !isPremiumDisabled || abs(starsState.balance.value) > 0 { let balanceText: NSAttributedString - if starsState.balance > StarsAmount.zero { + if abs(starsState.balance.value) > 0 { let formattedLabel = formatStarsAmountText(starsState.balance, dateTimeFormat: presentationData.dateTimeFormat) let smallLabelFont = Font.regular(floor(presentationData.listsFontSize.itemListBaseFontSize / 17.0 * 13.0)) let labelFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize) diff --git a/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/BUILD b/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/BUILD index faa2fbb5e0..07d4ac7084 100644 --- a/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/BUILD +++ b/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/BUILD @@ -69,6 +69,7 @@ swift_library( "//submodules/TelegramUI/Components/EmojiStatusComponent", "//submodules/Components/HierarchyTrackingLayer", "//submodules/TelegramUI/Components/ChatListTitleView", + "//submodules/TelegramUI/Components/Utils/AnimatableProperty", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/MetalResources/storyBlob.metal b/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/MetalResources/storyBlob.metal index 5f1848a3d7..2af505f4af 100644 --- a/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/MetalResources/storyBlob.metal +++ b/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/MetalResources/storyBlob.metal @@ -87,7 +87,7 @@ fragment half4 cameraBlobFragment( } else if (primaryParameters.y < 0) { float cutRadius = abs(primaryParameters.y); float2 primaryFeatheredOffset = primaryOffset; - primaryFeatheredOffset.x *= 1.129; + primaryFeatheredOffset.x *= 1.131; float distFromCenter = length(uv - primaryFeatheredOffset); diff --git a/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryComposeLayer.swift b/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryComposeLayer.swift index 1ebf14db78..5ff4735024 100644 --- a/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryComposeLayer.swift +++ b/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryComposeLayer.swift @@ -5,7 +5,7 @@ import MetalKit import MetalEngine import ComponentFlow import TelegramPresentationData - +import AnimatableProperty private var metalLibraryValue: MTLLibrary? func metalLibrary(device: MTLDevice) -> MTLLibrary? { @@ -28,124 +28,7 @@ func metalLibrary(device: MTLDevice) -> MTLLibrary? { return library } -private final class PropertyAnimation { - let from: T - let to: T - let animation: ComponentTransition.Animation - let startTimestamp: Double - private let interpolator: (Interpolatable, Interpolatable, CGFloat) -> Interpolatable - - init(fromValue: T, toValue: T, animation: ComponentTransition.Animation, startTimestamp: Double) { - self.from = fromValue - self.to = toValue - self.animation = animation - self.startTimestamp = startTimestamp - self.interpolator = T.interpolator() - } - - func valueAt(_ t: CGFloat) -> Interpolatable { - if t <= 0.0 { - return self.from - } else if t >= 1.0 { - return self.to - } else { - return self.interpolator(self.from, self.to, t) - } - } -} -private final class AnimatableProperty { - var presentationValue: T - var value: T - private var animation: PropertyAnimation? - - init(value: T) { - self.value = value - self.presentationValue = value - } - - func update(value: T, transition: ComponentTransition = .immediate) { - let currentTimestamp = CACurrentMediaTime() - if case .none = transition.animation { - if let animation = self.animation, case let .curve(duration, curve) = animation.animation { - self.value = value - let elapsed = duration - (currentTimestamp - animation.startTimestamp) - if let presentationValue = self.presentationValue as? CGFloat, let newValue = value as? CGFloat, abs(presentationValue - newValue) > 0.56 { - self.animation = PropertyAnimation(fromValue: self.presentationValue, toValue: value, animation: .curve(duration: elapsed * 0.8, curve: curve), startTimestamp: currentTimestamp) - } else { - self.animation = PropertyAnimation(fromValue: self.presentationValue, toValue: value, animation: .curve(duration: elapsed, curve: curve), startTimestamp: currentTimestamp) - } - } else { - self.value = value - self.presentationValue = value - self.animation = nil - } - } else { - self.value = value - self.animation = PropertyAnimation(fromValue: self.presentationValue, toValue: value, animation: transition.animation, startTimestamp: currentTimestamp) - } - } - - func tick(timestamp: Double) -> Bool { - guard let animation = self.animation, case let .curve(duration, curve) = animation.animation else { - return false - } - - let timeFromStart = timestamp - animation.startTimestamp - var t = max(0.0, timeFromStart / duration) - switch curve { - case .linear: - break - case .easeInOut: - t = listViewAnimationCurveEaseInOut(t) - case .spring: - t = lookupSpringValue(t) - case let .custom(x1, y1, x2, y2): - t = bezierPoint(CGFloat(x1), CGFloat(y1), CGFloat(x2), CGFloat(y2), t) - } - self.presentationValue = animation.valueAt(t) as! T - - if timeFromStart <= duration { - return true - } - self.animation = nil - return false - } -} - -private func lookupSpringValue(_ t: CGFloat) -> CGFloat { - let table: [(CGFloat, CGFloat)] = [ - (0.0, 0.0), - (0.0625, 0.1123005598783493), - (0.125, 0.31598418951034546), - (0.1875, 0.5103585720062256), - (0.25, 0.6650152802467346), - (0.3125, 0.777747631072998), - (0.375, 0.8557760119438171), - (0.4375, 0.9079672694206238), - (0.5, 0.942038357257843), - (0.5625, 0.9638798832893372), - (0.625, 0.9776856303215027), - (0.6875, 0.9863143563270569), - (0.75, 0.991658091545105), - (0.8125, 0.9949421286582947), - (0.875, 0.9969474077224731), - (0.9375, 0.9981651306152344), - (1.0, 1.0) - ] - - for i in 0 ..< table.count - 2 { - let lhs = table[i] - let rhs = table[i + 1] - - if t >= lhs.0 && t <= rhs.0 { - let fraction = (t - lhs.0) / (rhs.0 - lhs.0) - let value = lhs.1 + fraction * (rhs.1 - lhs.1) - return value - } - } - return 1.0 -} final class StoryBlobLayer: MetalEngineSubjectLayer, MetalEngineSubject { var internalData: MetalEngineSubjectInternalData? diff --git a/submodules/TelegramUI/Components/Utils/AnimatableProperty/BUILD b/submodules/TelegramUI/Components/Utils/AnimatableProperty/BUILD new file mode 100644 index 0000000000..f71b179806 --- /dev/null +++ b/submodules/TelegramUI/Components/Utils/AnimatableProperty/BUILD @@ -0,0 +1,19 @@ +load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") + +swift_library( + name = "AnimatableProperty", + module_name = "AnimatableProperty", + srcs = glob([ + "Sources/**/*.swift", + ]), + copts = [ + "-warnings-as-errors", + ], + deps = [ + "//submodules/Display", + "//submodules/ComponentFlow", + ], + visibility = [ + "//visibility:public", + ], +) diff --git a/submodules/TelegramUI/Components/Utils/AnimatableProperty/Sources/AnimatableProperty.swift b/submodules/TelegramUI/Components/Utils/AnimatableProperty/Sources/AnimatableProperty.swift new file mode 100644 index 0000000000..8e9885e9b4 --- /dev/null +++ b/submodules/TelegramUI/Components/Utils/AnimatableProperty/Sources/AnimatableProperty.swift @@ -0,0 +1,123 @@ +import Foundation +import UIKit +import ComponentFlow +import Display + +private final class PropertyAnimation { + let from: T + let to: T + let animation: ComponentTransition.Animation + let startTimestamp: Double + private let interpolator: (Interpolatable, Interpolatable, CGFloat) -> Interpolatable + + init(fromValue: T, toValue: T, animation: ComponentTransition.Animation, startTimestamp: Double) { + self.from = fromValue + self.to = toValue + self.animation = animation + self.startTimestamp = startTimestamp + self.interpolator = T.interpolator() + } + + func valueAt(_ t: CGFloat) -> Interpolatable { + if t <= 0.0 { + return self.from + } else if t >= 1.0 { + return self.to + } else { + return self.interpolator(self.from, self.to, t) + } + } +} + +public final class AnimatableProperty { + public private(set) var presentationValue: T + public private(set) var value: T + private var animation: PropertyAnimation? + + public init(value: T) { + self.value = value + self.presentationValue = value + } + + public func update(value: T, transition: ComponentTransition = .immediate) { + let currentTimestamp = CACurrentMediaTime() + if case .none = transition.animation { + if let animation = self.animation, case let .curve(duration, curve) = animation.animation { + self.value = value + let elapsed = duration - (currentTimestamp - animation.startTimestamp) + if let presentationValue = self.presentationValue as? CGFloat, let newValue = value as? CGFloat, abs(presentationValue - newValue) > 0.56 { + self.animation = PropertyAnimation(fromValue: self.presentationValue, toValue: value, animation: .curve(duration: elapsed * 0.8, curve: curve), startTimestamp: currentTimestamp) + } else { + self.animation = PropertyAnimation(fromValue: self.presentationValue, toValue: value, animation: .curve(duration: elapsed, curve: curve), startTimestamp: currentTimestamp) + } + } else { + self.value = value + self.presentationValue = value + self.animation = nil + } + } else { + self.value = value + self.animation = PropertyAnimation(fromValue: self.presentationValue, toValue: value, animation: transition.animation, startTimestamp: currentTimestamp) + } + } + + public func tick(timestamp: Double) -> Bool { + guard let animation = self.animation, case let .curve(duration, curve) = animation.animation else { + return false + } + + let timeFromStart = timestamp - animation.startTimestamp + var t = max(0.0, timeFromStart / duration) + switch curve { + case .linear: + break + case .easeInOut: + t = listViewAnimationCurveEaseInOut(t) + case .spring: + t = lookupSpringValue(t) + case let .custom(x1, y1, x2, y2): + t = bezierPoint(CGFloat(x1), CGFloat(y1), CGFloat(x2), CGFloat(y2), t) + } + self.presentationValue = animation.valueAt(t) as! T + + if timeFromStart <= duration { + return true + } + self.animation = nil + return false + } +} + +private func lookupSpringValue(_ t: CGFloat) -> CGFloat { + let table: [(CGFloat, CGFloat)] = [ + (0.0, 0.0), + (0.0625, 0.1123005598783493), + (0.125, 0.31598418951034546), + (0.1875, 0.5103585720062256), + (0.25, 0.6650152802467346), + (0.3125, 0.777747631072998), + (0.375, 0.8557760119438171), + (0.4375, 0.9079672694206238), + (0.5, 0.942038357257843), + (0.5625, 0.9638798832893372), + (0.625, 0.9776856303215027), + (0.6875, 0.9863143563270569), + (0.75, 0.991658091545105), + (0.8125, 0.9949421286582947), + (0.875, 0.9969474077224731), + (0.9375, 0.9981651306152344), + (1.0, 1.0) + ] + + for i in 0 ..< table.count - 2 { + let lhs = table[i] + let rhs = table[i + 1] + + if t >= lhs.0 && t <= rhs.0 { + let fraction = (t - lhs.0) / (rhs.0 - lhs.0) + let value = lhs.1 + fraction * (rhs.1 - lhs.1) + return value + } + } + return 1.0 +}