├── 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 | App icon 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 | --------------------------------------------------------------------------------