Backup shortcuts (#144)

* Add initial option to back up shortcuts

* Show list of backups

* Reload backups on change

* Restore backups

* Improve UX of backup ui

* Reorganize ui

* Update version in cargo.toml

* Update flatpak description

* Update cargo-lock.json
This commit is contained in:
Philip Kristoffersen
2022-05-20 21:53:21 +02:00
committed by GitHub
parent f5fef331ab
commit 967465d326
9 changed files with 269 additions and 37 deletions
+6
View File
@@ -37,6 +37,12 @@ pub fn get_cache_file() -> PathBuf {
get_config_folder().join("cache.json").to_path_buf()
}
pub fn get_backups_flder() -> PathBuf {
let backups_path = get_config_folder().join("backup");
let _ = create_dir_all(&backups_path);
backups_path.to_path_buf()
}
#[cfg(target_family = "unix")]
pub fn get_boilr_links_path() -> PathBuf {
get_config_folder().join("links").to_path_buf()
+2
View File
@@ -1,10 +1,12 @@
mod defines;
mod ui_backup;
mod ui_image_download;
mod ui_import_games;
mod ui_settings;
mod uiapp;
pub use defines::*;
pub use ui_backup::*;
pub use ui_image_download::*;
pub use ui_import_games::*;
pub use ui_settings::*;
+124
View File
@@ -0,0 +1,124 @@
use std::path::{Path, PathBuf};
use chrono::Local;
use egui::ScrollArea;
use crate::{
config::get_backups_flder,
steam::{get_shortcuts_paths, SteamSettings},
};
use super::MyEguiApp;
#[derive(Default)]
pub struct BackupState {
pub available_backups: Option<Vec<PathBuf>>,
pub last_restore: Option<PathBuf>,
}
impl MyEguiApp {
pub fn render_backup(&mut self, ui: &mut egui::Ui) {
ui.heading("Backups");
ui.label("Here you can restore backed up shortcuts files");
ui.label("Click a backup to restore it, your current shortcuts will be backed up first");
ui.add_space(15.0);
if let Some(last_restore) = self.backup_state.last_restore.as_ref() {
ui.heading(format!("Last restored {:?}", last_restore));
}
if ui.button("Click here to create a new backup").clicked() {
backup_shortcuts(&self.settings.steam);
self.backup_state.available_backups = None;
}
let available_backups = self
.backup_state
.available_backups
.get_or_insert_with(|| load_backups());
if available_backups.is_empty() {
ui.label("No backups found, they will be created every time you run import");
} else {
ScrollArea::vertical()
.stick_to_right()
.auto_shrink([false, true])
.show(ui, |ui| {
for backup_path in available_backups {
if ui
.button(backup_path.to_string_lossy().to_string())
.clicked()
{
//Restore
backup_shortcuts(&self.settings.steam);
if restore_backup(&self.settings.steam, backup_path.as_path()) {
self.backup_state.last_restore = Some(backup_path.clone());
}
}
}
});
}
}
}
pub fn restore_backup(steam_settings: &SteamSettings, shortcut_path: &Path) -> bool {
let file_name = shortcut_path.file_name().unwrap();
let paths = get_shortcuts_paths(steam_settings);
if let Ok(paths) = paths {
for user in paths {
if let Some(user_shortcut_path) = user.shortcut_path {
if file_name.to_string_lossy().starts_with(&user.user_id) {
std::fs::copy(shortcut_path, Path::new(&user_shortcut_path)).unwrap();
println!("Restored shortcut to path : {}", user_shortcut_path);
return true;
}
}
}
}
return false;
}
pub fn load_backups() -> Vec<PathBuf> {
let backup_folder = get_backups_flder();
let files = std::fs::read_dir(&backup_folder);
let mut result = vec![];
if let Ok(files) = files {
for file in files {
if let Ok(file) = file {
if file
.path()
.extension()
.unwrap_or_default()
.to_string_lossy()
== "vdf"
{
result.push(file.path().to_path_buf());
}
}
}
}
result.sort();
result.reverse();
return result;
}
pub fn backup_shortcuts(steam_settings: &SteamSettings) {
let backup_folder = get_backups_flder();
let paths = get_shortcuts_paths(&steam_settings);
let date = Local::now();
let date_string = date.format("%Y-%m-%d-%H-%M-%S");
if let Ok(user_infos) = paths {
for user_info in user_infos {
if let Some(shortcut_path) = user_info.shortcut_path {
let new_path = backup_folder.join(format!(
"{}-{}-shortcuts.vdf",
user_info.user_id, date_string
));
println!("Backed up shortcut at: {:?}", new_path);
std::fs::copy(&shortcut_path, &new_path).unwrap();
}
}
}
}
+5 -1
View File
@@ -9,7 +9,7 @@ use crate::sync;
use crate::sync::{download_images, SyncProgress};
use super::ImageSelectState;
use super::{ImageSelectState, backup_shortcuts};
use super::{
ui_colors::{BACKGROUND_COLOR, EXTRA_BACKGROUND_COLOR},
MyEguiApp,
@@ -42,6 +42,9 @@ impl<T> FetcStatus<T> {
}
impl MyEguiApp {
pub(crate) fn render_import_games(&mut self, ui: &mut egui::Ui) {
ui.heading("Import Games");
@@ -118,6 +121,7 @@ impl MyEguiApp {
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 task = download_images(&settings, &usersinfo, &mut some_sender);
block_on(task);
+21 -6
View File
@@ -17,7 +17,7 @@ use super::{
},
ui_images::{get_import_image, get_logo, get_logo_icon},
ui_import_games::FetcStatus,
ImageSelectState,
BackupState, ImageSelectState,
};
const SECTION_SPACING: f32 = 25.0;
@@ -37,6 +37,7 @@ pub struct MyEguiApp {
pub(crate) status_reciever: Receiver<SyncProgress>,
pub(crate) epic_manifests: Option<Vec<ManifestItem>>,
pub(crate) image_selected_state: ImageSelectState,
pub(crate) backup_state: BackupState,
}
impl MyEguiApp {
@@ -51,6 +52,7 @@ impl MyEguiApp {
status_reciever: watch::channel(SyncProgress::NotStarted).1,
epic_manifests: None,
image_selected_state: ImageSelectState::default(),
backup_state: BackupState::default(),
}
}
}
@@ -60,6 +62,7 @@ enum Menues {
Import,
Settings,
Images,
Backup,
}
impl Default for Menues {
@@ -82,19 +85,28 @@ impl App for MyEguiApp {
ui.image(texture, size);
ui.add_space(SECTION_SPACING);
let changed = ui
let mut changed = ui
.selectable_value(&mut self.selected_menu, Menues::Import, "Import Games")
.changed();
let mut changed = changed
|| ui
.selectable_value(&mut self.selected_menu, Menues::Settings, "Settings")
.changed();
if self.settings.steamgrid_db.auth_key.is_some() {
changed = changed
|| ui
.selectable_value(&mut self.selected_menu, Menues::Images, "Images")
.changed();
}
changed = changed
|| ui
.selectable_value(&mut self.selected_menu, Menues::Settings, "Settings")
.changed();
changed = changed
|| ui
.selectable_value(&mut self.selected_menu, Menues::Backup, "Backup")
.changed();
if changed {
self.backup_state.available_backups = None;
}
if changed && self.selected_menu == Menues::Settings {
//We reset games here, since user might change settings
self.games_to_sync = watch::channel(FetcStatus::NeedsFetched).1;
@@ -155,6 +167,9 @@ impl App for MyEguiApp {
Menues::Images => {
self.render_ui_images(ui);
}
Menues::Backup => {
self.render_backup(ui);
}
};
});
}