feat: add ability to customize backup folder

- added setting for back up folder

 - added pre-selected icons when importing icons.json to icommon

 - added Backup / Restore category when device is connected
This commit is contained in:
Ed B 2024-04-28 17:08:41 +03:00
commit 6931fb422f
8 changed files with 356 additions and 40 deletions

265
Cargo.lock generated
View file

@ -141,6 +141,24 @@ dependencies = [
"libloading 0.7.4",
]
[[package]]
name = "ashpd"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd884d7c72877a94102c3715f3b1cd09ff4fac28221add3e57cfbe25c236d093"
dependencies = [
"async-fs 2.1.1",
"async-net",
"enumflags2",
"futures-channel",
"futures-util",
"rand",
"serde",
"serde_repr",
"url",
"zbus 4.1.2",
]
[[package]]
name = "async-broadcast"
version = "0.5.1"
@ -151,6 +169,18 @@ dependencies = [
"futures-core",
]
[[package]]
name = "async-broadcast"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "258b52a1aa741b9f09783b2d86cf0aeeb617bbf847f6933340a39644227acbdb"
dependencies = [
"event-listener 5.2.0",
"event-listener-strategy 0.5.0",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-channel"
version = "2.2.0"
@ -190,6 +220,17 @@ dependencies = [
"futures-lite 1.13.0",
]
[[package]]
name = "async-fs"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc19683171f287921f2405677dd2ed2549c3b3bda697a563ebc3a121ace2aba1"
dependencies = [
"async-lock 3.3.0",
"blocking",
"futures-lite 2.3.0",
]
[[package]]
name = "async-io"
version = "1.13.0"
@ -249,6 +290,17 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "async-net"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7"
dependencies = [
"async-io 2.3.2",
"blocking",
"futures-lite 2.3.0",
]
[[package]]
name = "async-process"
version = "1.8.1"
@ -266,6 +318,26 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "async-process"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a53fc6301894e04a92cb2584fedde80cb25ba8e02d9dc39d4a87d036e22f397d"
dependencies = [
"async-channel",
"async-io 2.3.2",
"async-lock 3.3.0",
"async-signal",
"async-task",
"blocking",
"cfg-if",
"event-listener 5.2.0",
"futures-lite 2.3.0",
"rustix 0.38.32",
"tracing",
"windows-sys 0.52.0",
]
[[package]]
name = "async-recursion"
version = "1.1.0"
@ -829,8 +901,8 @@ dependencies = [
"rust-ini",
"web-sys",
"winreg",
"zbus",
"zvariant",
"zbus 3.15.1",
"zvariant 3.15.1",
]
[[package]]
@ -979,6 +1051,12 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "endi"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
[[package]]
name = "enumflags2"
version = "0.7.9"
@ -1986,7 +2064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
dependencies = [
"cfg-if",
"windows-targets 0.48.5",
"windows-targets 0.52.4",
]
[[package]]
@ -2204,6 +2282,19 @@ dependencies = [
"memoffset 0.7.1",
]
[[package]]
name = "nix"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
"bitflags 2.5.0",
"cfg-if",
"cfg_aliases 0.1.1",
"libc",
"memoffset 0.9.0",
]
[[package]]
name = "num-traits"
version = "0.2.18"
@ -2559,6 +2650,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "pollster"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@ -2791,6 +2888,29 @@ dependencies = [
"rand",
]
[[package]]
name = "rfd"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a73a7337fc24366edfca76ec521f51877b114e42dab584008209cca6719251"
dependencies = [
"ashpd",
"block",
"dispatch",
"js-sys",
"log",
"objc",
"objc-foundation",
"objc_id",
"pollster",
"raw-window-handle",
"urlencoding",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows-sys 0.48.0",
]
[[package]]
name = "ring"
version = "0.17.8"
@ -3488,6 +3608,7 @@ dependencies = [
"log",
"regex",
"retry",
"rfd",
"serde",
"serde_json",
"static_init",
@ -3611,8 +3732,15 @@ dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "version_check"
version = "0.9.4"
@ -4423,16 +4551,16 @@ checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1"
[[package]]
name = "zbus"
version = "3.15.2"
version = "3.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6"
checksum = "5acecd3f8422f198b1a2f954bcc812fe89f3fa4281646f3da1da7925db80085d"
dependencies = [
"async-broadcast",
"async-broadcast 0.5.1",
"async-executor",
"async-fs",
"async-fs 1.6.0",
"async-io 1.13.0",
"async-lock 2.8.0",
"async-process",
"async-process 1.8.1",
"async-recursion",
"async-task",
"async-trait",
@ -4445,7 +4573,7 @@ dependencies = [
"futures-sink",
"futures-util",
"hex",
"nix",
"nix 0.26.4",
"once_cell",
"ordered-stream",
"rand",
@ -4457,16 +4585,55 @@ dependencies = [
"uds_windows",
"winapi",
"xdg-home",
"zbus_macros",
"zbus_names",
"zvariant",
"zbus_macros 3.15.1",
"zbus_names 2.6.1",
"zvariant 3.15.1",
]
[[package]]
name = "zbus"
version = "4.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9ff46f2a25abd690ed072054733e0bc3157e3d4c45f41bd183dce09c2ff8ab9"
dependencies = [
"async-broadcast 0.7.0",
"async-executor",
"async-fs 2.1.1",
"async-io 2.3.2",
"async-lock 3.3.0",
"async-process 2.2.2",
"async-recursion",
"async-task",
"async-trait",
"blocking",
"derivative",
"enumflags2",
"event-listener 5.2.0",
"futures-core",
"futures-sink",
"futures-util",
"hex",
"nix 0.28.0",
"ordered-stream",
"rand",
"serde",
"serde_repr",
"sha1",
"static_assertions",
"tracing",
"uds_windows",
"windows-sys 0.52.0",
"xdg-home",
"zbus_macros 4.1.2",
"zbus_names 3.0.0",
"zvariant 4.0.2",
]
[[package]]
name = "zbus_macros"
version = "3.15.2"
version = "3.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5"
checksum = "2207eb71efebda17221a579ca78b45c4c5f116f074eb745c3a172e688ccf89f5"
dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro2",
@ -4476,6 +4643,20 @@ dependencies = [
"zvariant_utils",
]
[[package]]
name = "zbus_macros"
version = "4.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e0e3852c93dcdb49c9462afe67a2a468f7bd464150d866e861eaf06208633e0"
dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"regex",
"syn 1.0.109",
"zvariant_utils",
]
[[package]]
name = "zbus_names"
version = "2.6.1"
@ -4484,7 +4665,18 @@ checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d"
dependencies = [
"serde",
"static_assertions",
"zvariant",
"zvariant 3.15.1",
]
[[package]]
name = "zbus_names"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
dependencies = [
"serde",
"static_assertions",
"zvariant 4.0.2",
]
[[package]]
@ -4530,23 +4722,37 @@ dependencies = [
[[package]]
name = "zvariant"
version = "3.15.2"
version = "3.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db"
checksum = "c5b4fcf3660d30fc33ae5cd97e2017b23a96e85afd7a1dd014534cd0bf34ba67"
dependencies = [
"byteorder",
"enumflags2",
"libc",
"serde",
"static_assertions",
"zvariant_derive",
"zvariant_derive 3.15.1",
]
[[package]]
name = "zvariant"
version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c1b3ca6db667bfada0f1ebfc94b2b1759ba25472ee5373d4551bb892616389a"
dependencies = [
"endi",
"enumflags2",
"serde",
"static_assertions",
"url",
"zvariant_derive 4.0.2",
]
[[package]]
name = "zvariant_derive"
version = "3.15.2"
version = "3.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9"
checksum = "0277758a8a0afc0e573e80ed5bfd9d9c2b48bd3108ffe09384f9f738c83f4a55"
dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro2",
@ -4556,10 +4762,23 @@ dependencies = [
]
[[package]]
name = "zvariant_utils"
version = "1.0.1"
name = "zvariant_derive"
version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200"
checksum = "b7a4b236063316163b69039f77ce3117accb41a09567fd24c168e43491e521bc"
dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn 1.0.109",
"zvariant_utils",
]
[[package]]
name = "zvariant_utils"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00bedb16a193cc12451873fee2a1bc6550225acece0e36f333e68326c73c8172"
dependencies = [
"proc-macro2",
"quote",

View file

@ -31,6 +31,7 @@ dirs = "^5.0.0"
ureq = { version = "*", features = ["json"] }
retry = "^2.0.0"
iced = { version = "^0.12.0", features = ["advanced", "image"] }
rfd = "^0.14"
[target.'cfg(not(target_os = "windows"))'.dependencies]
flate2 = { version = "^1", optional = true }

View file

@ -416,8 +416,11 @@
{
"ligatures": "folder-open, directory2",
"name": "folder-open",
"order": 0,
"id": 49
"order": 4,
"id": 49,
"prevSize": 28,
"code": 59696,
"tempChar": ""
},
{
"ligatures": "folder-plus, directory3",
@ -1016,8 +1019,11 @@
{
"ligatures": "cog, gear",
"name": "cog",
"order": 0,
"id": 149
"order": 3,
"id": 149,
"prevSize": 28,
"code": 59796,
"tempChar": ""
},
{
"ligatures": "cogs, gears",

Binary file not shown.

View file

@ -1,6 +1,7 @@
use crate::core::sync::{get_android_sdk, User};
use crate::core::utils::DisplayablePath;
use crate::gui::views::settings::Settings;
use crate::CACHE_DIR;
use crate::CONFIG_DIR;
use serde::{Deserialize, Serialize};
use static_init::dynamic;
@ -14,10 +15,11 @@ pub struct Config {
pub devices: Vec<DeviceSettings>,
}
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GeneralSettings {
pub theme: String,
pub expert_mode: bool,
pub backup_folder: PathBuf,
}
#[derive(Default, Debug, Clone)]
@ -38,6 +40,16 @@ pub struct DeviceSettings {
pub backup: BackupSettings,
}
impl Default for GeneralSettings {
fn default() -> Self {
Self {
theme: String::from("Dark"),
expert_mode: false,
backup_folder: CACHE_DIR.join("backups"),
}
}
}
impl Default for DeviceSettings {
fn default() -> Self {
Self {

View file

@ -1,4 +1,4 @@
use crate::core::config::DeviceSettings;
use crate::core::config::{Config, DeviceSettings};
use crate::core::sync::{apply_pkg_state_commands, CorePackage, Phone, User};
use crate::core::utils::DisplayablePath;
use crate::gui::widgets::package_row::PackageRow;
@ -51,7 +51,8 @@ pub async fn backup_phone(
match serde_json::to_string_pretty(&backup) {
Ok(json) => {
let backup_path = &*BACKUP_DIR.join(device_id);
let backup_dir: PathBuf = Config::load_configuration_file().general.backup_folder;
let backup_path = &*backup_dir.join(device_id);
if let Err(e) = fs::create_dir_all(backup_path) {
error!("BACKUP: could not create backup dir: {}", e);

View file

@ -8,6 +8,11 @@ use std::path::PathBuf;
use std::process::Command;
use std::{fmt, fs};
#[derive(Debug, Clone)]
pub enum Error {
DialogClosed(String),
}
pub fn fetch_packages(uad_lists: &PackageHashMap, user_id: Option<&User>) -> Vec<PackageRow> {
let all_system_packages = list_all_system_packages(user_id); // installed and uninstalled packages
let enabled_system_packages = hashset_system_packages(PackageState::Enabled, user_id);
@ -129,3 +134,12 @@ impl fmt::Display for DisplayablePath {
write!(f, "{stem}")
}
}
pub async fn open_folder() -> Result<PathBuf, Error> {
let picked_folder = rfd::AsyncFileDialog::new()
.pick_folder()
.await
.ok_or(Error::DialogClosed(err))?;
Ok(picked_folder.path().to_owned())
}

View file

@ -2,25 +2,29 @@ use crate::core::sync::AdbError;
use crate::core::config::{BackupSettings, Config, DeviceSettings, GeneralSettings};
use crate::core::save::{
backup_phone, list_available_backup_user, list_available_backups, restore_backup, BACKUP_DIR,
backup_phone, list_available_backup_user, list_available_backups, restore_backup,
};
use crate::core::sync::{get_android_sdk, perform_adb_commands, CommandType, Phone};
use crate::core::theme::Theme;
use crate::core::utils::{open_url, string_to_theme, DisplayablePath};
use crate::core::utils::{open_folder, open_url, string_to_theme, DisplayablePath};
use crate::gui::style;
use crate::gui::views::list::PackageInfo;
use crate::gui::widgets::navigation_menu::ICONS;
use crate::gui::widgets::package_row::PackageRow;
use iced::widget::{
button, checkbox, column, container, pick_list, radio, row, scrollable, text, Space,
button, checkbox, column, container, pick_list, radio, row, scrollable, text, Space, Text,
};
use iced::{alignment, Alignment, Command, Element, Length, Renderer};
use std::path::PathBuf;
use crate::core::utils::Error;
#[derive(Debug, Clone)]
pub struct Settings {
pub general: GeneralSettings,
pub device: DeviceSettings,
is_loading: bool,
}
impl Default for Settings {
@ -28,6 +32,7 @@ impl Default for Settings {
Self {
general: Config::load_configuration_file().general,
device: DeviceSettings::default(),
is_loading: false,
}
}
}
@ -45,6 +50,8 @@ pub enum Message {
RestoreDevice,
RestoringDevice(Result<CommandType, AdbError>),
DeviceBackedUp(Result<(), String>),
ChooseBackUpFolder,
FolderChosen(Result<PathBuf, Error>),
}
impl Settings {
@ -87,7 +94,8 @@ impl Settings {
Command::none()
}
Message::LoadDeviceSettings => {
let backups = list_available_backups(&BACKUP_DIR.join(&phone.adb_id));
let backups =
list_available_backups(&self.general.backup_folder.join(&phone.adb_id));
let backup = BackupSettings {
backups: backups.clone(),
selected: backups.first().cloned(),
@ -131,7 +139,7 @@ impl Settings {
Message::DeviceBackedUp(_) => {
info!("[BACKUP] Backup successfully created");
self.device.backup.backups =
list_available_backups(&BACKUP_DIR.join(phone.adb_id.clone()));
list_available_backups(&self.general.backup_folder.join(phone.adb_id.clone()));
self.device.backup.selected = self.device.backup.backups.first().cloned();
Command::none()
}
@ -178,6 +186,32 @@ impl Settings {
},
// Trigger an action in mod.rs (Message::SettingsAction(msg))
Message::RestoringDevice(_) => Command::none(),
Message::FolderChosen(result) => {
self.is_loading = false;
if let Ok(path) = result {
self.general.backup_folder = path;
Config::save_changes(self, &phone.adb_id);
#[allow(unused_must_use)]
{
self.update(
phone,
packages,
nb_running_async_adb_commands,
Message::LoadDeviceSettings,
);
}
}
Command::none()
}
Message::ChooseBackUpFolder => {
if self.is_loading {
Command::none()
} else {
self.is_loading = true;
Command::perform(open_folder(), Message::FolderChosen)
}
}
}
}
@ -212,11 +246,37 @@ impl Settings {
text("Most unsafe packages are known to bootloop the device if removed.")
.style(style::Text::Commentary);
let general_ctn = container(column![expert_mode_checkbox, expert_mode_descr].spacing(10))
.padding(10)
.width(Length::Fill)
.height(Length::Shrink)
.style(style::Container::Frame);
let choose_backup_descr = text("Note: If you have previous backups, you will need to transfer them manually to newly changed backup folder to be able to use Restore functionality")
.style(style::Text::Commentary);
let choose_backup_btn = button(Text::new("\u{E930}").font(ICONS))
.padding([5, 10])
.on_press(Message::ChooseBackUpFolder)
.style(style::Button::Primary);
let choose_backup_row = row![
choose_backup_btn,
"Choose backup folder",
Space::new(Length::Fill, Length::Shrink),
"Current folder: ",
Text::new(self.general.backup_folder.to_string_lossy())
]
.spacing(10)
.align_items(Alignment::Center);
let general_ctn = container(
column![
expert_mode_checkbox,
expert_mode_descr,
choose_backup_row,
choose_backup_descr,
]
.spacing(10),
)
.padding(10)
.width(Length::Fill)
.height(Length::Shrink)
.style(style::Container::Frame);
let warning_ctn = container(
row![
@ -346,7 +406,9 @@ impl Settings {
.style(style::Button::Primary)
} else {
button("Open backup directory")
.on_press(Message::UrlPressed(BACKUP_DIR.join(phone.adb_id.clone())))
.on_press(Message::UrlPressed(
self.general.backup_folder.join(phone.adb_id.clone()),
))
.padding([5, 10])
.style(style::Button::Primary)
};
@ -409,6 +471,7 @@ impl Settings {
text("Current device").size(26),
warning_ctn,
device_specific_ctn,
text("Backup / Restore").size(26),
backup_restore_ctn,
]
.width(Length::Fill)