diff --git a/Projects/UserInterface/DesignSystem/Project.swift b/Projects/UserInterface/DesignSystem/Project.swift index ba7c8817..6ca7a560 100644 --- a/Projects/UserInterface/DesignSystem/Project.swift +++ b/Projects/UserInterface/DesignSystem/Project.swift @@ -22,5 +22,8 @@ let project = Project.module( .demo(module: .userInterface(.DesignSystem), dependencies: [ .userInterface(target: .DesignSystem) ]) + ], + resourceSynthesizers: .default + [ + .custom(name: "Lottie", parser: .json, extensions: ["json"]) ] ) diff --git a/Projects/UserInterface/DesignSystem/Resources/Lottie/DotoriLoading.json b/Projects/UserInterface/DesignSystem/Resources/Lottie/DotoriLoading.json new file mode 100644 index 00000000..ceb232fd --- /dev/null +++ b/Projects/UserInterface/DesignSystem/Resources/Lottie/DotoriLoading.json @@ -0,0 +1 @@ +{"v":"4.6.3","fr":25,"ip":0,"op":15,"w":200,"h":200,"nm":"Graph Load","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 3","ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":6,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":12,"s":[100],"e":[0]},{"t":15}]},"r":{"a":0,"k":0},"p":{"a":0,"k":[128,100,0]},"a":{"a":0,"k":[3.481,-1.019,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.963,14.963]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[0.7921569,0.8156863,0.8352941,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[3.481,-1.019],"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":15,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":3,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":6,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":12}]},"r":{"a":0,"k":0},"p":{"a":0,"k":[99.875,100,0]},"a":{"a":0,"k":[3.481,-1.019,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.963,14.963]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[0.7921569,0.8156863,0.8352941,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[3.481,-1.019],"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":15,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":3,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":6,"s":[100],"e":[0]},{"t":9}]},"r":{"a":0,"k":0},"p":{"a":0,"k":[71.75,100,0]},"a":{"a":0,"k":[3.481,-1.019,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.963,14.963]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[0.7921569,0.8156863,0.8352941,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[3.481,-1.019],"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":15,"st":0,"bm":0,"sr":1}]} \ No newline at end of file diff --git a/Tuist/ResourceSynthesizers/Lottie.stencil b/Tuist/ResourceSynthesizers/Lottie.stencil new file mode 100644 index 00000000..6247ee23 --- /dev/null +++ b/Tuist/ResourceSynthesizers/Lottie.stencil @@ -0,0 +1,56 @@ +// swiftformat:disable all +// swiftlint:disable all +{% if files %} +{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %} +{% set documentPrefix %}{{param.documentName|default:"Document"}}{% endset %} +import Foundation +#if canImport(Lottie) +import Lottie +// MARK: - Animations Assets +{{accessModifier}} extension AnimationAsset { + {% for file in files %} + static let {{file.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = Self(named: "{{file.name}}") + {% endfor %} +} +// MARK: - Animation Helpers +{{accessModifier}} extension AnimationAsset { + /// All the available animation. Can be used to preload them + static let allAnimations: [Self] = [ + {% for file in files %} + Self.{{file.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}, + {% endfor %} + ] +} +// MARK: - Structures +{{accessModifier}} struct AnimationAsset: Hashable { + {{accessModifier}} fileprivate(set) var name: String + {{accessModifier}} let animation: LottieAnimation? + {{accessModifier}} init(named name: String) { + self.name = name + if let url = Bundle.module.url(forResource: name, withExtension: "json") { + self.animation = LottieAnimation.filepath(url.path) + } else { + self.animation = nil + } + } + // MARK: Hashable Conformance + {{accessModifier}} static func == (lhs: Self, rhs: Self) -> Bool { + return lhs.name == rhs.name + } + {{accessModifier}} func hash(into hasher: inout Hasher) { + hasher.combine(self.name) + } +} +// MARK: - Preload Helpers +{{accessModifier}} extension AnimationAsset { + /// Preloads all the Lottie Animations to avoid performance issues when loading them + static func preload() -> Void { + for animationAsset in Self.allAnimations { + _ = animationAsset.animation + } + } +} +#endif +{% else %} +// No files found +{% endif %}