Skip to content

Commit 817e189

Browse files
author
Isaac
committed
Video improvements
1 parent 2f9d5c4 commit 817e189

File tree

10 files changed

+240
-84
lines changed

10 files changed

+240
-84
lines changed

submodules/GalleryUI/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ swift_library(
5858
"//submodules/TelegramUI/Components/RasterizedCompositionComponent",
5959
"//submodules/TelegramUI/Components/BadgeComponent",
6060
"//submodules/TelegramUI/Components/AnimatedTextComponent",
61+
"//submodules/TelegramUI/Components/LottieComponent",
6162
"//submodules/Components/MultilineTextComponent",
63+
"//submodules/Components/BalancedTextComponent",
6264
"//submodules/Components/ComponentDisplayAdapters",
6365
"//submodules/ComponentFlow",
6466
],

submodules/GalleryUI/Sources/GalleryRateToastAnimationComponent.swift

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,27 @@ import ComponentFlow
55
import AppBundle
66

77
final class GalleryRateToastAnimationComponent: Component {
8-
init() {
8+
let speedFraction: CGFloat
9+
10+
init(speedFraction: CGFloat) {
11+
self.speedFraction = speedFraction
912
}
1013

1114
static func ==(lhs: GalleryRateToastAnimationComponent, rhs: GalleryRateToastAnimationComponent) -> Bool {
15+
if lhs.speedFraction != rhs.speedFraction {
16+
return false
17+
}
1218
return true
1319
}
1420

1521
final class View: UIView {
1622
private let itemViewContainer: UIView
1723
private var itemViews: [UIImageView] = []
1824

25+
private var link: SharedDisplayLinkDriver.Link?
26+
private var timeValue: CGFloat = 0.0
27+
private var speedFraction: CGFloat = 1.0
28+
1929
override init(frame: CGRect) {
2030
self.itemViewContainer = UIView()
2131

@@ -36,49 +46,60 @@ final class GalleryRateToastAnimationComponent: Component {
3646
fatalError("init(coder:) has not been implemented")
3747
}
3848

49+
deinit {
50+
self.link?.invalidate()
51+
}
52+
3953
private func setupAnimations() {
40-
let beginTime = self.layer.convertTime(CACurrentMediaTime(), from: nil)
41-
42-
for i in 0 ..< self.itemViews.count {
43-
if self.itemViews[i].layer.animation(forKey: "idle-opacity") != nil {
44-
continue
54+
if self.link == nil {
55+
var previousTimestamp = CACurrentMediaTime()
56+
self.link = SharedDisplayLinkDriver.shared.add { [weak self] _ in
57+
guard let self else {
58+
return
59+
}
60+
61+
let timestamp = CACurrentMediaTime()
62+
let deltaMultiplier = 1.0 * (1.0 - self.speedFraction) + 3.0 * self.speedFraction
63+
let deltaTime = (timestamp - previousTimestamp) * deltaMultiplier
64+
previousTimestamp = timestamp
65+
66+
self.timeValue += deltaTime
67+
68+
let duration: CGFloat = 1.2
69+
70+
for i in 0 ..< self.itemViews.count {
71+
var itemFraction = (self.timeValue + CGFloat(i) * 0.1).truncatingRemainder(dividingBy: duration) / duration
72+
73+
if itemFraction >= 0.5 {
74+
itemFraction = (1.0 - itemFraction) / 0.5
75+
} else {
76+
itemFraction = itemFraction / 0.5
77+
}
78+
79+
let itemAlpha = 0.6 * (1.0 - itemFraction) + 1.0 * itemFraction
80+
let itemScale = 0.9 * (1.0 - itemFraction) + 1.1 * itemFraction
81+
82+
self.itemViews[i].alpha = itemAlpha
83+
self.itemViews[i].transform = CGAffineTransformMakeScale(itemScale, itemScale)
84+
}
4585
}
46-
47-
let delay = Double(i) * 0.1
48-
49-
let animation = CABasicAnimation(keyPath: "opacity")
50-
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
51-
animation.beginTime = beginTime + delay
52-
animation.fromValue = 0.6 as NSNumber
53-
animation.toValue = 1.0 as NSNumber
54-
animation.repeatCount = Float.infinity
55-
animation.autoreverses = true
56-
animation.fillMode = .both
57-
animation.duration = 0.4
58-
self.itemViews[i].layer.add(animation, forKey: "idle-opacity")
59-
60-
let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
61-
scaleAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
62-
scaleAnimation.beginTime = beginTime + delay
63-
scaleAnimation.fromValue = 0.9 as NSNumber
64-
scaleAnimation.toValue = 1.1 as NSNumber
65-
scaleAnimation.repeatCount = Float.infinity
66-
scaleAnimation.autoreverses = true
67-
scaleAnimation.fillMode = .both
68-
scaleAnimation.duration = 0.4
69-
self.itemViews[i].layer.add(scaleAnimation, forKey: "idle-scale")
7086
}
7187
}
7288

7389
func update(component: GalleryRateToastAnimationComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
90+
self.speedFraction = component.speedFraction
91+
7492
let itemSize = self.itemViews[0].image?.size ?? CGSize(width: 10.0, height: 10.0)
7593
let itemSpacing: CGFloat = 1.0
7694

7795
let size = CGSize(width: itemSize.width * 2.0 + itemSpacing, height: 12.0)
7896

7997
for i in 0 ..< self.itemViews.count {
8098
let itemFrame = CGRect(origin: CGPoint(x: CGFloat(i) * (itemSize.width + itemSpacing), y: UIScreenPixel), size: itemSize)
81-
self.itemViews[i].frame = itemFrame
99+
self.itemViews[i].center = itemFrame.center
100+
self.itemViews[i].bounds = CGRect(origin: CGPoint(), size: itemFrame.size)
101+
102+
self.itemViews[i].layer.speed = Float(1.0 * (1.0 - component.speedFraction) + 2.0 * component.speedFraction)
82103
}
83104

84105
self.setupAnimations()

submodules/GalleryUI/Sources/GalleryRateToastComponent.swift

Lines changed: 120 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,26 @@ import UIKit
33
import Display
44
import ComponentFlow
55
import AppBundle
6-
import MultilineTextComponent
6+
import BalancedTextComponent
77
import AnimatedTextComponent
8+
import LottieComponent
89

910
final class GalleryRateToastComponent: Component {
1011
let rate: Double
12+
let displayTooltip: String?
1113

12-
init(rate: Double) {
14+
init(rate: Double, displayTooltip: String?) {
1315
self.rate = rate
16+
self.displayTooltip = displayTooltip
1417
}
1518

1619
static func ==(lhs: GalleryRateToastComponent, rhs: GalleryRateToastComponent) -> Bool {
1720
if lhs.rate != rhs.rate {
1821
return false
1922
}
23+
if lhs.displayTooltip != rhs.displayTooltip {
24+
return false
25+
}
2026
return true
2127
}
2228

@@ -25,6 +31,14 @@ final class GalleryRateToastComponent: Component {
2531
private let text = ComponentView<Empty>()
2632
private let arrows = ComponentView<Empty>()
2733

34+
private var tooltipText: ComponentView<Empty>?
35+
private var tooltipAnimation: ComponentView<Empty>?
36+
37+
private var tooltipIsHidden: Bool = false
38+
private var tooltipTimer: Foundation.Timer?
39+
40+
private weak var state: EmptyComponentState?
41+
2842
override init(frame: CGRect) {
2943
super.init(frame: frame)
3044
}
@@ -33,7 +47,13 @@ final class GalleryRateToastComponent: Component {
3347
fatalError("init(coder:) has not been implemented")
3448
}
3549

50+
deinit {
51+
self.tooltipTimer?.invalidate()
52+
}
53+
3654
func update(component: GalleryRateToastComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
55+
self.state = state
56+
3757
let insets = UIEdgeInsets(top: 5.0, left: 11.0, bottom: 5.0, right: 16.0)
3858
let spacing: CGFloat = 5.0
3959

@@ -55,17 +75,19 @@ final class GalleryRateToastComponent: Component {
5575
let textSize = self.text.update(
5676
transition: transition,
5777
component: AnyComponent(AnimatedTextComponent(
58-
font: Font.semibold(17.0),
78+
font: Font.with(size: 17.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]),
5979
color: .white,
6080
items: textItems
6181
)),
6282
environment: {},
6383
containerSize: CGSize(width: 100.0, height: 100.0)
6484
)
6585

86+
var speedFraction = (component.rate - 1.0) / (2.5 - 1.0)
87+
speedFraction = max(0.0, min(1.0, speedFraction))
6688
let arrowsSize = self.arrows.update(
6789
transition: transition,
68-
component: AnyComponent(GalleryRateToastAnimationComponent()),
90+
component: AnyComponent(GalleryRateToastAnimationComponent(speedFraction: speedFraction)),
6991
environment: {},
7092
containerSize: CGSize(width: 200.0, height: 100.0)
7193
)
@@ -82,15 +104,15 @@ final class GalleryRateToastComponent: Component {
82104
environment: {},
83105
containerSize: size
84106
)
85-
let backgroundFrame = CGRect(origin: CGPoint(), size: size)
107+
let backgroundFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - size.width) * 0.5), y: 0.0), size: size)
86108
if let backgroundView = self.background.view {
87109
if backgroundView.superview == nil {
88110
self.addSubview(backgroundView)
89111
}
90112
transition.setFrame(view: backgroundView, frame: backgroundFrame)
91113
}
92114

93-
let textFrame = CGRect(origin: CGPoint(x: insets.left, y: floorToScreenPixels((size.height - textSize.height) * 0.5)), size: textSize)
115+
let textFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + insets.left, y: backgroundFrame.minY + floorToScreenPixels((size.height - textSize.height) * 0.5)), size: textSize)
94116
if let textView = self.text.view {
95117
if textView.superview == nil {
96118
textView.layer.anchorPoint = CGPoint()
@@ -100,15 +122,105 @@ final class GalleryRateToastComponent: Component {
100122
textView.bounds = CGRect(origin: CGPoint(), size: textFrame.size)
101123
}
102124

103-
let arrowsFrame = CGRect(origin: CGPoint(x: textFrame.maxX + spacing, y: floorToScreenPixels((size.height - arrowsSize.height) * 0.5)), size: arrowsSize)
125+
let arrowsFrame = CGRect(origin: CGPoint(x: textFrame.maxX + spacing, y: backgroundFrame.minY + floorToScreenPixels((size.height - arrowsSize.height) * 0.5)), size: arrowsSize)
104126
if let arrowsView = self.arrows.view {
105127
if arrowsView.superview == nil {
106128
self.addSubview(arrowsView)
107129
}
108130
transition.setFrame(view: arrowsView, frame: arrowsFrame)
109131
}
110132

111-
return size
133+
if let displayTooltip = component.displayTooltip {
134+
var tooltipTransition = transition
135+
136+
let tooltipText: ComponentView<Empty>
137+
if let current = self.tooltipText {
138+
tooltipText = current
139+
} else {
140+
tooltipText = ComponentView()
141+
self.tooltipText = tooltipText
142+
tooltipTransition = tooltipTransition.withAnimation(.none)
143+
}
144+
145+
let tooltipAnimation: ComponentView<Empty>
146+
if let current = self.tooltipAnimation {
147+
tooltipAnimation = current
148+
} else {
149+
tooltipAnimation = ComponentView()
150+
self.tooltipAnimation = tooltipAnimation
151+
}
152+
153+
let tooltipTextSize = tooltipText.update(
154+
transition: .immediate,
155+
component: AnyComponent(BalancedTextComponent(
156+
text: .plain(NSAttributedString(string: displayTooltip, font: Font.regular(15.0), textColor: UIColor(white: 1.0, alpha: 0.8))),
157+
horizontalAlignment: .center,
158+
maximumNumberOfLines: 0
159+
)),
160+
environment: {},
161+
containerSize: CGSize(width: availableSize.width - 8.0 * 2.0, height: 1000.0)
162+
)
163+
let tooltipTextFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - tooltipTextSize.width) * 0.5), y: backgroundFrame.maxY + 10.0), size: tooltipTextSize)
164+
if let tooltipTextView = tooltipText.view {
165+
if tooltipTextView.superview == nil {
166+
self.addSubview(tooltipTextView)
167+
}
168+
tooltipTransition.setPosition(view: tooltipTextView, position: tooltipTextFrame.center)
169+
tooltipTextView.bounds = CGRect(origin: CGPoint(), size: tooltipTextFrame.size)
170+
171+
transition.setAlpha(view: tooltipTextView, alpha: self.tooltipIsHidden ? 0.0 : 1.0)
172+
}
173+
174+
let tooltipAnimationSize = tooltipAnimation.update(
175+
transition: .immediate,
176+
component: AnyComponent(LottieComponent(
177+
content: LottieComponent.AppBundleContent(name: "video_toast_speedup"),
178+
color: .white,
179+
startingPosition: .begin,
180+
loop: true
181+
)),
182+
environment: {},
183+
containerSize: CGSize(width: 60.0, height: 60.0)
184+
)
185+
let tooltipAnimationFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - tooltipAnimationSize.width) * 0.5), y: tooltipTextFrame.maxY + 10.0), size: tooltipAnimationSize)
186+
if let tooltipAnimationView = tooltipAnimation.view {
187+
if tooltipAnimationView.superview == nil {
188+
self.addSubview(tooltipAnimationView)
189+
}
190+
tooltipTransition.setFrame(view: tooltipAnimationView, frame: tooltipAnimationFrame)
191+
192+
transition.setAlpha(view: tooltipAnimationView, alpha: self.tooltipIsHidden ? 0.0 : 0.8)
193+
}
194+
} else {
195+
if let tooltipText = self.tooltipText {
196+
self.tooltipText = nil
197+
if let tooltipTextView = tooltipText.view {
198+
transition.setAlpha(view: tooltipTextView, alpha: 0.0, completion: { [weak tooltipTextView] _ in
199+
tooltipTextView?.removeFromSuperview()
200+
})
201+
}
202+
}
203+
if let tooltipAnimation = self.tooltipAnimation {
204+
self.tooltipAnimation = nil
205+
if let tooltipAnimationView = tooltipAnimation.view {
206+
transition.setAlpha(view: tooltipAnimationView, alpha: 0.0, completion: { [weak tooltipAnimationView] _ in
207+
tooltipAnimationView?.removeFromSuperview()
208+
})
209+
}
210+
}
211+
}
212+
213+
if self.tooltipTimer == nil {
214+
self.tooltipTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false, block: { [weak self] _ in
215+
guard let self else {
216+
return
217+
}
218+
self.tooltipIsHidden = true
219+
self.state?.updated(transition: .easeInOut(duration: 0.25), isLocal: true)
220+
})
221+
}
222+
223+
return CGSize(width: availableSize.width, height: size.height)
112224
}
113225
}
114226

submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,13 +1619,15 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
16191619
activeEdgeRateIndicatorTransition = .immediate
16201620
}
16211621

1622+
//TODO:localize
16221623
let activeEdgeRateIndicatorSize = activeEdgeRateIndicator.update(
16231624
transition: ComponentTransition(activeEdgeRateIndicatorTransition),
16241625
component: AnyComponent(GalleryRateToastComponent(
1625-
rate: activeEdgeRateState.currentRate
1626+
rate: activeEdgeRateState.currentRate,
1627+
displayTooltip: "Swipe sideways to adjust speed."
16261628
)),
16271629
environment: {},
1628-
containerSize: CGSize(width: 200.0, height: 100.0)
1630+
containerSize: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: 100.0)
16291631
)
16301632
let activeEdgeRateIndicatorFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - activeEdgeRateIndicatorSize.width) * 0.5), y: max(navigationBarHeight, layout.statusBarHeight ?? 0.0) + 8.0), size: activeEdgeRateIndicatorSize)
16311633
if let activeEdgeRateIndicatorView = activeEdgeRateIndicator.view {

submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode/Sources/ChatMessageDateAndStatusNode.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
362362
selectedStarsForeground: themeColors.reactionStarsActiveForeground.argb,
363363
extractedBackground: arguments.presentationData.theme.theme.contextMenu.backgroundColor.argb,
364364
extractedForeground: arguments.presentationData.theme.theme.contextMenu.primaryColor.argb,
365-
extractedSelectedForeground: arguments.presentationData.theme.theme.overallDarkAppearance ? themeColors.reactionActiveForeground.argb : arguments.presentationData.theme.theme.list.itemCheckColors.foregroundColor.argb,
365+
extractedSelectedForeground: arguments.presentationData.theme.theme.overallDarkAppearance ? themeColors.reactionActiveForeground.argb : arguments.presentationData.theme.theme.contextMenu.primaryColor.argb,
366366
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
367367
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
368368
)

0 commit comments

Comments
 (0)