Skip to content

Commit

Permalink
feat: added dotlottie_manager
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelOsborne committed Jan 17, 2024
1 parent 9bea5a1 commit 8511f93
Show file tree
Hide file tree
Showing 13 changed files with 386 additions and 16 deletions.
1 change: 1 addition & 0 deletions dotlottie-ffi/src/dotlottie_player.udl
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ interface DotLottiePlayer {
boolean set_frame(f32 no);
boolean render();
boolean resize(u32 width, u32 height);
boolean load_dotlottie([ByRef] bytes file_data);
void clear();
};
6 changes: 5 additions & 1 deletion dotlottie-fms/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
[package]
name = "dotlottie-fms"
name = "dotlottie_fms"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["staticlib", "cdylib", "rlib"]
name = "dotlottie_fms"

[dependencies]
zip = { version = "0.6.6", default-features = false, features = ["deflate"] }
Expand All @@ -12,3 +15,4 @@ serde_json = "1.0.107"
serde = { version = "1.0.188", features = ["derive"] }
base64 = "0.21.4"
json = "0.12.4"
jzon = "0.12.5"
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[derive(Debug)]
pub struct AnimationData {
pub struct Animation {
pub id: String,
pub animation_data: String,
}
217 changes: 217 additions & 0 deletions dotlottie-fms/src/dolottie_manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
use std::{collections::HashMap, ops::Index};

use crate::{get_manifest, Animation, DotLottieError, Manifest, ManifestAnimation};

pub struct DotLottieManager {
current_animation_id: String,
manifest: Manifest,
zip_data: Vec<u8>,
animation_settings_cache: HashMap<String, ManifestAnimation>,
}

impl DotLottieManager {
pub fn new(dotlottie: Option<Vec<u8>>) -> Self {
if let Some(dotlottie) = dotlottie {
// Initialize the manager with the dotLottie file
let manifest = get_manifest(&dotlottie).unwrap();
let mut id = String::new();

if let Some(first_animation) = &manifest.active_animation_id {
id = first_animation.clone();
} else if let Ok(animations) = manifest.animations.lock() {
id = animations.index(0).id.clone();
} else {
panic!("No animations found in dotLottie file");
}

DotLottieManager {
current_animation_id: id,
manifest,
zip_data: dotlottie,
animation_settings_cache: HashMap::new(),
}
} else {
DotLottieManager {
current_animation_id: String::new(),
manifest: Manifest::new(),
zip_data: vec![],
animation_settings_cache: HashMap::new(),
}
}

// // Initialize the manager with the dotLottie file
// let manifest = get_manifest(&dotlottie).unwrap();
// let mut id = String::new();

// if let Some(first_animation) = &manifest.active_animation_id {
// id = first_animation.clone();
// } else if let Ok(animations) = manifest.animations.lock() {
// id = animations.index(0).id.clone();
// } else {
// panic!("No animations found in dotLottie file");
// }

// DotLottieManager {
// current_animation_id: String::new(),
// manifest: Manifest::new(),
// zip_data: vec![],
// animation_settings_cache: HashMap::new(),
// }
}

// pub fn new() -> Self {
// Initialize the manager with the dotLottie file
// let manifest = get_manifest(&dotlottie).unwrap();
// let mut id = String::new();

// if let Some(first_animation) = &manifest.active_animation_id {
// id = first_animation.clone();
// } else if let Ok(animations) = manifest.animations.lock() {
// id = animations.index(0).id.clone();
// } else {
// panic!("No animations found in dotLottie file");
// }
// DotLottieManager {
// current_animation_id: String::new(),
// manifest: Manifest::new(),
// zip_data: vec![],
// animation_settings_cache: HashMap::new(),
// }
// }

pub fn init(dotlottie: Vec<u8>) -> Self {
// Initialize the manager with the dotLottie file
let manifest = get_manifest(&dotlottie).unwrap();
let mut id = String::new();

if let Some(first_animation) = &manifest.active_animation_id {
id = first_animation.clone();
} else if let Ok(animations) = manifest.animations.lock() {
id = animations.index(0).id.clone();
} else {
panic!("No animations found in dotLottie file");
}

DotLottieManager {
current_animation_id: id,
manifest,
zip_data: dotlottie,
animation_settings_cache: HashMap::new(),
}
}

/// Advances to the next animation and returns it's animation data as a string.
pub fn next_animation(&mut self) -> Result<String, DotLottieError> {
let mut i = 0;

if let Ok(animations) = self.manifest.animations.lock() {
for anim in animations.iter() {
if anim.id == self.current_animation_id {
// return Result::Ok(true);
if i + 1 < animations.len() {
self.current_animation_id = animations[i + 1].id.clone();
}
}
i += 1;
}
}

self.get_animation(&self.current_animation_id)
}

/// Reverses to the previous animation and returns it's animation data as a string.
pub fn previous_animation(&mut self) -> Result<String, DotLottieError> {
if let Ok(animations) = self.manifest.animations.lock() {
let mut i = animations.len();

for anim in animations.iter() {
if anim.id == self.current_animation_id {
if i - 1 > 0 {
self.current_animation_id = animations[i + 1].id.clone();
}
}
i -= 1;
}
}

self.get_animation(&self.current_animation_id)
}

/// Returns the playback settings for the animation with the given ID.
/// Memoizes the settings in a HashMap for faster access.
pub fn get_playback_settings(
&mut self,
animation_id: &str,
) -> Result<ManifestAnimation, DotLottieError> {
if let Some(manifest_animation) = self.animation_settings_cache.get(animation_id) {
let cloned_animation = manifest_animation.clone(); // Clone the value

return Result::Ok(cloned_animation);
}

if let Ok(animations) = self.manifest.animations.lock() {
for anim in animations.iter() {
if &anim.id == animation_id {
self.animation_settings_cache
.insert(animation_id.to_string().clone(), anim.clone());

return Result::Ok(anim.clone());
}
}
}

return Result::Err(DotLottieError::MutexLockError);
}

pub fn contains_animation(&self, animation_id: &str) -> Result<bool, DotLottieError> {
if let Ok(animations) = self.manifest.animations.lock() {
for anim in animations.iter() {
if anim.id == animation_id {
return Result::Ok(true);
}
}

return Result::Ok(false);
}

return Result::Err(DotLottieError::MutexLockError);
}

pub fn current_animation_playback_settings(
&mut self,
) -> Result<ManifestAnimation, DotLottieError> {
let animation_id = self.current_animation_id.clone();

self.get_playback_settings(&animation_id)
}

pub fn get_animation(&self, animation_id: &str) -> Result<String, DotLottieError> {
crate::get_animation(&self.zip_data, animation_id)
}

pub fn get_animations(&self) -> Result<Vec<Animation>, DotLottieError> {
crate::get_animations(&self.zip_data)
}

pub fn set_active_animation(&mut self, animation_id: &str) -> Result<String, DotLottieError> {
if let Ok(contains) = self.contains_animation(animation_id) {
if contains {
self.current_animation_id = animation_id.to_string();

return Result::Ok(self.get_animation(animation_id)?);
}
}

return Result::Err(DotLottieError::AnimationNotFound {
animation_id: animation_id.to_string(),
});
}

pub fn manifest(&self) -> &Manifest {
&self.manifest
}

pub fn current_animation_id(&self) -> &str {
&self.current_animation_id.as_str()
}
}
6 changes: 6 additions & 0 deletions dotlottie-fms/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,10 @@ pub enum DotLottieError {

#[error("Unable to read the contents")]
ReadContentError,

#[error("Unable to lock the animations mutex")]
MutexLockError,

#[error("Animation not found")]
AnimationNotFound { animation_id: String },
}
40 changes: 29 additions & 11 deletions dotlottie-fms/src/functions.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::{errors::*, AnimationData, Manifest};
use crate::{errors::*, Animation, Manifest};
use std::io::{self, Read};
use std::path::Path;

use base64::{engine::general_purpose, Engine};
// use json::JsonValue;
use serde_json::{json, Value};
use zip::ZipArchive;

Expand Down Expand Up @@ -36,7 +37,8 @@ pub fn get_animation(bytes: &Vec<u8>, animation_id: &str) -> Result<String, DotL
let animation_data = String::from_utf8_lossy(&content).to_string();

// Untyped JSON value
let mut lottie_animation: Value = serde_json::from_str(&animation_data).unwrap();
// let mut lottie_animation: Value = serde_json::from_str(&animation_data).unwrap();
let mut lottie_animation = jzon::parse(&animation_data).unwrap();

// Loop through the parsed lottie animation and check for image assets
if let Some(assets) = lottie_animation["assets"].as_array_mut() {
Expand Down Expand Up @@ -68,24 +70,40 @@ pub fn get_animation(bytes: &Vec<u8>, animation_id: &str) -> Result<String, DotL
// Write the image data to the lottie
let image_data_base64 = general_purpose::STANDARD.encode(&content);

assets[i]["u"] = json!("".to_string());
assets[i]["p"] = json!(format!(
"data:image/{};base64,{}",
image_ext, image_data_base64
)
.to_string());
// assets[i]["u"] = serde_json::Value::String("".to_string());
// assets[i]["p"] = serde_json::Value::String(
// format!("data:image/{};base64,{}", image_ext, image_data_base64).to_string(),
// );

assets[i]["u"] = "".into();
assets[i]["p"] =
format!("data:image/{};base64,{}", image_ext, image_data_base64).into();
}
}
}
// let mut ad = serde_json::to_string(&animation_data).unwrap();

