Skip to content
This repository has been archived by the owner on Dec 16, 2024. It is now read-only.

Commit

Permalink
Merge pull request #3 from dotlottie/eh/appearance
Browse files Browse the repository at this point in the history
[FIX] Fixed loading dotLottie from local folder
  • Loading branch information
eharrison authored Oct 20, 2021
2 parents e8c5822 + 839e6c9 commit b84cf3e
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 82 deletions.
18 changes: 18 additions & 0 deletions Example/Pods/Pods.xcodeproj/project.pbxproj

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions Example/dotLottieLoader/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,24 @@ class ViewController: UIViewController {
// Do any additional setup after loading the view, typically from a nib.

DotLottieUtils.isLogEnabled = true
DotLottieLoader.dotLottie(fromJsonLottieAt: URL(string: "https://assets7.lottiefiles.com/packages/lf20_6k4jsmai.json")!) { url in
// file compressed into dotLottie

let creator = DotLottieCreator(animationUrl: URL(string: "https://assets7.lottiefiles.com/private_files/lf30_p25uf33d.json")!)

creator.create { url in
guard let url = url else { return }
DotLottieLoader.load(from: url) { dotLottieFile in
// file decompressed from dotLottie
guard let dotLottieFile = dotLottieFile else {
print("invalid dotLottie file")
return
}
print("dotLottieFile decompressed successfuly with \(dotLottieFile.animations.count) animation\(dotLottieFile.animations.count == 1 ? "" : "s")")

print("""
dotLottieFile decompressed successfuly with:
- \(dotLottieFile.animations.count) animations
- \(dotLottieFile.images.count) images
- Default animation: \(dotLottieFile.animationUrl?.absoluteString ?? "not defined")
""")
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ DotLottieLoader.load(from: URL(string:"https://dotlottie.io/sample_files/animati
##### Creating .lottie file from JSON animation file

```swift
DotLottieLoader.dotLottie(fromJsonLottieAt: URL(string: "https://assets7.lottiefiles.com/packages/lf20_6k4jsmai.json")!) { dotLottieFileUrl in
// share or play `dotLottieFileUrl` using [DotLottie library](https://github.com/dotlottie/dotlottie-ios)
var creator = DotLottieCreator(animationUrl: URL(string: "https://assets7.lottiefiles.com/private_files/lf30_p25uf33d.json")!)
creator.create { url in
// use url to dotLottie
}
```

Expand Down
22 changes: 22 additions & 0 deletions Sources/dotLottieLoader/DotLottieAnimation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// DotLottieAnimation.swift
// Pods
//
// Created by Evandro Harrison Hoffmann on 28/06/2021.
//

import Foundation

public struct DotLottieAnimation: Codable {
/// Loop enabled
public var loop: Bool

// appearance color in HEX
public var themeColor: String

/// Animation Playback Speed
public var speed: Float

/// Id of Animation
public var id: String
}
26 changes: 26 additions & 0 deletions Sources/dotLottieLoader/DotLottieColor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// DotLottieColor.swift
// Pods
//
// Created by Evandro Harrison Hoffmann on 28/06/2021.
//

import Foundation

public struct DotLottieColor: Codable {
/// Layer tree
public var layer: [String]

/// Color in HEX
public var color: String

public init(layer: [String], color: String) {
self.layer = layer
self.color = color
}

/// Layer key path
public var layerKeyPath: String {
layer.joined(separator: ".")
}
}
167 changes: 167 additions & 0 deletions Sources/dotLottieLoader/DotLottieCreator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
//
// DotLottieConfiguration.swift
// Pods
//
// Created by Evandro Harrison Hoffmann on 23/06/2021.
//

import Foundation
import Zip

/// Configuration model
public struct DotLottieCreator {
/// URL to main animation JSON file
public var url: URL

/// Loop enabled - Default true
public var loop: Bool = true

/// appearance color in HEX - Default #ffffff
public var themeColor: String = "#ffffff"

/// URL to directory where we are saving the files
public var directory: URL = DotLottieUtils.tempDirectoryURL

public init(animationUrl: URL) {
url = animationUrl
}

/// directory for dotLottie
private var dotLottieDirectory: URL {
directory.appendingPathComponent(fileName)
}

/// Animations directory
private var animationsDirectory: URL {
dotLottieDirectory.appendingPathComponent("animations")
}

/// checks if is a lottie file
private var isLottie: Bool {
url.isJsonFile
}

/// Filename
private var fileName: String {
url.deletingPathExtension().lastPathComponent
}

/// URL for main animation
private var animationUrl: URL {
animationsDirectory.appendingPathComponent(fileName).appendingPathExtension("json")
}

/// URL for manifest file
private var manifestUrl: URL {
dotLottieDirectory.appendingPathComponent("manifest").appendingPathExtension("json")
}

/// URL for output
private var outputUrl: URL {
directory.appendingPathComponent(fileName).appendingPathExtension("lottie")
}

/// Downloads file from URL and returns local URL
/// - Parameters:
/// - url: Remote file URL
/// - saveUrl: Local file URL to persist
/// - completion: Local URL
private static func download(from url: URL, to saveUrl: URL, completion: @escaping (Bool) -> Void) {
/// file is not remote, save the animation content to the proper same URL and return
guard url.isRemoteFile else {
let animationData = try? Data(contentsOf: url)
do {
try animationData?.write(to: saveUrl)
completion(true)
return
} catch {
DotLottieUtils.log("Failed to save animation data: \(error.localizedDescription)")
completion(false)
return
}
}

DotLottieUtils.log("Downloading from url: \(url.path)")
URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
guard let data = data else {
DotLottieUtils.log("Failed to download data: \(error?.localizedDescription ?? "no description")")
completion(false)
return
}

do {
try data.write(to: saveUrl)
completion(true)
} catch {
DotLottieUtils.log("Failed to save downloaded data: \(error.localizedDescription)")
completion(false)
}
}).resume()
}

/// Creates folders File
/// - Throws: Error
private func createFolders() throws {
try FileManager.default.createDirectory(at: dotLottieDirectory, withIntermediateDirectories: true, attributes: nil)
try FileManager.default.createDirectory(at: animationsDirectory, withIntermediateDirectories: true, attributes: nil)
}

/// Creates main animation File
private func createAnimation(completion: @escaping (Bool) -> Void) {
Self.download(from: url, to: animationUrl, completion: completion)
}

/// Creates manifest File
/// - Throws: Error
private func createManifest(completed: @escaping (Bool) -> Void) {
let manifest = DotLottieManifest(animations: [
DotLottieAnimation(loop: loop, themeColor: themeColor, speed: 1.0, id: fileName)
], version: "1.0", author: "LottieFiles", generator: "LottieFiles dotLottieLoader-iOS 0.1.4")

do {
let manifestData = try manifest.encode()
try manifestData.write(to: manifestUrl)
completed(true)
} catch {
completed(false)
}
}

/// Creates dotLottieFile with given configurations
/// - Parameters:
/// - configuration: configuration for DotLottie file
/// - Returns: URL of .lottie file
public func create(completion: @escaping (URL?) -> Void) {
guard isLottie else {
DotLottieUtils.log("Not a json file")
completion(nil)
return
}

do {
try createFolders()
createAnimation { success in
guard success else { return }

createManifest { success in
guard success else { return }

do {
Zip.addCustomFileExtension(DotLottieUtils.dotLottieExtension)
try Zip.zipFiles(paths: [animationsDirectory, manifestUrl], zipFilePath: outputUrl, password: nil, compression: .DefaultCompression, progress: { progress in
DotLottieUtils.log("Compressing dotLottie file: \(progress)")
})

DotLottieUtils.log("Created dotLottie file at \(outputUrl)")
completion(outputUrl)
} catch {
completion(nil)
}
}
}
} catch {
DotLottieUtils.log("Failed to create dotLottie file \(error)")
completion(nil)
}
}
}
50 changes: 2 additions & 48 deletions Sources/dotLottieLoader/DotLottieFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,9 @@ public struct DotLottieFile {
/// - cache: Cache type
/// - Returns: success true/false
private func decompress(from url: URL, in directory: URL, cache: DotLottieCache) -> Bool {
guard cache.shouldDecompress(from: url) else {
DotLottieUtils.log("File already decompressed at \(directory.path)")
return true
}

Zip.addCustomFileExtension(DotLottieUtils.dotLottieExtension)

do {
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil)
Zip.addCustomFileExtension(DotLottieUtils.dotLottieExtension)
try Zip.unzipFile(url, destination: directory, overwrite: true, password: nil)
DotLottieUtils.log("File decompressed to \(directory.path)")
return true
Expand All @@ -88,45 +82,5 @@ public struct DotLottieFile {
return false
}
}

/// Creates dotLottieFile from animation json
/// - Parameters:
/// - url: url of JSON lottie animation
/// - directory: directory to save file
/// - loop: loop enabled
/// - themeColor: theme color
/// - Returns: URL of .lottie file
static func compress(jsonLottieAt url: URL, in directory: URL = DotLottieUtils.tempDirectoryURL, loop: Bool = true, themeColor: String = "#ffffff") -> URL? {
Zip.addCustomFileExtension(DotLottieUtils.dotLottieExtension)

do {
let fileName = url.deletingPathExtension().lastPathComponent
let dotLottieDirectory = directory.appendingPathComponent(fileName)
try FileManager.default.createDirectory(at: dotLottieDirectory, withIntermediateDirectories: true, attributes: nil)

let animationsDirectory = dotLottieDirectory.appendingPathComponent("animations")
try FileManager.default.createDirectory(at: animationsDirectory, withIntermediateDirectories: true, attributes: nil)

let animationData = try Data(contentsOf: url)
try animationData.write(to: animationsDirectory.appendingPathComponent(fileName).appendingPathExtension("json"))

let manifest = DotLottieManifest(animations: [
DotLottieAnimation(loop: loop, themeColor: themeColor, speed: 1.0, id: fileName)
], version: "1.0", author: "LottieFiles", generator: "LottieFiles dotLottieLoader-iOS 0.1.4")
let manifestUrl = dotLottieDirectory.appendingPathComponent("manifest").appendingPathExtension("json")
let manifestData = try manifest.encode()
try manifestData.write(to: manifestUrl)

let dotLottieUrl = directory.appendingPathComponent(fileName).appendingPathExtension("lottie")
try Zip.zipFiles(paths: [animationsDirectory, manifestUrl], zipFilePath: dotLottieUrl, password: nil, compression: .DefaultCompression, progress: { progress in
DotLottieUtils.log("Compressing dotLottie file: \(progress)")
})

return dotLottieUrl
} catch {
DotLottieUtils.log("Extraction of dotLottie archive failed with error: \(error)")
return nil
}
}

}

Loading

0 comments on commit b84cf3e

Please sign in to comment.