rooms-launcher/src/utils/visual_helper.rs

174 lines
No EOL
5.9 KiB
Rust

use std::{fs::DirEntry, io::{Cursor, Write}, sync::Arc};
use directories::ProjectDirs;
use file_format::FileFormat;
use iced_video_player::Video;
use ::image::{DynamicImage, ImageReader};
use iced::{gradient, widget::container, Color};
use tempfile::NamedTempFile;
use crate::{LauncherBackground, PossibleGames};
use super::img_utils::round_image;
pub fn get_game_background(game: &PossibleGames) -> LauncherBackground {
let proj_dirs = ProjectDirs::from("com", "RabbyDevs", "rr-launcher").unwrap();
let background_bytes = get_background_file(&proj_dirs, game).unwrap();
let data = Arc::new(background_bytes);
let file_format = FileFormat::from_bytes(&*data);
if file_format.extension() == "mp4" {
let mut temp_file = NamedTempFile::new().unwrap();
temp_file.write_all(&data).unwrap();
let temp_path = temp_file.path().to_str().unwrap().to_string();
match Video::new(url::Url::from_file_path(temp_path).unwrap()) {
Ok(mut video) => {
video.set_looping(true);
LauncherBackground::Video(video)
},
Err(err) => {
panic!("{:#?}", err)
},
}
} else {
let img = ImageReader::new(Cursor::new(&*data))
.with_guessed_format()
.unwrap()
.decode()
.unwrap();
LauncherBackground::Image(img)
}
}
fn get_background_file(proj_dirs: &ProjectDirs, game: &PossibleGames) -> Result<Vec<u8>, std::io::Error> {
let game_dir = match game {
PossibleGames::WutheringWaves => proj_dirs.data_dir().join("kuro/wuwa"),
PossibleGames::ZenlessZoneZero => proj_dirs.data_dir().join("hoyoverse/zzz"),
PossibleGames::HonkaiStarRail => proj_dirs.data_dir().join("hoyoverse/hsr"),
PossibleGames::GenshinImpact => proj_dirs.data_dir().join("hoyoverse/gi"),
};
if !game_dir.exists() {
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("Game directory does not exist: {:?}", game_dir)
));
}
let entries = std::fs::read_dir(&game_dir)?;
for entry in entries {
let entry = entry?;
let file_name = entry.file_name().into_string().unwrap_or_default();
if file_name.starts_with("background_") {
return std::fs::read(entry.path());
}
}
Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("No background file found in {:?}", game_dir)
))
}
pub fn get_game_splash_dynamic_image(game: &PossibleGames) -> Option<DynamicImage> {
let proj_dirs = ProjectDirs::from("com", "RabbyDevs", "rr-launcher").unwrap();
let file_data = get_splash_file(&proj_dirs, game);
if let Some(data) = file_data {
let data_cursor = Cursor::new(data);
Some(ImageReader::new(data_cursor)
.with_guessed_format()
.unwrap()
.decode()
.unwrap())
} else {None}
}
pub fn get_game_icon_dynamic_image(game: &PossibleGames) -> DynamicImage {
let proj_dirs = ProjectDirs::from("com", "RabbyDevs", "rr-launcher").unwrap();
let file_data: &[u8] = match game {
PossibleGames::WutheringWaves => include_bytes!("../../resources/wutheringwaves-icon.png"),
PossibleGames::ZenlessZoneZero => &get_hoyo_game_icon_file(&proj_dirs, game),
PossibleGames::HonkaiStarRail => &get_hoyo_game_icon_file(&proj_dirs, game),
PossibleGames::GenshinImpact => &get_hoyo_game_icon_file(&proj_dirs, game),
};
let data_cursor = Cursor::new(file_data);
let img = ImageReader::new(data_cursor)
.with_guessed_format()
.unwrap()
.decode()
.unwrap()
.resize(128, 128, ::image::imageops::FilterType::Lanczos3);
round_image(img)
.unwrap()
}
fn get_hoyo_game_icon_file(proj_dirs: &ProjectDirs, game: &PossibleGames) -> Vec<u8> {
let game_abbrevation = match game {
PossibleGames::ZenlessZoneZero => "zzz",
PossibleGames::HonkaiStarRail => "hsr",
PossibleGames::GenshinImpact => "gi",
_ => panic!("Wuwa inputted in hoyo only func")
};
let data_dir = proj_dirs.data_dir().join(format!("hoyoverse/{}", game_abbrevation));
let icon: Option<DirEntry> = {
let mut icon = None;
for path in data_dir.read_dir().unwrap() {
let path = path.unwrap();
if path.file_name().into_string().unwrap().starts_with("icon_") {
icon = Some(path);
}
}
icon
};
std::fs::read(icon.expect("installation went wrong.").path()).unwrap()
}
fn get_splash_file(proj_dirs: &ProjectDirs, game: &PossibleGames) -> Option<Vec<u8>> {
let game_path = match game {
PossibleGames::ZenlessZoneZero => "hoyoverse/zzz",
PossibleGames::HonkaiStarRail => "hoyoverse/hsr",
PossibleGames::GenshinImpact => "hoyoverse/gi",
PossibleGames::WutheringWaves => "kuro/wuwa"
};
let data_dir = proj_dirs.data_dir().join(game_path);
let icon: Option<DirEntry> = {
let mut icon = None;
for path in data_dir.read_dir().unwrap() {
let path = path.unwrap();
if path.file_name().into_string().unwrap().starts_with("splash_") {
icon = Some(path);
}
}
icon
};
icon.map(|icon| std::fs::read(icon.path()).unwrap())
}
fn rad(deg: f32) -> f32 {
deg * std::f32::consts::PI / 180.0
}
pub fn style_container(direction: f32, use_gradient: bool) -> container::Style {
let angle = rad(direction);
let gradient: Option<iced::Background> = if use_gradient {
Some(gradient::Linear::new(angle)
.add_stop(0.0, Color::from_rgba8(0, 0, 0, 0.0))
.add_stop(0.75, Color::from_rgba8(0, 0, 0, 0.75)).into())
} else {None};
container::Style {
text_color: Color::from_rgba8(255, 255, 255, 1.0).into(),
background: gradient,
..container::Style::default()
}
}