// ad = ad.replace("\\", "");
// ad.remove(0);
// ad.remove(ad.len() - 1);

// Ok(ad)

// Ok(animation_data)

// Ok(lottie_animation.to_string())

// Ok(serde_json::to_string(&lottie_animation.clone()).unwrap())

Ok(lottie_animation.to_string())
//works
Ok(jzon::stringify(lottie_animation))
}

/// Extract every animation with its image assets inlined.
///
/// bytes: The bytes of the dotLottie file
/// Result<Vec<AnimationData>, DotLottieError>: The extracted animations, or an error
pub fn get_animations(bytes: &Vec<u8>) -> Result<Vec<AnimationData>, DotLottieError> {
pub fn get_animations(bytes: &Vec<u8>) -> Result<Vec<Animation>, DotLottieError> {
let mut archive =
ZipArchive::new(io::Cursor::new(bytes)).map_err(|_| DotLottieError::ArchiveOpenError)?;
let mut file_contents = Vec::new();
Expand All @@ -102,7 +120,7 @@ pub fn get_animations(bytes: &Vec<u8>) -> Result<Vec<AnimationData>, DotLottieEr
if let Some(file_stem_str) = file_stem.to_str() {
let animation = get_animation(bytes, file_stem_str).unwrap();

let item = AnimationData {
let item = Animation {
id: String::from(file.name()),
animation_data: animation,
};
Expand Down
8 changes: 6 additions & 2 deletions dotlottie-fms/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod animation_data;
mod animation;
mod dolottie_manager;
mod errors;
mod functions;
mod manifest;
Expand All @@ -7,10 +8,13 @@ mod manifest_themes;
mod tests;
mod utils;

pub use crate::animation_data::*;
pub use crate::animation::*;
pub use crate::dolottie_manager::*;
pub use crate::errors::*;
pub use crate::functions::*;
pub use crate::manifest::*;
pub use crate::manifest_animation::*;
pub use crate::manifest_themes::*;
pub use crate::utils::*;

extern crate jzon;
2 changes: 1 addition & 1 deletion dotlottie-fms/src/manifest_animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use json::object;
use serde::{Deserialize, Serialize};
use std::fmt::Display;

#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ManifestAnimation {
pub autoplay: Option<bool>,
pub default_theme: Option<String>,
Expand Down
Loading

0 comments on commit 8511f93

Please sign in to comment.