Use lottie animation for text loading indicator

This commit is contained in:
Ali 2022-06-07 17:01:45 +04:00
parent f72ab6bd3d
commit 8888c68097
4 changed files with 88 additions and 3 deletions

View File

@ -13,6 +13,7 @@ swift_library(
"//submodules/ComponentFlow:ComponentFlow", "//submodules/ComponentFlow:ComponentFlow",
"//submodules/AppBundle:AppBundle", "//submodules/AppBundle:AppBundle",
"//submodules/Display:Display", "//submodules/Display:Display",
"//submodules/Components/LottieAnimationComponent:LottieAnimationComponent",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -3,6 +3,7 @@ import UIKit
import ComponentFlow import ComponentFlow
import AppBundle import AppBundle
import Display import Display
import LottieAnimationComponent
public final class AudioTranscriptionPendingIndicatorComponent: Component { public final class AudioTranscriptionPendingIndicatorComponent: Component {
public let color: UIColor public let color: UIColor
@ -98,3 +99,80 @@ public final class AudioTranscriptionPendingIndicatorComponent: Component {
return view.update(component: self, availableSize: availableSize, transition: transition) return view.update(component: self, availableSize: availableSize, transition: transition)
} }
} }
public final class AudioTranscriptionPendingLottieIndicatorComponent: Component {
public let color: UIColor
public let font: UIFont
public init(color: UIColor, font: UIFont) {
self.color = color
self.font = font
}
public static func ==(lhs: AudioTranscriptionPendingLottieIndicatorComponent, rhs: AudioTranscriptionPendingLottieIndicatorComponent) -> Bool {
if lhs.color != rhs.color {
return false
}
if lhs.font != rhs.font {
return false
}
return true
}
public final class View: UIView {
private let animationView: ComponentHostView<Empty>
override init(frame: CGRect) {
self.animationView = ComponentHostView<Empty>()
super.init(frame: frame)
self.addSubview(self.animationView)
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(component: AudioTranscriptionPendingLottieIndicatorComponent, availableSize: CGSize, transition: Transition) -> CGSize {
let originalSize = CGSize(width: 48.0, height: 66.0)
let animationSize = originalSize.aspectFitted(CGSize(width: 15.0, height: 100.0))
let _ = self.animationView.update(
transition: .immediate,
component: AnyComponent(LottieAnimationComponent(
animation: LottieAnimationComponent.AnimationItem(
name: "animated_text_dots",
colors: [
"Comp 1.Point 3.Group 1.Fill 1": component.color,
"Comp 1.Point 2.Group 1.Fill 1": component.color,
"Comp 1.Point 1.Group 1.Fill 1": component.color
],
mode: .animating(loop: true)
),
size: animationSize
)),
environment: {},
containerSize: animationSize
)
var stringSize = NSAttributedString(string: "...", font: component.font, textColor: .black).boundingRect(with: CGSize(width: 100.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil).size
stringSize.width = ceil(stringSize.width)
stringSize.height = ceil(stringSize.height)
let size = CGSize(width: min(availableSize.width, stringSize.width), height: min(availableSize.height, 10.0))
self.animationView.frame = CGRect(origin: CGPoint(x: -2.0, y: size.height - animationSize.height + 4.0 + UIScreenPixel), size: animationSize)
return size
}
}
public func makeView() -> View {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View File

@ -0,0 +1 @@
{"v":"5.8.1","fr":60,"ip":0,"op":60,"w":48,"h":66,"nm":"Comp 2","ddd":0,"assets":[{"id":"comp_0","nm":"Comp 1","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Point 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":12,"s":[118.6,256,0],"to":[-0.6,-119,0],"ti":[-1.438,-92.469,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.32,"y":0},"t":32,"s":[255.938,275.469,0],"to":[0,0,0],"ti":[0,0,0]},{"t":42,"s":[255.938,255.969,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-102.4,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-17.673,0],[0,-17.673],[17.673,0],[0,17.673]],"o":[[17.673,0],[0,17.673],[-17.673,0],[0,-17.673]],"v":[[-102.4,-32],[-70.4,0],[-102.4,32],[-134.4,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Point 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":0,"s":[256,256,0],"to":[1.75,-110,0],"ti":[-5.25,-93.219,0]},{"i":{"x":0.42,"y":1},"o":{"x":0.3,"y":0},"t":20,"s":[393.25,276.969,0],"to":[0,0,0],"ti":[0,0,0]},{"t":30,"s":[393.25,255.969,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-17.673,0],[0,-17.673],[17.673,0],[0,17.673]],"o":[[17.673,0],[0,17.673],[-17.673,0],[0,-17.673]],"v":[[0,-32],[32,0],[0,32],[-32,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Point 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[393.4,256,0],"to":[0,0,0],"ti":[0,0,0]},{"t":40,"s":[118.562,255.969,0]}],"ix":2,"l":2},"a":{"a":0,"k":[102.4,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-17.673,0],[0,-17.673],[17.673,0],[0,17.673]],"o":[[17.673,0],[0,17.673],[-17.673,0],[0,-17.673]],"v":[[102.4,-32],[134.4,0],[102.4,32],[70.4,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[24,48,0],"ix":2,"l":2},"a":{"a":0,"k":[256,256,0],"ix":1,"l":2},"s":{"a":0,"k":[10.8,10.8,100],"ix":6,"l":2}},"ao":0,"w":512,"h":512,"ip":0,"op":180,"st":0,"bm":0}],"markers":[]}

View File

@ -659,12 +659,12 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
case let .success(text, isPending): case let .success(text, isPending):
textString = NSAttributedString(string: text, font: textFont, textColor: messageTheme.primaryTextColor) textString = NSAttributedString(string: text, font: textFont, textColor: messageTheme.primaryTextColor)
/*#if DEBUG #if DEBUG
var isPending = isPending var isPending = isPending
if "".isEmpty { if "".isEmpty {
isPending = true isPending = true
} }
#endif*/ #endif
if isPending { if isPending {
let modifiedString = NSMutableAttributedString(attributedString: textString!) let modifiedString = NSMutableAttributedString(attributedString: textString!)
@ -1027,9 +1027,14 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
strongSelf.transcriptionPendingIndicator = transcriptionPendingIndicator strongSelf.transcriptionPendingIndicator = transcriptionPendingIndicator
strongSelf.textClippingNode.view.addSubview(transcriptionPendingIndicator) strongSelf.textClippingNode.view.addSubview(transcriptionPendingIndicator)
} }
let indicatorComponent: AnyComponent<Empty>
indicatorComponent = AnyComponent(AudioTranscriptionPendingLottieIndicatorComponent(color: messageTheme.primaryTextColor, font: textFont))
//indicatorComponent = AnyComponent(AudioTranscriptionPendingIndicatorComponent(color: messageTheme.primaryTextColor, font: textFont))
let indicatorSize = transcriptionPendingIndicator.update( let indicatorSize = transcriptionPendingIndicator.update(
transition: .immediate, transition: .immediate,
component: AnyComponent(AudioTranscriptionPendingIndicatorComponent(color: messageTheme.primaryTextColor, font: textFont)), component: indicatorComponent,
environment: {}, environment: {},
containerSize: CGSize(width: 100.0, height: 100.0) containerSize: CGSize(width: 100.0, height: 100.0)
) )