UI optimizations

This commit is contained in:
Ali 2023-02-07 23:23:06 +04:00
parent 5c71c08b6e
commit 5f3de7a40b
17 changed files with 158 additions and 74 deletions

View File

@ -5,7 +5,7 @@ import Lottie
import AppBundle import AppBundle
import Display import Display
public final class AnimationNode : ASDisplayNode { public final class AnimationNode: ASDisplayNode {
private let scale: CGFloat private let scale: CGFloat
public var speed: CGFloat = 1.0 { public var speed: CGFloat = 1.0 {
didSet { didSet {
@ -15,8 +15,6 @@ public final class AnimationNode : ASDisplayNode {
} }
} }
//private var colorCallbacks: [LOTColorValueCallback] = []
public var didPlay = false public var didPlay = false
public var completion: (() -> Void)? public var completion: (() -> Void)?
private var internalCompletion: (() -> Void)? private var internalCompletion: (() -> Void)?
@ -43,9 +41,6 @@ public final class AnimationNode : ASDisplayNode {
if let colors = colors { if let colors = colors {
for (key, value) in colors { for (key, value) in colors {
view.setValueProvider(ColorValueProvider(value.lottieColorValue), keypath: AnimationKeypath(keypath: "\(key).Color")) view.setValueProvider(ColorValueProvider(value.lottieColorValue), keypath: AnimationKeypath(keypath: "\(key).Color"))
/*let colorCallback = LOTColorValueCallback(color: value.cgColor)
self.colorCallbacks.append(colorCallback)
view.setValueDelegate(colorCallback, for: LOTKeypath(string: "\(key).Color"))*/
} }
if let value = colors["__allcolors__"] { if let value = colors["__allcolors__"] {
@ -77,9 +72,6 @@ public final class AnimationNode : ASDisplayNode {
if let colors = colors { if let colors = colors {
for (key, value) in colors { for (key, value) in colors {
view.setValueProvider(ColorValueProvider(value.lottieColorValue), keypath: AnimationKeypath(keypath: "\(key).Color")) view.setValueProvider(ColorValueProvider(value.lottieColorValue), keypath: AnimationKeypath(keypath: "\(key).Color"))
/*let colorCallback = LOTColorValueCallback(color: value.cgColor)
self.colorCallbacks.append(colorCallback)
view.setValueDelegate(colorCallback, for: LOTKeypath(string: "\(key).Color"))*/
} }
if let value = colors["__allcolors__"] { if let value = colors["__allcolors__"] {
@ -121,9 +113,6 @@ public final class AnimationNode : ASDisplayNode {
if let colors = colors { if let colors = colors {
for (key, value) in colors { for (key, value) in colors {
self.animationView()?.setValueProvider(ColorValueProvider(value.lottieColorValue), keypath: AnimationKeypath(keypath: "\(key).Color")) self.animationView()?.setValueProvider(ColorValueProvider(value.lottieColorValue), keypath: AnimationKeypath(keypath: "\(key).Color"))
/*let colorCallback = LOTColorValueCallback(color: value.cgColor)
self.colorCallbacks.append(colorCallback)
self.animationView()?.setValueDelegate(colorCallback, for: LOTKeypath(string: "\(key).Color"))*/
} }
} }
} }

View File

@ -75,8 +75,6 @@ func localizedCountryNamesAndCodes(strings: PresentationStrings) -> [((String, S
} }
} }
result.append(((englishCountryName, countryName), country.id, codes)) result.append(((englishCountryName, countryName), country.id, codes))
} else {
assertionFailure()
} }
} }
return result return result

View File

@ -6,6 +6,22 @@ public enum DeviceType {
} }
public enum DeviceMetrics: CaseIterable, Equatable { public enum DeviceMetrics: CaseIterable, Equatable {
public struct Performance {
public let isGraphicallyCapable: Bool
init() {
var length: Int = 4
var cpuCount: UInt32 = 0
sysctlbyname("hw.ncpu", &cpuCount, &length, nil, 0)
#if DEBUG
cpuCount = 2
#endif
self.isGraphicallyCapable = cpuCount >= 6
}
}
case iPhone4 case iPhone4
case iPhone5 case iPhone5
case iPhone6 case iPhone6
@ -33,6 +49,8 @@ public enum DeviceMetrics: CaseIterable, Equatable {
case iPadPro3rdGen case iPadPro3rdGen
case iPadMini6thGen case iPadMini6thGen
case unknown(screenSize: CGSize, statusBarHeight: CGFloat, onScreenNavigationHeight: CGFloat?) case unknown(screenSize: CGSize, statusBarHeight: CGFloat, onScreenNavigationHeight: CGFloat?)
public static let performance = Performance()
public static var allCases: [DeviceMetrics] { public static var allCases: [DeviceMetrics] {
return [ return [

View File

@ -290,7 +290,7 @@ private final class ChatListViewSpaceState {
postboxLog("existingEntityIds not unique: \(allEntityIds)") postboxLog("existingEntityIds not unique: \(allEntityIds)")
postboxLog("allIndices: \(allIndices)") postboxLog("allIndices: \(allIndices)")
assert(false) //assert(false)
//preconditionFailure() //preconditionFailure()
} }

View File

@ -327,8 +327,6 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe
let animationNode = AnimationNode(animation: animationName, colors: colors, scale: 1.0) let animationNode = AnimationNode(animation: animationName, colors: colors, scale: 1.0)
self.animationNode = animationNode self.animationNode = animationNode
animationNode.animationView()?.logHierarchyKeypaths()
let animationBackgroundNode = ASDisplayNode() let animationBackgroundNode = ASDisplayNode()
animationBackgroundNode.cornerRadius = 20.0 animationBackgroundNode.cornerRadius = 20.0
animationBackgroundNode.backgroundColor = backgroundColor animationBackgroundNode.backgroundColor = backgroundColor

View File

@ -1,5 +1,6 @@
import Foundation import Foundation
import UIKit import UIKit
import Display
import TelegramCore import TelegramCore
import TelegramUIPreferences import TelegramUIPreferences
import Postbox import Postbox
@ -28,6 +29,10 @@ public func selectReactionFillStaticColor(theme: PresentationTheme, wallpaper: T
} }
public func dateFillNeedsBlur(theme: PresentationTheme, wallpaper: TelegramWallpaper) -> Bool { public func dateFillNeedsBlur(theme: PresentationTheme, wallpaper: TelegramWallpaper) -> Bool {
if !DeviceMetrics.performance.isGraphicallyCapable {
return false
}
if case .builtin = wallpaper { if case .builtin = wallpaper {
return false return false
} else if case .color = wallpaper { } else if case .color = wallpaper {

View File

@ -353,6 +353,7 @@ swift_library(
"//submodules/TelegramUI/Components/ChatEntityKeyboardInputNode", "//submodules/TelegramUI/Components/ChatEntityKeyboardInputNode",
"//submodules/TelegramUI/Components/StorageUsageScreen", "//submodules/TelegramUI/Components/StorageUsageScreen",
"//submodules/TelegramUI/Components/AvatarEditorScreen", "//submodules/TelegramUI/Components/AvatarEditorScreen",
"//submodules/TelegramUI/Components/LottieComponent",
"//submodules/MediaPasteboardUI:MediaPasteboardUI", "//submodules/MediaPasteboardUI:MediaPasteboardUI",
"//submodules/DrawingUI:DrawingUI", "//submodules/DrawingUI:DrawingUI",
"//submodules/FeaturedStickersScreen:FeaturedStickersScreen", "//submodules/FeaturedStickersScreen:FeaturedStickersScreen",

View File

@ -39,10 +39,10 @@ private final class LottieDirectContent: LottieComponent.Content {
return true return true
} }
override func load(_ f: @escaping (Data) -> Void) -> Disposable { override func load(_ f: @escaping (Data, String?) -> Void) -> Disposable {
if let data = try? Data(contentsOf: URL(fileURLWithPath: self.path)) { if let data = try? Data(contentsOf: URL(fileURLWithPath: self.path)) {
let result = TGGUnzipData(data, 2 * 1024 * 1024) ?? data let result = TGGUnzipData(data, 2 * 1024 * 1024) ?? data
f(result) f(result, nil)
} }
return EmptyDisposable return EmptyDisposable

View File

@ -15,6 +15,7 @@ swift_library(
"//submodules/Components/HierarchyTrackingLayer", "//submodules/Components/HierarchyTrackingLayer",
"//submodules/rlottie:RLottieBinding", "//submodules/rlottie:RLottieBinding",
"//submodules/SSignalKit/SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit",
"//submodules/AppBundle",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -5,7 +5,7 @@ import ComponentFlow
import HierarchyTrackingLayer import HierarchyTrackingLayer
import RLottieBinding import RLottieBinding
import SwiftSignalKit import SwiftSignalKit
import Accelerate import AppBundle
public final class LottieComponent: Component { public final class LottieComponent: Component {
public typealias EnvironmentType = Empty public typealias EnvironmentType = Empty
@ -25,10 +25,36 @@ public final class LottieComponent: Component {
preconditionFailure() preconditionFailure()
} }
open func load(_ f: @escaping (Data) -> Void) -> Disposable { open func load(_ f: @escaping (Data, String?) -> Void) -> Disposable {
preconditionFailure() preconditionFailure()
} }
} }
public final class AppBundleContent: Content {
public let name: String
public init(name: String) {
self.name = name
}
override public func isEqual(to other: Content) -> Bool {
guard let other = other as? AppBundleContent else {
return false
}
if self.name != other.name {
return false
}
return true
}
override public func load(_ f: @escaping (Data, String?) -> Void) -> Disposable {
if let url = getAppBundle().url(forResource: self.name, withExtension: "json"), let data = try? Data(contentsOf: url) {
f(data, url.path)
}
return EmptyDisposable
}
}
public let content: Content public let content: Content
public let color: UIColor public let color: UIColor
@ -63,6 +89,9 @@ public final class LottieComponent: Component {
private var currentFrame: Int = 0 private var currentFrame: Int = 0
private var currentFrameStartTime: Double? private var currentFrameStartTime: Double?
private var hierarchyTrackingLayer: HierarchyTrackingLayer?
private var isVisible: Bool = false
private var displayLink: SharedDisplayLinkDriver.Link? private var displayLink: SharedDisplayLinkDriver.Link?
private var currentTemplateFrameImage: UIImage? private var currentTemplateFrameImage: UIImage?
@ -76,11 +105,30 @@ public final class LottieComponent: Component {
} }
override init(frame: CGRect) { override init(frame: CGRect) {
//self.hierarchyTrackingLayer = HierarchyTrackingLayer()
super.init(frame: frame) super.init(frame: frame)
//self.layer.addSublayer(self.hierarchyTrackingLayer) let hierarchyTrackingLayer = HierarchyTrackingLayer()
self.hierarchyTrackingLayer = hierarchyTrackingLayer
self.layer.addSublayer(hierarchyTrackingLayer)
hierarchyTrackingLayer.didEnterHierarchy = { [weak self] in
guard let self else {
return
}
if !self.isVisible {
self.isVisible = true
self.visibilityUpdated()
}
}
hierarchyTrackingLayer.didExitHierarchy = { [weak self] in
guard let self else {
return
}
if self.isVisible {
self.isVisible = false
self.visibilityUpdated()
}
}
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
@ -91,11 +139,22 @@ public final class LottieComponent: Component {
self.currentContentDisposable?.dispose() self.currentContentDisposable?.dispose()
} }
private func visibilityUpdated() {
if self.isVisible {
if self.scheduledPlayOnce {
self.playOnce()
}
}
}
public func playOnce(delay: Double = 0.0) { public func playOnce(delay: Double = 0.0) {
guard let _ = self.animationInstance else { guard let _ = self.animationInstance else {
self.scheduledPlayOnce = true self.scheduledPlayOnce = true
return return
} }
if !self.isVisible {
return
}
self.scheduledPlayOnce = false self.scheduledPlayOnce = false
@ -135,8 +194,8 @@ public final class LottieComponent: Component {
} }
} }
private func loadAnimation(data: Data) { private func loadAnimation(data: Data, cacheKey: String?) {
self.animationInstance = LottieInstance(data: data, fitzModifier: .none, colorReplacements: nil, cacheKey: "") self.animationInstance = LottieInstance(data: data, fitzModifier: .none, colorReplacements: nil, cacheKey: cacheKey ?? "")
if self.scheduledPlayOnce { if self.scheduledPlayOnce {
self.scheduledPlayOnce = false self.scheduledPlayOnce = false
self.playOnce() self.playOnce()
@ -184,12 +243,6 @@ public final class LottieComponent: Component {
return return
} }
var destinationBuffer = vImage_Buffer()
destinationBuffer.width = UInt(context.scaledSize.width)
destinationBuffer.height = UInt(context.scaledSize.height)
destinationBuffer.data = context.bytes
destinationBuffer.rowBytes = context.bytesPerRow
animationInstance.renderFrame(with: Int32(self.currentFrame % Int(animationInstance.frameCount)), into: context.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(currentDisplaySize.width), height: Int32(currentDisplaySize.height), bytesPerRow: Int32(context.bytesPerRow)) animationInstance.renderFrame(with: Int32(self.currentFrame % Int(animationInstance.frameCount)), into: context.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(currentDisplaySize.width), height: Int32(currentDisplaySize.height), bytesPerRow: Int32(context.bytesPerRow))
self.currentTemplateFrameImage = context.generateImage()?.withRenderingMode(.alwaysTemplate) self.currentTemplateFrameImage = context.generateImage()?.withRenderingMode(.alwaysTemplate)
self.image = self.currentTemplateFrameImage self.image = self.currentTemplateFrameImage
@ -216,12 +269,12 @@ public final class LottieComponent: Component {
if previousComponent?.content != component.content { if previousComponent?.content != component.content {
self.currentContentDisposable?.dispose() self.currentContentDisposable?.dispose()
let content = component.content let content = component.content
self.currentContentDisposable = component.content.load { [weak self, weak content] data in self.currentContentDisposable = component.content.load { [weak self, weak content] data, cacheKey in
Queue.mainQueue().async { Queue.mainQueue().async {
guard let self, self.component?.content == content else { guard let self, self.component?.content == content else {
return return
} }
self.loadAnimation(data: data) self.loadAnimation(data: data, cacheKey: cacheKey)
} }
} }
} else if redrawImage { } else if redrawImage {

View File

@ -30,7 +30,7 @@ public extension LottieComponent {
return true return true
} }
override public func load(_ f: @escaping (Data) -> Void) -> Disposable { override public func load(_ f: @escaping (Data, String?) -> Void) -> Disposable {
let fileId = self.fileId let fileId = self.fileId
let mediaBox = self.context.account.postbox.mediaBox let mediaBox = self.context.account.postbox.mediaBox
return (self.context.engine.stickers.resolveInlineStickers(fileIds: [fileId]) return (self.context.engine.stickers.resolveInlineStickers(fileIds: [fileId])
@ -60,7 +60,7 @@ public extension LottieComponent {
guard let data else { guard let data else {
return return
} }
f(data) f(data, nil)
}) })
} }
} }

View File

@ -491,7 +491,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if (strongSelf.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion { if (strongSelf.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion {
return return
} }
strongSelf.backgroundNode.animateEvent(transition: transition, extendAnimation: false) if DeviceMetrics.performance.isGraphicallyCapable {
strongSelf.backgroundNode.animateEvent(transition: transition, extendAnimation: false)
}
} }
getMessageTransitionNode = { [weak self] in getMessageTransitionNode = { [weak self] in
@ -2214,7 +2216,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if (self.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion { if (self.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion {
return return
} }
self.backgroundNode.animateEvent(transition: transition, extendAnimation: false) if DeviceMetrics.performance.isGraphicallyCapable {
self.backgroundNode.animateEvent(transition: transition, extendAnimation: false)
}
} }
//self.historyNode.didScrollWithOffset?(listBottomInset - previousListBottomInset, transition, nil) //self.historyNode.didScrollWithOffset?(listBottomInset - previousListBottomInset, transition, nil)
} }

View File

@ -184,10 +184,16 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode {
self.addSubnode(self.containerNode) self.addSubnode(self.containerNode)
self.containerNode.addSubnode(self.backgroundColorNode) self.containerNode.addSubnode(self.backgroundColorNode)
self.containerNode.addSubnode(self.effectNode)
if DeviceMetrics.performance.isGraphicallyCapable {
self.containerNode.addSubnode(self.effectNode)
}
self.addSubnode(self.borderNode) self.addSubnode(self.borderNode)
self.borderNode.addSubnode(self.borderEffectNode)
if DeviceMetrics.performance.isGraphicallyCapable {
self.borderNode.addSubnode(self.borderEffectNode)
}
} }
override func didLoad() { override func didLoad() {
@ -196,7 +202,9 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode {
self.containerNode.view.mask = self.maskNode.view self.containerNode.view.mask = self.maskNode.view
self.borderNode.view.mask = self.borderMaskNode.view self.borderNode.view.mask = self.borderMaskNode.view
self.backgroundNode?.updateIsLooping(true) if DeviceMetrics.performance.isGraphicallyCapable {
self.backgroundNode?.updateIsLooping(true)
}
} }
private var bottomInset: (Int, CGFloat)? private var bottomInset: (Int, CGFloat)?

View File

@ -12,6 +12,7 @@ import AudioBlob
import ChatPresentationInterfaceState import ChatPresentationInterfaceState
import ComponentFlow import ComponentFlow
import LottieAnimationComponent import LottieAnimationComponent
import LottieComponent
private let offsetThreshold: CGFloat = 10.0 private let offsetThreshold: CGFloat = 10.0
private let dismissOffsetThreshold: CGFloat = 70.0 private let dismissOffsetThreshold: CGFloat = 70.0
@ -289,11 +290,17 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
} }
} }
private lazy var micLock: (UIView & TGModernConversationInputMicButtonLock) = { private var micLockValue: (UIView & TGModernConversationInputMicButtonLock)?
let lockView = LockView(frame: CGRect(origin: CGPoint(), size: CGSize(width: 40.0, height: 60.0)), theme: self.theme, strings: self.strings) private var micLock: UIView & TGModernConversationInputMicButtonLock {
lockView.addTarget(self, action: #selector(handleStopTap), for: .touchUpInside) if let current = self.micLockValue {
return lockView return current
}() } else {
let lockView = LockView(frame: CGRect(origin: CGPoint(), size: CGSize(width: 40.0, height: 60.0)), theme: self.theme, strings: self.strings)
lockView.addTarget(self, action: #selector(handleStopTap), for: .touchUpInside)
self.micLockValue = lockView
return lockView
}
}
init(theme: PresentationTheme, strings: PresentationStrings, presentController: @escaping (ViewController) -> Void) { init(theme: PresentationTheme, strings: PresentationStrings, presentController: @escaping (ViewController) -> Void) {
self.theme = theme self.theme = theme
@ -363,37 +370,34 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
animationName = "anim_micToVideo" animationName = "anim_micToVideo"
} }
var animationMode: LottieAnimationComponent.AnimationItem.Mode = .still(position: .end) //var animationMode: LottieAnimationComponent.AnimationItem.Mode = .still(position: .end)
if previousMode != mode {
animationMode = .animating(loop: false)
}
let colorKeys = ["__allcolors__"] /*let colorKeys = ["__allcolors__"]
var colors: [String: UIColor] = [:] var colors: [String: UIColor] = [:]
for colorKey in colorKeys { for colorKey in colorKeys {
colors[colorKey] = self.theme.chat.inputPanel.panelControlColor.blitOver(self.theme.chat.inputPanel.inputBackgroundColor, alpha: 1.0) colors[colorKey] = self.theme.chat.inputPanel.panelControlColor.blitOver(self.theme.chat.inputPanel.inputBackgroundColor, alpha: 1.0)
} }*/
let _ = animationView.update( let _ = animationView.update(
transition: .immediate, transition: .immediate,
component: AnyComponent(LottieAnimationComponent( component: AnyComponent(LottieComponent(
animation: LottieAnimationComponent.AnimationItem( content: LottieComponent.AppBundleContent(name: animationName),
name: animationName, color: self.theme.chat.inputPanel.panelControlColor.blitOver(self.theme.chat.inputPanel.inputBackgroundColor, alpha: 1.0)
mode: animationMode
),
colors: colors,
size: animationFrame.size
)), )),
environment: {}, environment: {},
containerSize: animationFrame.size containerSize: animationFrame.size
) )
if let view = animationView.view { if let view = animationView.view as? LottieComponent.View {
view.isUserInteractionEnabled = false view.isUserInteractionEnabled = false
if view.superview == nil { if view.superview == nil {
self.insertSubview(view, at: 0) self.insertSubview(view, at: 0)
} }
view.frame = animationFrame view.frame = animationFrame
if previousMode != mode {
view.playOnce()
}
} }
} }
@ -404,7 +408,7 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
self.pallete = legacyInputMicPalette(from: theme) self.pallete = legacyInputMicPalette(from: theme)
self.micDecorationValue?.setColor(self.theme.chat.inputPanel.actionControlFillColor) self.micDecorationValue?.setColor(self.theme.chat.inputPanel.actionControlFillColor)
(self.micLock as? LockView)?.updateTheme(theme) (self.micLockValue as? LockView)?.updateTheme(theme)
} }
deinit { deinit {

View File

@ -33,6 +33,7 @@ import ChatControllerInteraction
import UndoUI import UndoUI
import PremiumUI import PremiumUI
import StickerPeekUI import StickerPeekUI
import LottieComponent
private let accessoryButtonFont = Font.medium(14.0) private let accessoryButtonFont = Font.medium(14.0)
private let counterFont = Font.with(size: 14.0, design: .regular, traits: [.monospacedNumbers]) private let counterFont = Font.with(size: 14.0, design: .regular, traits: [.monospacedNumbers])
@ -184,11 +185,11 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
if let animationView = self.animationView { if let animationView = self.animationView {
let width = AccessoryItemIconButtonNode.calculateWidth(item: item, image: image, text: "", strings: self.strings) let width = AccessoryItemIconButtonNode.calculateWidth(item: item, image: image, text: "", strings: self.strings)
let iconSize = CGSize(width: width, height: width) //let iconSize = CGSize(width: width, height: width)
let animationFrame = CGRect(origin: CGPoint(x: floor((size.width - width) / 2.0), y: floor((size.height - width) / 2.0) - bottomInset), size: CGSize(width: width, height: width)) let animationFrame = CGRect(origin: CGPoint(x: floor((size.width - width) / 2.0), y: floor((size.height - width) / 2.0) - bottomInset), size: CGSize(width: width, height: width))
let colorKeys: [String] = ["__allcolors__"] //let colorKeys: [String] = ["__allcolors__"]
let animationName: String let animationName: String
var animationMode: LottieAnimationComponent.AnimationItem.Mode = .still(position: .end) var animationMode: LottieAnimationComponent.AnimationItem.Mode = .still(position: .end)
@ -286,30 +287,30 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
} }
} }
var colors: [String: UIColor] = [:] /*var colors: [String: UIColor] = [:]
for colorKey in colorKeys { for colorKey in colorKeys {
colors[colorKey] = self.theme.chat.inputPanel.inputControlColor.blitOver(self.theme.chat.inputPanel.inputBackgroundColor, alpha: 1.0) colors[colorKey] = self.theme.chat.inputPanel.inputControlColor.blitOver(self.theme.chat.inputPanel.inputBackgroundColor, alpha: 1.0)
} }*/
let animationSize = animationView.update( let animationSize = animationView.update(
transition: .immediate, transition: .immediate,
component: AnyComponent(LottieAnimationComponent( component: AnyComponent(LottieComponent(
animation: LottieAnimationComponent.AnimationItem( content: LottieComponent.AppBundleContent(name: animationName),
name: animationName, color: self.theme.chat.inputPanel.inputControlColor.blitOver(self.theme.chat.inputPanel.inputBackgroundColor, alpha: 1.0)
mode: animationMode
),
colors: colors,
size: iconSize
)), )),
environment: {}, environment: {},
containerSize: animationFrame.size containerSize: animationFrame.size
) )
if let view = animationView.view { if let view = animationView.view as? LottieComponent.View {
view.isUserInteractionEnabled = false view.isUserInteractionEnabled = false
if view.superview == nil { if view.superview == nil {
self.view.addSubview(view) self.view.addSubview(view)
} }
view.frame = CGRect(origin: CGPoint(x: animationFrame.minX + floor((animationFrame.width - animationSize.width) / 2.0), y: animationFrame.minY + floor((animationFrame.height - animationSize.height) / 2.0)), size: animationSize) view.frame = CGRect(origin: CGPoint(x: animationFrame.minX + floor((animationFrame.width - animationSize.width) / 2.0), y: animationFrame.minY + floor((animationFrame.height - animationSize.height) / 2.0)), size: animationSize)
if case .animating = animationMode {
view.playOnce()
}
} }
} }
} }

View File

@ -43,7 +43,7 @@
} }
} }
_animation = rlottie::Animation::loadFromData(std::string(reinterpret_cast<const char *>(data.bytes), data.length), std::string([cacheKey UTF8String]), "", false, colorsVector, modifier); _animation = rlottie::Animation::loadFromData(std::string(reinterpret_cast<const char *>(data.bytes), data.length), std::string([cacheKey UTF8String]), "", cacheKey.length != 0, colorsVector, modifier);
if (_animation == nullptr) { if (_animation == nullptr) {
return nil; return nil;
} }

View File

@ -22,4 +22,8 @@
#define LOTTIE_IMAGE_MODULE_DISABLED #define LOTTIE_IMAGE_MODULE_DISABLED
#endif #endif
#ifndef LOTTIE_CACHE_SUPPORT
#define LOTTIE_CACHE_SUPPORT
#endif
#endif // CONFIG_H #endif // CONFIG_H