Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion src/core/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl Default for GeneralSettings {
impl Default for DeviceSettings {
fn default() -> Self {
Self {
device_id: String::new(),
device_id: String::default(),
multi_user_mode: get_android_sdk() > 21,
disable_mode: false,
backup: BackupSettings::default(),
Expand Down
16 changes: 8 additions & 8 deletions src/core/save.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,23 @@ use std::path::{Path, PathBuf};
pub static BACKUP_DIR: PathBuf = CACHE_DIR.join("backups");

#[derive(Default, Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
struct PhoneBackup {
device_id: String,
users: Vec<UserBackup>,
pub struct PhoneBackup {
pub device_id: String,
pub users: Vec<UserBackup>,
}

#[derive(Default, Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
struct UserBackup {
id: u16,
packages: Vec<CorePackage>,
pub struct UserBackup {
pub id: u16,
pub packages: Vec<CorePackage>,
}

// Backup all `Uninstalled` and `Disabled` packages
Rudxain marked this conversation as resolved.
Show resolved Hide resolved
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()
Expand Down Expand Up @@ -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()),
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Default for Phone {
model: "fetching devices...".to_string(),
android_sdk: 0,
user_list: vec![],
adb_id: String::new(),
adb_id: String::default(),
}
}
}
Expand Down Expand Up @@ -165,7 +165,7 @@ pub fn hashset_system_packages(state: PackageState, user_id: Option<&User>) -> H
let action = match state {
PackageState::Enabled => format!("pm list packages -s -e{user}"),
PackageState::Disabled => format!("pm list package -s -d{user}"),
_ => String::new(), // You probably don't need to use this function for anything else
_ => String::default(), // You probably don't need to use this function for anything else
};

adb_shell_command(true, &action)
Expand Down
1 change: 1 addition & 0 deletions src/core/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
40 changes: 39 additions & 1 deletion src/core/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -12,6 +13,7 @@ use std::{fmt, fs};
/// track of the current device serial.
pub const ANDROID_SERIAL: &str = "ANDROID_SERIAL";
pub const EXPORT_FILE_NAME: &str = "selection_export.txt";
pub const UNINSTALLED_PACKAGES_FILE_NAME: &str = "uninstalled_packages";

#[derive(Debug, Clone)]
pub enum Error {
Expand Down Expand Up @@ -115,6 +117,8 @@ pub fn format_diff_time_from_now(date: DateTime<Utc>) -> String {
}
}

/// Export selected packages.
/// File will be saved in same directory where UAD-ng is located.
pub async fn export_selection(packages: Vec<PackageRow>) -> Result<bool, String> {
let selected = packages
.iter()
Expand Down Expand Up @@ -154,6 +158,7 @@ impl fmt::Display for DisplayablePath {
}
}

/// Can be used to choose any folder.
pub async fn open_folder() -> Result<PathBuf, Error> {
let picked_folder = rfd::AsyncFileDialog::new()
.pick_folder()
Expand All @@ -162,3 +167,36 @@ pub async fn open_folder() -> Result<PathBuf, Error> {

Ok(picked_folder.path().to_owned())
}

/// Export uninstalled packages in a csv file.
/// Exported information will contain package name and description.
pub async fn export_packages(
user: Option<User>,
phone_packages: Vec<Vec<PackageRow>>,
) -> Result<bool, String> {
let uninstalled_packages: Vec<&PackageRow> = phone_packages[user.unwrap().index]
.iter()
.filter(|p| p.state.to_string() == "Uninstalled")
.collect();

let backup_file = format!(
"{}_{}.csv",
UNINSTALLED_PACKAGES_FILE_NAME,
Local::now().format("%Y%m%d")
);

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)
}
3 changes: 2 additions & 1 deletion src/gui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ impl Application for UadGui {
&self.apps_view.phone_packages,
&mut self.nb_running_async_adb_commands,
msg,
&self.apps_view.selected_user,
)
.map(Message::SettingsAction)
}
Expand Down Expand Up @@ -377,7 +378,7 @@ impl Application for UadGui {
.map(Message::AboutAction),
View::Settings => self
.settings_view
.view(&selected_device)
.view(&selected_device, &self.apps_view)
.map(Message::SettingsAction),
};

Expand Down
2 changes: 1 addition & 1 deletion src/gui/views/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub struct List {
selected_package_state: Option<PackageState>,
selected_removal: Option<Removal>,
selected_list: Option<UadList>,
selected_user: Option<User>,
pub selected_user: Option<User>,
all_selected: bool,
pub input_value: String,
description: String,
Expand Down
Loading