Remove unwraps (#316)

Remove all unwraps and clippy warnings
This commit is contained in:
Philip Kristoffersen
2023-01-07 13:48:26 +01:00
committed by GitHub
parent 59b67a11b7
commit f6188b130d
30 changed files with 706 additions and 553 deletions
+4 -4
View File
@@ -64,10 +64,10 @@ mod tests {
// Parameters for set environment 'XDG_CONFIG_HOME' // Parameters for set environment 'XDG_CONFIG_HOME'
std::env::set_var( std::env::set_var(
"XDG_CONFIG_HOME", "XDG_CONFIG_HOME",
std::env::var("HOME").unwrap() + "/.config/boilr", std::env::var("HOME").unwrap_or_default() + "/.config/boilr",
); );
let xdg_config_home = std::env::var("XDG_CONFIG_HOME").unwrap(); let xdg_config_home = std::env::var("XDG_CONFIG_HOME").unwrap_or_default();
let config_path = get_config_folder(); let config_path = get_config_folder();
let test_path = PathBuf::from(xdg_config_home); let test_path = PathBuf::from(xdg_config_home);
@@ -79,11 +79,11 @@ mod tests {
fn check_return_config_path() { fn check_return_config_path() {
std::env::set_var( std::env::set_var(
"XDG_CONFIG_HOME", "XDG_CONFIG_HOME",
std::env::var("HOME").unwrap() + "/.config/boilr", std::env::var("HOME").unwrap_or_default() + "/.config/boilr",
); );
let config_path = get_config_folder(); let config_path = get_config_folder();
let current_path = std::env::var("HOME").unwrap() + "/.config/boilr"; let current_path = std::env::var("HOME").unwrap_or_default() + "/.config/boilr";
assert_eq!(config_path, PathBuf::from(current_path)); assert_eq!(config_path, PathBuf::from(current_path));
} }
+6 -2
View File
@@ -1,3 +1,7 @@
#![deny(clippy::unwrap_in_result)]
#![deny(clippy::get_unwrap)]
#![deny(clippy::unwrap_used)]
mod config; mod config;
mod migration; mod migration;
mod platforms; mod platforms;
@@ -16,9 +20,9 @@ fn main() -> Result<()> {
let args: Vec<String> = std::env::args().collect(); let args: Vec<String> = std::env::args().collect();
if args.contains(&"--no-ui".to_string()) { if args.contains(&"--no-ui".to_string()) {
ui::run_sync(); ui::run_sync()?;
} else { } else {
ui::run_ui(args); ui::run_ui(args)?;
} }
Ok(()) Ok(())
} }
+3 -1
View File
@@ -38,7 +38,9 @@ pub fn migrate_config() {
if let Ok(mut settings) = crate::settings::Settings::new() { if let Ok(mut settings) = crate::settings::Settings::new() {
settings.config_version = Some(1); settings.config_version = Some(1);
let platforms = get_platforms(); let platforms = get_platforms();
save_settings(&settings, &platforms); if let Err(err) = save_settings(&settings, &platforms){
eprintln!("Failed to load settings {:?}", err);
}
} }
} }
} }
+3
View File
@@ -185,6 +185,9 @@ impl ManifestItem {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
//Okay to unwrap in tests
#![allow(clippy::unwrap_in_result)]
#![allow(clippy::unwrap_used)]
use super::*; use super::*;
#[test] #[test]
+1 -1
View File
@@ -42,7 +42,7 @@ impl From<GogShortcut> for ShortcutOwned {
let icon_file = format!("goggame-{}.ico", gogs.game_id); let icon_file = format!("goggame-{}.ico", gogs.game_id);
let icon_path = Path::new(&gogs.game_folder).join(icon_file); let icon_path = Path::new(&gogs.game_folder).join(icon_file);
let icon = if icon_path.exists() { let icon = if icon_path.exists() {
icon_path.to_str().unwrap().to_string() icon_path.to_string_lossy().to_string()
} else { } else {
"".to_string() "".to_string()
}; };
+3
View File
@@ -62,6 +62,9 @@ fn parse_path(i: &[u8]) -> nom::IResult<&[u8], DbPaths> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
//Okay to unwrap in tests
#![allow(clippy::unwrap_in_result)]
#![allow(clippy::unwrap_used)]
use super::*; use super::*;
+1 -1
View File
@@ -18,7 +18,7 @@ pub struct ItchGame {
impl From<ItchGame> for ShortcutOwned { impl From<ItchGame> for ShortcutOwned {
fn from(game: ItchGame) -> Self { fn from(game: ItchGame) -> Self {
let exe = Path::new(&game.install_path).join(&game.executable); let exe = Path::new(&game.install_path).join(&game.executable);
let exe = exe.to_str().unwrap().to_string(); let exe = exe.to_string_lossy().to_string();
let shortcut = Shortcut::new( let shortcut = Shortcut::new(
"0", "0",
game.title.as_str(), game.title.as_str(),
+14 -12
View File
@@ -29,7 +29,7 @@ impl ItchPlatform {
)); ));
} }
let shortcut_bytes = std::fs::read(&itch_db_location).unwrap(); let shortcut_bytes = std::fs::read(&itch_db_location)?;
let paths = match parse_butler_db(&shortcut_bytes) { let paths = match parse_butler_db(&shortcut_bytes) {
Ok((_, shortcuts)) => Ok(shortcuts), Ok((_, shortcuts)) => Ok(shortcuts),
@@ -59,17 +59,19 @@ fn dbpath_to_game(paths: &DbPaths) -> Option<ItchGame> {
.iter() .iter()
.filter(|p| Path::new(&paths.base_path).join(p).is_executable()) .filter(|p| Path::new(&paths.base_path).join(p).is_executable())
.find_map(|executable| { .find_map(|executable| {
let gz_bytes = std::fs::read(&recipt).unwrap(); if let Ok(gz_bytes) = std::fs::read(&recipt) {
let mut d = GzDecoder::new(gz_bytes.as_slice()); let mut d = GzDecoder::new(gz_bytes.as_slice());
let mut s = String::new(); let mut s = String::new();
d.read_to_string(&mut s).unwrap(); if d.read_to_string(&mut s).is_ok() {
let receipt_op: Option<Receipt> = serde_json::from_str(&s).ok();
let receipt_op: Option<Receipt> = serde_json::from_str(&s).ok(); return receipt_op.map(|re| ItchGame {
receipt_op.map(|re| ItchGame { install_path: paths.base_path.to_owned(),
install_path: paths.base_path.to_owned(), executable: executable.to_owned(),
executable: executable.to_owned(), title: re.game.title,
title: re.game.title, });
}) }
}
None
}) })
} }
+1 -5
View File
@@ -32,11 +32,7 @@ impl NeedsPorton<OriginPlatform> for OriginGame {
impl OriginPlatform { impl OriginPlatform {
fn get_shortcuts(&self) -> eyre::Result<Vec<OriginGame>> { fn get_shortcuts(&self) -> eyre::Result<Vec<OriginGame>> {
let origin_folders = get_default_locations(); let origin_folders = get_default_locations().ok_or(eyre::format_err!("Default path not found"))?;
if origin_folders.is_none() {
return Err(eyre::format_err!("Default path not found"));
}
let origin_folders = origin_folders.unwrap();
let origin_folder = origin_folders.local_content_path; let origin_folder = origin_folders.local_content_path;
let origin_exe = origin_folders.exe_path; let origin_exe = origin_folders.exe_path;
let game_folders = origin_folder.join("LocalContent").read_dir()?; let game_folders = origin_folder.join("LocalContent").read_dir()?;
+4 -3
View File
@@ -69,8 +69,8 @@ pub fn load_setting_sections() -> eyre::Result<HashMap<String, String>> {
Ok(result) Ok(result)
} }
pub fn save_settings(settings: &Settings, platforms: &Platforms) { pub fn save_settings(settings: &Settings, platforms: &Platforms) -> eyre::Result<()>{
let mut toml = toml::to_string(&settings).unwrap(); let mut toml = toml::to_string(&settings)?;
for platform in platforms { for platform in platforms {
let section_name = format!("[{}]", platform.code_name()); let section_name = format!("[{}]", platform.code_name());
@@ -82,7 +82,8 @@ pub fn save_settings(settings: &Settings, platforms: &Platforms) {
} }
let config_path = crate::config::get_config_file(); let config_path = crate::config::get_config_file();
std::fs::write(config_path, toml).unwrap(); std::fs::write(config_path, toml)?;
Ok(())
} }
fn add_sections( fn add_sections(
+17 -16
View File
@@ -158,7 +158,7 @@ pub fn write_collections<S: AsRef<str>>(
&vdf_collections, &vdf_collections,
); );
if let Some(new_string) = new_string { if let Some(new_string) = new_string {
std::fs::write(path, new_string).unwrap(); std::fs::write(path, new_string)?;
} }
} }
} }
@@ -242,22 +242,19 @@ fn get_categories<S: AsRef<str>>(
Ok(res) Ok(res)
} }
fn open_db() -> Result<DB, Box<dyn Error>> { fn open_db() -> eyre::Result<DB> {
let location = get_level_db_location(); use eyre::eyre;
let location = get_level_db_location().ok_or(eyre!("Collections db not found"))?;
let options = Options::default(); let options = Options::default();
let open_res = DB::open(location.unwrap(), options); let open_res = DB::open(location, options);
if let Err(e) = &open_res { open_res.map_err(|e|{
match &e.code { use rusty_leveldb::StatusCode::*;
rusty_leveldb::StatusCode::LockError => { match e.code{
println!("Could not lock the steam level database, make sure steam is turned off when running synchronizations"); LockError => eyre!("Could not lock the steam level database, make sure steam is turned off when running synchronizations"),
} NotFound => eyre!("Could not find the steam level database, try to open and close steam once and synchronize again"),
rusty_leveldb::StatusCode::NotFound => { _ => eyre!("Failed opening collections file: {}",e.err),
println!("Could not find the steam level database, try to open and close steam once and synchronize again"); }
} })
_ => {}
};
}
Ok(open_res?)
} }
fn get_namespace_keys<S: AsRef<str>>(steamid: S, db: &mut DB) -> HashSet<String> { fn get_namespace_keys<S: AsRef<str>>(steamid: S, db: &mut DB) -> HashSet<String> {
@@ -394,6 +391,10 @@ pub struct VdfCollection {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
//Allow unwraps in test
#![allow(clippy::unwrap_in_result)]
#![allow(clippy::get_unwrap)]
#![allow(clippy::unwrap_used)]
use super::*; use super::*;
#[test] #[test]
+13 -7
View File
@@ -66,19 +66,25 @@ fn parse_manifest_string<S: AsRef<str>>(string: S) -> Option<SteamGameInfo> {
let app_id_line = lines.find(|l| l.contains("\"appid\"")); let app_id_line = lines.find(|l| l.contains("\"appid\""));
let name_line = lines.find(|l| l.contains("\"name\"")); let name_line = lines.find(|l| l.contains("\"name\""));
match (app_id_line, name_line) { match (app_id_line, name_line) {
(Some(app_id_line), Some(name_line)) => Some(SteamGameInfo { (Some(app_id_line), Some(name_line)) => {
name: name_line[10..name_line.len() - 1].to_string(), let appid = app_id_line[11..app_id_line.len() - 1].to_string().parse();
appid: app_id_line[11..app_id_line.len() - 1] match appid {
.to_string() Ok(appid) => Some(SteamGameInfo {
.parse() name: name_line[10..name_line.len() - 1].to_string(),
.unwrap(), appid,
}), }),
Err(_) => None,
}
}
_ => None, _ => None,
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
//Okay to unwrap in tests
#![allow(clippy::unwrap_in_result)]
#![allow(clippy::unwrap_used)]
use super::*; use super::*;
+6 -2
View File
@@ -2,16 +2,17 @@ use std::path::Path;
use nom::FindSubstring; use nom::FindSubstring;
pub fn setup_proton_games<B: AsRef<str>>(games: &[B]) { pub fn setup_proton_games<B: AsRef<str>>(games: &[B]) -> eyre::Result<()>{
if let Ok(home) = std::env::var("HOME") { if let Ok(home) = std::env::var("HOME") {
let config_file = Path::new(&home).join(".local/share/Steam/config/config.vdf"); let config_file = Path::new(&home).join(".local/share/Steam/config/config.vdf");
if config_file.exists() { if config_file.exists() {
if let Ok(config_content) = std::fs::read_to_string(&config_file) { if let Ok(config_content) = std::fs::read_to_string(&config_file) {
let new_string = enable_proton_games(config_content, games); let new_string = enable_proton_games(config_content, games);
std::fs::write(config_file, new_string).unwrap(); std::fs::write(config_file, new_string)?;
} }
} }
} }
Ok(())
} }
fn enable_proton_games<S: AsRef<str>, B: AsRef<str>>(vdf_content: S, games: &[B]) -> String { fn enable_proton_games<S: AsRef<str>, B: AsRef<str>>(vdf_content: S, games: &[B]) -> String {
@@ -96,6 +97,9 @@ fn find_indexes<S: AsRef<str>>(vdf_content: S) -> Option<SectionInfo> {
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
mod tests { mod tests {
//Okay to unwrap in tests
#![allow(clippy::unwrap_in_result)]
#![allow(clippy::unwrap_used)]
use super::*; use super::*;
#[test] #[test]
+20 -20
View File
@@ -8,14 +8,14 @@ use steam_shortcuts_util::{parse_shortcuts, shortcut::ShortcutOwned};
use super::SteamSettings; use super::SteamSettings;
pub fn get_shortcuts_for_user(user: &SteamUsersInfo) -> ShortcutInfo { pub fn get_shortcuts_for_user(user: &SteamUsersInfo) -> eyre::Result<ShortcutInfo> {
let mut shortcuts = vec![]; let mut shortcuts = vec![];
let new_path = match &user.shortcut_path { let new_path = match &user.shortcut_path {
Some(shortcut_path) => { Some(shortcut_path) => {
let content = std::fs::read(shortcut_path).unwrap(); let content = std::fs::read(shortcut_path)?;
shortcuts = parse_shortcuts(content.as_slice()) shortcuts = parse_shortcuts(content.as_slice())
.unwrap() .map_err(|e| eyre::format_err!("Could not parse shortcuts: {:?}", e))?
.iter() .iter()
.map(|s| s.to_owned()) .map(|s| s.to_owned())
.collect(); .collect();
@@ -27,15 +27,15 @@ pub fn get_shortcuts_for_user(user: &SteamUsersInfo) -> ShortcutInfo {
user.steam_user_data_folder user.steam_user_data_folder
); );
let path = Path::new(&user.steam_user_data_folder).join("config"); let path = Path::new(&user.steam_user_data_folder).join("config");
std::fs::create_dir_all(path.clone()).unwrap(); std::fs::create_dir_all(path.clone())?;
path.join("shortcuts.vdf") path.join("shortcuts.vdf")
} }
}; };
ShortcutInfo { Ok(ShortcutInfo {
shortcuts, shortcuts,
path: new_path, path: new_path,
} })
} }
pub struct ShortcutInfo { pub struct ShortcutInfo {
@@ -51,22 +51,22 @@ pub struct SteamUsersInfo {
} }
/// Get the paths to the steam users shortcuts (one for each user) /// Get the paths to the steam users shortcuts (one for each user)
pub fn get_shortcuts_paths( pub fn get_shortcuts_paths(settings: &SteamSettings) -> eyre::Result<Vec<SteamUsersInfo>> {
settings: &SteamSettings,
) -> Result<Vec<SteamUsersInfo>, Box<dyn Error + Sync + Send>> {
let steam_path_str = get_steam_path(settings)?; let steam_path_str = get_steam_path(settings)?;
let steam_path = Path::new(&steam_path_str); let steam_path = Path::new(&steam_path_str);
if !steam_path.exists() { if !steam_path.exists() {
return Result::Err(Box::new(SteamFolderNotFound { return Err(eyre::format_err!(
location_tried: format!("{:?}", steam_path), "Steam folder not found at: {:?}",
})); steam_path
));
} }
let user_data_path = steam_path.join("userdata"); let user_data_path = steam_path.join("userdata");
if !user_data_path.exists() { if !user_data_path.exists() {
return Result::Err(Box::new(SteamFolderNotFound { return Err(eyre::format_err!(
location_tried: format!("{:?}", user_data_path), "Steam user data folder not found at: {:?}",
})); user_data_path
));
} }
if !user_data_path.exists() {} if !user_data_path.exists() {}
@@ -89,7 +89,7 @@ pub fn get_shortcuts_paths(
if shortcuts_path.exists() { if shortcuts_path.exists() {
return SteamUsersInfo { return SteamUsersInfo {
steam_user_data_folder: folder_string, steam_user_data_folder: folder_string,
shortcut_path: Some(shortcuts_path.to_str().unwrap().to_string()), shortcut_path: Some(shortcuts_path.to_string_lossy().to_string()),
user_id, user_id,
}; };
} else { } else {
@@ -104,7 +104,7 @@ pub fn get_shortcuts_paths(
Ok(users_info) Ok(users_info)
} }
pub fn get_steam_path(settings: &SteamSettings) -> Result<String, Box<dyn Error + Sync + Send>> { pub fn get_steam_path(settings: &SteamSettings) -> eyre::Result<String> {
let user_location = settings.location.clone(); let user_location = settings.location.clone();
let steam_path_str = match user_location { let steam_path_str = match user_location {
Some(location) => location, Some(location) => location,
@@ -113,7 +113,7 @@ pub fn get_steam_path(settings: &SteamSettings) -> Result<String, Box<dyn Error
Ok(steam_path_str) Ok(steam_path_str)
} }
pub fn get_default_location() -> Result<String, Box<dyn Error + Sync + Send>> { pub fn get_default_location() -> eyre::Result<String> {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let path_string = { let path_string = {
let key = "PROGRAMFILES(X86)"; let key = "PROGRAMFILES(X86)";
@@ -198,8 +198,8 @@ impl Error for SteamUsersDataEmpty {
self.location_tried.as_str() self.location_tried.as_str()
} }
} }
pub fn get_users_images(user: &SteamUsersInfo) -> Result<Vec<String>, Box<dyn Error>> { pub fn get_users_images(data_folder: &str) -> Result<Vec<String>, Box<dyn Error>> {
let grid_folder = Path::new(user.steam_user_data_folder.as_str()).join("config/grid"); let grid_folder = Path::new(data_folder).join("config/grid");
if !grid_folder.exists() { if !grid_folder.exists() {
std::fs::create_dir_all(&grid_folder)?; std::fs::create_dir_all(&grid_folder)?;
} }
+14 -7
View File
@@ -19,7 +19,9 @@ impl<'a> CachedSearch<'a> {
} }
pub fn save(&self) { pub fn save(&self) {
save_search_map(&self.search_map); if let Err(err) = save_search_map(&self.search_map){
eprintln!("Failed saving searchmap : {:?}",err);
}
} }
pub fn set_cache<S>(&mut self, app_id: u32, name: S, new_grid_id: usize) pub fn set_cache<S>(&mut self, app_id: u32, name: S, new_grid_id: usize)
@@ -58,16 +60,21 @@ impl<'a> CachedSearch<'a> {
fn get_search_map() -> SearchMap { fn get_search_map() -> SearchMap {
let path = get_cache_file(); let path = get_cache_file();
if path.exists() { if path.exists() {
let string = std::fs::read_to_string(path).unwrap(); std::fs::read_to_string(path)
serde_json::from_str::<SearchMap>(&string).expect("Failed to parse cache.json") .ok()
.and_then(|string| {
serde_json::from_str::<SearchMap>(&string).ok()
})
.unwrap_or_default()
} else { } else {
SearchMap::new() SearchMap::new()
} }
} }
fn save_search_map(search_map: &SearchMap) { fn save_search_map(search_map: &SearchMap) -> eyre::Result<()> {
let string = serde_json::to_string(search_map).unwrap(); let string = serde_json::to_string(search_map)?;
let path = get_cache_file(); let path = get_cache_file();
let mut file = File::create(path).unwrap(); let mut file = File::create(path)?;
file.write_all(string.as_bytes()).unwrap(); file.write_all(string.as_bytes())?;
Ok(())
} }
+73 -38
View File
@@ -23,10 +23,31 @@ use crate::sync::SyncProgress;
const CONCURRENT_REQUESTS: usize = 10; const CONCURRENT_REQUESTS: usize = 10;
impl SearchSettings for Settings {
fn download_animated(&self) -> bool {
self.steamgrid_db.prefer_animated
}
fn download_big_picture(&self) -> bool {
self.steam.optimize_for_big_picture
}
fn allow_nsfw(&self) -> bool {
self.steamgrid_db.allow_nsfw
}
fn only_download_boilr_images(&self) -> bool {
self.steamgrid_db.only_download_boilr_images
}
fn is_image_banned(&self, image_type: &ImageType, app_id: u32) -> bool {
self.steamgrid_db.is_image_banned(image_type, app_id)
}
}
pub async fn download_images_for_users<'b>( pub async fn download_images_for_users<'b>(
settings: &Settings, settings: &Settings,
users: &[SteamUsersInfo], users: &[SteamUsersInfo],
download_animated: bool,
sender: &mut Option<Sender<SyncProgress>>, sender: &mut Option<Sender<SyncProgress>>,
) { ) {
let auth_key = &settings.steamgrid_db.auth_key; let auth_key = &settings.steamgrid_db.auth_key;
@@ -40,24 +61,29 @@ pub async fn download_images_for_users<'b>(
if let Some(sender) = sender { if let Some(sender) = sender {
let _ = sender.send(SyncProgress::FindingImages); let _ = sender.send(SyncProgress::FindingImages);
} }
let to_downloads = stream::iter(users)
.map(|user| { let users_info = users.iter().filter_map(|user| {
let shortcut_info = get_shortcuts_for_user(user); let shortcut_info = get_shortcuts_for_user(user);
async move { shortcut_info
let known_images = get_users_images(user).unwrap_or_default(); .map(|shortcut_info| {
let res = search_for_images_to_download( let data_folder = &user.steam_user_data_folder;
known_images, (shortcut_info, data_folder)
user.steam_user_data_folder.as_str(), })
&shortcut_info.shortcuts, .ok()
search, });
client, let to_downloads = stream::iter(users_info)
download_animated, .map(|(shortcut_info, data_folder)| async move {
settings.steam.optimize_for_big_picture, let known_images = get_users_images(data_folder).unwrap_or_default();
settings, let res = search_for_images_to_download(
) known_images,
.await; data_folder.as_str(),
res.unwrap_or_default() &shortcut_info.shortcuts,
} search,
client,
settings,
)
.await;
res.unwrap_or_default()
}) })
.buffer_unordered(CONCURRENT_REQUESTS) .buffer_unordered(CONCURRENT_REQUESTS)
.collect::<Vec<Vec<ToDownload>>>() .collect::<Vec<Vec<ToDownload>>>()
@@ -128,15 +154,21 @@ pub struct PublicGameResponse {
data: Option<PublicGameResponseData>, data: Option<PublicGameResponseData>,
} }
async fn search_for_images_to_download( pub trait SearchSettings {
fn download_animated(&self) -> bool;
fn download_big_picture(&self) -> bool;
fn allow_nsfw(&self) -> bool;
fn only_download_boilr_images(&self) -> bool;
fn is_image_banned(&self, image_type: &ImageType, app_id: u32) -> bool;
}
async fn search_for_images_to_download<T: SearchSettings>(
known_images: Vec<String>, known_images: Vec<String>,
user_data_folder: &str, user_data_folder: &str,
shortcuts: &[ShortcutOwned], shortcuts: &[ShortcutOwned],
search: &CachedSearch<'_>, search: &CachedSearch<'_>,
client: &Client, client: &Client,
download_animated: bool, search_settins: &T,
download_big_picture: bool,
settings: &Settings,
) -> Result<Vec<ToDownload>, Box<dyn Error>> { ) -> Result<Vec<ToDownload>, Box<dyn Error>> {
let types = { let types = {
let mut types = vec![ let mut types = vec![
@@ -146,7 +178,7 @@ async fn search_for_images_to_download(
ImageType::WideGrid, ImageType::WideGrid,
ImageType::Icon, ImageType::Icon,
]; ];
if download_big_picture { if search_settins.download_big_picture() {
types.push(ImageType::BigPicture); types.push(ImageType::BigPicture);
} }
types types
@@ -154,7 +186,7 @@ async fn search_for_images_to_download(
let shortcuts_to_search_for = shortcuts let shortcuts_to_search_for = shortcuts
.iter() .iter()
.filter(|s| !settings.steamgrid_db.only_download_boilr_images || s.is_boilr_shortcut()) .filter(|s| !search_settins.only_download_boilr_images() || s.is_boilr_shortcut())
.filter(|s| { .filter(|s| {
// if we are missing any of the images we need to search for them // if we are missing any of the images we need to search for them
types types
@@ -171,13 +203,10 @@ async fn search_for_images_to_download(
let search_results_a = stream::iter(shortcuts_to_search_for) let search_results_a = stream::iter(shortcuts_to_search_for)
.map(|s| async move { .map(|s| async move {
let search_result = search.search(s.app_id, &s.app_name).await; let search_result = search.search(s.app_id, &s.app_name).await;
if search_result.is_err() { match search_result {
return None; Ok(Some(search_result)) => Some((s.app_id, search_result)),
_ => None,
} }
let search_result = search_result.unwrap();
search_result?;
let search_result = search_result.unwrap();
Some((s.app_id, search_result))
}) })
.buffer_unordered(CONCURRENT_REQUESTS) .buffer_unordered(CONCURRENT_REQUESTS)
.collect::<Vec<Option<(u32, usize)>>>() .collect::<Vec<Option<(u32, usize)>>>()
@@ -192,7 +221,7 @@ async fn search_for_images_to_download(
let images_needed = shortcuts let images_needed = shortcuts
.iter() .iter()
.filter(|s| search_results.contains_key(&s.app_id)) .filter(|s| search_results.contains_key(&s.app_id))
.filter(|s| !settings.steamgrid_db.is_image_banned(&image_type, s.app_id)) .filter(|s| !search_settins.is_image_banned(&image_type, s.app_id))
.filter(|s| !known_images.contains(&image_type.file_name_no_extension(s.app_id))); .filter(|s| !known_images.contains(&image_type.file_name_no_extension(s.app_id)));
let image_ids: Vec<usize> = images_needed let image_ids: Vec<usize> = images_needed
.clone() .clone()
@@ -203,8 +232,14 @@ async fn search_for_images_to_download(
let shortcuts: Vec<&ShortcutOwned> = images_needed.collect(); let shortcuts: Vec<&ShortcutOwned> = images_needed.collect();
for image_ids in image_ids.chunks(99) { for image_ids in image_ids.chunks(99) {
let image_search_result = let image_search_result = get_images_for_ids(
get_images_for_ids(client, image_ids, &image_type, download_animated, settings.steamgrid_db.allow_nsfw).await; client,
image_ids,
&image_type,
search_settins.download_animated(),
search_settins.allow_nsfw(),
)
.await;
match image_search_result { match image_search_result {
Ok(images) => { Ok(images) => {
let images = images let images = images
@@ -237,7 +272,7 @@ async fn search_for_images_to_download(
to_download.extend(download_for_this_type); to_download.extend(download_for_this_type);
} }
Err(err) => println!("Error getting images: {}", err), Err(err) => eprintln!("Error getting images: {}", err),
} }
} }
} }
@@ -388,17 +423,17 @@ fn icon_url(steam_app_id: &str, icon_id: &str) -> String {
) )
} }
pub async fn download_to_download(to_download: &ToDownload) -> Result<(), Box<dyn Error>> { pub async fn download_to_download(to_download: &ToDownload) -> eyre::Result<()> {
println!( println!(
"Downloading {:?} for {} to {:?}", "Downloading {:?} for {} to {:?}",
to_download.image_type, to_download.app_name, to_download.path to_download.image_type, to_download.app_name, to_download.path
); );
let path = &to_download.path; let path = &to_download.path;
let url = &to_download.url; let url = &to_download.url;
let mut file = File::create(path).unwrap(); let mut file = File::create(path)?;
let response = reqwest::get(url).await?; let response = reqwest::get(url).await?;
let content = response.bytes().await?; let content = response.bytes().await?;
file.write_all(&content).unwrap(); file.write_all(&content)?;
Ok(()) Ok(())
} }
+36 -27
View File
@@ -34,15 +34,16 @@ pub fn disconnect_shortcut(settings: &Settings, app_id: u32) -> Result<(), Strin
.map_err(|e| format!("Getting shortcut paths failed: {e}"))?; .map_err(|e| format!("Getting shortcut paths failed: {e}"))?;
for user in userinfo_shortcuts.iter_mut() { for user in userinfo_shortcuts.iter_mut() {
let mut shortcut_info = get_shortcuts_for_user(user); let shortcut_info = get_shortcuts_for_user(user);
if let Ok(mut shortcut_info) = shortcut_info {
for shortcut in shortcut_info.shortcuts.iter_mut() { for shortcut in shortcut_info.shortcuts.iter_mut() {
if shortcut.app_id == app_id { if shortcut.app_id == app_id {
shortcut.dev_kit_game_id = "".to_string(); shortcut.dev_kit_game_id = "".to_string();
shortcut.tags.retain(|s| s != BOILR_TAG); shortcut.tags.retain(|s| s != BOILR_TAG);
}
} }
save_shortcuts(&shortcut_info.shortcuts, Path::new(&shortcut_info.path));
} }
save_shortcuts(&shortcut_info.shortcuts, Path::new(&shortcut_info.path));
} }
Ok(()) Ok(())
@@ -53,9 +54,8 @@ pub fn sync_shortcuts(
platform_shortcuts: &[(String, Vec<ShortcutOwned>)], platform_shortcuts: &[(String, Vec<ShortcutOwned>)],
sender: &mut Option<Sender<SyncProgress>>, sender: &mut Option<Sender<SyncProgress>>,
renames: &HashMap<u32, String>, renames: &HashMap<u32, String>,
) -> Result<Vec<SteamUsersInfo>, String> { ) -> eyre::Result<Vec<SteamUsersInfo>> {
let mut userinfo_shortcuts = get_shortcuts_paths(&settings.steam) let mut userinfo_shortcuts = get_shortcuts_paths(&settings.steam)?;
.map_err(|e| format!("Getting shortcut paths failed: {e}"))?;
let mut all_shortcuts: Vec<ShortcutOwned> = platform_shortcuts let mut all_shortcuts: Vec<ShortcutOwned> = platform_shortcuts
.iter() .iter()
.flat_map(|s| s.1.clone()) .flat_map(|s| s.1.clone())
@@ -86,10 +86,14 @@ pub fn sync_shortcuts(
println!("Appid: {} name: {}", shortcut.app_id, shortcut.app_name); println!("Appid: {} name: {}", shortcut.app_id, shortcut.app_name);
} }
println!("Found {} user(s)", userinfo_shortcuts.len()); println!("Found {} user(s)", userinfo_shortcuts.len());
for user in userinfo_shortcuts.iter_mut() { let ok_shorcuts = userinfo_shortcuts.iter_mut().filter_map(|user|{
let shortcut_info = get_shortcuts_for_user(user).ok();
shortcut_info.map(|shortcut_info| {
(user,shortcut_info)
})
});
for (user,mut shortcut_info) in ok_shorcuts {
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
let mut shortcut_info = get_shortcuts_for_user(user);
println!( println!(
"Found {} shortcuts for user: {}", "Found {} shortcuts for user: {}",
shortcut_info.shortcuts.len(), shortcut_info.shortcuts.len(),
@@ -122,11 +126,12 @@ pub async fn download_images(
sender: &mut Option<Sender<SyncProgress>>, sender: &mut Option<Sender<SyncProgress>>,
) { ) {
if settings.steamgrid_db.enabled { if settings.steamgrid_db.enabled {
if settings.steamgrid_db.prefer_animated { download_images_for_users(settings, userinfo_shortcuts, sender).await;
println!("downloading animated images"); if settings.steamgrid_db.prefer_animated{
download_images_for_users(settings, userinfo_shortcuts, true, sender).await; let mut set = settings.clone();
set.steamgrid_db.prefer_animated = false;
download_images_for_users(&set, userinfo_shortcuts, sender).await;
} }
download_images_for_users(settings, userinfo_shortcuts, false, sender).await;
} }
} }
@@ -157,21 +162,25 @@ fn remove_old_shortcuts(shortcut_info: &mut ShortcutInfo) {
.retain(|shortcut| !shortcut.is_boilr_shortcut()); .retain(|shortcut| !shortcut.is_boilr_shortcut());
} }
pub fn fix_all_shortcut_icons ( pub fn fix_all_shortcut_icons(settings: &Settings) -> eyre::Result<()> {
settings: &Settings, let mut userinfo_shortcuts = get_shortcuts_paths(&settings.steam)
) -> eyre::Result<()>{ .map_err(|e| eyre::format_err!("Could not find steam shortcuts; {e}"))?;
let mut userinfo_shortcuts = get_shortcuts_paths(&settings.steam).map_err(|e|eyre::format_err!("Could not find steam shortcuts; {e}"))?;
for user in userinfo_shortcuts.iter_mut() { for user in userinfo_shortcuts.iter_mut() {
let mut shortcut_info = get_shortcuts_for_user(user); let shortcut_info = get_shortcuts_for_user(user);
let changes = fix_shortcut_icons(user,&mut shortcut_info.shortcuts,settings.steam.optimize_for_big_picture); if let Ok(mut shortcut_info) = shortcut_info {
if changes{ let changes = fix_shortcut_icons(
save_shortcuts(&shortcut_info.shortcuts, Path::new(&shortcut_info.path)); user,
&mut shortcut_info.shortcuts,
settings.steam.optimize_for_big_picture,
);
if changes {
save_shortcuts(&shortcut_info.shortcuts, Path::new(&shortcut_info.path));
}
} }
} }
Ok(()) Ok(())
} }
fn fix_shortcut_icons( fn fix_shortcut_icons(
user: &SteamUsersInfo, user: &SteamUsersInfo,
shortcuts: &mut Vec<ShortcutOwned>, shortcuts: &mut Vec<ShortcutOwned>,
@@ -194,7 +203,7 @@ fn fix_shortcut_icons(
let path = image_folder.join(image_type.file_name(app_id, ext)); let path = image_folder.join(image_type.file_name(app_id, ext));
if !icon_exsists && path.exists() { if !icon_exsists && path.exists() {
shortcut.icon = path.to_string_lossy().to_string(); shortcut.icon = path.to_string_lossy().to_string();
has_changes= true; has_changes = true;
break; break;
} }
} }
+172 -133
View File
@@ -1,147 +1,186 @@
use std::path::Path; use std::path::{Path, PathBuf};
use egui::{Button, ImageButton}; use egui::{Button, ImageButton};
use futures::executor::block_on; use futures::executor::block_on;
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
use crate::steamgriddb::{ImageType, ToDownload}; use crate::steamgriddb::{ToDownload, ImageType};
use crate::ui::images::{clamp_to_width, ImageHandles, TextureDownloadState}; use crate::ui::images::{clamp_to_width, ImageHandles, TextureDownloadState};
use crate::ui::ui_images::load_image_from_path; use crate::ui::ui_images::load_image_from_path;
pub struct GameButton {
pub fn render_image_from_path( path: PathBuf,
ui: &mut egui::Ui,
image_handles: &ImageHandles,
path: &Path,
max_width: f32, max_width: f32,
text: &str, text: String,
) -> bool { image_type: ImageType,
render_possible_image(ui, image_handles, path, max_width, text, &ImageType::Grid, None, None)
} }
pub fn render_image_from_path_image_type( impl GameButton {
ui: &mut egui::Ui, pub fn new(path: &Path) -> Self {
image_handles: &ImageHandles, Self {
path: &Path, max_width: 200.0,
max_width: f32, path: path.to_path_buf(),
text: &str, text: Default::default(),
image_type: &ImageType, image_type: ImageType::Grid,
) -> bool { }
render_possible_image(ui, image_handles, path, max_width, text, image_type, None, None) }
} pub fn width(&mut self, max_width: f32) -> &mut Self {
self.max_width = max_width;
self
pub fn render_image_from_path_or_url( }
ui: &mut egui::Ui,
image_handles: &ImageHandles, pub fn text(&mut self, text: &str) -> &mut Self {
path: &Path, self.text = text.to_string();
max_width: f32, self
text: &str, }
image_type: &ImageType,
rt: &Runtime, pub fn image_type(&mut self, image_type:&ImageType) -> &mut Self{
url: &str, self.image_type = *image_type;
) -> bool { self
render_possible_image( }
ui,
image_handles, pub fn show_download(
path, &self,
max_width, ui: &mut egui::Ui,
text, image_handles: &ImageHandles,
image_type, rt: &Runtime,
Some(rt), url: &str,
Some(url), ) -> bool {
) self.render_possible_image(ui, image_handles, Some(rt), Some(url))
} }
fn render_possible_image( pub fn show(&self, ui: &mut egui::Ui, image_handles: &ImageHandles) -> bool {
ui: &mut egui::Ui, self.render_possible_image(ui, image_handles, None, None)
image_handles: &ImageHandles, }
path: &Path,
max_width: f32, fn render_possible_image(
text: &str, &self,
image_type: &ImageType, ui: &mut egui::Ui,
rt: Option<&Runtime>, image_handles: &ImageHandles,
url: Option<&str>, rt: Option<&Runtime>,
) -> bool { url: Option<&str>,
let image_key = path.to_string_lossy().to_string(); ) -> bool {
{
match image_handles.get_mut(&image_key) { let path = &self.path;
Some(mut state) => { let image_key = path.to_string_lossy().to_string();
match state.value() { match image_handles.get_mut(&image_key) {
TextureDownloadState::Downloading => { Some(mut state) => {
ui.ctx().request_repaint(); match state.value() {
//nothing to do,just wait TextureDownloadState::Downloading => {
ui.spinner(); ui.ctx().request_repaint();
} //nothing to do,just wait
TextureDownloadState::Downloaded => { ui.spinner();
//Need to load }
let image_data = load_image_from_path(path); TextureDownloadState::Downloaded => {
match image_data { //Need to load
Ok(image_data) => { let image_data = load_image_from_path(path);
let handle = ui.ctx().load_texture( match image_data {
&image_key, Ok(image_data) => {
image_data, let handle = ui.ctx().load_texture(
egui::TextureOptions::LINEAR, &image_key,
); image_data,
*state.value_mut() = TextureDownloadState::Loaded(handle); egui::TextureOptions::LINEAR,
ui.spinner(); );
} *state.value_mut() = TextureDownloadState::Loaded(handle);
Err(_) => *state.value_mut() = TextureDownloadState::Failed, ui.spinner();
} }
ui.ctx().request_repaint(); Err(_) => *state.value_mut() = TextureDownloadState::Failed,
} }
TextureDownloadState::Loaded(texture_handle) => { ui.ctx().request_repaint();
//need to show }
let mut size = texture_handle.size_vec2(); TextureDownloadState::Loaded(texture_handle) => {
clamp_to_width(&mut size, max_width); //need to show
let image_button = ImageButton::new(texture_handle, size); let mut size = texture_handle.size_vec2();
if ui clamp_to_width(&mut size, self.max_width);
.add_sized(size, image_button) let image_button = ImageButton::new(texture_handle, size);
.on_hover_text(text) if ui
.clicked() .add_sized(size, image_button)
{ .on_hover_text(&self.text)
return true; .clicked()
} {
} return true;
TextureDownloadState::Failed => { }
let button = }
ui.add_sized([max_width, max_width * image_type.ratio()], Button::new(text).wrap(true)); TextureDownloadState::Failed => {
if button.clicked() { let button = ui.add_sized(
return true; [self.max_width, self.max_width * self.image_type.ratio()],
} Button::new(&self.text).wrap(true),
} );
} if button.clicked() {
} return true;
None => { }
if !path.exists() && url.is_none() { }
image_handles.insert(image_key, TextureDownloadState::Failed); }
} else { }
//We need to start a download None => {
//Redownload if file is too small match url {
if !path.exists() Some(url) => {
|| std::fs::metadata(path).map(|m| m.len()).unwrap_or_default() < 2 download_image(
{ path,
image_handles.insert(image_key.clone(), TextureDownloadState::Downloading); image_handles,
let to_download = ToDownload { &image_key,
path: path.to_path_buf(), url,
url: url.unwrap().to_string(), &self.image_type,
app_name: "Thumbnail".to_string(), rt,
image_type: *image_type, );
}; }
let image_handles = image_handles.clone(); None => {
let image_key = image_key.clone(); //Not possible to download
if let Some(rt) = rt { if !path.exists() {
rt.spawn_blocking(move || { image_handles.insert(image_key, TextureDownloadState::Failed);
block_on(crate::steamgriddb::download_to_download(&to_download)) }
.unwrap(); }
image_handles.insert(image_key, TextureDownloadState::Downloaded); }
}); }
} }
} else { false
image_handles.insert(image_key.clone(), TextureDownloadState::Downloaded);
}
}
} }
} }
false }
impl Default for GameButton {
fn default() -> Self {
Self::new(Path::new(""))
}
}
fn download_image(
path: &Path,
image_handles: &ImageHandles,
image_key: &str,
url: &str,
image_type: &ImageType,
rt: Option<&Runtime>,
) {
//We need to start a download
//Redownload if file is too small
if !path.exists() || std::fs::metadata(path).map(|m| m.len()).unwrap_or_default() < 2 {
image_handles.insert(image_key.to_string(), TextureDownloadState::Downloading);
let to_download = ToDownload {
path: path.to_path_buf(),
url: url.to_string(),
app_name: "Thumbnail".to_string(),
image_type: *image_type,
};
let image_handles = image_handles.clone();
let image_key = image_key.to_string();
if let Some(rt) = rt {
rt.spawn_blocking(move || {
match block_on(crate::steamgriddb::download_to_download(&to_download)) {
Ok(_) => {
image_handles.insert(image_key, TextureDownloadState::Downloaded);
}
Err(err) => {
println!(
"Failed downloading image {} error: {:?}",
to_download.url, err
);
image_handles.insert(image_key, TextureDownloadState::Failed);
}
}
});
}
} else {
image_handles.insert(image_key.to_string(), TextureDownloadState::Downloaded);
}
} }
+1 -3
View File
@@ -2,6 +2,4 @@ mod steam_user_select;
mod game_image_button; mod game_image_button;
pub use steam_user_select::render_user_select; pub use steam_user_select::render_user_select;
pub use game_image_button::render_image_from_path; pub use game_image_button::GameButton;
pub use game_image_button::render_image_from_path_or_url;
pub use game_image_button::render_image_from_path_image_type;
+4 -4
View File
@@ -23,19 +23,19 @@ pub mod ui_images {
pub const LOGO_ICON: &[u8] = include_bytes!("../../resources/logo_small.png"); pub const LOGO_ICON: &[u8] = include_bytes!("../../resources/logo_small.png");
pub fn get_import_image() -> ImageData { pub fn get_import_image() -> ImageData {
ImageData::Color(load_image_from_memory(IMPORT_GAMES_IMAGE).unwrap()) ImageData::Color(load_image_from_memory(IMPORT_GAMES_IMAGE).unwrap_or_default())
} }
pub fn get_save_image() -> ImageData { pub fn get_save_image() -> ImageData {
ImageData::Color(load_image_from_memory(SAVE_IMAGE).unwrap()) ImageData::Color(load_image_from_memory(SAVE_IMAGE).unwrap_or_default())
} }
pub fn get_logo() -> ImageData { pub fn get_logo() -> ImageData {
ImageData::Color(load_image_from_memory(LOGO_32).unwrap()) ImageData::Color(load_image_from_memory(LOGO_32).unwrap_or_default())
} }
pub fn get_logo_icon() -> IconData { pub fn get_logo_icon() -> IconData {
let image = image::load_from_memory(LOGO_ICON).unwrap(); let image = image::load_from_memory(LOGO_ICON).unwrap_or_default();
let image_buffer = image.to_rgba8(); let image_buffer = image.to_rgba8();
let pixels = image_buffer.as_flat_samples(); let pixels = image_buffer.as_flat_samples();
IconData { IconData {
+1 -1
View File
@@ -6,7 +6,7 @@ use crate::{steam::SteamGameInfo};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum GameType { pub enum GameType {
Shortcut(ShortcutOwned), Shortcut(Box<ShortcutOwned>),
SteamGame(SteamGameInfo), SteamGame(SteamGameInfo),
} }
+15 -21
View File
@@ -2,19 +2,15 @@ use std::path::{Path, PathBuf};
use steam_shortcuts_util::shortcut::ShortcutOwned; use steam_shortcuts_util::shortcut::ShortcutOwned;
use crate::{steamgriddb::ImageType, steam::SteamGameInfo}; use crate::{steam::SteamGameInfo, steamgriddb::ImageType};
use super::{gametype::GameType, constants::POSSIBLE_EXTENSIONS};
use super::{constants::POSSIBLE_EXTENSIONS, gametype::GameType};
pub trait HasImageKey { pub trait HasImageKey {
///Gives a unique key to an image given its type and user path ///Gives a unique key to an image given its type and user path
fn key(&self, image_type: &ImageType, user_path: &Path) -> (PathBuf, String); fn key(&self, image_type: &ImageType, user_path: &Path) -> (PathBuf, String);
} }
impl HasImageKey for GameType { impl HasImageKey for GameType {
fn key(&self, image_type: &ImageType, user_path: &Path) -> (PathBuf, String) { fn key(&self, image_type: &ImageType, user_path: &Path) -> (PathBuf, String) {
match self { match self {
@@ -24,31 +20,29 @@ impl HasImageKey for GameType {
} }
} }
impl HasImageKey for SteamGameInfo { impl HasImageKey for SteamGameInfo {
fn key(&self, image_type: &ImageType, user_path: &Path) -> (PathBuf, String) { fn key(&self, image_type: &ImageType, user_path: &Path) -> (PathBuf, String) {
let mut keys = POSSIBLE_EXTENSIONS let app_id = self.appid;
.iter() key(app_id, image_type, user_path)
.map(|ext| key_from_extension(self.appid, image_type, user_path, ext));
let first = keys.next().unwrap();
let other = keys.find(|(exsists, _, _)| *exsists);
let (_, path, key) = other.unwrap_or(first);
(path, key)
} }
} }
impl HasImageKey for ShortcutOwned { impl HasImageKey for ShortcutOwned {
fn key(&self, image_type: &ImageType, user_path: &Path) -> (PathBuf, String) { fn key(&self, image_type: &ImageType, user_path: &Path) -> (PathBuf, String) {
let mut keys = POSSIBLE_EXTENSIONS let app_id = self.app_id;
.iter() key(app_id, image_type, user_path)
.map(|ext| key_from_extension(self.app_id, image_type, user_path, ext));
let first = keys.next().unwrap();
let other = keys.find(|(exsists, _, _)| *exsists);
let (_, path, key) = other.unwrap_or(first);
(path, key)
} }
} }
fn key(app_id: u32, image_type: &ImageType, user_path: &Path) -> (PathBuf, String) {
let ext = |ext| key_from_extension(app_id, image_type, user_path, ext);
let keys = POSSIBLE_EXTENSIONS.map(ext);
let other = keys.iter().find(|(exsists, _, _)| *exsists);
let first = ext(POSSIBLE_EXTENSIONS[0]);
let (_, path, key) = other.unwrap_or(&first);
(path.to_path_buf(), key.to_string())
}
fn key_from_extension( fn key_from_extension(
app_id: u32, app_id: u32,
image_type: &ImageType, image_type: &ImageType,
+77 -83
View File
@@ -1,20 +1,18 @@
use std::path::Path; use std::path::{Path, PathBuf};
use egui::{Grid, }; use egui::Grid;
use futures::executor::block_on; use futures::executor::block_on;
use tokio::{ sync::watch}; use tokio::sync::watch;
use crate::{ use crate::{
steamgriddb::{get_image_extension, ImageType, ToDownload}, steamgriddb::{get_image_extension, ImageType, ToDownload},
ui::{ ui::{
components::GameButton,
images::{ images::{
constants::MAX_WIDTH, constants::MAX_WIDTH, hasimagekey::HasImageKey, image_select_state::ImageSelectState,
hasimagekey::HasImageKey, possible_image::PossibleImage, useraction::UserAction,
image_select_state::{ ImageSelectState},
possible_image::PossibleImage,
useraction::UserAction,
}, },
FetcStatus, MyEguiApp, components::render_image_from_path_or_url, FetcStatus, MyEguiApp,
}, },
}; };
@@ -61,16 +59,10 @@ pub fn render_page_pick_image(
.show(ui, |ui| { .show(ui, |ui| {
for image in images { for image in images {
let path = image.thumbnail_path.as_path(); let path = image.thumbnail_path.as_path();
if render_image_from_path_or_url( let mut button = GameButton::new(path);
ui, button.width(column_width);
&state.image_handles, button.text("Pick image");
path, if button.show_download(ui, &state.image_handles, &app.rt,&image.thumbnail_url) {
column_width,
&image.full_url,
image_type,
&app.rt,
&image.thumbnail_url,
) {
return Some(image.clone()); return Some(image.clone());
} }
column += 1; column += 1;
@@ -82,9 +74,9 @@ pub fn render_page_pick_image(
None None
}) })
.inner; .inner;
if let Some(x) = x { if let Some(x) = x {
return Some(UserAction::ImageSelected(x)); return Some(UserAction::ImageSelected(x));
} }
} }
_ => { _ => {
ui.horizontal(|ui| { ui.horizontal(|ui| {
@@ -99,76 +91,78 @@ pub fn render_page_pick_image(
pub fn handle_image_selected(app: &mut MyEguiApp, image: PossibleImage) { pub fn handle_image_selected(app: &mut MyEguiApp, image: PossibleImage) {
//We must have a user here //We must have a user here
let user = app.image_selected_state.steam_user.as_ref().unwrap(); let state = &app.image_selected_state;
let selected_image_type = app if let (Some(user), Some(selected_image_type), Some(selected_shortcut)) = (
.image_selected_state state.steam_user.as_ref(),
.image_type_selected state.image_type_selected.as_ref(),
.as_ref() state.selected_shortcut.as_ref(),
.unwrap(); ) {
let selected_shortcut = app.image_selected_state.selected_shortcut.as_ref().unwrap(); let get_image_extension = &get_image_extension(&image.mime);
let ext = get_image_extension;
let to_download_to_path = Path::new(&user.steam_user_data_folder)
.join("config")
.join("grid")
.join(selected_image_type.file_name(selected_shortcut.app_id(), ext));
let ext = get_image_extension(&image.mime); delete_images_of_type(user, selected_shortcut, selected_image_type);
let to_download_to_path = Path::new(&user.steam_user_data_folder)
.join("config")
.join("grid")
.join(selected_image_type.file_name(selected_shortcut.app_id(), ext));
//Delete old possible images //Put the loaded thumbnail into the image handler map, we can use that for preview
let full_image_key = to_download_to_path.to_string_lossy().to_string();
let data_folder = Path::new(&user.steam_user_data_folder); let _ = app
.image_selected_state
//Keep deleting images of this type untill we don't find any more
let mut path = get_shortcut_image_path(app, data_folder);
while Path::new(&path).exists() {
let _ = std::fs::remove_file(&path);
path = get_shortcut_image_path(app, data_folder);
}
//Put the loaded thumbnail into the image handler map, we can use that for preview
let full_image_key = to_download_to_path.to_string_lossy().to_string();
let _ = app
.image_selected_state
.image_handles
.remove(&full_image_key);
let thumbnail_key = image.thumbnail_path.to_string_lossy().to_string();
let thumbnail = app
.image_selected_state
.image_handles
.remove(&thumbnail_key);
if let Some((_key, thumbnail)) = thumbnail {
app.image_selected_state
.image_handles .image_handles
.insert(full_image_key, thumbnail); .remove(&full_image_key);
} let thumbnail_key = image.thumbnail_path.to_string_lossy().to_string();
let thumbnail = app
.image_selected_state
.image_handles
.remove(&thumbnail_key);
if let Some((_key, thumbnail)) = thumbnail {
app.image_selected_state
.image_handles
.insert(full_image_key, thumbnail);
}
let app_name = selected_shortcut.name(); let app_name = selected_shortcut.name();
let to_download = ToDownload { let to_download = ToDownload {
path: to_download_to_path, path: to_download_to_path,
url: image.full_url.clone(), url: image.full_url.clone(),
app_name: app_name.to_string(), app_name: app_name.to_string(),
image_type: *selected_image_type, image_type: *selected_image_type,
}; };
app.rt.spawn_blocking(move || { app.rt.spawn_blocking(move || {
let _ = block_on(crate::steamgriddb::download_to_download(&to_download)); let _ = block_on(crate::steamgriddb::download_to_download(&to_download));
}); });
clear_loaded_images(app); clear_loaded_images(app);
{ {
app.image_selected_state.image_type_selected = None; app.image_selected_state.image_type_selected = None;
app.image_selected_state.image_options = watch::channel(FetcStatus::NeedsFetched).1; app.image_selected_state.image_options = watch::channel(FetcStatus::NeedsFetched).1;
}
} }
} }
fn get_shortcut_image_path(app: &MyEguiApp, data_folder: &Path) -> String { fn delete_images_of_type(
app.image_selected_state user: &crate::steam::SteamUsersInfo,
.selected_shortcut selected_shortcut: &crate::ui::images::gametype::GameType,
.as_ref() selected_image_type: &ImageType,
.unwrap() ) {
.key( //Delete old possible images
&app.image_selected_state.image_type_selected.unwrap(), let data_folder = Path::new(&user.steam_user_data_folder);
data_folder, //Keep deleting images of this type untill we don't find any more
) let mut path = image_path(selected_shortcut, selected_image_type, data_folder);
.1 while path.exists() {
let _ = std::fs::remove_file(path);
path = image_path(selected_shortcut, selected_image_type, data_folder);
}
}
fn image_path(
selected_shortcut: &crate::ui::images::gametype::GameType,
selected_image_type: &ImageType,
data_folder: &Path,
) -> PathBuf {
selected_shortcut.key(selected_image_type, data_folder).0
} }
fn clear_loaded_images(app: &mut MyEguiApp) { fn clear_loaded_images(app: &mut MyEguiApp) {
+57 -52
View File
@@ -1,10 +1,11 @@
use std::path::Path; use std::path::Path;
use crate::ui::components::GameButton;
use crate::ui::images::{ use crate::ui::images::{
gametype::GameType, hasimagekey::HasImageKey, image_select_state::ImageSelectState, gametype::GameType, hasimagekey::HasImageKey, image_select_state::ImageSelectState,
useraction::UserAction, ImageHandles, useraction::UserAction, ImageHandles,
}; };
use crate::{steamgriddb::ImageType, ui::components::render_image_from_path_image_type}; use crate::{steamgriddb::ImageType};
const MAX_WIDTH: f32 = 300.; const MAX_WIDTH: f32 = 300.;
@@ -12,59 +13,65 @@ pub fn render_page_shortcut_select_image_type(
ui: &mut egui::Ui, ui: &mut egui::Ui,
state: &ImageSelectState, state: &ImageSelectState,
) -> Option<UserAction> { ) -> Option<UserAction> {
let shortcut = state.selected_shortcut.as_ref().unwrap(); let shortcut = &state.selected_shortcut.as_ref();
let user_path = &state.steam_user.as_ref().unwrap().steam_user_data_folder; let user_path = state
.steam_user
let thumbnail = |ui: &mut egui::Ui, image_type: &ImageType| { .as_ref()
if render_thumbnail(ui, &state.image_handles, shortcut, image_type, user_path) { .map(|user| &user.steam_user_data_folder);
Some(UserAction::ImageTypeSelected(*image_type)) if let (Some(shortcut), Some(user_path)) = (shortcut, user_path) {
} else { let thumbnail = |ui: &mut egui::Ui, image_type: &ImageType| {
None if render_thumbnail(ui, &state.image_handles, shortcut, image_type, user_path) {
} Some(UserAction::ImageTypeSelected(*image_type))
}; } else {
let x = if ui.available_width() > MAX_WIDTH * 3. { None
ui.horizontal(|ui| {
let x = ui.vertical(|ui| thumbnail(ui, &ImageType::Grid)).inner;
if x.is_some() {
return x;
} }
let x = ui };
.vertical(|ui| { let x = if ui.available_width() > MAX_WIDTH * 3. {
let types = &[ImageType::Hero, ImageType::WideGrid, ImageType::Logo]; ui.horizontal(|ui| {
let x = ui.vertical(|ui| thumbnail(ui, &ImageType::Grid)).inner;
if x.is_some() {
return x;
}
let x = ui
.vertical(|ui| {
let types = &[ImageType::Hero, ImageType::WideGrid, ImageType::Logo];
types
.iter()
.flat_map(|image_type| thumbnail(ui, image_type))
.next()
})
.inner;
if x.is_some() {
return x;
}
ui.vertical(|ui| {
let types = &[ImageType::Icon, ImageType::BigPicture];
types types
.iter() .iter()
.flat_map(|image_type| thumbnail(ui, image_type)) .flat_map(|image_type| thumbnail(ui, image_type))
.next() .next()
}) })
.inner; .inner
if x.is_some() {
return x;
}
ui.vertical(|ui| {
let types = &[ImageType::Icon, ImageType::BigPicture];
types
.iter()
.flat_map(|image_type| thumbnail(ui, image_type))
.next()
}) })
.inner .inner
}) } else {
.inner let types = ImageType::all();
} else { types
let types = ImageType::all(); .iter()
types .flat_map(|image_type| thumbnail(ui, image_type))
.iter() .next()
.flat_map(|image_type| thumbnail(ui, image_type)) };
.next()
};
if ui if ui
.button("Click here if the images are for a wrong game") .button("Click here if the images are for a wrong game")
.clicked() .clicked()
{ {
return Some(UserAction::CorrectGridId); return Some(UserAction::CorrectGridId);
}
x
} else {
None
} }
x
} }
fn render_thumbnail( fn render_thumbnail(
@@ -76,12 +83,10 @@ fn render_thumbnail(
) -> bool { ) -> bool {
let (path, _key) = shortcut.key(image_type, Path::new(&user_path)); let (path, _key) = shortcut.key(image_type, Path::new(&user_path));
let text = format!("Pick {} image", image_type.name()); let text = format!("Pick {} image", image_type.name());
render_image_from_path_image_type( let mut image = GameButton::new(&path);
ui, image
image_handles, .width(MAX_WIDTH)
path.as_path(), .text(&text)
MAX_WIDTH, .image_type(image_type)
&text, .show(ui, image_handles)
image_type,
)
} }
+23 -16
View File
@@ -4,27 +4,30 @@ use steam_shortcuts_util::shortcut::ShortcutOwned;
use crate::{ use crate::{
steam::SteamUsersInfo, steam::SteamUsersInfo,
steamgriddb::{ImageType, CachedSearch}, steamgriddb::{CachedSearch, ImageType},
ui::{ ui::{
images::{ images::{
gametype::GameType, hasimagekey::HasImageKey, gametype::GameType, hasimagekey::HasImageKey, texturestate::TextureDownloadState,
texturestate::TextureDownloadState, useraction::UserAction, useraction::UserAction,
}, },
MyEguiApp, ui_images::load_image_from_path, components::render_image_from_path, ui_images::load_image_from_path,
MyEguiApp, components::GameButton,
}, },
}; };
pub fn render_page_shortcut_images_overview(app: &MyEguiApp, ui: &mut egui::Ui) -> Option<UserAction> { pub fn render_page_shortcut_images_overview(
app: &MyEguiApp,
ui: &mut egui::Ui,
) -> Option<UserAction> {
let user_info = &app.image_selected_state.steam_user;
let shortcuts = &app.image_selected_state.user_shortcuts; let shortcuts = &app.image_selected_state.user_shortcuts;
let width = ui.available_size().x; let width = ui.available_size().x;
let column_width = 100.; let column_width = 100.;
let column_padding = 23.; let column_padding = 23.;
let columns = (width / (column_width + column_padding)).floor() as u32; let columns = (width / (column_width + column_padding)).floor() as u32;
let mut cur_column = 0; let mut cur_column = 0;
match shortcuts { match (user_info, shortcuts) {
Some(shortcuts) => { (Some(user_info), Some(shortcuts)) => {
let user_info = &app.image_selected_state.steam_user.as_ref().unwrap();
if let Some(action) = egui::Grid::new("ui_images") if let Some(action) = egui::Grid::new("ui_images")
.show(ui, |ui| { .show(ui, |ui| {
for shortcut in shortcuts { for shortcut in shortcuts {
@@ -46,7 +49,7 @@ pub fn render_page_shortcut_images_overview(app: &MyEguiApp, ui: &mut egui::Ui)
return action; return action;
} }
} }
None => { _ => {
ui.label("Could not find any shortcuts"); ui.label("Could not find any shortcuts");
} }
} }
@@ -56,7 +59,7 @@ pub fn render_page_shortcut_images_overview(app: &MyEguiApp, ui: &mut egui::Ui)
fn render_image( fn render_image(
app: &MyEguiApp, app: &MyEguiApp,
shortcut: &ShortcutOwned, shortcut: &ShortcutOwned,
user_info: &&SteamUsersInfo, user_info: &SteamUsersInfo,
column_width: f32, column_width: f32,
ui: &mut egui::Ui, ui: &mut egui::Ui,
) -> Option<Option<UserAction>> { ) -> Option<Option<UserAction>> {
@@ -65,18 +68,21 @@ fn render_image(
Path::new(&user_info.steam_user_data_folder), Path::new(&user_info.steam_user_data_folder),
); );
let clicked= render_image_from_path(ui, &app.image_selected_state.image_handles, Path::new(&key), column_width, &shortcut.app_name); let mut button = GameButton::new(Path::new(&key));
button.text(&shortcut.app_name);
button.width(column_width);
let clicked = button.show(ui, &app.image_selected_state.image_handles);
if clicked { if clicked {
return Some(Some(UserAction::ShortcutSelected(GameType::Shortcut( return Some(Some(UserAction::ShortcutSelected(GameType::Shortcut(
shortcut.clone(), Box::new(shortcut.clone()),
)))); ))));
} }
None None
} }
pub fn handle_shortcut_selected(app: &mut MyEguiApp, shortcut: GameType, ui: &mut egui::Ui) { pub fn handle_shortcut_selected(app: &mut MyEguiApp, shortcut: GameType, ui: &mut egui::Ui) {
let state = &mut app.image_selected_state; let state = &mut app.image_selected_state;
//We must have a user to make see this action; //We must have a user to make see this action;
let user = state.steam_user.as_ref().unwrap(); if let Some(user) = state.steam_user.as_ref() {
if let Some(auth_key) = &app.settings.steamgrid_db.auth_key { if let Some(auth_key) = &app.settings.steamgrid_db.auth_key {
let client = steamgriddb_api::Client::new(auth_key); let client = steamgriddb_api::Client::new(auth_key);
let search = CachedSearch::new(&client); let search = CachedSearch::new(&client);
@@ -102,3 +108,4 @@ pub fn handle_shortcut_selected(app: &mut MyEguiApp, shortcut: GameType, ui: &mu
} }
state.selected_shortcut = Some(shortcut); state.selected_shortcut = Some(shortcut);
} }
}
+59 -54
View File
@@ -4,9 +4,9 @@ use super::{
hasimagekey::HasImageKey, hasimagekey::HasImageKey,
image_select_state::ImageSelectState, image_select_state::ImageSelectState,
pages::{ pages::{
handle_correct_grid_request, handle_grid_change, handle_shortcut_selected, handle_correct_grid_request, handle_grid_change, handle_image_selected,
render_page_pick_image, render_page_shortcut_images_overview, handle_shortcut_selected, render_page_pick_image, render_page_shortcut_images_overview,
render_page_shortcut_select_image_type, render_page_steam_images_overview, handle_image_selected, render_page_shortcut_select_image_type, render_page_steam_images_overview,
}, },
possible_image::PossibleImage, possible_image::PossibleImage,
texturestate::TextureDownloadState, texturestate::TextureDownloadState,
@@ -157,7 +157,7 @@ impl MyEguiApp {
self.handle_image_type_selected(image_type); self.handle_image_type_selected(image_type);
} }
UserAction::ImageSelected(image) => { UserAction::ImageSelected(image) => {
handle_image_selected(self,image); handle_image_selected(self, image);
} }
UserAction::BackButton => { UserAction::BackButton => {
self.handle_back_button_action(); self.handle_back_button_action();
@@ -197,11 +197,13 @@ impl MyEguiApp {
.image_selected_state .image_selected_state
.selected_shortcut .selected_shortcut
.as_ref() .as_ref()
.unwrap() .map(|m| m.app_id());
.app_id(); if let Some(app_id) = app_id {
self.settings self.settings
.steamgrid_db .steamgrid_db
.set_image_banned(&image_type, app_id, should_ban); .set_image_banned(&image_type, app_id, should_ban);
}
self.handle_image_type_clear(image_type); self.handle_image_type_clear(image_type);
} }
@@ -222,38 +224,39 @@ impl MyEguiApp {
self.rt.spawn_blocking(move || { self.rt.spawn_blocking(move || {
let task = download_images(&settings, &users, &mut sender_op); let task = download_images(&settings, &users, &mut sender_op);
block_on(task); block_on(task);
let _ = sender_op.unwrap().send(SyncProgress::Done); if let Some(sender_op) = sender_op {
let _ = sender_op.send(SyncProgress::Done);
}
}); });
} }
} }
fn handle_image_type_clear(&mut self, image_type: ImageType) { fn handle_image_type_clear(&mut self, image_type: ImageType) {
let app_id = self
.image_selected_state
.selected_shortcut
.as_ref()
.map(|s| s.app_id());
let data_folder = &self let data_folder = &self
.image_selected_state .image_selected_state
.steam_user .steam_user
.as_ref() .as_ref()
.unwrap() .map(|s| &s.steam_user_data_folder);
.steam_user_data_folder; if let (Some(app_id), Some(data_folder)) = (app_id, data_folder) {
for ext in POSSIBLE_EXTENSIONS { for ext in POSSIBLE_EXTENSIONS {
let file_name = image_type.file_name( let file_name = image_type.file_name(app_id, ext);
self.image_selected_state let path = Path::new(data_folder)
.selected_shortcut .join("config")
.as_ref() .join("grid")
.unwrap() .join(file_name);
.app_id(), if path.exists() {
ext, let _ = std::fs::remove_file(&path);
); }
let path = Path::new(data_folder) let key = path.to_string_lossy().to_string();
.join("config") self.image_selected_state.image_handles.remove(&key);
.join("grid")
.join(file_name);
if path.exists() {
let _ = std::fs::remove_file(&path);
} }
let key = path.to_string_lossy().to_string(); self.image_selected_state.image_type_selected = None;
self.image_selected_state.image_handles.remove(&key);
} }
self.image_selected_state.image_type_selected = None;
} }
fn handle_set_game_mode(&mut self, game_mode: GameMode) { fn handle_set_game_mode(&mut self, game_mode: GameMode) {
@@ -304,11 +307,6 @@ impl MyEguiApp {
}; };
} }
fn handle_back_button_action(&mut self) { fn handle_back_button_action(&mut self) {
let state = &mut self.image_selected_state; let state = &mut self.image_selected_state;
if state.possible_names.is_some() { if state.possible_names.is_some() {
@@ -331,28 +329,35 @@ fn load_image_grids(
ui: &mut egui::Ui, ui: &mut egui::Ui,
) -> Vec<ShortcutOwned> { ) -> Vec<ShortcutOwned> {
let user_info = crate::steam::get_shortcuts_for_user(user); let user_info = crate::steam::get_shortcuts_for_user(user);
let mut user_folder = user_info.path.clone(); match user_info {
user_folder.pop(); Ok(user_info) => {
user_folder.pop(); let mut user_folder = user_info.path.clone();
let mut shortcuts = user_info.shortcuts; user_folder.pop();
shortcuts.sort_by_key(|s| s.app_name.clone()); user_folder.pop();
let image_type = &ImageType::Grid; let mut shortcuts = user_info.shortcuts;
for shortcut in &shortcuts { shortcuts.sort_by_key(|s| s.app_name.clone());
let (path, key) = shortcut.key(image_type, &user_folder); let image_type = &ImageType::Grid;
let loaded = state.image_handles.contains_key(&key); for shortcut in &shortcuts {
if !loaded && path.exists() { let (path, key) = shortcut.key(image_type, &user_folder);
let image = load_image_from_path(&path); let loaded = state.image_handles.contains_key(&key);
if let Ok(image) = image { if !loaded && path.exists() {
let texture = ui let image = load_image_from_path(&path);
.ctx() if let Ok(image) = image {
.load_texture(&key, image, egui::TextureOptions::LINEAR); let texture =
state ui.ctx()
.image_handles .load_texture(&key, image, egui::TextureOptions::LINEAR);
.insert(key, TextureDownloadState::Loaded(texture)); state
.image_handles
.insert(key, TextureDownloadState::Loaded(texture));
}
}
} }
shortcuts
}
Err(_err) => {
vec![]
} }
} }
shortcuts
} }
fn render_shortcut_mode_select(state: &ImageSelectState, ui: &mut egui::Ui) -> Option<UserAction> { fn render_shortcut_mode_select(state: &ImageSelectState, ui: &mut egui::Ui) -> Option<UserAction> {
+30 -11
View File
@@ -62,14 +62,23 @@ impl MyEguiApp {
} }
pub fn restore_backup(steam_settings: &SteamSettings, shortcut_path: &Path) -> bool { pub fn restore_backup(steam_settings: &SteamSettings, shortcut_path: &Path) -> bool {
let file_name = shortcut_path.file_name().unwrap(); let file_name = shortcut_path.file_name();
let paths = get_shortcuts_paths(steam_settings); let paths = get_shortcuts_paths(steam_settings);
if let Ok(paths) = paths { if let (Ok(paths), Some(file_name)) = (paths, file_name) {
for user in paths { for user in paths {
if let Some(user_shortcut_path) = user.shortcut_path { if let Some(user_shortcut_path) = user.shortcut_path {
if file_name.to_string_lossy().starts_with(&user.user_id) { if file_name.to_string_lossy().starts_with(&user.user_id) {
std::fs::copy(shortcut_path, Path::new(&user_shortcut_path)).unwrap(); match std::fs::copy(shortcut_path, Path::new(&user_shortcut_path)) {
println!("Restored shortcut to path : {}", user_shortcut_path); Ok(_) => {
println!("Restored shortcut to path : {}", user_shortcut_path);
}
Err(err) => {
eprintln!(
"Failed to restored shortcut to path : {} gave error: {:?}",
user_shortcut_path, err
);
}
}
return true; return true;
} }
} }
@@ -100,7 +109,7 @@ pub fn load_backups() -> Vec<PathBuf> {
result result
} }
const DATE_FORMAT :&str = "[year]-[month]-[day]-[hour]-[minute]-[second]"; const DATE_FORMAT: &str = "[year]-[month]-[day]-[hour]-[minute]-[second]";
pub fn backup_shortcuts(steam_settings: &SteamSettings) { pub fn backup_shortcuts(steam_settings: &SteamSettings) {
use time::OffsetDateTime; use time::OffsetDateTime;
@@ -108,18 +117,28 @@ pub fn backup_shortcuts(steam_settings: &SteamSettings) {
let backup_folder = get_backups_flder(); let backup_folder = get_backups_flder();
let paths = get_shortcuts_paths(steam_settings); let paths = get_shortcuts_paths(steam_settings);
let date = OffsetDateTime::now_utc(); let date = OffsetDateTime::now_utc();
let format = format_description::parse(DATE_FORMAT).unwrap(); let format = format_description::parse(DATE_FORMAT);
let date_string = date.format(&format).unwrap(); if let Ok(format) = format{
if let Ok(user_infos) = paths { let date_string = date.format(&format);
if let (Ok(date_string),Ok(user_infos)) = (date_string,paths) {
for user_info in user_infos { for user_info in user_infos {
if let Some(shortcut_path) = user_info.shortcut_path { if let Some(shortcut_path) = user_info.shortcut_path {
let new_path = backup_folder.join(format!( let new_path = backup_folder.join(format!(
"{}-{}-shortcuts.vdf", "{}-{}-shortcuts.vdf",
user_info.user_id, date_string user_info.user_id, date_string
)); ));
println!("Backed up shortcut at: {:?}", new_path); match std::fs::copy(shortcut_path, &new_path) {
std::fs::copy(shortcut_path, &new_path).unwrap(); Ok(_) => {
println!("Backed up shortcut at: {:?}", new_path);
}
Err(err) => {
eprintln!(
"Failed to backup shortcut at: {:?}, error: {:?}",
new_path, err
);
}
}
} }
} }}
} }
} }
+3 -1
View File
@@ -26,7 +26,9 @@ impl MyEguiApp {
let mut user_info = vec![]; let mut user_info = vec![];
for user in users { for user in users {
let shortcut_info = get_shortcuts_for_user(&user); let shortcut_info = get_shortcuts_for_user(&user);
user_info.push(shortcut_info); if let Ok(shortcut_info) = shortcut_info {
user_info.push(shortcut_info);
}
} }
user_info user_info
}) })
+18 -7
View File
@@ -4,6 +4,7 @@ use futures::executor::block_on;
use steam_shortcuts_util::shortcut::ShortcutOwned; use steam_shortcuts_util::shortcut::ShortcutOwned;
use tokio::sync::watch; use tokio::sync::watch;
use tokio::task::JoinHandle;
use crate::config::get_renames_file; use crate::config::get_renames_file;
use crate::platforms::ShortcutToImport; use crate::platforms::ShortcutToImport;
@@ -123,7 +124,14 @@ impl MyEguiApp {
}); });
} }
pub fn run_sync(&mut self, wait: bool) { pub fn run_sync_blocking(&mut self) -> eyre::Result<()> {
self.run_sync(true)
}
pub fn run_sync_async(&mut self) {
let _ = self.run_sync(false);
}
fn run_sync(&mut self, wait: bool) -> eyre::Result<()> {
let (sender, reciever) = watch::channel(SyncProgress::NotStarted); let (sender, reciever) = watch::channel(SyncProgress::NotStarted);
let settings = self.settings.clone(); let settings = self.settings.clone();
if settings.steam.stop_steam { if settings.steam.stop_steam {
@@ -136,7 +144,7 @@ impl MyEguiApp {
let _ = sender.send(SyncProgress::Starting); let _ = sender.send(SyncProgress::Starting);
if all_ready { if all_ready {
let shortcuts_to_import = get_all_games(&self.games_to_sync); let shortcuts_to_import = get_all_games(&self.games_to_sync);
let handle = self.rt.spawn_blocking(move || { let handle: JoinHandle<eyre::Result<()>> = self.rt.spawn_blocking(move || {
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
setup_proton(shortcuts_to_import.iter()); setup_proton(shortcuts_to_import.iter());
@@ -145,12 +153,11 @@ impl MyEguiApp {
let mut some_sender = Some(sender); let mut some_sender = Some(sender);
backup_shortcuts(&settings.steam); backup_shortcuts(&settings.steam);
let usersinfo = let usersinfo =
sync::sync_shortcuts(&settings, &import_games, &mut some_sender, &renames) sync::sync_shortcuts(&settings, &import_games, &mut some_sender, &renames)?;
.unwrap();
let task = download_images(&settings, &usersinfo, &mut some_sender); let task = download_images(&settings, &usersinfo, &mut some_sender);
block_on(task); block_on(task);
//Run a second time to fix up shortcuts after images are downloaded //Run a second time to fix up shortcuts after images are downloaded
if let Err(e) = sync::fix_all_shortcut_icons(&settings){ if let Err(e) = sync::fix_all_shortcut_icons(&settings) {
eprintln!("Could not fix shortcuts with error {e}"); eprintln!("Could not fix shortcuts with error {e}");
} }
@@ -160,11 +167,13 @@ impl MyEguiApp {
if settings.steam.start_steam { if settings.steam.start_steam {
crate::steam::ensure_steam_started(&settings.steam); crate::steam::ensure_steam_started(&settings.steam);
} }
Ok(())
}); });
if wait { if wait {
self.rt.block_on(handle).unwrap(); self.rt.block_on(handle)??;
} }
} }
Ok(())
} }
} }
@@ -202,6 +211,8 @@ where
crate::sync::symlinks::create_sym_links(&shortcut_info.shortcut); crate::sync::symlinks::create_sym_links(&shortcut_info.shortcut);
} }
} }
setup_proton_games(&shortcuts_to_proton); if let Err(err) = setup_proton_games(&shortcuts_to_proton){
eprintln!("failed to save proton settings: {:?}",err);
}
} }
} }
+26 -20
View File
@@ -15,13 +15,14 @@ use crate::{
}; };
use super::{ use super::{
images::ImageSelectState,
ui_colors::{ ui_colors::{
BACKGROUND_COLOR, BG_STROKE_COLOR, EXTRA_BACKGROUND_COLOR, LIGHT_ORANGE, ORANGE, PURLPLE, BACKGROUND_COLOR, BG_STROKE_COLOR, EXTRA_BACKGROUND_COLOR, LIGHT_ORANGE, ORANGE, PURLPLE,
TEXT_COLOR, TEXT_COLOR,
}, },
ui_images::{get_import_image, get_logo, get_logo_icon, get_save_image}, ui_images::{get_import_image, get_logo, get_logo_icon, get_save_image},
ui_import_games::FetcStatus, ui_import_games::FetcStatus,
BackupState, DiconnectState, images::ImageSelectState, BackupState, DiconnectState,
}; };
const SECTION_SPACING: f32 = 25.0; const SECTION_SPACING: f32 = 25.0;
@@ -70,12 +71,12 @@ pub struct MyEguiApp {
} }
impl MyEguiApp { impl MyEguiApp {
pub fn new() -> Self { pub fn new() -> eyre::Result<Self> {
let mut runtime = Runtime::new().unwrap(); let mut runtime = Runtime::new()?;
let settings = Settings::new().expect("We must be able to load our settings"); let settings = Settings::new()?;
let platforms = get_platforms(); let platforms = get_platforms();
let games_to_sync = create_games_to_sync(&mut runtime, &platforms); let games_to_sync = create_games_to_sync(&mut runtime, &platforms);
Self { Ok(Self {
selected_menu: Menues::Import, selected_menu: Menues::Import,
settings, settings,
rt: runtime, rt: runtime,
@@ -88,7 +89,7 @@ impl MyEguiApp {
rename_map: get_rename_map(), rename_map: get_rename_map(),
current_edit: Option::None, current_edit: Option::None,
platforms, platforms,
} })
} }
fn render_import_button(&mut self, ui: &mut egui::Ui) { fn render_import_button(&mut self, ui: &mut egui::Ui) {
@@ -121,17 +122,19 @@ impl MyEguiApp {
let texture = self.get_import_image(ui); let texture = self.get_import_image(ui);
let size = texture.size_vec2(); let size = texture.size_vec2();
let image_button = ImageButton::new(texture, size * 0.40); let image_button = ImageButton::new(texture, size * 0.40);
if all_ready && !syncing{ if all_ready && !syncing {
if ui if ui
.add(image_button) .add(image_button)
.on_hover_text("Import your games into steam") .on_hover_text("Import your games into steam")
.clicked(){ .clicked()
save_settings(&self.settings, &self.platforms); {
self.run_sync(false); if let Err(err) = save_settings(&self.settings, &self.platforms){
eprintln!("Failed to save settings {:?}",err);
} }
}else{ self.run_sync_async();
ui }
.add(image_button) } else {
ui.add(image_button)
.on_hover_text("Waiting for sync to finish"); .on_hover_text("Waiting for sync to finish");
} }
} }
@@ -265,7 +268,9 @@ impl App for MyEguiApp {
let save_button = ImageButton::new(texture, size * 0.5); let save_button = ImageButton::new(texture, size * 0.5);
if ui.add(save_button).on_hover_text("Save settings").clicked() { if ui.add(save_button).on_hover_text("Save settings").clicked() {
save_settings(&self.settings, &self.platforms); if let Err(err) = save_settings(&self.settings, &self.platforms){
eprintln!("Failed to save settings: {:?}",err);
}
} }
}); });
} }
@@ -341,17 +346,17 @@ fn setup(ctx: &egui::Context) {
create_style(&mut style); create_style(&mut style);
ctx.set_style(style); ctx.set_style(style);
} }
pub fn run_sync() { pub fn run_sync() -> eyre::Result<()>{
let mut app = MyEguiApp::new(); let mut app = MyEguiApp::new()?;
while !all_ready(&app.games_to_sync) { while !all_ready(&app.games_to_sync) {
println!("Finding games, trying again in 500ms"); println!("Finding games, trying again in 500ms");
std::thread::sleep(Duration::from_secs_f32(0.5)); std::thread::sleep(Duration::from_secs_f32(0.5));
} }
app.run_sync(true); app.run_sync_blocking()
} }
pub fn run_ui(args: Vec<String>) { pub fn run_ui(args: Vec<String>) -> eyre::Result<()>{
let app = MyEguiApp::new(); let app = MyEguiApp::new()?;
let no_v_sync = args.contains(&"--no-vsync".to_string()); let no_v_sync = args.contains(&"--no-vsync".to_string());
let fullscreen = is_fullscreen(&args); let fullscreen = is_fullscreen(&args);
let native_options = eframe::NativeOptions { let native_options = eframe::NativeOptions {
@@ -370,6 +375,7 @@ pub fn run_ui(args: Vec<String>) {
Box::new(app) Box::new(app)
}), }),
); );
Ok(())
} }
fn is_fullscreen(args: &[String]) -> bool { fn is_fullscreen(args: &[String]) -> bool {
@@ -377,5 +383,5 @@ fn is_fullscreen(args: &[String]) -> bool {
Ok(value) => !value.is_empty(), Ok(value) => !value.is_empty(),
Err(_) => false, Err(_) => false,
}; };
is_steam_mode || args.contains(&"--fullscreen".to_string()) is_steam_mode || args.contains(&"--fullscreen".to_string())
} }