diff --git a/build.rs b/build.rs index 9699618..9aaad96 100644 --- a/build.rs +++ b/build.rs @@ -13,4 +13,4 @@ fn main() { println!("cargo:rustc-link-lib=static=stdc++"); println!("cargo:rustc-link-lib=static=winpthread"); } -} \ No newline at end of file +} diff --git a/src/core/mod.rs b/src/core/mod.rs index b4d859a..93ecf8a 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,4 +1,4 @@ pub mod sync; +pub mod theme; pub mod uad_lists; pub mod utils; -pub mod theme; \ No newline at end of file diff --git a/src/core/sync.rs b/src/core/sync.rs index f90a391..558812a 100644 --- a/src/core/sync.rs +++ b/src/core/sync.rs @@ -1,15 +1,14 @@ -use std::process::Command; -use std::collections::{HashSet}; -use regex::Regex; -use crate::core::uad_lists::{PackageState}; +use crate::core::uad_lists::PackageState; use crate::gui::views::settings::Settings; use crate::gui::widgets::package_row::PackageRow; -use static_init::{dynamic}; +use regex::Regex; +use static_init::dynamic; +use std::collections::HashSet; +use std::process::Command; #[cfg(target_os = "windows")] use std::os::windows::process::CommandExt; - #[derive(Debug)] pub struct Phone { pub model: String, @@ -35,36 +34,27 @@ pub struct User { impl std::fmt::Display for User { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - format!("user {}", self.id), - ) + write!(f, "{}", format!("user {}", self.id),) } -} -pub fn adb_shell_command(args: &str) -> Result { - +} +pub fn adb_shell_command(args: &str) -> Result { #[cfg(target_os = "windows")] - let output = Command::new("adb") - .args(&["shell", args]) - .creation_flags(0x08000000) // do not open a cmd window - .output(); + let output = Command::new("adb") + .args(&["shell", args]) + .creation_flags(0x08000000) // do not open a cmd window + .output(); #[cfg(target_os = "macos")] - let output = Command::new("adb") - .args(&["shell", args]) - .output(); + let output = Command::new("adb").args(&["shell", args]).output(); #[cfg(not(any(target_os = "macos", target_os = "windows")))] - let output = Command::new("adb") - .args(&["shell", args]) - .output(); + let output = Command::new("adb").args(&["shell", args]).output(); match output { Err(e) => { error!("ADB: {}", e); Err("ADB was not found".to_string()) - }, + } Ok(o) => { if !o.status.success() { let stdout = String::from_utf8(o.stdout).unwrap().trim_end().to_string(); @@ -77,11 +67,9 @@ pub fn adb_shell_command(args: &str) -> Result { Ok(String::from_utf8(o.stdout).unwrap().trim_end().to_string()) } } - } - + } } - pub fn list_all_system_packages(user_id: &Option<&User>) -> String { let action = match user_id { Some(user_id) => format!("pm list packages -s -u --user {}", user_id.id), @@ -96,7 +84,7 @@ pub fn list_all_system_packages(user_id: &Option<&User>) -> String { pub fn hashset_system_packages(state: PackageState, user_id: &Option<&User>) -> HashSet { let user = match user_id { Some(user_id) => format!(" --user {}", user_id.id), - None => "".to_string() + None => "".to_string(), }; let action = match state { @@ -113,80 +101,105 @@ pub fn hashset_system_packages(state: PackageState, user_id: &Option<&User>) -> .collect() } -pub fn action_handler(selected_user: &User, package: &PackageRow, phone: &Phone, settings: &Settings) -> Result { +pub fn action_handler( + selected_user: &User, + package: &PackageRow, + phone: &Phone, + settings: &Settings, +) -> Result { let actions: Vec = match package.state { - PackageState::Enabled => { - match settings.disable_mode { - true => { - if phone.android_sdk < 21 { - vec![ - format!("am force-stop {}", package.name), - format!("pm disable-user {}", package.name), - format!("pm clear {}", package.name) - ] - } else if settings.multi_user_mode{ - phone.user_list - .iter() - .flat_map( - |u| [ - format!("am force-stop --user {} {}", u.id, package.name), - format!("pm disable-user --user {} {}", u.id, package.name), - format!("pm clear --user {} {}", u.id, package.name) - ]) - .collect() - } else { - vec![ - format!("am force-stop --user {} {}", selected_user.id, package.name), - format!("pm disable-user --user {} {}", selected_user.id, package.name), - format!("pm clear --user {} {}", selected_user.id, package.name) - ] - } - } - false => { - if phone.android_sdk < 21 { - vec![format!("pm uninstall {}", package.name)] - } else if settings.multi_user_mode { - phone.user_list - .iter() - .map(|u| format!("pm uninstall --user {} {}", u.id, package.name)) - .collect() - } else { - vec![format!("pm uninstall --user {} {}", selected_user.id, package.name)] - } + PackageState::Enabled => match settings.disable_mode { + true => { + if phone.android_sdk < 21 { + vec![ + format!("am force-stop {}", package.name), + format!("pm disable-user {}", package.name), + format!("pm clear {}", package.name), + ] + } else if settings.multi_user_mode { + phone + .user_list + .iter() + .flat_map(|u| { + [ + format!("am force-stop --user {} {}", u.id, package.name), + format!("pm disable-user --user {} {}", u.id, package.name), + format!("pm clear --user {} {}", u.id, package.name), + ] + }) + .collect() + } else { + vec![ + format!("am force-stop --user {} {}", selected_user.id, package.name), + format!( + "pm disable-user --user {} {}", + selected_user.id, package.name + ), + format!("pm clear --user {} {}", selected_user.id, package.name), + ] } } - } + false => { + if phone.android_sdk < 21 { + vec![format!("pm uninstall {}", package.name)] + } else if settings.multi_user_mode { + phone + .user_list + .iter() + .map(|u| format!("pm uninstall --user {} {}", u.id, package.name)) + .collect() + } else { + vec![format!( + "pm uninstall --user {} {}", + selected_user.id, package.name + )] + } + } + }, PackageState::Uninstalled => { if phone.android_sdk < 21 { Vec::new() // action already prevented by the GUI } else if settings.multi_user_mode { - phone.user_list + phone + .user_list .iter() - .map(|u| format!("cmd package install-existing --user {} {}", u.id, package.name)) + .map(|u| { + format!( + "cmd package install-existing --user {} {}", + u.id, package.name + ) + }) .collect() } else { - vec![format!("cmd package install-existing --user {} {}", selected_user.id, package.name)] + vec![format!( + "cmd package install-existing --user {} {}", + selected_user.id, package.name + )] } - }, + } PackageState::Disabled => { if phone.android_sdk < 21 { vec![format!("pm enable {}", package.name)] } else if settings.multi_user_mode { - phone.user_list + phone + .user_list .iter() .map(|u| format!("pm enable --user {} {}", u.id, package.name)) .collect() } else { - vec![format!("pm enable --user {} {}", selected_user.id, package.name)] + vec![format!( + "pm enable --user {} {}", + selected_user.id, package.name + )] } - }, + } PackageState::All => vec![], // This can't happen (like... never) }; for action in actions { match adb_shell_command(&action) { - Ok(_) => { - info!("[{}] {}", package.removal , action); + Ok(_) => { + info!("[{}] {}", package.removal, action); } Err(err) => { if err.contains("[not installed for") { @@ -211,21 +224,22 @@ pub fn get_phone_model() -> String { err } } - } } pub fn get_android_sdk() -> u8 { match adb_shell_command("getprop ro.build.version.sdk") { Ok(sdk) => sdk.parse().unwrap(), - Err(_) => 0, + Err(_) => 0, } } - pub fn get_phone_brand() -> String { - format!("{} {}", - adb_shell_command("getprop ro.product.brand").unwrap_or_else(|_| "".to_string()).trim(), + format!( + "{} {}", + adb_shell_command("getprop ro.product.brand") + .unwrap_or_else(|_| "".to_string()) + .trim(), get_phone_model() ) } @@ -235,10 +249,14 @@ pub fn get_user_list() -> Vec { static RE: Regex = Regex::new(r"\{([0-9]+)").unwrap(); match adb_shell_command("pm list users") { - Ok(users) => RE.find_iter(&users) - .enumerate() - .map(|(i,u)| User { id: u.as_str()[1..].parse().unwrap(), index: i}) - .collect(), + Ok(users) => RE + .find_iter(&users) + .enumerate() + .map(|(i, u)| User { + id: u.as_str()[1..].parse().unwrap(), + index: i, + }) + .collect(), Err(_) => vec![], } -} \ No newline at end of file +} diff --git a/src/core/theme.rs b/src/core/theme.rs index de397a3..6f3613e 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -1,5 +1,5 @@ -use std::cmp::Ordering; use iced::Color; +use std::cmp::Ordering; #[derive(Debug, Clone)] pub struct Theme { @@ -38,11 +38,7 @@ pub struct ColorPalette { impl Theme { pub fn all() -> Vec { - vec![ - Theme::dark(), - Theme::light(), - Theme::lupin(), - ] + vec![Theme::dark(), Theme::light(), Theme::lupin()] } pub fn dark() -> Theme { @@ -116,7 +112,6 @@ impl Theme { }, } } - } impl PartialEq for Theme { @@ -173,4 +168,4 @@ fn hex_to_color(hex: &str) -> Option { } None -} \ No newline at end of file +} diff --git a/src/core/uad_lists.rs b/src/core/uad_lists.rs index 35bf437..e21c5a6 100644 --- a/src/core/uad_lists.rs +++ b/src/core/uad_lists.rs @@ -1,8 +1,7 @@ -use serde::{Deserialize}; +use serde::Deserialize; use serde_json; //use std::fs; -use std::{collections::HashMap}; - +use std::collections::HashMap; #[derive(Deserialize, Debug, Clone, PartialEq, Hash, Eq)] #[serde(rename_all = "camelCase")] @@ -16,7 +15,6 @@ pub struct Package { pub removal: Removal, } - #[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum UadList { All, @@ -90,7 +88,6 @@ impl PackageState { ]; } - impl std::fmt::Display for PackageState { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -114,8 +111,12 @@ impl Opposite for PackageState { fn opposite(&self, disable: bool) -> PackageState { match self { PackageState::Enabled => { - if disable {PackageState::Disabled} else {PackageState::Uninstalled} - }, + if disable { + PackageState::Disabled + } else { + PackageState::Uninstalled + } + } PackageState::Uninstalled => PackageState::Enabled, PackageState::Disabled => PackageState::Enabled, PackageState::All => PackageState::All, @@ -151,7 +152,6 @@ impl Removal { ]; } - impl std::fmt::Display for Removal { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -169,7 +169,6 @@ impl std::fmt::Display for Removal { } } - pub fn load_debloat_lists() -> HashMap { const DATA: &str = include_str!("../../ressources/assets/uad_lists.json"); let mut package_lists = HashMap::new(); @@ -185,6 +184,3 @@ pub fn load_debloat_lists() -> HashMap { package_lists } - - - diff --git a/src/core/utils.rs b/src/core/utils.rs index 7b3b118..49805c0 100644 --- a/src/core/utils.rs +++ b/src/core/utils.rs @@ -1,15 +1,18 @@ -use crate::core::uad_lists::{UadList, PackageState, Package, Removal}; -use crate::gui::widgets::package_row::PackageRow; +use crate::core::sync::{hashset_system_packages, list_all_system_packages, User}; +use crate::core::uad_lists::{Package, PackageState, Removal, UadList}; use crate::gui::views::list::Selection; -use crate::core::sync::{list_all_system_packages, hashset_system_packages, User}; +use crate::gui::widgets::package_row::PackageRow; use crate::gui::ICONS; -use iced::{Text, alignment, Length}; +use iced::{alignment, Length, Text}; use std::collections::HashMap; -use std::fs; +use std::fs; use std::io::{self, prelude::*, BufReader}; -pub fn fetch_packages(uad_lists: &'static HashMap, user_id: &Option<&User>) -> Vec { +pub fn fetch_packages( + uad_lists: &'static HashMap, + user_id: &Option<&User>, +) -> Vec { 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); let disabled_system_packages = hashset_system_packages(PackageState::Disabled, user_id); @@ -27,46 +30,49 @@ pub fn fetch_packages(uad_lists: &'static HashMap, user_id: &Op if uad_lists.contains_key(p_name) { description = match &uad_lists.get(p_name).unwrap().description { - Some(descr) => descr, - None => "[No description]", - }; + Some(descr) => descr, + None => "[No description]", + }; uad_list = uad_lists.get(p_name).unwrap().list; removal = uad_lists.get(p_name).unwrap().removal; } if enabled_system_packages.contains(p_name) { - state = PackageState::Enabled; + state = PackageState::Enabled; } else if disabled_system_packages.contains(p_name) { state = PackageState::Disabled; } - let package_row = PackageRow::new( - p_name, - state, - description, - uad_list, - removal, - false, - ); + let package_row = PackageRow::new(p_name, state, description, uad_list, removal, false); user_package.push(package_row); } user_package.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())); user_package } - - pub fn update_selection_count(selection: &mut Selection, p_state: PackageState, add: bool) { match p_state { PackageState::Enabled => { - if add { selection.enabled += 1 } else { selection.enabled -= 1 }; - }, + if add { + selection.enabled += 1 + } else { + selection.enabled -= 1 + }; + } PackageState::Disabled => { - if add { selection.disabled += 1 } else { selection.disabled -= 1 }; - }, + if add { + selection.disabled += 1 + } else { + selection.disabled -= 1 + }; + } PackageState::Uninstalled => { - if add { selection.uninstalled += 1 } else { selection.uninstalled -= 1 }; - }, + if add { + selection.uninstalled += 1 + } else { + selection.uninstalled -= 1 + }; + } PackageState::All => {} }; } @@ -81,12 +87,15 @@ pub async fn export_selection(packages: Vec) -> Result match fs::write("uad_exported_selection.txt", selected) { Ok(_) => Ok(true), - Err(err) => Err(err.to_string()) + Err(err) => Err(err.to_string()), } } #[allow(clippy::needless_collect)] // false positive: https://github.com/rust-lang/rust-clippy/issues/6164 -pub fn import_selection(packages: &mut Vec, selection: &mut Selection) -> io::Result<()> { +pub fn import_selection( + packages: &mut Vec, + selection: &mut Selection, +) -> io::Result<()> { let file = fs::File::open("uad_exported_selection.txt")?; let reader = BufReader::new(file); let imported_selection: Vec = reader @@ -96,7 +105,7 @@ pub fn import_selection(packages: &mut Vec, selection: &mut Selectio *selection = Selection::default(); // should already be empty normally - for (i,p) in packages.iter_mut().enumerate() { + for (i, p) in packages.iter_mut().enumerate() { if imported_selection.contains(&p.name) { p.selected = true; selection.selected_packages.push(i); diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 87f0bee..44eec76 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -2,16 +2,16 @@ pub mod style; pub mod views; pub mod widgets; +pub use crate::core::sync::Phone; +pub use crate::core::uad_lists::Package; +use crate::core::utils::icon; pub use views::about::About as AboutView; pub use views::list::{List as AppsView, Message as AppsMessage}; -pub use views::settings::{Settings as SettingsView, Message as SettingsMessage}; -pub use crate::core::uad_lists::Package; -pub use crate::core::sync::{Phone}; -use crate::core::utils::icon; +pub use views::settings::{Message as SettingsMessage, Settings as SettingsView}; use iced::{ - button, Alignment, Application, Button, Column, Command, Space, Font, - Container, Element, Length, Row, Settings, Text, window::Settings as Window, + button, window::Settings as Window, Alignment, Application, Button, Column, Command, Container, + Element, Font, Length, Row, Settings, Space, Text, }; pub const ICONS: Font = Font::External { @@ -19,12 +19,11 @@ pub const ICONS: Font = Font::External { bytes: include_bytes!("../../ressources/assets/icons.ttf"), }; - #[derive(Debug, Clone)] pub enum View { List, About, - Settings, + Settings, } impl Default for View { @@ -78,14 +77,20 @@ impl Application for UadGui { fn update(&mut self, message: Message) -> Command { match message { Message::Init(_) => { - info!("ANDROID_SDK: {} | PHONE: {}", self.phone.android_sdk, self.phone.model); + info!( + "ANDROID_SDK: {} | PHONE: {}", + self.phone.android_sdk, self.phone.model + ); Command::perform(Self::load_phone_packages(), Message::AppsAction) } Message::AppsRefreshPress => { self.phone = Phone::default(); self.settings_view = SettingsView::default(); info!("{:-^65}", "-"); - info!("ANDROID_SDK: {} | PHONE: {}", self.phone.android_sdk, self.phone.model); + info!( + "ANDROID_SDK: {} | PHONE: {}", + self.phone.android_sdk, self.phone.model + ); self.apps_view = AppsView::default(); self.view = View::List; Command::perform(Self::load_phone_packages(), Message::AppsAction) @@ -102,9 +107,10 @@ impl Application for UadGui { self.view = View::Settings; Command::none() } - Message::AppsAction(msg) => { - self.apps_view.update(&self.settings_view, &mut self.phone, msg).map(Message::AppsAction) - } + Message::AppsAction(msg) => self + .apps_view + .update(&self.settings_view, &mut self.phone, msg) + .map(Message::AppsAction), Message::SettingsAction(msg) => { self.settings_view.update(msg); Command::none() @@ -153,7 +159,10 @@ impl Application for UadGui { .style(style::NavigationContainer(self.settings_view.theme.palette)); let main_container = match self.view { - View::List => self.apps_view.view(&self.settings_view, &self.phone).map(Message::AppsAction), + View::List => self + .apps_view + .view(&self.settings_view, &self.phone) + .map(Message::AppsAction), View::About => self.about_view.view(&self.settings_view), View::Settings => self.settings_view.view().map(Message::SettingsAction), }; @@ -166,7 +175,6 @@ impl Application for UadGui { } } - impl UadGui { pub fn start() { let settings: Settings<()> = Settings { @@ -187,7 +195,6 @@ impl UadGui { } } - fn refresh_icon() -> Text { icon('\u{E900}') -} \ No newline at end of file +} diff --git a/src/gui/style.rs b/src/gui/style.rs index 7384eb5..56d5856 100644 --- a/src/gui/style.rs +++ b/src/gui/style.rs @@ -1,8 +1,5 @@ -use iced::{ - button, container, scrollable, Background, Color, checkbox, - text_input, pick_list, -}; use crate::core::theme::ColorPalette; +use iced::{button, checkbox, container, pick_list, scrollable, text_input, Background, Color}; pub struct Content(pub ColorPalette); impl container::StyleSheet for Content { @@ -80,7 +77,6 @@ impl button::StyleSheet for RefreshButton { } } - pub enum PackageButton { Uninstall(ColorPalette), Restore(ColorPalette), @@ -137,8 +133,8 @@ impl button::StyleSheet for PackageButton { match self { Self::Restore(palette) => button::Style { background: Some(Background::Color(Color { - a: 0.05, - ..palette.normal.primary + a: 0.05, + ..palette.normal.primary })), text_color: Color { a: 0.50, @@ -148,8 +144,8 @@ impl button::StyleSheet for PackageButton { }, Self::Uninstall(palette) => button::Style { background: Some(Background::Color(Color { - a: 0.01, - ..palette.bright.error + a: 0.01, + ..palette.bright.error })), text_color: Color { a: 0.50, @@ -184,12 +180,12 @@ impl button::StyleSheet for PackageRow { } } fn pressed(&self) -> button::Style { - button::Style { - background: Some(Background::Color(Color::from_rgb(0.35, 0.43, 0.46))), - text_color: self.0.bright.primary, - ..self.active() - } + button::Style { + background: Some(Background::Color(Color::from_rgb(0.35, 0.43, 0.46))), + text_color: self.0.bright.primary, + ..self.active() } + } } pub struct Description(pub ColorPalette); @@ -276,10 +272,9 @@ impl scrollable::StyleSheet for Scrollable { } } - pub enum SelectionCheckBox { Enabled(ColorPalette), - Disabled(ColorPalette) + Disabled(ColorPalette), } impl checkbox::StyleSheet for SelectionCheckBox { diff --git a/src/gui/views/about.rs b/src/gui/views/about.rs index 638bd22..de55cc5 100644 --- a/src/gui/views/about.rs +++ b/src/gui/views/about.rs @@ -1,6 +1,6 @@ use crate::gui::style; -use crate::gui::Message; use crate::gui::views::settings::Settings; +use crate::gui::Message; use iced::{Alignment, Column, Container, Element, Length, Text}; #[derive(Default, Debug, Clone)] @@ -25,4 +25,4 @@ impl About { .style(style::Content(settings.theme.palette)) .into() } -} \ No newline at end of file +} diff --git a/src/gui/views/list.rs b/src/gui/views/list.rs index 58030a8..a63c08a 100644 --- a/src/gui/views/list.rs +++ b/src/gui/views/list.rs @@ -1,25 +1,39 @@ -use crate::gui::style; -use crate::core::sync::{Phone, action_handler, User}; +use crate::core::sync::{action_handler, Phone, User}; use crate::core::uad_lists::{ - UadList, PackageState, Package, Removal, Opposite, load_debloat_lists + load_debloat_lists, Opposite, Package, PackageState, Removal, UadList, }; use crate::core::utils::{ - import_selection, export_selection, update_selection_count, fetch_packages, + export_selection, fetch_packages, import_selection, update_selection_count, }; -use std::{collections::HashMap}; -use static_init::{dynamic}; +use crate::gui::style; +use static_init::dynamic; +use std::collections::HashMap; use crate::gui::views::settings::Settings; -use crate::gui::widgets::package_row::{ PackageRow, Message as RowMessage }; +use crate::gui::widgets::package_row::{Message as RowMessage, PackageRow}; use iced::{ - scrollable, Alignment, alignment, Column, Container, Element, Space, - Length, Row, Scrollable, Text, text_input, TextInput, Command,//Svg, - PickList, pick_list, Button, button, + alignment, + button, + pick_list, + scrollable, + text_input, + Alignment, + Button, + Column, + Command, //Svg, + Container, + Element, + Length, + PickList, + Row, + Scrollable, + Space, + Text, + TextInput, }; - #[dynamic] -static UAD_LISTS: HashMap = load_debloat_lists(); +static UAD_LISTS: HashMap = load_debloat_lists(); #[derive(Debug, Default, Clone)] pub struct Selection { @@ -60,7 +74,6 @@ pub struct List { description: String, } - #[derive(Debug, Clone)] pub enum Message { SearchInputChanged(String), @@ -76,22 +89,27 @@ pub enum Message { ExportedSelection(Result), } - impl List { - pub fn update(&mut self, settings: &Settings, phone: &mut Phone, message: Message) -> Command { - let i_user = &self.selected_user.unwrap_or(User {id: 0, index: 0}).index; // for readability + pub fn update( + &mut self, + settings: &Settings, + phone: &mut Phone, + message: Message, + ) -> Command { + let i_user = &self.selected_user.unwrap_or(User { id: 0, index: 0 }).index; // for readability match message { Message::LoadPackages => { self.selected_package_state = Some(PackageState::Enabled); self.selected_list = Some(UadList::All); self.selected_removal = Some(Removal::Recommended); - self.selected_user = Some(User {id: 0, index: 0}); + self.selected_user = Some(User { id: 0, index: 0 }); match phone.user_list.len() { - 0|1 => self.phone_packages.push(fetch_packages(&UAD_LISTS, &None)), + 0 | 1 => self.phone_packages.push(fetch_packages(&UAD_LISTS, &None)), _ => { for user in &phone.user_list { - self.phone_packages.push(fetch_packages(&UAD_LISTS, &Some(user))); + self.phone_packages + .push(fetch_packages(&UAD_LISTS, &Some(user))); } } } @@ -111,7 +129,6 @@ impl List { Command::none() } Message::ListSelected(list) => { - self.selected_list = Some(list); Self::filter_package_lists(self); Command::none() @@ -127,77 +144,97 @@ impl List { Command::none() } Message::List(i, row_message) => { - self.phone_packages[*i_user][i].update(row_message.clone()).map(move |row_message| Message::List(i, row_message)); - + self.phone_packages[*i_user][i] + .update(row_message.clone()) + .map(move |row_message| Message::List(i, row_message)); + match row_message { RowMessage::ToggleSelection(toggle) => { - if self.phone_packages[*i_user][i].removal == Removal::Unsafe && !settings.expert_mode { + if self.phone_packages[*i_user][i].removal == Removal::Unsafe + && !settings.expert_mode + { self.phone_packages[*i_user][i].selected = false; } else { self.phone_packages[*i_user][i].selected = toggle; if self.phone_packages[*i_user][i].selected { self.selection.selected_packages.push(i); - update_selection_count(&mut self.selection, self.phone_packages[*i_user][i].state, true); + update_selection_count( + &mut self.selection, + self.phone_packages[*i_user][i].state, + true, + ); } else { - self.selection.selected_packages.drain_filter(|s_i| *s_i == i); - update_selection_count(&mut self.selection, self.phone_packages[*i_user][i].state, false); + self.selection + .selected_packages + .drain_filter(|s_i| *s_i == i); + update_selection_count( + &mut self.selection, + self.phone_packages[*i_user][i].state, + false, + ); } } - - }, + } RowMessage::ActionPressed => { let success = action_handler( - &self.selected_user.unwrap(), - &self.phone_packages[*i_user][i], - phone, - settings, - ).unwrap_or_else(|err| err); - + &self.selected_user.unwrap(), + &self.phone_packages[*i_user][i], + phone, + settings, + ) + .unwrap_or_else(|err| err); + if success { let i = self.phone_packages[*i_user] .iter() .position(|p| p.name == self.phone_packages[*i_user][i].name) .unwrap(); if self.phone_packages[*i_user][i].selected { - update_selection_count(&mut self.selection, self.phone_packages[*i_user][i].state, false); + update_selection_count( + &mut self.selection, + self.phone_packages[*i_user][i].state, + false, + ); } - - self.phone_packages[*i_user][i].state = self.phone_packages[*i_user][i].state + + self.phone_packages[*i_user][i].state = self.phone_packages[*i_user][i] + .state .opposite(settings.disable_mode); if settings.multi_user_mode { for u in &phone.user_list { - self.phone_packages[u.index][i].state = self.phone_packages[*i_user][i].state; + self.phone_packages[u.index][i].state = + self.phone_packages[*i_user][i].state; self.phone_packages[u.index][i].selected = false; } } - self.selection.selected_packages.drain_filter(|s_i| *s_i == i); + self.selection + .selected_packages + .drain_filter(|s_i| *s_i == i); self.phone_packages[*i_user][i].selected = false; Self::filter_package_lists(self); } - }, + } RowMessage::PackagePressed => { self.description = self.phone_packages[*i_user][i].clone().description; - }, + } } Command::none() - }, + } Message::ApplyActionOnSelection(action) => { let mut selected_packages = self.selection.selected_packages.clone(); - + match action { Action::Remove => { - selected_packages.drain_filter( - |i| + selected_packages.drain_filter(|i| { self.phone_packages[*i_user][*i].state != PackageState::Enabled - ); + }); } Action::Restore => { - selected_packages.drain_filter( - |i| + selected_packages.drain_filter(|i| { self.phone_packages[*i_user][*i].state == PackageState::Enabled - ); + }); } } @@ -206,52 +243,62 @@ impl List { &self.selected_user.unwrap(), &self.phone_packages[*i_user][i], phone, - settings - ).unwrap_or_else(|err| err); - + settings, + ) + .unwrap_or_else(|err| err); + if success { update_selection_count( - &mut self.selection, - self.phone_packages[*i_user][i].state, - false + &mut self.selection, + self.phone_packages[*i_user][i].state, + false, ); if !settings.multi_user_mode { - self.phone_packages[*i_user][i].state = self.phone_packages[*i_user][i].state + self.phone_packages[*i_user][i].state = self.phone_packages[*i_user][i] + .state .opposite(settings.disable_mode); self.phone_packages[*i_user][i].selected = false; } for u in &phone.user_list { - self.phone_packages[u.index][i].state = self.phone_packages[u.index][i].state + self.phone_packages[u.index][i].state = self.phone_packages[u.index][i] + .state .opposite(settings.disable_mode); self.phone_packages[u.index][i].selected = false; } - self.selection.selected_packages.drain_filter(|s_i| *s_i == i); + self.selection + .selected_packages + .drain_filter(|s_i| *s_i == i); } } Self::filter_package_lists(self); Command::none() - }, + } Message::SelectAllPressed => { for i in self.filtered_packages.clone() { self.phone_packages[*i_user][i].selected = true; if !self.selection.selected_packages.contains(&i) { self.selection.selected_packages.push(i); - update_selection_count(&mut self.selection, self.phone_packages[*i_user][i].state, true); + update_selection_count( + &mut self.selection, + self.phone_packages[*i_user][i].state, + true, + ); } } Command::none() - }, - Message::ExportSelectionPressed => { - Command::perform(export_selection(self.phone_packages[*i_user].clone()), Message::ExportedSelection) - }, + } + Message::ExportSelectionPressed => Command::perform( + export_selection(self.phone_packages[*i_user].clone()), + Message::ExportedSelection, + ), Message::ExportedSelection(export) => { match export { Ok(_) => info!("Selection exported"), Err(err) => error!("Selection export: {}", err), }; - Command::none() - }, + Command::none() + } Message::UserSelected(user) => { for p in &mut self.phone_packages[*i_user] { p.selected = false; @@ -262,7 +309,7 @@ impl List { } self.filtered_packages = (0..self.phone_packages[user.index].len()).collect(); Self::filter_package_lists(self); - Command::none() + Command::none() } } } @@ -279,42 +326,41 @@ impl List { .style(style::SearchInput(settings.theme.palette)); // let package_amount = Text::new(format!("{} packages found", packages.len())); - + let user_picklist = PickList::new( - &mut self.user_picklist, - phone.user_list.clone(), - self.selected_user, - Message::UserSelected, - ) - .width(Length::Units(85)) - .style(style::PickList(settings.theme.palette)); + &mut self.user_picklist, + phone.user_list.clone(), + self.selected_user, + Message::UserSelected, + ) + .width(Length::Units(85)) + .style(style::PickList(settings.theme.palette)); let divider = Space::new(Length::Fill, Length::Shrink); let list_picklist = PickList::new( - &mut self.list_picklist, - &UadList::ALL[..], - self.selected_list, - Message::ListSelected, - ) - .style(style::PickList(settings.theme.palette)); + &mut self.list_picklist, + &UadList::ALL[..], + self.selected_list, + Message::ListSelected, + ) + .style(style::PickList(settings.theme.palette)); let package_state_picklist = PickList::new( - &mut self.package_state_picklist, - &PackageState::ALL[..], - self.selected_package_state, - Message::PackageStateSelected, - ) - .style(style::PickList(settings.theme.palette)); - + &mut self.package_state_picklist, + &PackageState::ALL[..], + self.selected_package_state, + Message::PackageStateSelected, + ) + .style(style::PickList(settings.theme.palette)); let removal_picklist = PickList::new( - &mut self.removal_picklist, - &Removal::ALL[..], - self.selected_removal, - Message::RemovalSelected, - ) - .style(style::PickList(settings.theme.palette)); + &mut self.removal_picklist, + &Removal::ALL[..], + self.selected_removal, + Message::RemovalSelected, + ) + .style(style::PickList(settings.theme.palette)); let control_panel = Row::new() .width(Length::Fill) @@ -330,9 +376,12 @@ impl List { let packages = self.phone_packages[self.selected_user.unwrap().index] .iter_mut() .enumerate() - .filter(|(i,_)| self.filtered_packages.contains(i)) - .fold(Column::new().spacing(6), |col, (i,p)| { - col.push(p.view(settings, phone).map(move |msg| Message::List(i, msg))) + .filter(|(i, _)| self.filtered_packages.contains(i)) + .fold(Column::new().spacing(6), |col, (i, p)| { + col.push( + p.view(settings, phone) + .map(move |msg| Message::List(i, msg)), + ) }); /* @@ -363,38 +412,56 @@ impl List { .width(Length::Fill) .style(style::Description(settings.theme.palette)); - let restore_action = if settings.disable_mode {"Enable/Restore"} else {"Restore"}; - let remove_action = if settings.disable_mode {"Disable"} else {"Uninstall"}; + let restore_action = if settings.disable_mode { + "Enable/Restore" + } else { + "Restore" + }; + let remove_action = if settings.disable_mode { + "Disable" + } else { + "Uninstall" + }; let apply_restore_selection = Button::new( - &mut self.apply_restore_selection, - Text::new(format!("{} selection ({})", - restore_action, - self.selection.uninstalled + self.selection.disabled) - ) - ) - .on_press(Message::ApplyActionOnSelection(Action::Restore)) - .padding(5) - .style(style::PrimaryButton(settings.theme.palette)); + &mut self.apply_restore_selection, + Text::new(format!( + "{} selection ({})", + restore_action, + self.selection.uninstalled + self.selection.disabled + )), + ) + .on_press(Message::ApplyActionOnSelection(Action::Restore)) + .padding(5) + .style(style::PrimaryButton(settings.theme.palette)); let apply_remove_selection = Button::new( - &mut self.apply_remove_selection, - Text::new(format!("{} selection ({})", remove_action, self.selection.enabled))) - .on_press(Message::ApplyActionOnSelection(Action::Remove)) - .padding(5) - .style(style::PrimaryButton(settings.theme.palette)); + &mut self.apply_remove_selection, + Text::new(format!( + "{} selection ({})", + remove_action, self.selection.enabled + )), + ) + .on_press(Message::ApplyActionOnSelection(Action::Remove)) + .padding(5) + .style(style::PrimaryButton(settings.theme.palette)); - let select_all_btn = Button::new(&mut self.select_all_btn_state, Text::new("Select all")) - .padding(5) - .on_press(Message::SelectAllPressed) - .style(style::PrimaryButton(settings.theme.palette)); + let select_all_btn = + Button::new(&mut self.select_all_btn_state, Text::new("Select all")) + .padding(5) + .on_press(Message::SelectAllPressed) + .style(style::PrimaryButton(settings.theme.palette)); let export_selection_btn = Button::new( - &mut self.export_selection_btn_state, - Text::new(format!("Export current selection ({})", self.selection.selected_packages.len()))) - .padding(5) - .on_press(Message::ExportSelectionPressed) - .style(style::PrimaryButton(settings.theme.palette)); + &mut self.export_selection_btn_state, + Text::new(format!( + "Export current selection ({})", + self.selection.selected_packages.len() + )), + ) + .padding(5) + .on_press(Message::ExportSelectionPressed) + .style(style::PrimaryButton(settings.theme.palette)); let action_row = Row::new() .width(Length::Fill) @@ -427,7 +494,6 @@ impl List { } fn filter_package_lists(&mut self) { - let list_filter: UadList = self.selected_list.unwrap(); let package_filter: PackageState = self.selected_package_state.unwrap(); let removal_filter: Removal = self.selected_removal.unwrap(); @@ -435,19 +501,17 @@ impl List { self.filtered_packages = self.phone_packages[self.selected_user.unwrap().index] .iter() .enumerate() - .filter( - |(_,p)| - (list_filter == UadList::All || p.uad_list == list_filter) && - (package_filter == PackageState::All || p.state == package_filter) && - (removal_filter == Removal::All || p.removal == removal_filter) && - (self.input_value.is_empty() || p.name.contains(&self.input_value)) - ) - .map(|(i,_)| i) + .filter(|(_, p)| { + (list_filter == UadList::All || p.uad_list == list_filter) + && (package_filter == PackageState::All || p.state == package_filter) + && (removal_filter == Removal::All || p.removal == removal_filter) + && (self.input_value.is_empty() || p.name.contains(&self.input_value)) + }) + .map(|(i, _)| i) .collect(); } } - fn loading_data<'a>(settings: &Settings) -> Element<'a, Message> { Container::new( Text::new("Pulling packages from the phone. Please wait...") @@ -461,4 +525,4 @@ fn loading_data<'a>(settings: &Settings) -> Element<'a, Message> { .center_x() .style(style::Content(settings.theme.palette)) .into() -} \ No newline at end of file +} diff --git a/src/gui/views/mod.rs b/src/gui/views/mod.rs index d1a434d..a288610 100644 --- a/src/gui/views/mod.rs +++ b/src/gui/views/mod.rs @@ -1,3 +1,3 @@ +pub mod about; pub mod list; pub mod settings; -pub mod about; \ No newline at end of file diff --git a/src/gui/views/settings.rs b/src/gui/views/settings.rs index e6c0e81..0dabaf1 100644 --- a/src/gui/views/settings.rs +++ b/src/gui/views/settings.rs @@ -1,9 +1,7 @@ -use crate::gui::style; -use crate::core::theme::{Theme}; use crate::core::sync::get_android_sdk; -use iced::{Checkbox, Column, Container, Element, Length, Text, Space, - pick_list, PickList, - }; +use crate::core::theme::Theme; +use crate::gui::style; +use iced::{pick_list, Checkbox, Column, Container, Element, Length, PickList, Space, Text}; #[derive(Debug, Clone)] pub struct Settings { @@ -21,7 +19,7 @@ impl Default for Settings { disable_mode: get_android_sdk() < 26, multi_user_mode: get_android_sdk() > 21, theme: Theme::lupin(), - theme_picklist: pick_list::State::default() + theme_picklist: pick_list::State::default(), } } } @@ -38,17 +36,26 @@ impl Settings { pub fn update(&mut self, msg: Message) { match msg { Message::ExpertMode(toggled) => { - info!("Expert mode {}", if toggled {"enabled"} else {"disabled"}); + info!( + "Expert mode {}", + if toggled { "enabled" } else { "disabled" } + ); self.expert_mode = toggled; - }, + } Message::DisableMode(toggled) => { - info!("Disable mode {}", if toggled {"enabled"} else {"disabled"}); + info!( + "Disable mode {}", + if toggled { "enabled" } else { "disabled" } + ); self.disable_mode = toggled; - }, + } Message::MultiUserMode(toggled) => { - info!("Multi-user mode {}", if toggled {"enabled"} else {"disabled"}); + info!( + "Multi-user mode {}", + if toggled { "enabled" } else { "disabled" } + ); self.multi_user_mode = toggled; - }, + } Message::ApplyTheme(theme) => { self.theme = theme; } @@ -63,19 +70,20 @@ impl Settings { Theme::all(), Some(self.theme.clone()), Message::ApplyTheme, - ) - .style(style::PickList(self.theme.palette)); + ) + .style(style::PickList(self.theme.palette)); let uad_category_text = Text::new("UAD").size(25); - let expert_mode_descr = Text::new("Most of unsafe packages are known to bootloop the device if removed.") - .size(15) - .color(self.theme.palette.normal.surface); + let expert_mode_descr = + Text::new("Most of unsafe packages are known to bootloop the device if removed.") + .size(15) + .color(self.theme.palette.normal.surface); let expert_mode_checkbox = Checkbox::new( - self.expert_mode, - "Allow to uninstall packages marked as \"unsafe\" (I KNOW WHAT I AM DOING)", - Message::ExpertMode + self.expert_mode, + "Allow to uninstall packages marked as \"unsafe\" (I KNOW WHAT I AM DOING)", + Message::ExpertMode, ); let disable_mode_descr = Text::new("Default mode on older phone (< Android 8.0) where uninstalled packages can't be restored.") @@ -83,19 +91,20 @@ impl Settings { .color(self.theme.palette.normal.surface); let disable_mode_checkbox = Checkbox::new( - self.disable_mode, + self.disable_mode, "Clear and disable packages instead of uninstalling them", - Message::DisableMode + Message::DisableMode, ); - let multi_user_mode_descr = Text::new("Disabling this setting will typically prevent affecting your work profile") - .size(15) - .color(self.theme.palette.normal.surface); + let multi_user_mode_descr = + Text::new("Disabling this setting will typically prevent affecting your work profile") + .size(15) + .color(self.theme.palette.normal.surface); let multi_user_mode_checkbox = Checkbox::new( - self.multi_user_mode, + self.multi_user_mode, "Affect all the users of the phone (not only the selected user)", - Message::MultiUserMode + Message::MultiUserMode, ); let content = Column::new() diff --git a/src/gui/widgets/mod.rs b/src/gui/widgets/mod.rs index b1c5fde..991386a 100644 --- a/src/gui/widgets/mod.rs +++ b/src/gui/widgets/mod.rs @@ -1 +1 @@ -pub mod package_row; \ No newline at end of file +pub mod package_row; diff --git a/src/gui/widgets/package_row.rs b/src/gui/widgets/package_row.rs index 574a760..92776a6 100644 --- a/src/gui/widgets/package_row.rs +++ b/src/gui/widgets/package_row.rs @@ -1,12 +1,11 @@ -use crate::core::uad_lists::{UadList, PackageState, Removal}; use crate::core::sync::Phone; +use crate::core::uad_lists::{PackageState, Removal, UadList}; use crate::gui::style; use crate::gui::views::settings::Settings; use iced::{ - Alignment, alignment, Command, Element, Space, Length, Row, Text, Button, - button, Checkbox, + alignment, button, Alignment, Button, Checkbox, Command, Element, Length, Row, Space, Text, }; #[derive(Clone, Debug)] @@ -36,7 +35,6 @@ impl PackageRow { uad_list: UadList, removal: Removal, selected: bool, - ) -> Self { Self { name: name.to_string(), @@ -62,10 +60,13 @@ impl PackageRow { let action_btn; let selection_checkbox; - match self.state { PackageState::Enabled => { - action_text = if settings.disable_mode { "Disable" } else { "Uninstall" }; + action_text = if settings.disable_mode { + "Disable" + } else { + "Uninstall" + }; button_style = style::PackageButton::Uninstall(settings.theme.palette); } PackageState::Disabled => { @@ -81,13 +82,11 @@ impl PackageRow { button_style = style::PackageButton::Restore(settings.theme.palette); warn!("Incredible! Something impossible happenned!"); } - } - if (self.state != PackageState::Uninstalled && settings.expert_mode) || - (self.removal != Removal::Unsafe && phone.android_sdk >= 26) + if (self.state != PackageState::Uninstalled && settings.expert_mode) + || (self.removal != Removal::Unsafe && phone.android_sdk >= 26) { - selection_checkbox = Checkbox::new(self.selected, "", Message::ToggleSelection) .style(style::SelectionCheckBox::Enabled(settings.theme.palette)); @@ -96,7 +95,6 @@ impl PackageRow { Text::new(action_text).horizontal_alignment(alignment::Horizontal::Center), ) .on_press(Message::ActionPressed); - } else { selection_checkbox = Checkbox::new(self.selected, "", Message::ToggleSelection) .style(style::SelectionCheckBox::Disabled(settings.theme.palette)); @@ -108,24 +106,22 @@ impl PackageRow { } Row::new() - .push(Button::new( - &mut self.package_btn_state, - Row::new() - .align_items(Alignment::Center) - .push(selection_checkbox) - .push(Text::new(&self.name).width(Length::FillPortion(8))) - .push(action_btn.width(Length::FillPortion(1)) - .style(button_style) - ) + .push( + Button::new( + &mut self.package_btn_state, + Row::new() + .align_items(Alignment::Center) + .push(selection_checkbox) + .push(Text::new(&self.name).width(Length::FillPortion(8))) + .push(action_btn.width(Length::FillPortion(1)).style(button_style)), ) .padding(8) .style(style::PackageRow(settings.theme.palette)) .width(Length::Fill) - .on_press(Message::PackagePressed) - + .on_press(Message::PackagePressed), ) .push(Space::with_width(Length::Units(15))) .align_items(Alignment::Center) .into() } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index b849cca..1815fbb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,14 @@ #![windows_subsystem = "windows"] #![feature(drain_filter)] -#[macro_use] extern crate log; +#[macro_use] +extern crate log; -use std::{fs::OpenOptions, fmt::Arguments}; -use fern::{FormatCallback, colors::{Color, ColoredLevelConfig}}; +use fern::{ + colors::{Color, ColoredLevelConfig}, + FormatCallback, +}; use log::Record; +use std::{fmt::Arguments, fs::OpenOptions}; mod core; mod gui; @@ -15,7 +19,6 @@ fn main() { } pub fn setup_logger() -> Result<(), fern::InitError> { - let colors = ColoredLevelConfig::new().info(Color::Green); let make_formatter = |use_colors: bool| { @@ -29,10 +32,7 @@ pub fn setup_logger() -> Result<(), fern::InitError> { format!("{:5}", record.level().to_string()) }, record.file().unwrap_or("?"), - record - .line() - .map(|l| l.to_string()) - .unwrap_or_default(), + record.line().map(|l| l.to_string()).unwrap_or_default(), message )) } @@ -64,4 +64,4 @@ pub fn setup_logger() -> Result<(), fern::InitError> { .apply()?; Ok(()) -} \ No newline at end of file +}