feat(backup): add ability to export uninstalled packages with their description

- changed export file to csv

 - silenced clippy error for now (dead code), until fixed or found solution
This commit is contained in:
Ed B 2024-07-03 00:57:12 +03:00
commit 4e954c0624
6 changed files with 60 additions and 37 deletions

22
Cargo.lock generated
View file

@ -861,6 +861,27 @@ dependencies = [
"typenum",
]
[[package]]
name = "csv"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
dependencies = [
"memchr",
]
[[package]]
name = "ctor"
version = "0.2.7"
@ -3600,6 +3621,7 @@ name = "uad-ng"
version = "1.0.3"
dependencies = [
"chrono",
"csv",
"dark-light",
"dirs 5.0.1",
"fern",

View file

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

View file

@ -28,7 +28,7 @@ pub async fn backup_phone(
users: Vec<User>,
device_id: String,
phone_packages: Vec<Vec<PackageRow>>,
) -> Result<(), String> {
) -> Result<bool, String> {
let mut backup = PhoneBackup {
device_id: device_id.clone(),
..PhoneBackup::default()
@ -63,7 +63,7 @@ pub async fn backup_phone(
format!("{}.json", chrono::Local::now().format("%Y-%m-%d_%H-%M-%S"));
match fs::write(backup_path.join(backup_filename), json) {
Ok(_) => Ok(()),
Ok(_) => Ok(true),
Err(err) => Err(err.to_string()),
}
}

View file

@ -17,6 +17,7 @@ pub struct BaseColors {
#[derive(Debug, Clone, Copy)]
pub struct NormalColors {
pub primary: Color,
#[allow(dead_code)]
pub secondary: Color,
pub surface: Color,
pub error: Color,

View file

@ -3,7 +3,8 @@ use crate::core::theme::Theme;
use crate::core::uad_lists::{PackageHashMap, PackageState, Removal, UadList};
use crate::gui::widgets::package_row::PackageRow;
use chrono::offset::Utc;
use chrono::DateTime;
use chrono::{DateTime, Local};
use csv::Writer;
use std::path::PathBuf;
use std::process::Command;
use std::{fmt, fs};
@ -167,41 +168,35 @@ pub async fn open_folder() -> Result<PathBuf, Error> {
Ok(picked_folder.path().to_owned())
}
/// Export uninstalled packages in a file.
/// Export uninstalled packages in a csv file.
/// Exported information will contain package name and description.
pub async fn export_packages(
user: Option<User>,
device_id: String,
phone_packages: Vec<Vec<PackageRow>>,
) -> Result<bool, String> {
let uninstalled_packages: Vec<String> = phone_packages[user.unwrap().index]
let uninstalled_packages: Vec<&PackageRow> = phone_packages[user.unwrap().index]
.iter()
.filter(|p| p.state.to_string() == "Uninstalled")
.map(|p| {
format!(
"{}Name: {}\nDescription: {}",
"-------------------------------------------------------------------\n",
p.name,
p.description.replace('\n', " ")
)
})
.collect();
let backup_content = format!(
"Device ID: {}\nUser ID: {}\n-------------------------------------------------------------------\n{}",
device_id,
user.unwrap().id,
uninstalled_packages.join("\n")
);
let backup_file = format!(
"{}_{}.txt",
"{}_{}.csv",
UNINSTALLED_PACKAGES_FILE_NAME,
chrono::Local::now().format("%Y%m%d")
Local::now().format("%Y%m%d")
);
match fs::write(backup_file, backup_content) {
Ok(_) => Ok(true),
Err(err) => Err(err.to_string()),
let file = fs::File::create(backup_file).map_err(|err| err.to_string())?;
let mut wtr = Writer::from_writer(file);
wtr.write_record(["Package Name", "Description"])
.map_err(|err| err.to_string())?;
for package in uninstalled_packages {
wtr.write_record([&package.name, &package.description.replace('\n', " ")])
.map_err(|err| err.to_string())?;
}
wtr.flush().map_err(|err| err.to_string())?;
Ok(true)
}

View file

@ -61,7 +61,7 @@ pub enum Message {
BackupDevice,
RestoreDevice,
RestoringDevice(Result<CommandType, AdbError>),
DeviceBackedUp(Result<(), String>),
DeviceBackedUp(Result<bool, String>),
ChooseBackUpFolder,
FolderChosen(Result<PathBuf, Error>),
ExportPackages,
@ -156,11 +156,19 @@ impl Settings {
),
Message::DeviceBackedUp,
),
Message::DeviceBackedUp(_) => {
info!("[BACKUP] Backup successfully created");
self.device.backup.backups =
list_available_backups(&self.general.backup_folder.join(phone.adb_id.clone()));
self.device.backup.selected = self.device.backup.backups.first().cloned();
Message::DeviceBackedUp(is_backed_up) => {
match is_backed_up {
Ok(_) => {
info!("[BACKUP] Backup successfully created");
self.device.backup.backups = list_available_backups(
&self.general.backup_folder.join(phone.adb_id.clone()),
);
self.device.backup.selected = self.device.backup.backups.first().cloned();
}
Err(err) => {
error!("[BACKUP FAILED] Backup creation failed: {:?}", err);
}
}
Command::none()
}
Message::RestoreDevice => match restore_backup(phone, packages, &self.device) {
@ -234,11 +242,7 @@ impl Settings {
}
}
Message::ExportPackages => Command::perform(
export_packages(
*selected_user,
self.device.device_id.clone(),
packages.to_vec(),
),
export_packages(*selected_user, packages.to_vec()),
Message::PackagesExported,
),
Message::PackagesExported(exported) => {