diff --git a/Readme.md b/Readme.md index 9f0197c..01cb9f4 100644 --- a/Readme.md +++ b/Readme.md @@ -30,6 +30,7 @@ There is also an [AUR package](https://aur.archlinux.org/packages/steam-boilr-gu - [Tips for Linux](#tips-for-linux) - [Configuration](#configuration) - [Run as CLI](#run-as-cli) + - [Rename shortcuts](#rename-shortcuts) - [Contributions](#contributions) - [How can I help/contribute?](#how-can-i-helpcontribute) - [I found a bug, what do I do?](#i-found-a-bug-what-do-i-do) @@ -96,6 +97,11 @@ In previous releases there was both a CLI and UI version of BoilR, now there is But you can add the commandline argument ``--no-ui`` and then the UI version will act like the old CLI version. This saves some CO2 from not having to build 2 versions of BoilR for each platform, and it also makes development easier. +### Rename shortcuts + +You can rename a shortcut from BoilR by double clicking it from the import list and picking a new name. +If you want to revert back to the original name, just clear the name and click rename. + ## Contributions ### How can I help/contribute? diff --git a/src/config.rs b/src/config.rs index 21ed4ba..d804450 100644 --- a/src/config.rs +++ b/src/config.rs @@ -33,6 +33,10 @@ pub fn get_config_file() -> PathBuf { get_config_folder().join("config.toml") } +pub fn get_renames_file() -> PathBuf { + get_config_folder().join("renames.json") +} + pub fn get_cache_file() -> PathBuf { get_config_folder().join("cache.json") } diff --git a/src/sync/synchronization.rs b/src/sync/synchronization.rs index cbcfc31..b0cd81e 100644 --- a/src/sync/synchronization.rs +++ b/src/sync/synchronization.rs @@ -1,4 +1,4 @@ -use steam_shortcuts_util::{shortcut::ShortcutOwned, shortcuts_to_bytes}; +use steam_shortcuts_util::{shortcut::ShortcutOwned, shortcuts_to_bytes, calculate_app_id_for_shortcut, Shortcut}; use tokio::sync::watch::Sender; use crate::{ @@ -21,7 +21,7 @@ use crate::heroic::HeroicPlatform; #[cfg(target_family = "unix")] use crate::flatpak::FlatpakPlatform; -use std::error::Error; +use std::{error::Error, collections::HashMap}; use crate::{gog::GogPlatform, itch::ItchPlatform, origin::OriginPlatform}; use std::{fs::File, io::Write, path::Path}; @@ -59,6 +59,7 @@ pub fn disconnect_shortcut(settings: &Settings, app_id: u32) -> Result<(), Strin pub fn run_sync( settings: &Settings, sender: &mut Option>, + renames: &HashMap ) -> Result, String> { if let Some(sender) = &sender { let _ = sender.send(SyncProgress::Starting); @@ -67,7 +68,7 @@ pub fn run_sync( .map_err(|e| format!("Getting shortcut paths failed: {e}"))?; let platform_shortcuts = get_platform_shortcuts(settings); - let all_shortcuts: Vec = platform_shortcuts + let mut all_shortcuts: Vec = platform_shortcuts .iter() .flat_map(|s| s.1.clone()) .filter(|s| !settings.blacklisted_games.contains(&s.app_id)) @@ -77,7 +78,20 @@ pub fn run_sync( games_found: all_shortcuts.len(), }); } - for shortcut in &all_shortcuts { + for shortcut in &mut all_shortcuts { + if let Some(rename) = renames.get(&shortcut.app_id){ + shortcut.app_name = rename.clone(); + let new_shortcut = Shortcut::new( + "0", + shortcut.app_name.as_str(), + &shortcut.exe, + "", + "", + "", + "" + ); + shortcut.app_id = calculate_app_id_for_shortcut(&new_shortcut); + } println!("Appid: {} name: {}", shortcut.app_id, shortcut.app_name); } println!("Found {} user(s)", userinfo_shortcuts.len()); diff --git a/src/ui/ui_import_games.rs b/src/ui/ui_import_games.rs index 449cdac..76f38b1 100644 --- a/src/ui/ui_import_games.rs +++ b/src/ui/ui_import_games.rs @@ -4,6 +4,7 @@ use futures::executor::block_on; use tokio::sync::watch; +use crate::config::get_renames_file; use crate::settings::Settings; use crate::sync; @@ -66,17 +67,46 @@ impl MyEguiApp { ui.label("Select the games you want to import into steam"); for (platform_name, shortcuts) in games_to_sync{ ui.heading(platform_name); + for shortcut in shortcuts { let mut import_game = !self.settings.blacklisted_games.contains(&shortcut.app_id); - let checkbox = egui::Checkbox::new(&mut import_game,&shortcut.app_name); - let response = ui.add(checkbox); - if response.clicked(){ - if !self.settings.blacklisted_games.contains(&shortcut.app_id){ - self.settings.blacklisted_games.push(shortcut.app_id); - }else{ - self.settings.blacklisted_games.retain(|id| *id != shortcut.app_id); + ui.horizontal(|ui|{ + if self.current_edit == Option::Some(shortcut.app_id){ + if let Some(new_name) = self.rename_map.get_mut(&shortcut.app_id){ + ui.text_edit_singleline(new_name).request_focus(); + if ui.button("Rename").clicked() { + if new_name.is_empty(){ + *new_name = shortcut.app_name.to_string(); + } + self.current_edit = Option::None; + let rename_file_path = get_renames_file(); + let contents = serde_json::to_string(&self.rename_map); + if let Ok(contents) = contents{ + let res = std::fs::write(&rename_file_path, contents); + println!("Write rename file at {:?} with result: {:?}",rename_file_path, res); + } + } + } + } else { + let name = self.rename_map.get(&shortcut.app_id).unwrap_or(&shortcut.app_name); + let checkbox = egui::Checkbox::new(&mut import_game,name); + let response = ui.add(checkbox); + if response.double_clicked(){ + if !self.rename_map.contains_key(&shortcut.app_id){ + self.rename_map.insert(shortcut.app_id,shortcut.app_name.to_owned()); + } + self.current_edit = Option::Some(shortcut.app_id); } - } + if response.clicked(){ + if !self.settings.blacklisted_games.contains(&shortcut.app_id){ + self.settings.blacklisted_games.push(shortcut.app_id); + }else{ + self.settings.blacklisted_games.retain(|id| *id != shortcut.app_id); + } + } + } + + }); } } ui.add_space(SECTION_SPACING); @@ -115,16 +145,17 @@ impl MyEguiApp { } self.status_reciever = reciever; + let renames = self.rename_map.clone(); let handle = self.rt.spawn_blocking(move || { MyEguiApp::save_settings_to_file(&settings); let mut some_sender = Some(sender); backup_shortcuts(&settings.steam); - let usersinfo = sync::run_sync(&settings, &mut some_sender).unwrap(); + let usersinfo = sync::run_sync(&settings, &mut some_sender,&renames).unwrap(); let task = download_images(&settings, &usersinfo, &mut some_sender); block_on(task); //Run a second time to fix up shortcuts after images are downloaded - sync::run_sync(&settings, &mut some_sender).unwrap(); + sync::run_sync(&settings, &mut some_sender,&renames).unwrap(); if let Some(sender) = some_sender { let _ = sender.send(SyncProgress::Done); diff --git a/src/ui/uiapp.rs b/src/ui/uiapp.rs index b6101fc..3fc6c14 100644 --- a/src/ui/uiapp.rs +++ b/src/ui/uiapp.rs @@ -1,3 +1,5 @@ +use std::{collections::HashMap, error::Error}; + #[cfg(target_family = "unix")] use crate::heroic::HeroicGameType; @@ -9,7 +11,7 @@ use tokio::{ sync::watch::{self, Receiver}, }; -use crate::{egs::ManifestItem, settings::Settings, sync::SyncProgress}; +use crate::{egs::ManifestItem, settings::Settings, sync::SyncProgress, config::get_renames_file}; use super::{ ui_colors::{ @@ -43,6 +45,8 @@ pub struct MyEguiApp { pub(crate) image_selected_state: ImageSelectState, pub(crate) backup_state: BackupState, pub(crate) disconect_state: DiconnectState, + pub(crate) rename_map : HashMap, + pub(crate) current_edit : Option, } impl MyEguiApp { @@ -61,10 +65,23 @@ impl MyEguiApp { image_selected_state: ImageSelectState::default(), backup_state: BackupState::default(), disconect_state: DiconnectState::default(), + rename_map: get_rename_map(), + current_edit: Option::None } } } +fn get_rename_map() -> HashMap{ + try_get_rename_map().unwrap_or_default() +} + +fn try_get_rename_map() -> Result,Box>{ + let rename_map = get_renames_file(); + let file_content = std::fs::read_to_string(rename_map)?; + let deserialized = serde_json::from_str(&file_content)?; + Ok(deserialized) +} + #[derive(PartialEq)] enum Menues { Import, @@ -283,7 +300,7 @@ pub fn run_ui(args: Vec) { let app = MyEguiApp::new(); let no_v_sync = args.contains(&"--no-vsync".to_string()); let native_options = eframe::NativeOptions { - initial_window_size: Some(egui::Vec2 { x: 800., y: 500. }), + initial_window_size: Some(egui::Vec2 { x: 1280., y: 800. }), icon_data: Some(get_logo_icon()), vsync: !no_v_sync, ..Default::default()