├── Brewfile
├── LottieViewer
├── Assets.xcassets
│ ├── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── icon_16x16.png
│ │ ├── icon_32x32.png
│ │ ├── icon_128x128.png
│ │ ├── icon_16x16@2x.png
│ │ ├── icon_256x256.png
│ │ ├── icon_32x32@2x.png
│ │ ├── icon_512x512.png
│ │ ├── icon_128x128@2x.png
│ │ ├── icon_256x256@2x.png
│ │ ├── icon_512x512@2x.png
│ │ └── Contents.json
│ ├── DocumentIcon.iconset
│ │ ├── icon_16x16.png
│ │ ├── icon_32x32.png
│ │ ├── icon_128x128.png
│ │ ├── icon_16x16@2x.png
│ │ ├── icon_256x256.png
│ │ ├── icon_32x32@2x.png
│ │ ├── icon_512x512.png
│ │ ├── icon_128x128@2x.png
│ │ ├── icon_256x256@2x.png
│ │ └── icon_512x512@2x.png
│ └── AccentColor.colorset
│ │ └── Contents.json
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
├── LottieViewer.entitlements
├── EnvironmentValues+Entries.swift
├── Model
│ ├── Package.swift
│ ├── AppStorageKey.swift
│ ├── LottieLibrary.swift
│ ├── AnimationFile.swift
│ ├── AnimationFileDocument.swift
│ └── LottieAnimationInfo.swift
├── Views
│ ├── SettingsView.swift
│ ├── AcknowledgementsView.swift
│ ├── DocumentView.swift
│ ├── AboutView.swift
│ ├── AnimationConfigurationView.swift
│ ├── InfoView.swift
│ └── AnimationView.swift
├── Scenes
│ ├── AcknowledgementsScene.swift
│ ├── Scene+Compatible.swift
│ └── AboutScene.swift
├── AppInitialization.swift
├── LottieViewerApp.swift
├── Info.plist
├── Localizable.xcstrings
└── Generated
│ └── ResolvedPackages.swift
├── LottieViewer.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── matej.jirasek.xcuserdatad
│ │ │ └── IDEFindNavigatorScopes.plist
│ └── xcshareddata
│ │ └── swiftpm
│ │ └── Package.resolved
├── xcuserdata
│ └── matej.jirasek.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
├── xcshareddata
│ └── xcschemes
│ │ ├── Thumbnail.xcscheme
│ │ ├── Preview.xcscheme
│ │ └── LottieViewer.xcscheme
└── project.pbxproj
├── Preview
├── Preview.entitlements
├── Info.plist
└── PreviewViewController.swift
├── Thumbnail
├── Thumbnail.entitlements
├── Info.plist
└── ThumbnailProvider.swift
├── LottieViewerCore
├── Sources
│ └── LottieViewerCore
│ │ ├── SupportedFileExtension.swift
│ │ ├── LottiePreviewError.swift
│ │ ├── Constant.swift
│ │ └── UTType+Extension.swift
├── Package.swift
└── .swiftpm
│ └── xcode
│ ├── xcuserdata
│ └── matej.jirasek.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
│ └── xcshareddata
│ └── xcschemes
│ └── LottieViewerCore.xcscheme
├── LottieViewerTests
└── LottieViewerTests.swift
├── LottieViewerUITests
├── LottieViewerUITestsLaunchTests.swift
└── LottieViewerUITests.swift
├── README.md
├── Scripts
└── generate-package-metadata.sh
└── LICENSE
/Brewfile:
--------------------------------------------------------------------------------
1 | brew "jq"
2 |
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/LottieViewer/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_16x16.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_32x32.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_128x128.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_16x16@2x.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_256x256.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_32x32@2x.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_512x512.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_128x128@2x.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_256x256@2x.png
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/LottieViewerMac/HEAD/LottieViewer/Assets.xcassets/DocumentIcon.iconset/icon_512x512@2x.png
--------------------------------------------------------------------------------
/LottieViewer.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Preview/Preview.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Thumbnail/Thumbnail.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LottieViewer/LottieViewer.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LottieViewer/EnvironmentValues+Entries.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Entries.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 16.02.2025.
6 | //
7 |
8 | import SwiftUI
9 |
10 | extension EnvironmentValues {
11 | @Entry var parseTime: TimeInterval?
12 | }
13 |
--------------------------------------------------------------------------------
/LottieViewer.xcodeproj/project.xcworkspace/xcuserdata/matej.jirasek.xcuserdatad/IDEFindNavigatorScopes.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LottieViewer/Model/Package.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Package.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 16.02.2025.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Represents Swift package metadata.
11 | struct Package {
12 | let location: URL
13 | let version: String
14 | let license: String
15 | }
16 |
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "platform" : "universal",
6 | "reference" : "systemMintColor"
7 | },
8 | "idiom" : "universal"
9 | }
10 | ],
11 | "info" : {
12 | "author" : "xcode",
13 | "version" : 1
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/LottieViewerCore/Sources/LottieViewerCore/SupportedFileExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SupportedFileExtension.swift
3 | // LottieViewerCore
4 | //
5 | // Created by Matěj Kašpar Jirásek on 07.01.2025.
6 | //
7 |
8 | public enum SupportedFileExtension: String {
9 | case lottie = "json"
10 | case dotLottie = "lottie"
11 | case rive = "riv"
12 | }
13 |
--------------------------------------------------------------------------------
/LottieViewerCore/Sources/LottieViewerCore/LottiePreviewError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LottiePreviewError.swift
3 | // LottieViewerCore
4 | //
5 | // Created by Matěj Kašpar Jirásek on 07.01.2025.
6 | //
7 |
8 | public enum LottiePreviewError: Error {
9 | /// Animation not decoded.
10 | case notDecoded
11 | /// Unknown file format.
12 | case unknownFileFormat
13 | }
14 |
--------------------------------------------------------------------------------
/LottieViewer/Views/SettingsView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct SettingsView: View {
4 | @ShowInfoAppStorage private var showInfoByDefault
5 |
6 | var body: some View {
7 | Form {
8 | Toggle("Show Info Panel by default", isOn: $showInfoByDefault)
9 | .padding()
10 | }
11 | }
12 | }
13 |
14 | #Preview {
15 | SettingsView()
16 | }
17 |
--------------------------------------------------------------------------------
/LottieViewer/Scenes/AcknowledgementsScene.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct AcknowledgementsScene: Scene {
4 | var body: some Scene {
5 | Window("Acknowledgements", id: WindowID.acknowledgements.rawValue) {
6 | AcknowledgementsView()
7 | }
8 | .defaultSize(width: 600, height: 400)
9 | .defaultPosition(.center)
10 | .compatibleDisabledRestorationBehavior()
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/LottieViewerTests/LottieViewerTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LottieViewerTests.swift
3 | // LottieViewerTests
4 | //
5 | // Created by Matěj Kašpar Jirásek on 03.01.2025.
6 | //
7 |
8 | import Testing
9 | @testable import LottieViewer
10 |
11 | struct LottieViewerTests {
12 |
13 | @Test func example() async throws {
14 | // Write your test here and use APIs like `#expect(...)` to check expected conditions.
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/LottieViewerCore/Sources/LottieViewerCore/Constant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constant.swift
3 | // LottieViewerCore
4 | //
5 | // Created by Matěj Kašpar Jirásek on 12.01.2025.
6 | //
7 |
8 | import Foundation
9 |
10 | public enum Constant {
11 | public static let githubUrl = URL(string: "https://github.com/mkj-is/LottieViewerMac")!
12 | public static let lottieBundleIdentifier = "io.airbnb.lottie"
13 | public static let loggingCategory = "LottieLogger"
14 | }
15 |
--------------------------------------------------------------------------------
/LottieViewer/Scenes/Scene+Compatible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Scene+CompatibleRestorationBehavior.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 23.02.2025.
6 | //
7 |
8 | import SwiftUI
9 |
10 | extension Scene {
11 | func compatibleDisabledRestorationBehavior() -> some Scene {
12 | if #available(macOS 15.0, *) {
13 | return self.restorationBehavior(.disabled)
14 | } else {
15 | return self
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/LottieViewerCore/Sources/LottieViewerCore/UTType+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UTType+Extension.swift
3 | // LottieViewerCore
4 | //
5 | // Created by Matěj Kašpar Jirásek on 07.01.2025.
6 | //
7 |
8 | import UniformTypeIdentifiers
9 |
10 | public extension UTType {
11 | static let lottie: UTType = .json
12 | static let dotLottie = UTType(importedAs: "io.dotlottie.lottie", conformingTo: .zip)
13 | static let rive = UTType(importedAs: "app.rive.rive-file", conformingTo: .data)
14 | }
15 |
--------------------------------------------------------------------------------
/LottieViewer/Scenes/AboutScene.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AboutScene.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 15.01.2025.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct AboutScene: Scene {
11 | var body: some Scene {
12 | Window("About Lottie Viewer", id: WindowID.about.rawValue) {
13 | AboutView()
14 | }
15 | .windowResizability(.contentSize)
16 | .defaultPosition(.center)
17 | .windowStyle(.hiddenTitleBar)
18 | .compatibleDisabledRestorationBehavior()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/LottieViewerCore/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 6.0
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "LottieViewerCore",
8 | platforms: [.macOS(.v14)],
9 | products: [
10 | .library(
11 | name: "LottieViewerCore",
12 | targets: ["LottieViewerCore"]
13 | ),
14 | ],
15 | targets: [
16 | .target(
17 | name: "LottieViewerCore"
18 | ),
19 | ]
20 | )
21 |
--------------------------------------------------------------------------------
/LottieViewer/Model/AppStorageKey.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppStorageKey.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 19.01.2025.
6 | //
7 |
8 |
9 | import SwiftUI
10 |
11 | @propertyWrapper
12 | struct ShowInfoAppStorage: DynamicProperty {
13 | @AppStorage("settings.show-info-by-default") private var showInfoByDefault = true
14 |
15 | var wrappedValue: Bool {
16 | get { showInfoByDefault }
17 | nonmutating set { showInfoByDefault = newValue }
18 | }
19 |
20 | var projectedValue: Binding {
21 | $showInfoByDefault
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/LottieViewerCore/.swiftpm/xcode/xcuserdata/matej.jirasek.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | LottieViewerCore.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 3
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | LottieViewerCore
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Thumbnail/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSExtension
6 |
7 | NSExtensionAttributes
8 |
9 | QLSupportedContentTypes
10 |
11 | io.dotlottie.lottie
12 | io.airbnb.lottie
13 |
14 | QLThumbnailMinimumDimension
15 | 0
16 |
17 | NSExtensionPointIdentifier
18 | com.apple.quicklook.thumbnail
19 | NSExtensionPrincipalClass
20 | $(PRODUCT_MODULE_NAME).ThumbnailProvider
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/LottieViewer/AppInitialization.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppInitialization.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 10.01.2025.
6 | //
7 |
8 | @preconcurrency import Lottie
9 | import LottieViewerCore
10 | import OSLog
11 |
12 | struct AppInitialization {
13 | func setup() {
14 | setupLottieLogging()
15 | }
16 |
17 | private func setupLottieLogging() {
18 | let logger = Logger(subsystem: Constant.lottieBundleIdentifier, category: Constant.loggingCategory)
19 | LottieLogger.shared = LottieLogger(warn: { message, _, _ in
20 | let message = message()
21 | logger.warning("\(message)")
22 | }, info: { message in
23 | let message = message()
24 | logger.info("\(message)")
25 | })
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Preview/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSExtension
6 |
7 | NSExtensionAttributes
8 |
9 | QLIsDataBasedPreview
10 |
11 | QLSupportedContentTypes
12 |
13 | io.dotlottie.lottie
14 | io.airbnb.lottie
15 |
16 | QLSupportsSearchableItems
17 |
18 |
19 | NSExtensionPointIdentifier
20 | com.apple.quicklook.preview
21 | NSExtensionPrincipalClass
22 | $(PRODUCT_MODULE_NAME).PreviewViewController
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/LottieViewer/Model/LottieLibrary.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LottieLibrary.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 15.02.2025.
6 | //
7 |
8 | import SwiftUI
9 |
10 | enum LottieLibrary: String, CaseIterable, Identifiable {
11 |
12 | /// Original AirBnb Lottie library.
13 | case lottie = "lottie-ios"
14 | /// Alternative LottieFiles DotLottie library.
15 | case dotLottie = "dotlottie-ios"
16 |
17 | var id: String {
18 | rawValue
19 | }
20 |
21 | private var name: String {
22 | switch self {
23 | case .lottie:
24 | return "Lottie"
25 | case .dotLottie:
26 | return "DotLottie"
27 | }
28 | }
29 |
30 | var description: String {
31 | if let package {
32 | return name + " " + package.version
33 | }
34 | return name
35 | }
36 |
37 | var package: Package? {
38 | ResolvedPackages.dictionary[rawValue]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/LottieViewer/Model/AnimationFile.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationModel.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 23.02.2025.
6 | //
7 |
8 | import LottieViewerCore
9 | @preconcurrency import Lottie
10 | @preconcurrency import RiveRuntime
11 |
12 | protocol AnimationFile: Sendable {
13 | var identifiers: [String] { get }
14 | var data: Data { get }
15 | }
16 |
17 | struct LottieAnimationFile: AnimationFile {
18 | let animation: LottieAnimation
19 | let data: Data
20 | let identifiers = [Constant.lottieBundleIdentifier]
21 | }
22 |
23 | struct DotLottieAnimationFile: AnimationFile {
24 | let file: DotLottieFile
25 | let data: Data
26 |
27 | var identifiers: [String] {
28 | file.animations.map(\.configuration.id)
29 | }
30 | }
31 |
32 | struct RiveAnimationFile: AnimationFile {
33 | let file: RiveFile
34 | let data: Data
35 |
36 | var identifiers: [String] {
37 | file.artboardNames()
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LottieViewerUITests/LottieViewerUITestsLaunchTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LottieViewerUITestsLaunchTests.swift
3 | // LottieViewerUITests
4 | //
5 | // Created by Matěj Kašpar Jirásek on 03.01.2025.
6 | //
7 |
8 | import XCTest
9 |
10 | final class LottieViewerUITestsLaunchTests: XCTestCase {
11 |
12 | override class var runsForEachTargetApplicationUIConfiguration: Bool {
13 | true
14 | }
15 |
16 | override func setUpWithError() throws {
17 | continueAfterFailure = false
18 | }
19 |
20 | @MainActor
21 | func testLaunch() throws {
22 | let app = XCUIApplication()
23 | app.launch()
24 |
25 | // Insert steps here to perform after app launch but before taking a screenshot,
26 | // such as logging into a test account or navigating somewhere in the app
27 |
28 | let attachment = XCTAttachment(screenshot: app.screenshot())
29 | attachment.name = "Launch Screen"
30 | attachment.lifetime = .keepAlways
31 | add(attachment)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/LottieViewer/LottieViewerApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LottieViewerApp.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 03.01.2025.
6 | //
7 |
8 | import SwiftUI
9 |
10 | enum WindowID: String {
11 | case about
12 | case acknowledgements
13 | case settings
14 | }
15 |
16 | @main
17 | struct LottieViewerApp: App {
18 | @Environment(\.openWindow) private var openWindow
19 |
20 | init() {
21 | AppInitialization().setup()
22 | }
23 |
24 | var body: some Scene {
25 | DocumentGroup(viewing: AnimationFileDocument.self) { file in
26 | DocumentView(document: file.$document)
27 | }
28 | .commands {
29 | CommandGroup(replacing: .appInfo) {
30 | Button("About Lottie Viewer") {
31 | openWindow(id: WindowID.about.rawValue)
32 | }
33 | }
34 | }
35 |
36 | Settings {
37 | SettingsView()
38 | }
39 |
40 | AboutScene()
41 | AcknowledgementsScene()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/LottieViewer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "originHash" : "f637a188faeff8d3088a08a84dce4a966f52ef4fb7957727835b2dbb9c2215eb",
3 | "pins" : [
4 | {
5 | "identity" : "dotlottie-ios",
6 | "kind" : "remoteSourceControl",
7 | "location" : "https://github.com/LottieFiles/dotlottie-ios",
8 | "state" : {
9 | "revision" : "4213e7298eb94b81ce08c226302759c34ce59366",
10 | "version" : "0.11.1"
11 | }
12 | },
13 | {
14 | "identity" : "lottie-ios",
15 | "kind" : "remoteSourceControl",
16 | "location" : "https://github.com/airbnb/lottie-ios.git",
17 | "state" : {
18 | "revision" : "a004050748dc197c56256a14dca49a035d74726c",
19 | "version" : "4.5.2"
20 | }
21 | },
22 | {
23 | "identity" : "rive-ios",
24 | "kind" : "remoteSourceControl",
25 | "location" : "https://github.com/rive-app/rive-ios",
26 | "state" : {
27 | "revision" : "db6704efa4621c14133ffa1b015550f16a7db7bb",
28 | "version" : "6.12.1"
29 | }
30 | }
31 | ],
32 | "version" : 3
33 | }
34 |
--------------------------------------------------------------------------------
/LottieViewer/Views/AcknowledgementsView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct AcknowledgementsView: View {
4 | var body: some View {
5 | ScrollView {
6 | ForEach(sortedPackages, id: \.key) { element in
7 | Link(element.key, destination: element.value.location)
8 | .underline()
9 | .foregroundColor(.accent)
10 | .font(.largeTitle)
11 | .padding()
12 | Text(element.value.license)
13 | .font(.system(.body, design: .monospaced))
14 | .padding(.bottom)
15 | .frame(maxWidth: .infinity)
16 | }
17 | }
18 | .frame(minWidth: 700)
19 | .textSelection(.enabled)
20 | }
21 |
22 | private var sortedPackages: [(key: String, value: Package)] {
23 | Array(ResolvedPackages.dictionary)
24 | .sorted { left, right in
25 | left.key.localizedCaseInsensitiveCompare(right.key) == .orderedAscending
26 | }
27 | }
28 | }
29 |
30 | #Preview {
31 | AcknowledgementsView()
32 | }
33 |
--------------------------------------------------------------------------------
/LottieViewer/Views/DocumentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DocumentView.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 03.01.2025.
6 | //
7 |
8 | import SwiftUI
9 | import Lottie
10 |
11 | struct DocumentView: View {
12 | @Binding var document: AnimationFileDocument
13 |
14 | @State private var selection: String?
15 |
16 | var body: some View {
17 | switch identifiers.count {
18 | case 2...:
19 | NavigationSplitView {
20 | List(identifiers, id: \.self, selection: $selection) { identifier in
21 | Text(identifier)
22 | }
23 | } detail: {
24 | AnimationView(animationFile: document.animationFile, id: selection)
25 | .environment(\.parseTime, document.parseTime)
26 | }
27 | case 1:
28 | AnimationView(animationFile: document.animationFile, id: selection)
29 | .environment(\.parseTime, document.parseTime)
30 | default:
31 | Text("No animations included in this file.")
32 | .frame(maxWidth: .infinity, maxHeight: .infinity)
33 | }
34 | }
35 |
36 | private var identifiers: [String] {
37 | document.animationFile.identifiers
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LottieViewer.xcodeproj/xcuserdata/matej.jirasek.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | LottieViewer.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 | Preview.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 1
16 |
17 | Thumbnail.xcscheme_^#shared#^_
18 |
19 | orderHint
20 | 2
21 |
22 |
23 | SuppressBuildableAutocreation
24 |
25 | 154478EB2D281E1F00DB7205
26 |
27 | primary
28 |
29 |
30 | 154478FF2D281E2100DB7205
31 |
32 | primary
33 |
34 |
35 | 154479092D281E2100DB7205
36 |
37 | primary
38 |
39 |
40 | 15447A162D2C698700DB7205
41 |
42 | primary
43 |
44 |
45 | 15447A592D2D617D00DB7205
46 |
47 | primary
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # LottieViewer for Mac
4 |
5 | LottieViewer is a macOS application that allows you to view and play Lottie and DotLottie animation files.
6 |
7 | ## Features
8 |
9 | - View Lottie Lottie JSON and DotLottie animations.
10 | - Preview animations using QuickLook.
11 | - Preview using both [original library from AirBnb](https://github.com/airbnb/lottie-ios)
12 | and alternative [DotLottie library from LottieFiles](https://github.com/LottieFiles/dotlottie-ios).
13 | - Display detailed information about the animation.
14 | - Document based native Swift app.
15 | - No login required, no tracking.
16 |
17 | ## Installation
18 |
19 | 1. Download the latest release from the [Releases](https://github.com/mkj-is/LottieViewerMac/releases) page.
20 | 2. Unzip the file and run the application.
21 |
22 | ## Requirements
23 |
24 | - macOS 14+
25 | - Xcode 15+
26 |
27 | ## Building
28 |
29 | 1. Clone the repository.
30 | 2. Install dev dependencies using `brew bundle` command.
31 | 3. Open project in Xcode.
32 | 3. Run the project.
33 |
34 | ## Contributing
35 |
36 | All contributions are welcome.
37 |
38 | Project was created by [Matěj Kašpar Jirásek](https://github.com/mkj-is).
39 |
40 | Project is licensed under [Apache 2.0 license](LICENSE).
41 |
--------------------------------------------------------------------------------
/Preview/PreviewViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PreviewViewController.swift
3 | // Preview
4 | //
5 | // Created by Matěj Kašpar Jirásek on 06.01.2025.
6 | //
7 |
8 | import Cocoa
9 | import Quartz
10 | import Lottie
11 | import LottieViewerCore
12 |
13 | final class PreviewViewController: NSViewController, QLPreviewingController {
14 |
15 | private var animationView: LottieAnimationView!
16 |
17 | override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
18 | let view = LottieAnimationView()
19 | self.animationView = view
20 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
21 | self.view = view
22 | }
23 |
24 | required init?(coder: NSCoder) {
25 | let lottieAnimationView = LottieAnimationView()
26 | self.animationView = lottieAnimationView
27 | super.init(coder: coder)
28 | self.view = lottieAnimationView
29 | }
30 |
31 | func preparePreviewOfFile(at url: URL) async throws {
32 | if url.pathExtension == SupportedFileExtension.dotLottie.rawValue {
33 | let file = try await DotLottieFile.loadedFrom(url: url)
34 | animationView.loadAnimation(from: file)
35 | } else if url.pathExtension == SupportedFileExtension.lottie.rawValue {
36 | animationView.animation = await LottieAnimation.loadedFrom(url: url)
37 | }
38 | animationView.contentMode = .scaleAspectFit
39 | animationView.loopMode = .loop
40 | animationView.play()
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/LottieViewerUITests/LottieViewerUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LottieViewerUITests.swift
3 | // LottieViewerUITests
4 | //
5 | // Created by Matěj Kašpar Jirásek on 03.01.2025.
6 | //
7 |
8 | import XCTest
9 |
10 | final class LottieViewerUITests: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
19 | }
20 |
21 | override func tearDownWithError() throws {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | @MainActor
26 | func testExample() throws {
27 | // UI tests must launch the application that they test.
28 | let app = XCUIApplication()
29 | app.launch()
30 |
31 | // Use XCTAssert and related functions to verify your tests produce the correct results.
32 | }
33 |
34 | @MainActor
35 | func testLaunchPerformance() throws {
36 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
37 | // This measures how long it takes to launch your application.
38 | measure(metrics: [XCTApplicationLaunchMetric()]) {
39 | XCUIApplication().launch()
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/LottieViewer/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_16x16.png",
5 | "idiom" : "mac",
6 | "scale" : "1x",
7 | "size" : "16x16"
8 | },
9 | {
10 | "filename" : "icon_16x16@2x.png",
11 | "idiom" : "mac",
12 | "scale" : "2x",
13 | "size" : "16x16"
14 | },
15 | {
16 | "filename" : "icon_32x32.png",
17 | "idiom" : "mac",
18 | "scale" : "1x",
19 | "size" : "32x32"
20 | },
21 | {
22 | "filename" : "icon_32x32@2x.png",
23 | "idiom" : "mac",
24 | "scale" : "2x",
25 | "size" : "32x32"
26 | },
27 | {
28 | "filename" : "icon_128x128.png",
29 | "idiom" : "mac",
30 | "scale" : "1x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "filename" : "icon_128x128@2x.png",
35 | "idiom" : "mac",
36 | "scale" : "2x",
37 | "size" : "128x128"
38 | },
39 | {
40 | "filename" : "icon_256x256.png",
41 | "idiom" : "mac",
42 | "scale" : "1x",
43 | "size" : "256x256"
44 | },
45 | {
46 | "filename" : "icon_256x256@2x.png",
47 | "idiom" : "mac",
48 | "scale" : "2x",
49 | "size" : "256x256"
50 | },
51 | {
52 | "filename" : "icon_512x512.png",
53 | "idiom" : "mac",
54 | "scale" : "1x",
55 | "size" : "512x512"
56 | },
57 | {
58 | "filename" : "icon_512x512@2x.png",
59 | "idiom" : "mac",
60 | "scale" : "2x",
61 | "size" : "512x512"
62 | }
63 | ],
64 | "info" : {
65 | "author" : "xcode",
66 | "version" : 1
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Scripts/generate-package-metadata.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ $# -lt 2 ]; then
4 | echo "Error: BUILD_DIR or BUILT_PRODUCTS_DIR directory not specified"
5 | echo "Usage: $0 "
6 | exit 1
7 | fi
8 |
9 | BUILD_DIR="$1"
10 | BUILT_PRODUCTS_DIR="$2"
11 |
12 | # Path during archive
13 | ARCHIVE_SPM_DIR="${BUILT_PRODUCTS_DIR}/SwiftPackageProducts"
14 |
15 | # Path during build
16 | BUILD_SPM_DIR="${BUILD_DIR%/Build/*}/SourcePackages/checkouts"
17 |
18 |
19 | if [ -d "$ARCHIVE_SPM_DIR" ]; then
20 | TARGET_SPM_DIR="$ARCHIVE_SPM_DIR"
21 | else
22 | TARGET_SPM_DIR="$BUILD_SPM_DIR"
23 | fi
24 |
25 | JSON_FILE="LottieViewer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved"
26 |
27 | # Output Swift file
28 | SWIFT_FILE="LottieViewer/Generated/ResolvedPackages.swift"
29 |
30 | # Generate the Swift constants file
31 | cat < "$SWIFT_FILE"
32 | //
33 | // ResolvedPackages.swift
34 | // LottieViewer
35 | //
36 | // Generated automatically - DO NOT EDIT
37 | //
38 |
39 | import Foundation
40 |
41 | enum ResolvedPackages {
42 | static let dictionary: [String: Package] = [
43 | EOF
44 |
45 | # Extract and iterate over the pins array
46 | jq -c '.pins[]' "$JSON_FILE" | while read -r pin; do
47 | IDENTITY=$(echo "$pin" | jq -r '.identity')
48 | LOCATION=$(echo "$pin" | jq -r '.location')
49 | VERSION=$(echo "$pin" | jq -r '.state.version')
50 |
51 | # Construct the license path based on the identity
52 | LICENSE_PATH="${TARGET_SPM_DIR}/${IDENTITY}/LICENSE"
53 | LICENSE=$(sed ':a;N;$!ba;s/\n/\\n/g' "$LICENSE_PATH")
54 |
55 | cat <> "$SWIFT_FILE"
56 | "$IDENTITY": Package(
57 | location: URL(string: "$LOCATION")!,
58 | version: "$VERSION",
59 | license: """
60 | $LICENSE
61 | """
62 | ),
63 | EOF
64 | done
65 |
66 | # Close dictionary and struct
67 | cat <> "$SWIFT_FILE"
68 | ]
69 | }
70 | EOF
71 |
--------------------------------------------------------------------------------
/LottieViewer/Views/AboutView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import LottieViewerCore
3 |
4 | struct AboutView: View {
5 | @Environment(\.openWindow) private var openWindow
6 | @Environment(\.openURL) private var openURL
7 |
8 | var body: some View {
9 | VStack(alignment: .center) {
10 | Image(nsImage: NSApp.applicationIconImage)
11 | .resizable()
12 | .frame(width: 64, height: 64)
13 |
14 | Text("Lottie Viewer for Mac")
15 | .font(.title)
16 |
17 | Text("Made by [Matěj Kašpar Jirásek](https://iosdev.space/@mkj) in Brno, Czechia")
18 | .font(.subheadline.bold())
19 | .textCase(.uppercase)
20 | .foregroundStyle(.secondary)
21 |
22 | Button("Source on GitHub") {
23 | openURL(Constant.githubUrl)
24 | }
25 | .buttonStyle(.link)
26 |
27 | if let longVersionString {
28 | Text("Version \(longVersionString)")
29 | .font(.subheadline)
30 | }
31 |
32 | ForEach(LottieLibrary.allCases) { library in
33 | Text(library.description)
34 | .font(.subheadline)
35 | }
36 | if let rive = ResolvedPackages.dictionary["rive-ios"] {
37 | Text("Rive \(rive.version)")
38 | .font(.subheadline)
39 | }
40 |
41 | Button("Acknowledgements") {
42 | openWindow(id: WindowID.acknowledgements.rawValue)
43 | }
44 | .padding(.top)
45 | }
46 | .padding()
47 | .frame(minWidth: 330, minHeight: 250)
48 | .textSelection(.enabled)
49 | }
50 |
51 | private var longVersionString: String? {
52 | let bundleInfo = Bundle.main.infoDictionary
53 | guard let shortVersionString = bundleInfo?["CFBundleShortVersionString"] as? String,
54 | let bundleVersion = bundleInfo?["CFBundleVersion"] as? String
55 | else {
56 | return nil
57 | }
58 | return "\(shortVersionString) (\(bundleVersion))"
59 |
60 |
61 | }
62 | }
63 |
64 | #Preview {
65 | AboutView()
66 | }
67 |
--------------------------------------------------------------------------------
/Thumbnail/ThumbnailProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThumbnailProvider.swift
3 | // Thumbnail
4 | //
5 | // Created by Matěj Kašpar Jirásek on 07.01.2025.
6 | //
7 |
8 | import QuickLookThumbnailing
9 | import Lottie
10 | import LottieViewerCore
11 | import OSLog
12 |
13 | final class ThumbnailProvider: QLThumbnailProvider {
14 |
15 | override func provideThumbnail(for request: QLFileThumbnailRequest, _ handler: @escaping (QLThumbnailReply?, Error?) -> Void) {
16 | Task.detached {
17 | do {
18 | let animation = try await self.loadAnimation(url: request.fileURL)
19 | let reply = QLThumbnailReply(contextSize: request.maximumSize) { context in
20 | let view = self.makeAnimationView(animation: animation, size: request.maximumSize)
21 | view.layer?.render(in: context)
22 | return true
23 | }
24 | handler(reply, nil)
25 | } catch {
26 | handler(nil, error)
27 | }
28 | }
29 | }
30 |
31 | private func makeAnimationView(animation: LottieAnimation, size: CGSize) -> LottieAnimationView {
32 | let animationView = LottieAnimationView(animation: animation)
33 | animationView.frame = CGRect(origin: .zero, size: size)
34 | animationView.contentMode = .scaleAspectFit
35 | animationView.currentFrame = 0
36 | return animationView
37 | }
38 |
39 | private func loadAnimation(url: URL) async throws -> LottieAnimation {
40 | if url.pathExtension == SupportedFileExtension.dotLottie.rawValue {
41 | let animations = try await DotLottieFile.loadedFrom(url: url).animations
42 | guard let firstAnimation = animations.first else {
43 | throw LottiePreviewError.noAnimations
44 | }
45 | return firstAnimation.animation
46 | } else if url.pathExtension == SupportedFileExtension.lottie.rawValue {
47 | let animation = await LottieAnimation.loadedFrom(url: url)
48 | guard let animation else {
49 | throw LottiePreviewError.noAnimations
50 | }
51 | return animation
52 | }
53 | throw LottiePreviewError.unknownFileFormat
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/LottieViewer/Model/AnimationFileDocument.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationFileDocument.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 03.01.2025.
6 | //
7 |
8 | import SwiftUI
9 | import UniformTypeIdentifiers
10 | @preconcurrency import Lottie
11 | import LottieViewerCore
12 | @preconcurrency import RiveRuntime
13 |
14 | struct AnimationFileDocument: FileDocument {
15 |
16 | enum FileWrapperError: Error {
17 | case writeNotSupported
18 | case noFilename
19 | case unknownContentType
20 | }
21 |
22 | let animationFile: AnimationFile
23 | let parseTime: TimeInterval
24 |
25 | static let readableContentTypes: [UTType] = [.lottie, .dotLottie, .rive]
26 |
27 | init(configuration: ReadConfiguration) throws {
28 | guard let data = configuration.file.regularFileContents else {
29 | throw CocoaError(.fileReadCorruptFile)
30 | }
31 |
32 | let parsingTimeStart: Date = .now
33 |
34 | if configuration.contentType == .lottie {
35 | let animation = try LottieAnimation.from(data: data)
36 | animationFile = LottieAnimationFile(animation: animation, data: data)
37 | } else if configuration.contentType == .dotLottie {
38 | let file = try AnimationFileDocument.loadDotLottie(configuration: configuration, data: data)
39 | animationFile = DotLottieAnimationFile(file: file, data: data)
40 | } else if configuration.contentType == .rive {
41 | let file = try RiveFile(data: data, loadCdn: false)
42 | animationFile = RiveAnimationFile(file: file, data: data)
43 | } else {
44 | throw FileWrapperError.unknownContentType
45 | }
46 |
47 | parseTime = Date.now.timeIntervalSince(parsingTimeStart)
48 | }
49 |
50 | private static func loadDotLottie(configuration: ReadConfiguration, data: Data) throws -> DotLottieFile {
51 | guard let filename = configuration.file.filename else {
52 | throw FileWrapperError.noFilename
53 | }
54 | return try DotLottieFile.SynchronouslyBlockingCurrentThread.loadedFrom(data: data, filename: filename).get()
55 | }
56 |
57 | func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
58 | throw FileWrapperError.writeNotSupported
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/LottieViewerCore/.swiftpm/xcode/xcshareddata/xcschemes/LottieViewerCore.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
10 |
16 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/LottieViewer/Views/AnimationConfigurationView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationConfigurationView.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 04.01.2025.
6 | //
7 |
8 | import SwiftUI
9 | import Lottie
10 |
11 | struct AnimationConfigurationViewState {
12 | var loopMode: LottieLoopMode = .loop
13 | /// Indicates step in slider, exponent of 2. Not actual speed.
14 | var speedExponent = 0.0
15 | var backgroundColor: Color = Color(nsColor: NSColor.windowBackgroundColor)
16 | var library: LottieLibrary = .lottie
17 |
18 | var speed: Double {
19 | pow(2.0, speedExponent)
20 | }
21 | }
22 |
23 | struct AnimationConfigurationView: View {
24 | let isLottie: Bool
25 |
26 | @Binding var state: AnimationConfigurationViewState
27 |
28 | @Environment(\.openURL) private var openURL
29 |
30 | var body: some View {
31 | VStack(alignment: .leading) {
32 | Picker(selection: $state.loopMode, label: Text("Loop mode")) {
33 | Text("Loop").tag(LottieLoopMode.loop)
34 | Text("Auto reverse").tag(LottieLoopMode.autoReverse)
35 | Text("Play once").tag(LottieLoopMode.playOnce)
36 | }
37 |
38 | if isLottie {
39 | Slider(value: $state.speedExponent, in: -2.0...3.0, step: 1.0) {
40 | Text("Playback speed")
41 | }
42 | minimumValueLabel: { Text("¼×") }
43 | maximumValueLabel: { Text("8×") }
44 | }
45 |
46 | ColorPicker("Background color", selection: $state.backgroundColor)
47 |
48 | if isLottie {
49 | HStack {
50 | Picker("Library", selection: $state.library) {
51 | ForEach(LottieLibrary.allCases) { library in
52 | Text(library.description).tag(library)
53 | }
54 | }
55 | Button(action: openLibraryURL) {
56 | Image(systemName: "arrowshape.forward.circle")
57 | .foregroundStyle(Color.accentColor)
58 | }
59 | .help("Open repository in browser")
60 | .buttonStyle(.plain)
61 | }
62 | }
63 | }
64 | }
65 |
66 | private func openLibraryURL() {
67 | guard let package = state.library.package else {
68 | return
69 | }
70 | openURL(package.location)
71 | }
72 | }
73 |
74 | #Preview {
75 | AnimationConfigurationView(isLottie: true, state: .constant(AnimationConfigurationViewState()))
76 | .frame(maxWidth: 300)
77 | .padding()
78 | }
79 |
--------------------------------------------------------------------------------
/LottieViewer/Model/LottieAnimationInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LottieAnimationInfo.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 04.01.2025.
6 | //
7 |
8 | import Lottie
9 | import Foundation
10 |
11 | struct LottieAnimationInfo {
12 | let startFrame, endFrame: AnimationFrameTime
13 | let frameRate: Double
14 | let markerCount: Int
15 |
16 | var version: String?
17 | var type: Lottie.CoordinateSpace?
18 | var width, height: Double?
19 | var layerCount: Int = 0
20 | var glyphCount: Int = 0
21 |
22 | var byteCount: Int?
23 |
24 | init(animation: LottieAnimation, data: Data) {
25 | self.startFrame = animation.startFrame
26 | self.endFrame = animation.endFrame
27 | self.frameRate = animation.framerate
28 | self.markerCount = animation.markerNames.count
29 |
30 | self.byteCount = data.count
31 |
32 | // Another possibility was to fork Lottie and make these properties public.
33 | let mirror = Mirror(reflecting: animation)
34 | for child in mirror.children {
35 | switch child.label {
36 | case "version":
37 | self.version = child.value as? String
38 | case "type":
39 | self.type = child.value as? Lottie.CoordinateSpace
40 | case "width":
41 | self.width = child.value as? Double
42 | case "height":
43 | self.height = child.value as? Double
44 | case "layers":
45 | self.layerCount = (child.value as? [Any])?.count ?? 0
46 | case "glyphs":
47 | self.glyphCount = (child.value as? [Any])?.count ?? 0
48 | default:
49 | break
50 | }
51 | }
52 | }
53 |
54 | /// For use in previews.
55 | init(
56 | startFrame: AnimationFrameTime, endFrame: AnimationFrameTime, frameRate: Double,
57 | markerCount: Int, version: String?, type: CoordinateSpace?,
58 | width: Double?, height: Double?, byteCount: Int?
59 | ) {
60 | self.startFrame = startFrame
61 | self.endFrame = endFrame
62 | self.frameRate = frameRate
63 | self.markerCount = markerCount
64 | self.version = version
65 | self.type = type
66 | self.width = width
67 | self.height = height
68 | self.byteCount = byteCount
69 | }
70 |
71 | var duration: Measurement {
72 | let duration = (endFrame - startFrame) / frameRate
73 | return Measurement(value: duration, unit: .seconds)
74 | }
75 |
76 | var byteMeasurement: Measurement? {
77 | guard let byteCount else {
78 | return nil
79 | }
80 | return Measurement(value: Double(byteCount), unit: UnitInformationStorage.bytes)
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/LottieViewer.xcodeproj/xcshareddata/xcschemes/Thumbnail.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
11 |
17 |
23 |
24 |
25 |
31 |
37 |
38 |
39 |
40 |
41 |
47 |
48 |
60 |
61 |
67 |
68 |
69 |
70 |
78 |
80 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/LottieViewer.xcodeproj/xcshareddata/xcschemes/Preview.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
11 |
17 |
23 |
24 |
25 |
31 |
37 |
38 |
39 |
40 |
41 |
47 |
48 |
60 |
62 |
68 |
69 |
70 |
71 |
79 |
81 |
87 |
88 |
89 |
90 |
92 |
93 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/LottieViewer.xcodeproj/xcshareddata/xcschemes/LottieViewer.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
10 |
16 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
36 |
42 |
43 |
44 |
47 |
53 |
54 |
55 |
56 |
57 |
67 |
69 |
75 |
76 |
77 |
78 |
84 |
86 |
92 |
93 |
94 |
95 |
97 |
98 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/LottieViewer/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDocumentTypes
6 |
7 |
8 | CFBundleTypeIconSystemGenerated
9 | 1
10 | CFBundleTypeName
11 | Lottie
12 | CFBundleTypeRole
13 | Viewer
14 | LSHandlerRank
15 | Default
16 | LSItemContentTypes
17 |
18 | public.json
19 |
20 | NSUbiquitousDocumentUserActivityType
21 | public.json
22 |
23 |
24 | CFBundleTypeIconSystemGenerated
25 | 1
26 | CFBundleTypeName
27 | DotLottie
28 | CFBundleTypeRole
29 | Viewer
30 | LSHandlerRank
31 | Default
32 | LSItemContentTypes
33 |
34 | io.dotlottie.lottie
35 |
36 | NSUbiquitousDocumentUserActivityType
37 | io.dotlottie.lottie
38 |
39 |
40 | CFBundleTypeIconSystemGenerated
41 | 1
42 | CFBundleTypeName
43 | Rive File
44 | CFBundleTypeRole
45 | Viewer
46 | LSHandlerRank
47 | Default
48 | LSItemContentTypes
49 |
50 | app.rive.rive-file
51 |
52 | NSUbiquitousDocumentUserActivityType
53 | app.rive.rive-file
54 |
55 |
56 | UTImportedTypeDeclarations
57 |
58 |
59 | UTTypeConformsTo
60 |
61 | public.zip-archive
62 |
63 | UTTypeDescription
64 | DotLottie
65 | UTTypeIcons
66 |
67 | UTTypeIconBadgeName
68 | DocumentIcon
69 | UTTypeIconText
70 | DotLottie
71 |
72 | UTTypeIdentifier
73 | io.dotlottie.lottie
74 | UTTypeTagSpecification
75 |
76 | public.filename-extension
77 |
78 | lottie
79 |
80 | public.mime-type
81 |
82 | application/zip
83 |
84 |
85 |
86 |
87 | UTTypeConformsTo
88 |
89 | public.text
90 |
91 | UTTypeDescription
92 | Lottie
93 | UTTypeIcons
94 |
95 | UTTypeIconBadgeName
96 | DocumentIcon
97 | UTTypeIconText
98 | Lottie
99 |
100 | UTTypeIdentifier
101 | public.json
102 | UTTypeTagSpecification
103 |
104 | public.filename-extension
105 |
106 | json
107 |
108 | public.mime-type
109 |
110 | application/json
111 |
112 |
113 |
114 |
115 | UTTypeConformsTo
116 |
117 | public.data
118 |
119 | UTTypeDescription
120 | Rive File
121 | UTTypeIconFile
122 |
123 | UTTypeIcons
124 |
125 | UTTypeIconBackgroundName
126 |
127 | UTTypeIconBadgeName
128 | DocumentIcon
129 | UTTypeIconText
130 | Rive
131 |
132 | UTTypeIdentifier
133 | app.rive.rive-file
134 | UTTypeTagSpecification
135 |
136 | public.filename-extension
137 |
138 | riv
139 |
140 | public.mime-type
141 |
142 | application/vnd.rive.editor
143 |
144 |
145 |
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/LottieViewer/Views/InfoView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InfoView.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 05.01.2025.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct InfoView: View {
11 | let info: LottieAnimationInfo
12 |
13 | @Environment(\.parseTime) private var parseTime
14 |
15 | var body: some View {
16 | Grid(alignment: .leading) {
17 | GridRow {
18 | Text("Info")
19 | .font(.title)
20 | .gridCellColumns(2)
21 | }
22 | if let width = info.width, let height = info.height {
23 | let width = Int(width)
24 | let height = Int(height)
25 | GridRow {
26 | Text("Resolution:")
27 | .font(.headline)
28 |
29 | let wideLabel = Text("\(width)×\(height) points", comment: "Wide unit – Points")
30 | ViewThatFits(in: .horizontal) {
31 | wideLabel
32 | Text("\(width)×\(height) pts", comment: "Abbreviated unit – Points")
33 | Text("\(width)×\(height) p", comment: "Narrow unit – Points")
34 | }
35 | .accessibilityLabel(wideLabel)
36 | }
37 | }
38 | GridRow {
39 | Text("Frame rate:")
40 | .font(.headline)
41 | measurementThatFits(unit: UnitFrequency.self) { width in
42 | Text(Measurement(value: info.frameRate, unit: UnitFrequency.framesPerSecond), format: .measurement(width: width))
43 | }
44 | }
45 | GridRow {
46 | Text("Duration:")
47 | .font(.headline)
48 | measurementThatFits(unit: UnitDuration.self) { width in
49 | Text(info.duration, format: .measurement(width: width, numberFormatStyle: .number.precision(.fractionLength(2))))
50 | }
51 | }
52 | GridRow {
53 | ViewThatFits(in: .horizontal) {
54 | Text("Start frame:")
55 | Text("Start:")
56 | }
57 | .font(.headline)
58 |
59 | Text(info.startFrame, format: .number)
60 | }
61 | GridRow {
62 | ViewThatFits(in: .horizontal) {
63 | Text("End frame:")
64 | Text("End:")
65 | }
66 | .font(.headline)
67 |
68 | Text(info.endFrame, format: .number)
69 | }
70 | GridRow {
71 | ViewThatFits(in: .horizontal) {
72 | Text("Root layer count:")
73 | Text("Layer count:")
74 | Text("Layers:")
75 | }
76 | .font(.headline)
77 |
78 | Text(info.layerCount, format: .number)
79 | }
80 | GridRow {
81 | ViewThatFits(in: .horizontal) {
82 | Text("Glyph count:")
83 | Text("Glyphs:")
84 | }
85 | .font(.headline)
86 |
87 | Text(info.layerCount, format: .number)
88 | }
89 | if let byteMeasurement = info.byteMeasurement {
90 | GridRow {
91 | Text("Size:")
92 | .font(.headline)
93 | Text(byteMeasurement, format: .byteCount(style: .file))
94 | }
95 | }
96 | if let version = info.version {
97 | GridRow {
98 | ViewThatFits(in: .horizontal) {
99 | Text("File version:")
100 | Text("Version:")
101 | }
102 | .font(.headline)
103 |
104 | Text(version)
105 | }
106 | }
107 | if let parseTime {
108 | GridRow {
109 | Text("Parse time:")
110 | .font(.headline)
111 |
112 | measurementThatFits(duration: Measurement(value: parseTime, unit: .seconds))
113 | }
114 | }
115 | }
116 | .textSelection(.enabled)
117 | }
118 |
119 | private func measurementThatFits(unit: U.Type = U.self, text: (Measurement.FormatStyle.UnitWidth) -> Text) -> some View {
120 | ViewThatFits(in: .horizontal) {
121 | text(.wide)
122 | text(.abbreviated)
123 | text(.narrow)
124 | }
125 | .accessibilityLabel(text(.wide))
126 | }
127 |
128 | private func measurementThatFits(duration: Measurement) -> some View {
129 | measurementThatFits(unit: UnitDuration.self) { width in
130 | Text(duration, format: .measurement(width: width, numberFormatStyle: .number.precision(.fractionLength(2))))
131 | }
132 | }
133 | }
134 |
135 | #Preview("Info") {
136 | InfoView(
137 | info: LottieAnimationInfo(startFrame: 0, endFrame: 100, frameRate: 30, markerCount: 10, version: "1.0.0", type: .type2d, width: 100, height: 100, byteCount: 30 * 1000)
138 | )
139 | }
140 |
--------------------------------------------------------------------------------
/LottieViewer/Views/AnimationView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationView.swift
3 | // LottieViewer
4 | //
5 | // Created by Matěj Kašpar Jirásek on 04.01.2025.
6 | //
7 |
8 | import Lottie
9 | import DotLottie
10 | import SwiftUI
11 | import RiveRuntime
12 |
13 | private struct AnimationViewState {
14 | var showInfo: Bool?
15 | var playing: Bool = true
16 | var configuration = AnimationConfigurationViewState()
17 |
18 | var dotLottieParseTime: TimeInterval?
19 | var dotLottieAnimation: DotLottieAnimation?
20 | }
21 |
22 | struct AnimationView: View {
23 | let animationFile: AnimationFile
24 | let id: String?
25 |
26 | @State private var state = AnimationViewState()
27 |
28 | @Environment(\.documentConfiguration) private var documentConfiguration
29 |
30 | @ShowInfoAppStorage private var showInfoByDefault
31 |
32 | var body: some View {
33 | HSplitView {
34 | animationRenderingView
35 | .frame(maxWidth: .infinity, maxHeight: .infinity)
36 | .background(state.configuration.backgroundColor)
37 |
38 | if showInfo {
39 | VStack(alignment: .leading) {
40 | AnimationConfigurationView(isLottie: isLottie, state: $state.configuration)
41 | Spacer()
42 | if let lottieAnimation {
43 | InfoView(info: LottieAnimationInfo(animation: lottieAnimation, data: animationFile.data))
44 | .transformEnvironment(\.parseTime) { parseTime in
45 | if state.configuration.library == .dotLottie {
46 | parseTime = state.dotLottieParseTime
47 | } else {
48 | parseTime = parseTime
49 | }
50 | }
51 | }
52 | }
53 | .padding()
54 | .frame(minWidth: 150, maxWidth: 300, maxHeight: .infinity)
55 | }
56 | }
57 | .toolbar {
58 | ToolbarItem(placement: .principal) {
59 | Button(
60 | state.playing ? "Pause" : "Play",
61 | systemImage: state.playing ? "pause.fill" : "play.fill",
62 | action: togglePlaying
63 | )
64 | .keyboardShortcut(.space, modifiers: [])
65 | }
66 | ToolbarItem {
67 | Button("Info", systemImage: showInfo ? "info.circle.fill" : "info.circle", action: toggleInfoView)
68 | .keyboardShortcut("I", modifiers: .command)
69 | }
70 | }
71 | }
72 |
73 | @ViewBuilder
74 | private var animationRenderingView: some View {
75 | switch animationFile {
76 | case let animationFile as RiveAnimationFile:
77 | riveViewModel(model: RiveModel(riveFile: animationFile.file)).view()
78 | case let animationFile as LottieAnimationFile:
79 | lottieLibraryView(animation: animationFile.animation)
80 | case let animationFile as DotLottieAnimationFile:
81 | if let id, let animation = animationFile.file.animations.first(where: { $0.configuration.id == id }) {
82 | lottieLibraryView(animation: animation.animation, configuration: animation.configuration)
83 | } else if let animation = animationFile.file.animations.first {
84 | lottieLibraryView(animation: animation.animation, configuration: animation.configuration)
85 | } else {
86 | Text("No animation found.")
87 | }
88 | default:
89 | Text("Unknown animation file.")
90 | }
91 | }
92 |
93 | private func riveViewModel(model: RiveModel) -> RiveViewModel {
94 | let viewModel = RiveViewModel(model, artboardName: id)
95 | switch state.configuration.loopMode {
96 | case .autoReverse:
97 | viewModel.play(loop: .pingPong)
98 | case .playOnce:
99 | viewModel.play(loop: .oneShot)
100 | case .loop:
101 | viewModel.play(loop: .loop)
102 | default:
103 | break
104 | }
105 | return viewModel
106 | }
107 |
108 | @ViewBuilder
109 | private func lottieLibraryView(animation: LottieAnimation, configuration: DotLottieConfiguration? = nil) -> some View {
110 | switch state.configuration.library {
111 | case .lottie:
112 | LottieView(animation: animation)
113 | .configure { configure(view: $0, configuration: configuration)}
114 | .playbackMode(playbackMode)
115 | .animationSpeed(state.configuration.speed)
116 | case .dotLottie:
117 | if let animation = state.dotLottieAnimation {
118 | animation.view()
119 | .task(id: state.configuration.library, priority: .userInitiated) {
120 | loadDotLottieAnimation()
121 | }
122 | } else {
123 | ProgressView()
124 | .progressViewStyle(.circular)
125 | .task(id: state.configuration.library, priority: .userInitiated) {
126 | loadDotLottieAnimation()
127 | }
128 | }
129 | }
130 | }
131 |
132 | private var showInfo: Bool {
133 | state.showInfo ?? showInfoByDefault
134 | }
135 |
136 | private var isLottie: Bool {
137 | animationFile is LottieAnimationFile || animationFile is DotLottieAnimationFile
138 | }
139 |
140 | // MARK: - Lottie configuration
141 |
142 | private var lottieAnimation: LottieAnimation? {
143 | switch animationFile {
144 | case let animationFile as LottieAnimationFile:
145 | return animationFile.animation
146 | case let animationFile as DotLottieAnimationFile:
147 | if let id, let animation = animationFile.file.animations.first(where: { $0.configuration.id == id }) {
148 | return animation.animation
149 | } else if let animation = animationFile.file.animations.first {
150 | return animation.animation
151 | }
152 | return nil
153 | default:
154 | return nil
155 | }
156 | }
157 |
158 | private var dotLottieConfiguration: DotLottieConfiguration? {
159 | guard case let animationFile as DotLottieAnimationFile = animationFile else {
160 | return nil
161 | }
162 | if let id, let animation = animationFile.file.animations.first(where: { $0.configuration.id == id }) {
163 | return animation.configuration
164 | } else if let animation = animationFile.file.animations.first {
165 | return animation.configuration
166 | }
167 | return nil
168 | }
169 |
170 | private var playbackMode: LottiePlaybackMode {
171 | if state.playing {
172 | return .playing(.fromProgress(0, toProgress: 1, loopMode: state.configuration.loopMode))
173 | } else {
174 | return .paused
175 | }
176 | }
177 |
178 | private func configure(view: LottieAnimationView, configuration: DotLottieConfiguration?) {
179 | if let imageProvider = configuration?.imageProvider {
180 | view.imageProvider = imageProvider
181 | }
182 | }
183 |
184 | // MARK: - DotLottie configuration
185 |
186 | private func loadDotLottieAnimation() {
187 | guard state.configuration.library == .dotLottie else {
188 | return
189 | }
190 | guard let fileURL = documentConfiguration?.fileURL, let data = try? Data(contentsOf: fileURL) else {
191 | return
192 | }
193 | let configuration = AnimationConfig(
194 | autoplay: state.playing,
195 | loop: state.configuration.loopMode == .loop,
196 | mode: state.configuration.loopMode == .autoReverse ? .bounce : .forward,
197 | speed: Float(state.configuration.speed),
198 | backgroundColor: CIColor(color: NSColor(state.configuration.backgroundColor)).flatMap { CIImage(color: $0) }
199 | )
200 |
201 | let parsingStartTime: Date = .now
202 |
203 | if fileURL.pathExtension == "json", let data = String(data: data, encoding: .utf8) {
204 | state.dotLottieAnimation = DotLottieAnimation(animationData: data, config: configuration)
205 | } else {
206 | let animation = DotLottieAnimation(dotLottieData: data, config: configuration)
207 | if let id {
208 | try? animation.loadAnimationById(id)
209 | }
210 | state.dotLottieAnimation = animation
211 | }
212 |
213 | state.dotLottieParseTime = Date.now.timeIntervalSince(parsingStartTime)
214 | }
215 |
216 | // MARK: - Actions
217 |
218 | private func togglePlaying() {
219 | state.playing.toggle()
220 | }
221 |
222 | private func toggleInfoView() {
223 | if state.showInfo == nil {
224 | state.showInfo = showInfoByDefault
225 | }
226 | state.showInfo?.toggle()
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2025 Matěj Kašpar Jirásek
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/LottieViewer/Localizable.xcstrings:
--------------------------------------------------------------------------------
1 | {
2 | "sourceLanguage" : "en",
3 | "strings" : {
4 | "%lld×%lld p" : {
5 | "comment" : "Narrow unit – Points",
6 | "localizations" : {
7 | "cs" : {
8 | "stringUnit" : {
9 | "state" : "translated",
10 | "value" : "%1$lld×%2$lld b"
11 | }
12 | },
13 | "en" : {
14 | "stringUnit" : {
15 | "state" : "new",
16 | "value" : "%1$lld×%2$lld p"
17 | }
18 | }
19 | }
20 | },
21 | "%lld×%lld points" : {
22 | "comment" : "Wide unit – Points",
23 | "localizations" : {
24 | "cs" : {
25 | "stringUnit" : {
26 | "state" : "translated",
27 | "value" : "%1$lld×%#@arg2@"
28 | },
29 | "substitutions" : {
30 | "arg2" : {
31 | "argNum" : 2,
32 | "formatSpecifier" : "lld",
33 | "variations" : {
34 | "plural" : {
35 | "few" : {
36 | "stringUnit" : {
37 | "state" : "translated",
38 | "value" : "%arg body"
39 | }
40 | },
41 | "many" : {
42 | "stringUnit" : {
43 | "state" : "translated",
44 | "value" : "%arg bodů"
45 | }
46 | },
47 | "one" : {
48 | "stringUnit" : {
49 | "state" : "translated",
50 | "value" : "%arg bod"
51 | }
52 | },
53 | "other" : {
54 | "stringUnit" : {
55 | "state" : "translated",
56 | "value" : "%arg bodů"
57 | }
58 | }
59 | }
60 | }
61 | }
62 | }
63 | },
64 | "en" : {
65 | "stringUnit" : {
66 | "state" : "translated",
67 | "value" : "%1$lld×%#@arg2@"
68 | },
69 | "substitutions" : {
70 | "arg2" : {
71 | "argNum" : 2,
72 | "formatSpecifier" : "lld",
73 | "variations" : {
74 | "plural" : {
75 | "one" : {
76 | "stringUnit" : {
77 | "state" : "translated",
78 | "value" : "%arg point"
79 | }
80 | },
81 | "other" : {
82 | "stringUnit" : {
83 | "state" : "translated",
84 | "value" : "%arg points"
85 | }
86 | }
87 | }
88 | }
89 | }
90 | }
91 | }
92 | }
93 | },
94 | "%lld×%lld pts" : {
95 | "comment" : "Abbreviated unit – Points",
96 | "localizations" : {
97 | "cs" : {
98 | "stringUnit" : {
99 | "state" : "translated",
100 | "value" : "%1$lld×%#@arg2@"
101 | },
102 | "substitutions" : {
103 | "arg2" : {
104 | "argNum" : 2,
105 | "formatSpecifier" : "lld",
106 | "variations" : {
107 | "plural" : {
108 | "few" : {
109 | "stringUnit" : {
110 | "state" : "translated",
111 | "value" : "%arg b"
112 | }
113 | },
114 | "many" : {
115 | "stringUnit" : {
116 | "state" : "translated",
117 | "value" : "%arg b"
118 | }
119 | },
120 | "one" : {
121 | "stringUnit" : {
122 | "state" : "translated",
123 | "value" : "%arg b"
124 | }
125 | },
126 | "other" : {
127 | "stringUnit" : {
128 | "state" : "translated",
129 | "value" : "%arg b"
130 | }
131 | }
132 | }
133 | }
134 | }
135 | }
136 | },
137 | "en" : {
138 | "stringUnit" : {
139 | "state" : "translated",
140 | "value" : "%1$lld×%#@arg2@"
141 | },
142 | "substitutions" : {
143 | "arg2" : {
144 | "argNum" : 2,
145 | "formatSpecifier" : "lld",
146 | "variations" : {
147 | "plural" : {
148 | "one" : {
149 | "stringUnit" : {
150 | "state" : "translated",
151 | "value" : "%arg pt"
152 | }
153 | },
154 | "other" : {
155 | "stringUnit" : {
156 | "state" : "translated",
157 | "value" : "%arg pts"
158 | }
159 | }
160 | }
161 | }
162 | }
163 | }
164 | }
165 | }
166 | },
167 | "8×" : {
168 | "shouldTranslate" : false
169 | },
170 | "¼×" : {
171 | "shouldTranslate" : false
172 | },
173 | "About Lottie Viewer" : {
174 | "localizations" : {
175 | "cs" : {
176 | "stringUnit" : {
177 | "state" : "translated",
178 | "value" : "O aplikaci Lottie Viewer"
179 | }
180 | }
181 | }
182 | },
183 | "Acknowledgements" : {
184 | "localizations" : {
185 | "cs" : {
186 | "stringUnit" : {
187 | "state" : "translated",
188 | "value" : "Licence"
189 | }
190 | }
191 | }
192 | },
193 | "Auto reverse" : {
194 | "localizations" : {
195 | "cs" : {
196 | "stringUnit" : {
197 | "state" : "translated",
198 | "value" : "Opakovat tam a zpět"
199 | }
200 | }
201 | }
202 | },
203 | "Background color" : {
204 | "localizations" : {
205 | "cs" : {
206 | "stringUnit" : {
207 | "state" : "translated",
208 | "value" : "Barva pozadí"
209 | }
210 | }
211 | }
212 | },
213 | "Duration:" : {
214 | "localizations" : {
215 | "cs" : {
216 | "stringUnit" : {
217 | "state" : "translated",
218 | "value" : "Délka:"
219 | }
220 | }
221 | }
222 | },
223 | "End frame:" : {
224 | "localizations" : {
225 | "cs" : {
226 | "stringUnit" : {
227 | "state" : "translated",
228 | "value" : "Poslední snímek:"
229 | }
230 | }
231 | }
232 | },
233 | "End:" : {
234 | "localizations" : {
235 | "cs" : {
236 | "stringUnit" : {
237 | "state" : "translated",
238 | "value" : "Konec:"
239 | }
240 | }
241 | }
242 | },
243 | "File version:" : {
244 | "localizations" : {
245 | "cs" : {
246 | "stringUnit" : {
247 | "state" : "translated",
248 | "value" : "Verze souboru:"
249 | }
250 | }
251 | }
252 | },
253 | "Frame rate:" : {
254 | "localizations" : {
255 | "cs" : {
256 | "stringUnit" : {
257 | "state" : "translated",
258 | "value" : "Frekvence obnovení:"
259 | }
260 | }
261 | }
262 | },
263 | "Glyph count:" : {
264 | "localizations" : {
265 | "cs" : {
266 | "stringUnit" : {
267 | "state" : "translated",
268 | "value" : "Počet symbolů:"
269 | }
270 | }
271 | }
272 | },
273 | "Glyphs:" : {
274 | "localizations" : {
275 | "cs" : {
276 | "stringUnit" : {
277 | "state" : "translated",
278 | "value" : "Symboly:"
279 | }
280 | }
281 | }
282 | },
283 | "Info" : {
284 | "localizations" : {
285 | "cs" : {
286 | "stringUnit" : {
287 | "state" : "translated",
288 | "value" : "Informace"
289 | }
290 | }
291 | }
292 | },
293 | "Layer count:" : {
294 | "localizations" : {
295 | "cs" : {
296 | "stringUnit" : {
297 | "state" : "translated",
298 | "value" : "Počet vrstev:"
299 | }
300 | }
301 | }
302 | },
303 | "Layers:" : {
304 | "localizations" : {
305 | "cs" : {
306 | "stringUnit" : {
307 | "state" : "translated",
308 | "value" : "Vrstvy:"
309 | }
310 | }
311 | }
312 | },
313 | "Library" : {
314 | "localizations" : {
315 | "cs" : {
316 | "stringUnit" : {
317 | "state" : "translated",
318 | "value" : "Knihovna"
319 | }
320 | }
321 | }
322 | },
323 | "Loop" : {
324 | "localizations" : {
325 | "cs" : {
326 | "stringUnit" : {
327 | "state" : "translated",
328 | "value" : "Opakovat"
329 | }
330 | }
331 | }
332 | },
333 | "Loop mode" : {
334 | "localizations" : {
335 | "cs" : {
336 | "stringUnit" : {
337 | "state" : "translated",
338 | "value" : "Mód opakování"
339 | }
340 | }
341 | }
342 | },
343 | "Lottie Viewer for Mac" : {
344 | "localizations" : {
345 | "cs" : {
346 | "stringUnit" : {
347 | "state" : "translated",
348 | "value" : "Lottie Viewer pro Mac"
349 | }
350 | }
351 | }
352 | },
353 | "Made by [Matěj Kašpar Jirásek](https://iosdev.space/@mkj) in Brno, Czechia" : {
354 | "localizations" : {
355 | "cs" : {
356 | "stringUnit" : {
357 | "state" : "translated",
358 | "value" : "Vytvořil [Matěj Kašpar Jirásek](https://iosdev.space/@mkj) v Brně"
359 | }
360 | }
361 | }
362 | },
363 | "No animation found." : {
364 | "localizations" : {
365 | "cs" : {
366 | "stringUnit" : {
367 | "state" : "translated",
368 | "value" : "Žádná animace nenalezena."
369 | }
370 | }
371 | }
372 | },
373 | "No animations included in this file." : {
374 | "localizations" : {
375 | "cs" : {
376 | "stringUnit" : {
377 | "state" : "translated",
378 | "value" : "V tomto souboru nejdou žádné animace."
379 | }
380 | }
381 | }
382 | },
383 | "Open repository in browser" : {
384 | "localizations" : {
385 | "cs" : {
386 | "stringUnit" : {
387 | "state" : "translated",
388 | "value" : "Otevřít repozitář v prohlížeči"
389 | }
390 | }
391 | }
392 | },
393 | "Parse time:" : {
394 | "localizations" : {
395 | "cs" : {
396 | "stringUnit" : {
397 | "state" : "translated",
398 | "value" : "Čas parsování:"
399 | }
400 | }
401 | }
402 | },
403 | "Pause" : {
404 | "localizations" : {
405 | "cs" : {
406 | "stringUnit" : {
407 | "state" : "translated",
408 | "value" : "Zastavit"
409 | }
410 | }
411 | }
412 | },
413 | "Play" : {
414 | "localizations" : {
415 | "cs" : {
416 | "stringUnit" : {
417 | "state" : "translated",
418 | "value" : "Přehrát"
419 | }
420 | }
421 | }
422 | },
423 | "Play once" : {
424 | "localizations" : {
425 | "cs" : {
426 | "stringUnit" : {
427 | "state" : "translated",
428 | "value" : "Přehrát jednou"
429 | }
430 | }
431 | }
432 | },
433 | "Playback speed" : {
434 | "localizations" : {
435 | "cs" : {
436 | "stringUnit" : {
437 | "state" : "translated",
438 | "value" : "Rychlost přehrávání"
439 | }
440 | }
441 | }
442 | },
443 | "Resolution:" : {
444 | "localizations" : {
445 | "cs" : {
446 | "stringUnit" : {
447 | "state" : "translated",
448 | "value" : "Rozlišení:"
449 | }
450 | }
451 | }
452 | },
453 | "Rive %@" : {
454 | "shouldTranslate" : false
455 | },
456 | "Root layer count:" : {
457 | "localizations" : {
458 | "cs" : {
459 | "stringUnit" : {
460 | "state" : "translated",
461 | "value" : "Počet kořenových vrstev:"
462 | }
463 | }
464 | }
465 | },
466 | "Show Info Panel by default" : {
467 | "localizations" : {
468 | "cs" : {
469 | "stringUnit" : {
470 | "state" : "translated",
471 | "value" : "Zobrazit informační panel automaticky"
472 | }
473 | }
474 | }
475 | },
476 | "Size:" : {
477 | "localizations" : {
478 | "cs" : {
479 | "stringUnit" : {
480 | "state" : "translated",
481 | "value" : "Velikost:"
482 | }
483 | }
484 | }
485 | },
486 | "Source on GitHub" : {
487 | "localizations" : {
488 | "cs" : {
489 | "stringUnit" : {
490 | "state" : "translated",
491 | "value" : "Zdrojový kód na serveru GitHub"
492 | }
493 | }
494 | }
495 | },
496 | "Start frame:" : {
497 | "localizations" : {
498 | "cs" : {
499 | "stringUnit" : {
500 | "state" : "translated",
501 | "value" : "První snímek:"
502 | }
503 | }
504 | }
505 | },
506 | "Start:" : {
507 | "localizations" : {
508 | "cs" : {
509 | "stringUnit" : {
510 | "state" : "translated",
511 | "value" : "Začatek:"
512 | }
513 | }
514 | }
515 | },
516 | "Unknown animation file." : {
517 | "localizations" : {
518 | "cs" : {
519 | "stringUnit" : {
520 | "state" : "translated",
521 | "value" : "Neznámý soubor animací."
522 | }
523 | }
524 | }
525 | },
526 | "Version %@" : {
527 | "localizations" : {
528 | "cs" : {
529 | "stringUnit" : {
530 | "state" : "translated",
531 | "value" : "Verze %@"
532 | }
533 | }
534 | }
535 | },
536 | "Version:" : {
537 | "localizations" : {
538 | "cs" : {
539 | "stringUnit" : {
540 | "state" : "translated",
541 | "value" : "Verze:"
542 | }
543 | }
544 | }
545 | }
546 | },
547 | "version" : "1.0"
548 | }
--------------------------------------------------------------------------------
/LottieViewer/Generated/ResolvedPackages.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResolvedPackages.swift
3 | // LottieViewer
4 | //
5 | // Generated automatically - DO NOT EDIT
6 | //
7 |
8 | import Foundation
9 |
10 | enum ResolvedPackages {
11 | static let dictionary: [String: Package] = [
12 | "dotlottie-ios": Package(
13 | location: URL(string: "https://github.com/LottieFiles/dotlottie-ios")!,
14 | version: "0.11.1",
15 | license: """
16 | MIT License
17 |
18 | Copyright (c) 2023 LottieFiles
19 |
20 | Permission is hereby granted, free of charge, to any person obtaining a copy
21 | of this software and associated documentation files (the "Software"), to deal
22 | in the Software without restriction, including without limitation the rights
23 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24 | copies of the Software, and to permit persons to whom the Software is
25 | furnished to do so, subject to the following conditions:
26 |
27 | The above copyright notice and this permission notice shall be included in all
28 | copies or substantial portions of the Software.
29 |
30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36 | SOFTWARE.
37 | """
38 | ),
39 | "lottie-ios": Package(
40 | location: URL(string: "https://github.com/airbnb/lottie-ios.git")!,
41 | version: "4.5.2",
42 | license: """
43 | Apache License
44 | Version 2.0, January 2004
45 | https://www.apache.org/licenses/
46 |
47 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
48 |
49 | 1. Definitions.
50 |
51 | "License" shall mean the terms and conditions for use, reproduction,
52 | and distribution as defined by Sections 1 through 9 of this document.
53 |
54 | "Licensor" shall mean the copyright owner or entity authorized by
55 | the copyright owner that is granting the License.
56 |
57 | "Legal Entity" shall mean the union of the acting entity and all
58 | other entities that control, are controlled by, or are under common
59 | control with that entity. For the purposes of this definition,
60 | "control" means (i) the power, direct or indirect, to cause the
61 | direction or management of such entity, whether by contract or
62 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
63 | outstanding shares, or (iii) beneficial ownership of such entity.
64 |
65 | "You" (or "Your") shall mean an individual or Legal Entity
66 | exercising permissions granted by this License.
67 |
68 | "Source" form shall mean the preferred form for making modifications,
69 | including but not limited to software source code, documentation
70 | source, and configuration files.
71 |
72 | "Object" form shall mean any form resulting from mechanical
73 | transformation or translation of a Source form, including but
74 | not limited to compiled object code, generated documentation,
75 | and conversions to other media types.
76 |
77 | "Work" shall mean the work of authorship, whether in Source or
78 | Object form, made available under the License, as indicated by a
79 | copyright notice that is included in or attached to the work
80 | (an example is provided in the Appendix below).
81 |
82 | "Derivative Works" shall mean any work, whether in Source or Object
83 | form, that is based on (or derived from) the Work and for which the
84 | editorial revisions, annotations, elaborations, or other modifications
85 | represent, as a whole, an original work of authorship. For the purposes
86 | of this License, Derivative Works shall not include works that remain
87 | separable from, or merely link (or bind by name) to the interfaces of,
88 | the Work and Derivative Works thereof.
89 |
90 | "Contribution" shall mean any work of authorship, including
91 | the original version of the Work and any modifications or additions
92 | to that Work or Derivative Works thereof, that is intentionally
93 | submitted to Licensor for inclusion in the Work by the copyright owner
94 | or by an individual or Legal Entity authorized to submit on behalf of
95 | the copyright owner. For the purposes of this definition, "submitted"
96 | means any form of electronic, verbal, or written communication sent
97 | to the Licensor or its representatives, including but not limited to
98 | communication on electronic mailing lists, source code control systems,
99 | and issue tracking systems that are managed by, or on behalf of, the
100 | Licensor for the purpose of discussing and improving the Work, but
101 | excluding communication that is conspicuously marked or otherwise
102 | designated in writing by the copyright owner as "Not a Contribution."
103 |
104 | "Contributor" shall mean Licensor and any individual or Legal Entity
105 | on behalf of whom a Contribution has been received by Licensor and
106 | subsequently incorporated within the Work.
107 |
108 | 2. Grant of Copyright License. Subject to the terms and conditions of
109 | this License, each Contributor hereby grants to You a perpetual,
110 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
111 | copyright license to reproduce, prepare Derivative Works of,
112 | publicly display, publicly perform, sublicense, and distribute the
113 | Work and such Derivative Works in Source or Object form.
114 |
115 | 3. Grant of Patent License. Subject to the terms and conditions of
116 | this License, each Contributor hereby grants to You a perpetual,
117 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
118 | (except as stated in this section) patent license to make, have made,
119 | use, offer to sell, sell, import, and otherwise transfer the Work,
120 | where such license applies only to those patent claims licensable
121 | by such Contributor that are necessarily infringed by their
122 | Contribution(s) alone or by combination of their Contribution(s)
123 | with the Work to which such Contribution(s) was submitted. If You
124 | institute patent litigation against any entity (including a
125 | cross-claim or counterclaim in a lawsuit) alleging that the Work
126 | or a Contribution incorporated within the Work constitutes direct
127 | or contributory patent infringement, then any patent licenses
128 | granted to You under this License for that Work shall terminate
129 | as of the date such litigation is filed.
130 |
131 | 4. Redistribution. You may reproduce and distribute copies of the
132 | Work or Derivative Works thereof in any medium, with or without
133 | modifications, and in Source or Object form, provided that You
134 | meet the following conditions:
135 |
136 | (a) You must give any other recipients of the Work or
137 | Derivative Works a copy of this License; and
138 |
139 | (b) You must cause any modified files to carry prominent notices
140 | stating that You changed the files; and
141 |
142 | (c) You must retain, in the Source form of any Derivative Works
143 | that You distribute, all copyright, patent, trademark, and
144 | attribution notices from the Source form of the Work,
145 | excluding those notices that do not pertain to any part of
146 | the Derivative Works; and
147 |
148 | (d) If the Work includes a "NOTICE" text file as part of its
149 | distribution, then any Derivative Works that You distribute must
150 | include a readable copy of the attribution notices contained
151 | within such NOTICE file, excluding those notices that do not
152 | pertain to any part of the Derivative Works, in at least one
153 | of the following places: within a NOTICE text file distributed
154 | as part of the Derivative Works; within the Source form or
155 | documentation, if provided along with the Derivative Works; or,
156 | within a display generated by the Derivative Works, if and
157 | wherever such third-party notices normally appear. The contents
158 | of the NOTICE file are for informational purposes only and
159 | do not modify the License. You may add Your own attribution
160 | notices within Derivative Works that You distribute, alongside
161 | or as an addendum to the NOTICE text from the Work, provided
162 | that such additional attribution notices cannot be construed
163 | as modifying the License.
164 |
165 | You may add Your own copyright statement to Your modifications and
166 | may provide additional or different license terms and conditions
167 | for use, reproduction, or distribution of Your modifications, or
168 | for any such Derivative Works as a whole, provided Your use,
169 | reproduction, and distribution of the Work otherwise complies with
170 | the conditions stated in this License.
171 |
172 | 5. Submission of Contributions. Unless You explicitly state otherwise,
173 | any Contribution intentionally submitted for inclusion in the Work
174 | by You to the Licensor shall be under the terms and conditions of
175 | this License, without any additional terms or conditions.
176 | Notwithstanding the above, nothing herein shall supersede or modify
177 | the terms of any separate license agreement you may have executed
178 | with Licensor regarding such Contributions.
179 |
180 | 6. Trademarks. This License does not grant permission to use the trade
181 | names, trademarks, service marks, or product names of the Licensor,
182 | except as required for reasonable and customary use in describing the
183 | origin of the Work and reproducing the content of the NOTICE file.
184 |
185 | 7. Disclaimer of Warranty. Unless required by applicable law or
186 | agreed to in writing, Licensor provides the Work (and each
187 | Contributor provides its Contributions) on an "AS IS" BASIS,
188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
189 | implied, including, without limitation, any warranties or conditions
190 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
191 | PARTICULAR PURPOSE. You are solely responsible for determining the
192 | appropriateness of using or redistributing the Work and assume any
193 | risks associated with Your exercise of permissions under this License.
194 |
195 | 8. Limitation of Liability. In no event and under no legal theory,
196 | whether in tort (including negligence), contract, or otherwise,
197 | unless required by applicable law (such as deliberate and grossly
198 | negligent acts) or agreed to in writing, shall any Contributor be
199 | liable to You for damages, including any direct, indirect, special,
200 | incidental, or consequential damages of any character arising as a
201 | result of this License or out of the use or inability to use the
202 | Work (including but not limited to damages for loss of goodwill,
203 | work stoppage, computer failure or malfunction, or any and all
204 | other commercial damages or losses), even if such Contributor
205 | has been advised of the possibility of such damages.
206 |
207 | 9. Accepting Warranty or Additional Liability. While redistributing
208 | the Work or Derivative Works thereof, You may choose to offer,
209 | and charge a fee for, acceptance of support, warranty, indemnity,
210 | or other liability obligations and/or rights consistent with this
211 | License. However, in accepting such obligations, You may act only
212 | on Your own behalf and on Your sole responsibility, not on behalf
213 | of any other Contributor, and only if You agree to indemnify,
214 | defend, and hold each Contributor harmless for any liability
215 | incurred by, or claims asserted against, such Contributor by reason
216 | of your accepting any such warranty or additional liability.
217 |
218 | END OF TERMS AND CONDITIONS
219 |
220 | APPENDIX: How to apply the Apache License to your work.
221 |
222 | To apply the Apache License to your work, attach the following
223 | boilerplate notice, with the fields enclosed by brackets "{}"
224 | replaced with your own identifying information. (Don't include
225 | the brackets!) The text should be enclosed in the appropriate
226 | comment syntax for the file format. We also recommend that a
227 | file or class name and description of purpose be included on the
228 | same "printed page" as the copyright notice for easier
229 | identification within third-party archives.
230 |
231 | Copyright 2018 Airbnb, Inc.
232 |
233 | Licensed under the Apache License, Version 2.0 (the "License");
234 | you may not use this file except in compliance with the License.
235 | You may obtain a copy of the License at
236 |
237 | https://www.apache.org/licenses/LICENSE-2.0
238 |
239 | Unless required by applicable law or agreed to in writing, software
240 | distributed under the License is distributed on an "AS IS" BASIS,
241 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
242 | See the License for the specific language governing permissions and
243 | limitations under the License.
244 | """
245 | ),
246 | "rive-ios": Package(
247 | location: URL(string: "https://github.com/rive-app/rive-ios")!,
248 | version: "6.12.1",
249 | license: """
250 | MIT License
251 |
252 | Copyright (c) 2020 Rive
253 |
254 | Permission is hereby granted, free of charge, to any person obtaining a copy
255 | of this software and associated documentation files (the "Software"), to deal
256 | in the Software without restriction, including without limitation the rights
257 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
258 | copies of the Software, and to permit persons to whom the Software is
259 | furnished to do so, subject to the following conditions:
260 |
261 | The above copyright notice and this permission notice shall be included in all
262 | copies or substantial portions of the Software.
263 |
264 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
265 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
266 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
267 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
268 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
269 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
270 | SOFTWARE.
271 | """
272 | ),
273 | ]
274 | }
275 |
--------------------------------------------------------------------------------
/LottieViewer.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 77;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 15447A1A2D2C698700DB7205 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15447A192D2C698700DB7205 /* Quartz.framework */; };
11 | 15447A272D2C698700DB7205 /* Preview.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 15447A172D2C698700DB7205 /* Preview.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
12 | 15447A5C2D2D617D00DB7205 /* QuickLookThumbnailing.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15447A5B2D2D617D00DB7205 /* QuickLookThumbnailing.framework */; };
13 | 15447A5D2D2D617E00DB7205 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15447A192D2C698700DB7205 /* Quartz.framework */; };
14 | 15447A6C2D2D62BB00DB7205 /* LottieViewerCore in Frameworks */ = {isa = PBXBuildFile; productRef = 15447A6B2D2D62BB00DB7205 /* LottieViewerCore */; };
15 | 15447A6E2D2D62C000DB7205 /* LottieViewerCore in Frameworks */ = {isa = PBXBuildFile; productRef = 15447A6D2D2D62C000DB7205 /* LottieViewerCore */; };
16 | 15447A702D2D62C500DB7205 /* LottieViewerCore in Frameworks */ = {isa = PBXBuildFile; productRef = 15447A6F2D2D62C500DB7205 /* LottieViewerCore */; };
17 | 15447A802D2D814600DB7205 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 15447A7F2D2D814600DB7205 /* Lottie */; };
18 | 15447A822D2D814A00DB7205 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 15447A812D2D814A00DB7205 /* Lottie */; };
19 | 15447A842D2D815100DB7205 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 15447A832D2D815100DB7205 /* Lottie */; };
20 | 15577F102D6A28420041E76B /* RiveRuntime in Frameworks */ = {isa = PBXBuildFile; productRef = 15577F0F2D6A28420041E76B /* RiveRuntime */; };
21 | 1570A7F52D5BD1F1004F4B46 /* DotLottie in Frameworks */ = {isa = PBXBuildFile; productRef = 1570A7F42D5BD1F1004F4B46 /* DotLottie */; };
22 | /* End PBXBuildFile section */
23 |
24 | /* Begin PBXContainerItemProxy section */
25 | 154479012D281E2100DB7205 /* PBXContainerItemProxy */ = {
26 | isa = PBXContainerItemProxy;
27 | containerPortal = 154478E42D281E1F00DB7205 /* Project object */;
28 | proxyType = 1;
29 | remoteGlobalIDString = 154478EB2D281E1F00DB7205;
30 | remoteInfo = LottieViewer;
31 | };
32 | 1544790B2D281E2100DB7205 /* PBXContainerItemProxy */ = {
33 | isa = PBXContainerItemProxy;
34 | containerPortal = 154478E42D281E1F00DB7205 /* Project object */;
35 | proxyType = 1;
36 | remoteGlobalIDString = 154478EB2D281E1F00DB7205;
37 | remoteInfo = LottieViewer;
38 | };
39 | 15447A252D2C698700DB7205 /* PBXContainerItemProxy */ = {
40 | isa = PBXContainerItemProxy;
41 | containerPortal = 154478E42D281E1F00DB7205 /* Project object */;
42 | proxyType = 1;
43 | remoteGlobalIDString = 15447A162D2C698700DB7205;
44 | remoteInfo = Preview;
45 | };
46 | /* End PBXContainerItemProxy section */
47 |
48 | /* Begin PBXCopyFilesBuildPhase section */
49 | 15447A282D2C698700DB7205 /* Embed Foundation Extensions */ = {
50 | isa = PBXCopyFilesBuildPhase;
51 | buildActionMask = 2147483647;
52 | dstPath = "";
53 | dstSubfolderSpec = 13;
54 | files = (
55 | 15447A272D2C698700DB7205 /* Preview.appex in Embed Foundation Extensions */,
56 | );
57 | name = "Embed Foundation Extensions";
58 | runOnlyForDeploymentPostprocessing = 0;
59 | };
60 | 15447A762D2D7A7C00DB7205 /* Embed Frameworks */ = {
61 | isa = PBXCopyFilesBuildPhase;
62 | buildActionMask = 2147483647;
63 | dstPath = "";
64 | dstSubfolderSpec = 10;
65 | files = (
66 | );
67 | name = "Embed Frameworks";
68 | runOnlyForDeploymentPostprocessing = 0;
69 | };
70 | 15447A7A2D2D7A8400DB7205 /* Embed Frameworks */ = {
71 | isa = PBXCopyFilesBuildPhase;
72 | buildActionMask = 2147483647;
73 | dstPath = "";
74 | dstSubfolderSpec = 10;
75 | files = (
76 | );
77 | name = "Embed Frameworks";
78 | runOnlyForDeploymentPostprocessing = 0;
79 | };
80 | 15447A7E2D2D7A8A00DB7205 /* Embed Frameworks */ = {
81 | isa = PBXCopyFilesBuildPhase;
82 | buildActionMask = 2147483647;
83 | dstPath = "";
84 | dstSubfolderSpec = 10;
85 | files = (
86 | );
87 | name = "Embed Frameworks";
88 | runOnlyForDeploymentPostprocessing = 0;
89 | };
90 | /* End PBXCopyFilesBuildPhase section */
91 |
92 | /* Begin PBXFileReference section */
93 | 154478EC2D281E1F00DB7205 /* LottieViewer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LottieViewer.app; sourceTree = BUILT_PRODUCTS_DIR; };
94 | 154479002D281E2100DB7205 /* LottieViewerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LottieViewerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
95 | 1544790A2D281E2100DB7205 /* LottieViewerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LottieViewerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
96 | 15447A172D2C698700DB7205 /* Preview.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Preview.appex; sourceTree = BUILT_PRODUCTS_DIR; };
97 | 15447A192D2C698700DB7205 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; };
98 | 15447A5A2D2D617D00DB7205 /* Thumbnail.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Thumbnail.appex; sourceTree = BUILT_PRODUCTS_DIR; };
99 | 15447A5B2D2D617D00DB7205 /* QuickLookThumbnailing.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLookThumbnailing.framework; path = System/Library/Frameworks/QuickLookThumbnailing.framework; sourceTree = SDKROOT; };
100 | 15447A6A2D2D625F00DB7205 /* LottieViewerCore */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = LottieViewerCore; sourceTree = ""; };
101 | /* End PBXFileReference section */
102 |
103 | /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
104 | 154479122D281E2100DB7205 /* Exceptions for "LottieViewer" folder in "LottieViewer" target */ = {
105 | isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
106 | membershipExceptions = (
107 | Info.plist,
108 | );
109 | target = 154478EB2D281E1F00DB7205 /* LottieViewer */;
110 | };
111 | 15447A2C2D2C698700DB7205 /* Exceptions for "Preview" folder in "Preview" target */ = {
112 | isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
113 | membershipExceptions = (
114 | Info.plist,
115 | );
116 | target = 15447A162D2C698700DB7205 /* Preview */;
117 | };
118 | 15447A692D2D617E00DB7205 /* Exceptions for "Thumbnail" folder in "Thumbnail" target */ = {
119 | isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
120 | membershipExceptions = (
121 | Info.plist,
122 | );
123 | target = 15447A592D2D617D00DB7205 /* Thumbnail */;
124 | };
125 | /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
126 |
127 | /* Begin PBXFileSystemSynchronizedRootGroup section */
128 | 154478EE2D281E1F00DB7205 /* LottieViewer */ = {
129 | isa = PBXFileSystemSynchronizedRootGroup;
130 | exceptions = (
131 | 154479122D281E2100DB7205 /* Exceptions for "LottieViewer" folder in "LottieViewer" target */,
132 | );
133 | path = LottieViewer;
134 | sourceTree = "";
135 | };
136 | 154479032D281E2100DB7205 /* LottieViewerTests */ = {
137 | isa = PBXFileSystemSynchronizedRootGroup;
138 | path = LottieViewerTests;
139 | sourceTree = "";
140 | };
141 | 1544790D2D281E2100DB7205 /* LottieViewerUITests */ = {
142 | isa = PBXFileSystemSynchronizedRootGroup;
143 | path = LottieViewerUITests;
144 | sourceTree = "";
145 | };
146 | 15447A1B2D2C698700DB7205 /* Preview */ = {
147 | isa = PBXFileSystemSynchronizedRootGroup;
148 | exceptions = (
149 | 15447A2C2D2C698700DB7205 /* Exceptions for "Preview" folder in "Preview" target */,
150 | );
151 | path = Preview;
152 | sourceTree = "";
153 | };
154 | 15447A5E2D2D617E00DB7205 /* Thumbnail */ = {
155 | isa = PBXFileSystemSynchronizedRootGroup;
156 | exceptions = (
157 | 15447A692D2D617E00DB7205 /* Exceptions for "Thumbnail" folder in "Thumbnail" target */,
158 | );
159 | path = Thumbnail;
160 | sourceTree = "";
161 | };
162 | /* End PBXFileSystemSynchronizedRootGroup section */
163 |
164 | /* Begin PBXFrameworksBuildPhase section */
165 | 154478E92D281E1F00DB7205 /* Frameworks */ = {
166 | isa = PBXFrameworksBuildPhase;
167 | buildActionMask = 2147483647;
168 | files = (
169 | 15447A6C2D2D62BB00DB7205 /* LottieViewerCore in Frameworks */,
170 | 15577F102D6A28420041E76B /* RiveRuntime in Frameworks */,
171 | 15447A842D2D815100DB7205 /* Lottie in Frameworks */,
172 | 1570A7F52D5BD1F1004F4B46 /* DotLottie in Frameworks */,
173 | );
174 | runOnlyForDeploymentPostprocessing = 0;
175 | };
176 | 154478FD2D281E2100DB7205 /* Frameworks */ = {
177 | isa = PBXFrameworksBuildPhase;
178 | buildActionMask = 2147483647;
179 | files = (
180 | );
181 | runOnlyForDeploymentPostprocessing = 0;
182 | };
183 | 154479072D281E2100DB7205 /* Frameworks */ = {
184 | isa = PBXFrameworksBuildPhase;
185 | buildActionMask = 2147483647;
186 | files = (
187 | );
188 | runOnlyForDeploymentPostprocessing = 0;
189 | };
190 | 15447A142D2C698700DB7205 /* Frameworks */ = {
191 | isa = PBXFrameworksBuildPhase;
192 | buildActionMask = 2147483647;
193 | files = (
194 | 15447A1A2D2C698700DB7205 /* Quartz.framework in Frameworks */,
195 | 15447A6E2D2D62C000DB7205 /* LottieViewerCore in Frameworks */,
196 | 15447A822D2D814A00DB7205 /* Lottie in Frameworks */,
197 | );
198 | runOnlyForDeploymentPostprocessing = 0;
199 | };
200 | 15447A572D2D617D00DB7205 /* Frameworks */ = {
201 | isa = PBXFrameworksBuildPhase;
202 | buildActionMask = 2147483647;
203 | files = (
204 | 15447A5C2D2D617D00DB7205 /* QuickLookThumbnailing.framework in Frameworks */,
205 | 15447A702D2D62C500DB7205 /* LottieViewerCore in Frameworks */,
206 | 15447A5D2D2D617E00DB7205 /* Quartz.framework in Frameworks */,
207 | 15447A802D2D814600DB7205 /* Lottie in Frameworks */,
208 | );
209 | runOnlyForDeploymentPostprocessing = 0;
210 | };
211 | /* End PBXFrameworksBuildPhase section */
212 |
213 | /* Begin PBXGroup section */
214 | 154478E32D281E1F00DB7205 = {
215 | isa = PBXGroup;
216 | children = (
217 | 15447A6A2D2D625F00DB7205 /* LottieViewerCore */,
218 | 154478EE2D281E1F00DB7205 /* LottieViewer */,
219 | 154479032D281E2100DB7205 /* LottieViewerTests */,
220 | 1544790D2D281E2100DB7205 /* LottieViewerUITests */,
221 | 15447A1B2D2C698700DB7205 /* Preview */,
222 | 15447A5E2D2D617E00DB7205 /* Thumbnail */,
223 | 15447A182D2C698700DB7205 /* Frameworks */,
224 | 154478ED2D281E1F00DB7205 /* Products */,
225 | );
226 | sourceTree = "";
227 | };
228 | 154478ED2D281E1F00DB7205 /* Products */ = {
229 | isa = PBXGroup;
230 | children = (
231 | 154478EC2D281E1F00DB7205 /* LottieViewer.app */,
232 | 154479002D281E2100DB7205 /* LottieViewerTests.xctest */,
233 | 1544790A2D281E2100DB7205 /* LottieViewerUITests.xctest */,
234 | 15447A172D2C698700DB7205 /* Preview.appex */,
235 | 15447A5A2D2D617D00DB7205 /* Thumbnail.appex */,
236 | );
237 | name = Products;
238 | sourceTree = "";
239 | };
240 | 15447A182D2C698700DB7205 /* Frameworks */ = {
241 | isa = PBXGroup;
242 | children = (
243 | 15447A192D2C698700DB7205 /* Quartz.framework */,
244 | 15447A5B2D2D617D00DB7205 /* QuickLookThumbnailing.framework */,
245 | );
246 | name = Frameworks;
247 | sourceTree = "";
248 | };
249 | /* End PBXGroup section */
250 |
251 | /* Begin PBXNativeTarget section */
252 | 154478EB2D281E1F00DB7205 /* LottieViewer */ = {
253 | isa = PBXNativeTarget;
254 | buildConfigurationList = 154479132D281E2100DB7205 /* Build configuration list for PBXNativeTarget "LottieViewer" */;
255 | buildPhases = (
256 | 15A64B712D3849A9004BE70E /* Generate Package Metadata */,
257 | 154478E82D281E1F00DB7205 /* Sources */,
258 | 154478E92D281E1F00DB7205 /* Frameworks */,
259 | 154478EA2D281E1F00DB7205 /* Resources */,
260 | 15447A282D2C698700DB7205 /* Embed Foundation Extensions */,
261 | 15447A762D2D7A7C00DB7205 /* Embed Frameworks */,
262 | );
263 | buildRules = (
264 | );
265 | dependencies = (
266 | 15447A262D2C698700DB7205 /* PBXTargetDependency */,
267 | );
268 | fileSystemSynchronizedGroups = (
269 | 154478EE2D281E1F00DB7205 /* LottieViewer */,
270 | );
271 | name = LottieViewer;
272 | packageProductDependencies = (
273 | 15447A6B2D2D62BB00DB7205 /* LottieViewerCore */,
274 | 15447A832D2D815100DB7205 /* Lottie */,
275 | 1570A7F42D5BD1F1004F4B46 /* DotLottie */,
276 | 15577F0F2D6A28420041E76B /* RiveRuntime */,
277 | );
278 | productName = LottieViewer;
279 | productReference = 154478EC2D281E1F00DB7205 /* LottieViewer.app */;
280 | productType = "com.apple.product-type.application";
281 | };
282 | 154478FF2D281E2100DB7205 /* LottieViewerTests */ = {
283 | isa = PBXNativeTarget;
284 | buildConfigurationList = 154479182D281E2100DB7205 /* Build configuration list for PBXNativeTarget "LottieViewerTests" */;
285 | buildPhases = (
286 | 154478FC2D281E2100DB7205 /* Sources */,
287 | 154478FD2D281E2100DB7205 /* Frameworks */,
288 | 154478FE2D281E2100DB7205 /* Resources */,
289 | );
290 | buildRules = (
291 | );
292 | dependencies = (
293 | 154479022D281E2100DB7205 /* PBXTargetDependency */,
294 | );
295 | fileSystemSynchronizedGroups = (
296 | 154479032D281E2100DB7205 /* LottieViewerTests */,
297 | );
298 | name = LottieViewerTests;
299 | packageProductDependencies = (
300 | );
301 | productName = LottieViewerTests;
302 | productReference = 154479002D281E2100DB7205 /* LottieViewerTests.xctest */;
303 | productType = "com.apple.product-type.bundle.unit-test";
304 | };
305 | 154479092D281E2100DB7205 /* LottieViewerUITests */ = {
306 | isa = PBXNativeTarget;
307 | buildConfigurationList = 1544791B2D281E2100DB7205 /* Build configuration list for PBXNativeTarget "LottieViewerUITests" */;
308 | buildPhases = (
309 | 154479062D281E2100DB7205 /* Sources */,
310 | 154479072D281E2100DB7205 /* Frameworks */,
311 | 154479082D281E2100DB7205 /* Resources */,
312 | );
313 | buildRules = (
314 | );
315 | dependencies = (
316 | 1544790C2D281E2100DB7205 /* PBXTargetDependency */,
317 | );
318 | fileSystemSynchronizedGroups = (
319 | 1544790D2D281E2100DB7205 /* LottieViewerUITests */,
320 | );
321 | name = LottieViewerUITests;
322 | packageProductDependencies = (
323 | );
324 | productName = LottieViewerUITests;
325 | productReference = 1544790A2D281E2100DB7205 /* LottieViewerUITests.xctest */;
326 | productType = "com.apple.product-type.bundle.ui-testing";
327 | };
328 | 15447A162D2C698700DB7205 /* Preview */ = {
329 | isa = PBXNativeTarget;
330 | buildConfigurationList = 15447A2B2D2C698700DB7205 /* Build configuration list for PBXNativeTarget "Preview" */;
331 | buildPhases = (
332 | 15447A132D2C698700DB7205 /* Sources */,
333 | 15447A142D2C698700DB7205 /* Frameworks */,
334 | 15447A152D2C698700DB7205 /* Resources */,
335 | 15447A7A2D2D7A8400DB7205 /* Embed Frameworks */,
336 | );
337 | buildRules = (
338 | );
339 | dependencies = (
340 | );
341 | fileSystemSynchronizedGroups = (
342 | 15447A1B2D2C698700DB7205 /* Preview */,
343 | );
344 | name = Preview;
345 | packageProductDependencies = (
346 | 15447A6D2D2D62C000DB7205 /* LottieViewerCore */,
347 | 15447A812D2D814A00DB7205 /* Lottie */,
348 | );
349 | productName = Preview;
350 | productReference = 15447A172D2C698700DB7205 /* Preview.appex */;
351 | productType = "com.apple.product-type.app-extension";
352 | };
353 | 15447A592D2D617D00DB7205 /* Thumbnail */ = {
354 | isa = PBXNativeTarget;
355 | buildConfigurationList = 15447A662D2D617E00DB7205 /* Build configuration list for PBXNativeTarget "Thumbnail" */;
356 | buildPhases = (
357 | 15447A562D2D617D00DB7205 /* Sources */,
358 | 15447A572D2D617D00DB7205 /* Frameworks */,
359 | 15447A582D2D617D00DB7205 /* Resources */,
360 | 15447A7E2D2D7A8A00DB7205 /* Embed Frameworks */,
361 | );
362 | buildRules = (
363 | );
364 | dependencies = (
365 | );
366 | fileSystemSynchronizedGroups = (
367 | 15447A5E2D2D617E00DB7205 /* Thumbnail */,
368 | );
369 | name = Thumbnail;
370 | packageProductDependencies = (
371 | 15447A6F2D2D62C500DB7205 /* LottieViewerCore */,
372 | 15447A7F2D2D814600DB7205 /* Lottie */,
373 | );
374 | productName = Thumbnail;
375 | productReference = 15447A5A2D2D617D00DB7205 /* Thumbnail.appex */;
376 | productType = "com.apple.product-type.app-extension";
377 | };
378 | /* End PBXNativeTarget section */
379 |
380 | /* Begin PBXProject section */
381 | 154478E42D281E1F00DB7205 /* Project object */ = {
382 | isa = PBXProject;
383 | attributes = {
384 | BuildIndependentTargetsInParallel = 1;
385 | LastSwiftUpdateCheck = 1620;
386 | LastUpgradeCheck = 2610;
387 | TargetAttributes = {
388 | 154478EB2D281E1F00DB7205 = {
389 | CreatedOnToolsVersion = 16.2;
390 | };
391 | 154478FF2D281E2100DB7205 = {
392 | CreatedOnToolsVersion = 16.2;
393 | TestTargetID = 154478EB2D281E1F00DB7205;
394 | };
395 | 154479092D281E2100DB7205 = {
396 | CreatedOnToolsVersion = 16.2;
397 | TestTargetID = 154478EB2D281E1F00DB7205;
398 | };
399 | 15447A162D2C698700DB7205 = {
400 | CreatedOnToolsVersion = 16.2;
401 | };
402 | 15447A592D2D617D00DB7205 = {
403 | CreatedOnToolsVersion = 16.2;
404 | };
405 | };
406 | };
407 | buildConfigurationList = 154478E72D281E1F00DB7205 /* Build configuration list for PBXProject "LottieViewer" */;
408 | developmentRegion = en;
409 | hasScannedForEncodings = 0;
410 | knownRegions = (
411 | en,
412 | Base,
413 | cs,
414 | );
415 | mainGroup = 154478E32D281E1F00DB7205;
416 | minimizedProjectReferenceProxies = 1;
417 | packageReferences = (
418 | 1544797B2D297DC100DB7205 /* XCRemoteSwiftPackageReference "lottie-ios" */,
419 | 1570A7F32D5BD1F1004F4B46 /* XCRemoteSwiftPackageReference "dotlottie-ios" */,
420 | 15577F0E2D6A28420041E76B /* XCRemoteSwiftPackageReference "rive-ios" */,
421 | );
422 | preferredProjectObjectVersion = 77;
423 | productRefGroup = 154478ED2D281E1F00DB7205 /* Products */;
424 | projectDirPath = "";
425 | projectRoot = "";
426 | targets = (
427 | 154478EB2D281E1F00DB7205 /* LottieViewer */,
428 | 15447A162D2C698700DB7205 /* Preview */,
429 | 15447A592D2D617D00DB7205 /* Thumbnail */,
430 | 154478FF2D281E2100DB7205 /* LottieViewerTests */,
431 | 154479092D281E2100DB7205 /* LottieViewerUITests */,
432 | );
433 | };
434 | /* End PBXProject section */
435 |
436 | /* Begin PBXResourcesBuildPhase section */
437 | 154478EA2D281E1F00DB7205 /* Resources */ = {
438 | isa = PBXResourcesBuildPhase;
439 | buildActionMask = 2147483647;
440 | files = (
441 | );
442 | runOnlyForDeploymentPostprocessing = 0;
443 | };
444 | 154478FE2D281E2100DB7205 /* Resources */ = {
445 | isa = PBXResourcesBuildPhase;
446 | buildActionMask = 2147483647;
447 | files = (
448 | );
449 | runOnlyForDeploymentPostprocessing = 0;
450 | };
451 | 154479082D281E2100DB7205 /* Resources */ = {
452 | isa = PBXResourcesBuildPhase;
453 | buildActionMask = 2147483647;
454 | files = (
455 | );
456 | runOnlyForDeploymentPostprocessing = 0;
457 | };
458 | 15447A152D2C698700DB7205 /* Resources */ = {
459 | isa = PBXResourcesBuildPhase;
460 | buildActionMask = 2147483647;
461 | files = (
462 | );
463 | runOnlyForDeploymentPostprocessing = 0;
464 | };
465 | 15447A582D2D617D00DB7205 /* Resources */ = {
466 | isa = PBXResourcesBuildPhase;
467 | buildActionMask = 2147483647;
468 | files = (
469 | );
470 | runOnlyForDeploymentPostprocessing = 0;
471 | };
472 | /* End PBXResourcesBuildPhase section */
473 |
474 | /* Begin PBXShellScriptBuildPhase section */
475 | 15A64B712D3849A9004BE70E /* Generate Package Metadata */ = {
476 | isa = PBXShellScriptBuildPhase;
477 | buildActionMask = 2147483647;
478 | files = (
479 | );
480 | inputFileListPaths = (
481 | );
482 | inputPaths = (
483 | "$(SRCROOT)/Scripts/generate-package-metadata.sh",
484 | "$(SRCROOT)/LottieViewer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved",
485 | "${BUILD_DIR%/Build/*}/SourcePackages/checkouts",
486 | "${BUILT_PRODUCTS_DIR}/SwiftPackageProducts",
487 | );
488 | name = "Generate Package Metadata";
489 | outputFileListPaths = (
490 | );
491 | outputPaths = (
492 | "$(SRCROOT)/LottieViewer/Generated/ResolvedPackages.swift",
493 | );
494 | runOnlyForDeploymentPostprocessing = 0;
495 | shellPath = /bin/sh;
496 | shellScript = "if [ -f \"${SRCROOT}/Scripts/generate-package-metadata.sh\" ]; then\n \"${SRCROOT}/Scripts/generate-package-metadata.sh\" ${BUILD_DIR} ${BUILT_PRODUCTS_DIR}\nfi\n";
497 | };
498 | /* End PBXShellScriptBuildPhase section */
499 |
500 | /* Begin PBXSourcesBuildPhase section */
501 | 154478E82D281E1F00DB7205 /* Sources */ = {
502 | isa = PBXSourcesBuildPhase;
503 | buildActionMask = 2147483647;
504 | files = (
505 | );
506 | runOnlyForDeploymentPostprocessing = 0;
507 | };
508 | 154478FC2D281E2100DB7205 /* Sources */ = {
509 | isa = PBXSourcesBuildPhase;
510 | buildActionMask = 2147483647;
511 | files = (
512 | );
513 | runOnlyForDeploymentPostprocessing = 0;
514 | };
515 | 154479062D281E2100DB7205 /* Sources */ = {
516 | isa = PBXSourcesBuildPhase;
517 | buildActionMask = 2147483647;
518 | files = (
519 | );
520 | runOnlyForDeploymentPostprocessing = 0;
521 | };
522 | 15447A132D2C698700DB7205 /* Sources */ = {
523 | isa = PBXSourcesBuildPhase;
524 | buildActionMask = 2147483647;
525 | files = (
526 | );
527 | runOnlyForDeploymentPostprocessing = 0;
528 | };
529 | 15447A562D2D617D00DB7205 /* Sources */ = {
530 | isa = PBXSourcesBuildPhase;
531 | buildActionMask = 2147483647;
532 | files = (
533 | );
534 | runOnlyForDeploymentPostprocessing = 0;
535 | };
536 | /* End PBXSourcesBuildPhase section */
537 |
538 | /* Begin PBXTargetDependency section */
539 | 154479022D281E2100DB7205 /* PBXTargetDependency */ = {
540 | isa = PBXTargetDependency;
541 | target = 154478EB2D281E1F00DB7205 /* LottieViewer */;
542 | targetProxy = 154479012D281E2100DB7205 /* PBXContainerItemProxy */;
543 | };
544 | 1544790C2D281E2100DB7205 /* PBXTargetDependency */ = {
545 | isa = PBXTargetDependency;
546 | target = 154478EB2D281E1F00DB7205 /* LottieViewer */;
547 | targetProxy = 1544790B2D281E2100DB7205 /* PBXContainerItemProxy */;
548 | };
549 | 15447A262D2C698700DB7205 /* PBXTargetDependency */ = {
550 | isa = PBXTargetDependency;
551 | target = 15447A162D2C698700DB7205 /* Preview */;
552 | targetProxy = 15447A252D2C698700DB7205 /* PBXContainerItemProxy */;
553 | };
554 | /* End PBXTargetDependency section */
555 |
556 | /* Begin XCBuildConfiguration section */
557 | 154479142D281E2100DB7205 /* Debug */ = {
558 | isa = XCBuildConfiguration;
559 | buildSettings = {
560 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
561 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
562 | CODE_SIGN_ENTITLEMENTS = LottieViewer/LottieViewer.entitlements;
563 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
564 | CODE_SIGN_STYLE = Automatic;
565 | COMBINE_HIDPI_IMAGES = YES;
566 | DEAD_CODE_STRIPPING = YES;
567 | DEVELOPMENT_ASSET_PATHS = "\"LottieViewer/Preview Content\"";
568 | ENABLE_APP_SANDBOX = YES;
569 | ENABLE_HARDENED_RUNTIME = YES;
570 | ENABLE_PREVIEWS = YES;
571 | ENABLE_USER_SELECTED_FILES = readwrite;
572 | GENERATE_INFOPLIST_FILE = YES;
573 | INFOPLIST_FILE = LottieViewer/Info.plist;
574 | INFOPLIST_KEY_CFBundleDisplayName = "Lottie Viewer";
575 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
576 | INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Matěj Kašpar Jirásek";
577 | LD_RUNPATH_SEARCH_PATHS = (
578 | "$(inherited)",
579 | "@executable_path/../Frameworks",
580 | );
581 | PRODUCT_BUNDLE_IDENTIFIER = dev.mkj.LottieViewer;
582 | PRODUCT_NAME = "$(TARGET_NAME)";
583 | SWIFT_EMIT_LOC_STRINGS = YES;
584 | SWIFT_VERSION = 5.0;
585 | };
586 | name = Debug;
587 | };
588 | 154479152D281E2100DB7205 /* Release */ = {
589 | isa = XCBuildConfiguration;
590 | buildSettings = {
591 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
592 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
593 | CODE_SIGN_ENTITLEMENTS = LottieViewer/LottieViewer.entitlements;
594 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
595 | CODE_SIGN_STYLE = Automatic;
596 | COMBINE_HIDPI_IMAGES = YES;
597 | DEAD_CODE_STRIPPING = YES;
598 | DEVELOPMENT_ASSET_PATHS = "\"LottieViewer/Preview Content\"";
599 | ENABLE_APP_SANDBOX = YES;
600 | ENABLE_HARDENED_RUNTIME = YES;
601 | ENABLE_PREVIEWS = YES;
602 | ENABLE_USER_SELECTED_FILES = readwrite;
603 | GENERATE_INFOPLIST_FILE = YES;
604 | INFOPLIST_FILE = LottieViewer/Info.plist;
605 | INFOPLIST_KEY_CFBundleDisplayName = "Lottie Viewer";
606 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
607 | INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Matěj Kašpar Jirásek";
608 | LD_RUNPATH_SEARCH_PATHS = (
609 | "$(inherited)",
610 | "@executable_path/../Frameworks",
611 | );
612 | PRODUCT_BUNDLE_IDENTIFIER = dev.mkj.LottieViewer;
613 | PRODUCT_NAME = "$(TARGET_NAME)";
614 | SWIFT_EMIT_LOC_STRINGS = YES;
615 | SWIFT_VERSION = 5.0;
616 | };
617 | name = Release;
618 | };
619 | 154479162D281E2100DB7205 /* Debug */ = {
620 | isa = XCBuildConfiguration;
621 | buildSettings = {
622 | ALWAYS_SEARCH_USER_PATHS = NO;
623 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
624 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
625 | CLANG_ANALYZER_NONNULL = YES;
626 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
627 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
628 | CLANG_ENABLE_MODULES = YES;
629 | CLANG_ENABLE_OBJC_ARC = YES;
630 | CLANG_ENABLE_OBJC_WEAK = YES;
631 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
632 | CLANG_WARN_BOOL_CONVERSION = YES;
633 | CLANG_WARN_COMMA = YES;
634 | CLANG_WARN_CONSTANT_CONVERSION = YES;
635 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
636 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
637 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
638 | CLANG_WARN_EMPTY_BODY = YES;
639 | CLANG_WARN_ENUM_CONVERSION = YES;
640 | CLANG_WARN_INFINITE_RECURSION = YES;
641 | CLANG_WARN_INT_CONVERSION = YES;
642 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
643 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
644 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
645 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
646 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
647 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
648 | CLANG_WARN_STRICT_PROTOTYPES = YES;
649 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
650 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
651 | CLANG_WARN_UNREACHABLE_CODE = YES;
652 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
653 | COPY_PHASE_STRIP = NO;
654 | CURRENT_PROJECT_VERSION = 9;
655 | DEAD_CODE_STRIPPING = YES;
656 | DEBUG_INFORMATION_FORMAT = dwarf;
657 | DEVELOPMENT_TEAM = QLPB86L68N;
658 | ENABLE_STRICT_OBJC_MSGSEND = YES;
659 | ENABLE_TESTABILITY = YES;
660 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
661 | GCC_C_LANGUAGE_STANDARD = gnu17;
662 | GCC_DYNAMIC_NO_PIC = NO;
663 | GCC_NO_COMMON_BLOCKS = YES;
664 | GCC_OPTIMIZATION_LEVEL = 0;
665 | GCC_PREPROCESSOR_DEFINITIONS = (
666 | "DEBUG=1",
667 | "$(inherited)",
668 | );
669 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
670 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
671 | GCC_WARN_UNDECLARED_SELECTOR = YES;
672 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
673 | GCC_WARN_UNUSED_FUNCTION = YES;
674 | GCC_WARN_UNUSED_VARIABLE = YES;
675 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
676 | MACOSX_DEPLOYMENT_TARGET = 14.0;
677 | MARKETING_VERSION = 1.5.0;
678 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
679 | MTL_FAST_MATH = YES;
680 | ONLY_ACTIVE_ARCH = YES;
681 | SDKROOT = macosx;
682 | STRING_CATALOG_GENERATE_SYMBOLS = YES;
683 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
684 | SWIFT_EMIT_LOC_STRINGS = YES;
685 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
686 | SWIFT_STRICT_CONCURRENCY = complete;
687 | };
688 | name = Debug;
689 | };
690 | 154479172D281E2100DB7205 /* Release */ = {
691 | isa = XCBuildConfiguration;
692 | buildSettings = {
693 | ALWAYS_SEARCH_USER_PATHS = NO;
694 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
695 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
696 | CLANG_ANALYZER_NONNULL = YES;
697 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
698 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
699 | CLANG_ENABLE_MODULES = YES;
700 | CLANG_ENABLE_OBJC_ARC = YES;
701 | CLANG_ENABLE_OBJC_WEAK = YES;
702 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
703 | CLANG_WARN_BOOL_CONVERSION = YES;
704 | CLANG_WARN_COMMA = YES;
705 | CLANG_WARN_CONSTANT_CONVERSION = YES;
706 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
707 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
708 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
709 | CLANG_WARN_EMPTY_BODY = YES;
710 | CLANG_WARN_ENUM_CONVERSION = YES;
711 | CLANG_WARN_INFINITE_RECURSION = YES;
712 | CLANG_WARN_INT_CONVERSION = YES;
713 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
714 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
715 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
716 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
717 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
718 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
719 | CLANG_WARN_STRICT_PROTOTYPES = YES;
720 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
721 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
722 | CLANG_WARN_UNREACHABLE_CODE = YES;
723 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
724 | COPY_PHASE_STRIP = NO;
725 | CURRENT_PROJECT_VERSION = 9;
726 | DEAD_CODE_STRIPPING = YES;
727 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
728 | DEVELOPMENT_TEAM = QLPB86L68N;
729 | ENABLE_NS_ASSERTIONS = NO;
730 | ENABLE_STRICT_OBJC_MSGSEND = YES;
731 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
732 | GCC_C_LANGUAGE_STANDARD = gnu17;
733 | GCC_NO_COMMON_BLOCKS = YES;
734 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
735 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
736 | GCC_WARN_UNDECLARED_SELECTOR = YES;
737 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
738 | GCC_WARN_UNUSED_FUNCTION = YES;
739 | GCC_WARN_UNUSED_VARIABLE = YES;
740 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
741 | MACOSX_DEPLOYMENT_TARGET = 14.0;
742 | MARKETING_VERSION = 1.5.0;
743 | MTL_ENABLE_DEBUG_INFO = NO;
744 | MTL_FAST_MATH = YES;
745 | SDKROOT = macosx;
746 | STRING_CATALOG_GENERATE_SYMBOLS = YES;
747 | SWIFT_COMPILATION_MODE = wholemodule;
748 | SWIFT_EMIT_LOC_STRINGS = YES;
749 | SWIFT_STRICT_CONCURRENCY = complete;
750 | };
751 | name = Release;
752 | };
753 | 154479192D281E2100DB7205 /* Debug */ = {
754 | isa = XCBuildConfiguration;
755 | buildSettings = {
756 | BUNDLE_LOADER = "$(TEST_HOST)";
757 | CODE_SIGN_STYLE = Automatic;
758 | DEAD_CODE_STRIPPING = YES;
759 | GENERATE_INFOPLIST_FILE = YES;
760 | PRODUCT_BUNDLE_IDENTIFIER = dev.mkj.LottieViewerTests;
761 | PRODUCT_NAME = "$(TARGET_NAME)";
762 | SWIFT_EMIT_LOC_STRINGS = NO;
763 | SWIFT_VERSION = 5.0;
764 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LottieViewer.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/LottieViewer";
765 | };
766 | name = Debug;
767 | };
768 | 1544791A2D281E2100DB7205 /* Release */ = {
769 | isa = XCBuildConfiguration;
770 | buildSettings = {
771 | BUNDLE_LOADER = "$(TEST_HOST)";
772 | CODE_SIGN_STYLE = Automatic;
773 | DEAD_CODE_STRIPPING = YES;
774 | GENERATE_INFOPLIST_FILE = YES;
775 | PRODUCT_BUNDLE_IDENTIFIER = dev.mkj.LottieViewerTests;
776 | PRODUCT_NAME = "$(TARGET_NAME)";
777 | SWIFT_EMIT_LOC_STRINGS = NO;
778 | SWIFT_VERSION = 5.0;
779 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LottieViewer.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/LottieViewer";
780 | };
781 | name = Release;
782 | };
783 | 1544791C2D281E2100DB7205 /* Debug */ = {
784 | isa = XCBuildConfiguration;
785 | buildSettings = {
786 | CODE_SIGN_STYLE = Automatic;
787 | DEAD_CODE_STRIPPING = YES;
788 | GENERATE_INFOPLIST_FILE = YES;
789 | PRODUCT_BUNDLE_IDENTIFIER = dev.mkj.LottieViewerUITests;
790 | PRODUCT_NAME = "$(TARGET_NAME)";
791 | SWIFT_EMIT_LOC_STRINGS = NO;
792 | SWIFT_VERSION = 5.0;
793 | TEST_TARGET_NAME = LottieViewer;
794 | };
795 | name = Debug;
796 | };
797 | 1544791D2D281E2100DB7205 /* Release */ = {
798 | isa = XCBuildConfiguration;
799 | buildSettings = {
800 | CODE_SIGN_STYLE = Automatic;
801 | DEAD_CODE_STRIPPING = YES;
802 | GENERATE_INFOPLIST_FILE = YES;
803 | PRODUCT_BUNDLE_IDENTIFIER = dev.mkj.LottieViewerUITests;
804 | PRODUCT_NAME = "$(TARGET_NAME)";
805 | SWIFT_EMIT_LOC_STRINGS = NO;
806 | SWIFT_VERSION = 5.0;
807 | TEST_TARGET_NAME = LottieViewer;
808 | };
809 | name = Release;
810 | };
811 | 15447A292D2C698700DB7205 /* Debug */ = {
812 | isa = XCBuildConfiguration;
813 | buildSettings = {
814 | CODE_SIGN_ENTITLEMENTS = Preview/Preview.entitlements;
815 | CODE_SIGN_STYLE = Automatic;
816 | DEAD_CODE_STRIPPING = YES;
817 | ENABLE_APP_SANDBOX = YES;
818 | ENABLE_HARDENED_RUNTIME = YES;
819 | ENABLE_USER_SELECTED_FILES = readonly;
820 | GENERATE_INFOPLIST_FILE = YES;
821 | INFOPLIST_FILE = Preview/Info.plist;
822 | INFOPLIST_KEY_CFBundleDisplayName = Preview;
823 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
824 | LD_RUNPATH_SEARCH_PATHS = (
825 | "$(inherited)",
826 | "@executable_path/../Frameworks",
827 | "@executable_path/../../../../Frameworks",
828 | );
829 | PRODUCT_BUNDLE_IDENTIFIER = dev.mkj.LottieViewer.Preview;
830 | PRODUCT_NAME = "$(TARGET_NAME)";
831 | SKIP_INSTALL = YES;
832 | SWIFT_EMIT_LOC_STRINGS = YES;
833 | SWIFT_VERSION = 5.0;
834 | };
835 | name = Debug;
836 | };
837 | 15447A2A2D2C698700DB7205 /* Release */ = {
838 | isa = XCBuildConfiguration;
839 | buildSettings = {
840 | CODE_SIGN_ENTITLEMENTS = Preview/Preview.entitlements;
841 | CODE_SIGN_STYLE = Automatic;
842 | DEAD_CODE_STRIPPING = YES;
843 | ENABLE_APP_SANDBOX = YES;
844 | ENABLE_HARDENED_RUNTIME = YES;
845 | ENABLE_USER_SELECTED_FILES = readonly;
846 | GENERATE_INFOPLIST_FILE = YES;
847 | INFOPLIST_FILE = Preview/Info.plist;
848 | INFOPLIST_KEY_CFBundleDisplayName = Preview;
849 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
850 | LD_RUNPATH_SEARCH_PATHS = (
851 | "$(inherited)",
852 | "@executable_path/../Frameworks",
853 | "@executable_path/../../../../Frameworks",
854 | );
855 | PRODUCT_BUNDLE_IDENTIFIER = dev.mkj.LottieViewer.Preview;
856 | PRODUCT_NAME = "$(TARGET_NAME)";
857 | SKIP_INSTALL = YES;
858 | SWIFT_EMIT_LOC_STRINGS = YES;
859 | SWIFT_VERSION = 5.0;
860 | };
861 | name = Release;
862 | };
863 | 15447A672D2D617E00DB7205 /* Debug */ = {
864 | isa = XCBuildConfiguration;
865 | buildSettings = {
866 | CODE_SIGN_ENTITLEMENTS = Thumbnail/Thumbnail.entitlements;
867 | CODE_SIGN_STYLE = Automatic;
868 | DEAD_CODE_STRIPPING = YES;
869 | ENABLE_APP_SANDBOX = YES;
870 | ENABLE_HARDENED_RUNTIME = YES;
871 | ENABLE_USER_SELECTED_FILES = readonly;
872 | GENERATE_INFOPLIST_FILE = YES;
873 | INFOPLIST_FILE = Thumbnail/Info.plist;
874 | INFOPLIST_KEY_CFBundleDisplayName = Thumbnail;
875 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
876 | LD_RUNPATH_SEARCH_PATHS = (
877 | "$(inherited)",
878 | "@executable_path/../Frameworks",
879 | "@executable_path/../../../../Frameworks",
880 | );
881 | PRODUCT_BUNDLE_IDENTIFIER = dev.mkj.LottieViewer.Thumbnail;
882 | PRODUCT_NAME = "$(TARGET_NAME)";
883 | SKIP_INSTALL = YES;
884 | SWIFT_EMIT_LOC_STRINGS = YES;
885 | SWIFT_VERSION = 5.0;
886 | };
887 | name = Debug;
888 | };
889 | 15447A682D2D617E00DB7205 /* Release */ = {
890 | isa = XCBuildConfiguration;
891 | buildSettings = {
892 | CODE_SIGN_ENTITLEMENTS = Thumbnail/Thumbnail.entitlements;
893 | CODE_SIGN_STYLE = Automatic;
894 | DEAD_CODE_STRIPPING = YES;
895 | ENABLE_APP_SANDBOX = YES;
896 | ENABLE_HARDENED_RUNTIME = YES;
897 | ENABLE_USER_SELECTED_FILES = readonly;
898 | GENERATE_INFOPLIST_FILE = YES;
899 | INFOPLIST_FILE = Thumbnail/Info.plist;
900 | INFOPLIST_KEY_CFBundleDisplayName = Thumbnail;
901 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
902 | LD_RUNPATH_SEARCH_PATHS = (
903 | "$(inherited)",
904 | "@executable_path/../Frameworks",
905 | "@executable_path/../../../../Frameworks",
906 | );
907 | PRODUCT_BUNDLE_IDENTIFIER = dev.mkj.LottieViewer.Thumbnail;
908 | PRODUCT_NAME = "$(TARGET_NAME)";
909 | SKIP_INSTALL = YES;
910 | SWIFT_EMIT_LOC_STRINGS = YES;
911 | SWIFT_VERSION = 5.0;
912 | };
913 | name = Release;
914 | };
915 | /* End XCBuildConfiguration section */
916 |
917 | /* Begin XCConfigurationList section */
918 | 154478E72D281E1F00DB7205 /* Build configuration list for PBXProject "LottieViewer" */ = {
919 | isa = XCConfigurationList;
920 | buildConfigurations = (
921 | 154479162D281E2100DB7205 /* Debug */,
922 | 154479172D281E2100DB7205 /* Release */,
923 | );
924 | defaultConfigurationIsVisible = 0;
925 | defaultConfigurationName = Release;
926 | };
927 | 154479132D281E2100DB7205 /* Build configuration list for PBXNativeTarget "LottieViewer" */ = {
928 | isa = XCConfigurationList;
929 | buildConfigurations = (
930 | 154479142D281E2100DB7205 /* Debug */,
931 | 154479152D281E2100DB7205 /* Release */,
932 | );
933 | defaultConfigurationIsVisible = 0;
934 | defaultConfigurationName = Release;
935 | };
936 | 154479182D281E2100DB7205 /* Build configuration list for PBXNativeTarget "LottieViewerTests" */ = {
937 | isa = XCConfigurationList;
938 | buildConfigurations = (
939 | 154479192D281E2100DB7205 /* Debug */,
940 | 1544791A2D281E2100DB7205 /* Release */,
941 | );
942 | defaultConfigurationIsVisible = 0;
943 | defaultConfigurationName = Release;
944 | };
945 | 1544791B2D281E2100DB7205 /* Build configuration list for PBXNativeTarget "LottieViewerUITests" */ = {
946 | isa = XCConfigurationList;
947 | buildConfigurations = (
948 | 1544791C2D281E2100DB7205 /* Debug */,
949 | 1544791D2D281E2100DB7205 /* Release */,
950 | );
951 | defaultConfigurationIsVisible = 0;
952 | defaultConfigurationName = Release;
953 | };
954 | 15447A2B2D2C698700DB7205 /* Build configuration list for PBXNativeTarget "Preview" */ = {
955 | isa = XCConfigurationList;
956 | buildConfigurations = (
957 | 15447A292D2C698700DB7205 /* Debug */,
958 | 15447A2A2D2C698700DB7205 /* Release */,
959 | );
960 | defaultConfigurationIsVisible = 0;
961 | defaultConfigurationName = Release;
962 | };
963 | 15447A662D2D617E00DB7205 /* Build configuration list for PBXNativeTarget "Thumbnail" */ = {
964 | isa = XCConfigurationList;
965 | buildConfigurations = (
966 | 15447A672D2D617E00DB7205 /* Debug */,
967 | 15447A682D2D617E00DB7205 /* Release */,
968 | );
969 | defaultConfigurationIsVisible = 0;
970 | defaultConfigurationName = Release;
971 | };
972 | /* End XCConfigurationList section */
973 |
974 | /* Begin XCRemoteSwiftPackageReference section */
975 | 1544797B2D297DC100DB7205 /* XCRemoteSwiftPackageReference "lottie-ios" */ = {
976 | isa = XCRemoteSwiftPackageReference;
977 | repositoryURL = "https://github.com/airbnb/lottie-ios.git";
978 | requirement = {
979 | kind = upToNextMajorVersion;
980 | minimumVersion = 4.5.1;
981 | };
982 | };
983 | 15577F0E2D6A28420041E76B /* XCRemoteSwiftPackageReference "rive-ios" */ = {
984 | isa = XCRemoteSwiftPackageReference;
985 | repositoryURL = "https://github.com/rive-app/rive-ios";
986 | requirement = {
987 | kind = upToNextMajorVersion;
988 | minimumVersion = 6.7.0;
989 | };
990 | };
991 | 1570A7F32D5BD1F1004F4B46 /* XCRemoteSwiftPackageReference "dotlottie-ios" */ = {
992 | isa = XCRemoteSwiftPackageReference;
993 | repositoryURL = "https://github.com/LottieFiles/dotlottie-ios";
994 | requirement = {
995 | kind = upToNextMajorVersion;
996 | minimumVersion = 0.0.0;
997 | };
998 | };
999 | /* End XCRemoteSwiftPackageReference section */
1000 |
1001 | /* Begin XCSwiftPackageProductDependency section */
1002 | 15447A6B2D2D62BB00DB7205 /* LottieViewerCore */ = {
1003 | isa = XCSwiftPackageProductDependency;
1004 | productName = LottieViewerCore;
1005 | };
1006 | 15447A6D2D2D62C000DB7205 /* LottieViewerCore */ = {
1007 | isa = XCSwiftPackageProductDependency;
1008 | productName = LottieViewerCore;
1009 | };
1010 | 15447A6F2D2D62C500DB7205 /* LottieViewerCore */ = {
1011 | isa = XCSwiftPackageProductDependency;
1012 | productName = LottieViewerCore;
1013 | };
1014 | 15447A7F2D2D814600DB7205 /* Lottie */ = {
1015 | isa = XCSwiftPackageProductDependency;
1016 | package = 1544797B2D297DC100DB7205 /* XCRemoteSwiftPackageReference "lottie-ios" */;
1017 | productName = Lottie;
1018 | };
1019 | 15447A812D2D814A00DB7205 /* Lottie */ = {
1020 | isa = XCSwiftPackageProductDependency;
1021 | package = 1544797B2D297DC100DB7205 /* XCRemoteSwiftPackageReference "lottie-ios" */;
1022 | productName = Lottie;
1023 | };
1024 | 15447A832D2D815100DB7205 /* Lottie */ = {
1025 | isa = XCSwiftPackageProductDependency;
1026 | package = 1544797B2D297DC100DB7205 /* XCRemoteSwiftPackageReference "lottie-ios" */;
1027 | productName = Lottie;
1028 | };
1029 | 15577F0F2D6A28420041E76B /* RiveRuntime */ = {
1030 | isa = XCSwiftPackageProductDependency;
1031 | package = 15577F0E2D6A28420041E76B /* XCRemoteSwiftPackageReference "rive-ios" */;
1032 | productName = RiveRuntime;
1033 | };
1034 | 1570A7F42D5BD1F1004F4B46 /* DotLottie */ = {
1035 | isa = XCSwiftPackageProductDependency;
1036 | package = 1570A7F32D5BD1F1004F4B46 /* XCRemoteSwiftPackageReference "dotlottie-ios" */;
1037 | productName = DotLottie;
1038 | };
1039 | /* End XCSwiftPackageProductDependency section */
1040 | };
1041 | rootObject = 154478E42D281E1F00DB7205 /* Project object */;
1042 | }
1043 |
--------------------------------------------------------------------------------