diff --git a/.github/ISSUE_TEMPLATE/add-new-package-s-.md b/.github/ISSUE_TEMPLATE/add-new-package-s-.md index adcd949..95492d7 100644 --- a/.github/ISSUE_TEMPLATE/add-new-package-s-.md +++ b/.github/ISSUE_TEMPLATE/add-new-package-s-.md @@ -1,28 +1,34 @@ --- name: Add new package(s) about: You want to add new apps in the debloat list -title: '' +title: "" labels: package::addition -assignees: '' - +assignees: "" --- -**Your phone:** +**Your phone model:** **Packages:** + ``` com.this.is.a.bad.application com.this.is.another.bad.application ... ``` + - [ ] **I removed all those packages on my phone** -If not why. Leave the brackets blank and explain why. + If not why. Leave the brackets blank and explain why. ## Document each package the best you can -**List**: `Google`|`Misc`|`Oem` (manufacturer)|`Aosp`|`Pending`|`Carrier` (isp). -**Removal**: `Recommended`, `Advanced`, `Expert` (this can break important features), `Unsafe` (this can bootloop the phone or break extremely important features). + +**List**: `Google`|`Misc`|`OEM` (manufacturer)|`AOSP`|`Pending`|`Carrier` (isp). + +**Removal**: `Recommended`, `Advanced`, `Expert` (this can break important features), +or `Unsafe` (this can bootloop the phone or break extremely important features). ### \ -**List**: \ + +**List**: \ **Removal**: \ + > Description. Link to its Playstore page if it exists. diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 91cbc68..ff0523b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,10 +1,9 @@ --- name: Bug report about: You have an issue with the UAD software itself -title: '' +title: "" labels: bug -assignees: '' - +assignees: "" --- **Describe the bug** diff --git a/.github/ISSUE_TEMPLATE/debloat-issue-report.md b/.github/ISSUE_TEMPLATE/debloat-issue-report.md index 8c3675c..e660ca6 100644 --- a/.github/ISSUE_TEMPLATE/debloat-issue-report.md +++ b/.github/ISSUE_TEMPLATE/debloat-issue-report.md @@ -1,13 +1,12 @@ --- name: Debloat issue report about: Your phone has unexpected issues after debloating -title: '' +title: "" labels: package::breakage -assignees: '' - +assignees: "" --- -**Your phone**: \ +**Your phone model**: **Describe the issue** A clear and concise description of what the problem is. @@ -16,4 +15,4 @@ A clear and concise description of what the problem is. What to do to fix the issue. **UAD log** -Upload the logfile generated by UAD. You can hardly be helped without. +Upload the logfile generated by UAD. It would be difficult to help you without it. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 5f98c43..b91ffca 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,10 +1,9 @@ --- name: Feature request about: You want a new feature -title: '' +title: "" labels: enhancement -assignees: '' - +assignees: "" --- **Describe the feature you want** diff --git a/.github/ISSUE_TEMPLATE/update-apps-description-or-recommendation.md b/.github/ISSUE_TEMPLATE/update-apps-description-or-recommendation.md index 9a5ec9b..2f1770b 100644 --- a/.github/ISSUE_TEMPLATE/update-apps-description-or-recommendation.md +++ b/.github/ISSUE_TEMPLATE/update-apps-description-or-recommendation.md @@ -1,30 +1,37 @@ --- name: Update apps description or recommendation about: You want to improve/update a description/recommendation -title: '' +title: "" labels: package::documentation -assignees: '' - +assignees: "" --- -**Your phone**: \ +**Your phone model**: **Packages documentation to update:** + ``` com.this.is.a.application com.this.is.another.application ... ``` -## Documentation chage -**List**: `Google`|`Misc`|`Oem` (manufacturer)|`Aosp`|`Pending`|`Carrier` (isp). -**Removal**: `Recommended`, `Advanced`, `Expert` (this can break important features), `Unsafe` (this can bootloop the phone or break extremely important features). + +## Documentation Change + +**List**: `Google`|`Misc`|`OEM` (manufacturer)|`AOSP`|`Pending`|`Carrier` (isp). +**Removal**: `Recommended`, `Advanced`, `Expert` (this can break important features), +or `Unsafe` (this can bootloop the phone or break extremely important features). ### \ -**List**: \ :arrow_right: \ -**Removal**: \ :arrow_right: \ -**Current description** +**List**: \ :arrow_right: \ +**Removal**: \ +:arrow_right: \ + +### Current description + > Current description -**Proposed description** +### Proposed description + > Proposed description diff --git a/.github/workflows/build_artifacts.yml b/.github/workflows/build_artifacts.yml index 6435c6a..c5c1d23 100644 --- a/.github/workflows/build_artifacts.yml +++ b/.github/workflows/build_artifacts.yml @@ -25,9 +25,9 @@ jobs: - graphics: glow renderer: "-opengl" - graphics: wgpu - renderer: '' # Vulkan but we don't want this in the binary filename + renderer: "" # Vulkan but we don't want this in the binary filename - update_feature: self-update - update_name: '' # we don't want this in the binary filename + update_name: "" # we don't want this in the binary filename - update_feature: no-self-update update_name: "-noseflupdate" steps: @@ -62,4 +62,4 @@ jobs: uses: actions/upload-artifact@v3 with: name: uad_gui${{ matrix.update_name }}-${{ matrix.build_target }}${{ matrix.renderer }} - path: bin/uad_gui-* \ No newline at end of file + path: bin/uad_gui-* diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc44f15..8774054 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,16 +2,16 @@ name: Continuous Integration on: push: paths: - - '**.rs' - - 'Cargo.lock' - - 'Cargo.toml' - - '**.json' + - "**.rs" + - "Cargo.lock" + - "Cargo.toml" + - "**.json" pull_request: paths: - - '**.rs' - - 'Cargo.lock' - - 'Cargo.toml' - - '**.json' + - "**.rs" + - "Cargo.lock" + - "Cargo.toml" + - "**.json" jobs: lint: @@ -33,7 +33,7 @@ jobs: - lint: check args: " --all-features" - lint: test - args: '' + args: "" - lint: clippy args: " --all --all-features -- -D warnings" - lint: fmt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 409d1c8..e56f565 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,9 +5,9 @@ on: branches: - main paths: - - '**.rs' - - 'Cargo.lock' - - 'Cargo.toml' + - "**.rs" + - "Cargo.lock" + - "Cargo.toml" tags-ignore: - dev-build diff --git a/.gitignore b/.gitignore index ddaaa38..ef930cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ debug/ target/ -*.log \ No newline at end of file +*.log diff --git a/LICENSE b/LICENSE index a91c83b..b1fdb54 100644 --- a/LICENSE +++ b/LICENSE @@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Universal Android Debloater GUI - Copyright (C) 2021 W1nst0n + Copyright (C) 2021 W1nst0n This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Copyright (C) 2021 W1nst0n + Universal Android Debloater GUI Copyright (C) 2021 W1nst0n This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/README.md b/README.md index 7940235..c4598a6 100644 --- a/README.md +++ b/README.md @@ -1,97 +1,122 @@ # Universal Android Debloater GUI -**DISCLAIMER**: Use at your own risk. I am not responsible for anything that could happen to your phone. + +**DISCLAIMER**: Use at your own risk. I am not responsible for anything that +could happen to your phone. uad_screenshot **This software is still in an early stage of development. Check out the issues, and feel free to contribute!** ## Summary -This is a complete rewrite in Rust of the [UAD project](https://gitlab.com/W1nst0n/universal-android-debloater), which aims to improve privacy and battery performance by removing unnecessary and obscure system apps. This can also contribute to improve security by reducing [the attack surface](https://en.wikipedia.org/wiki/Attack_surface). -Packages are as well documented as possible in order to provide a better understanding of what you can delete or not. The worst thing which could happen is removing an essential system package needed during boot causing then an unfortunate bootloop. After about 5 failed system boots, the phone will automatically reboot in recovery mode and you'll have to perform a FACTORY RESET. So make a backup first! +This is a complete rewrite in Rust of the [UAD project](https://gitlab.com/W1nst0n/universal-android-debloater), +which aims to improve privacy and battery performance by removing unnecessary +and obscure system apps. +This can also contribute to improve security by reducing [the attack surface](https://en.wikipedia.org/wiki/Attack_surface). -In any case, you can NOT brick your device with this software! That's the main thing, right? +Packages are as well documented as possible in order to provide a better +understanding of what you can delete or not. The worst issue that could happen +is removing an essential system package needed during boot causing then an unfortunate +bootloop. After about 5 failed system boots, the phone will automatically reboot +in recovery mode, and you'll have to perform a FACTORY RESET. Make a backup first! + +In any case, you **CANNOT** brick your device with this software! +That's the main point, right? ## Features -* [X] Uninstall/Disable and Restore/Enable system packages -* [X] Multi-user support (e.g apps in work profiles) -* [X] Export/Import your selection in `uad_exported_selection.txt` -* [X] Multi-device support: you can connect multiple phones at the same time -* [X] All your actions are logged so you never forget what you've done -NB : System apps cannot really be uninstalled without root (see the [FAQ](https://github.com/0x192/universal-android-debloater/wiki/FAQ)) +- [x] Uninstall/Disable and Restore/Enable system packages +- [x] Multi-user support (e.g. apps in work profiles) +- [x] Export/Import your selection in `uad_exported_selection.txt` +- [x] Multi-device support: you can connect multiple phones at the same time +- [x] All your actions are logged, so you never forget what you've done -## Universal debloat lists -* [X] GFAM (Google/Facebook/Amazon/Microsoft) -* [X] AOSP -* [X] Manufacturers (OEM) -* [X] Mobile carriers -* [X] Qualcomm / Mediatek / Miscellaneous +NB : System apps cannot truly be uninstalled without root (see the [FAQ](https://github.com/0x192/universal-android-debloater/wiki/FAQ)) + +## Universal Debloat Lists + +- [x] GFAM (Google/Facebook/Amazon/Microsoft) +- [x] AOSP +- [x] Manufacturers (OEM) +- [x] Mobile carriers +- [x] Qualcomm / Mediatek / Miscellaneous ## Manufacturers debloat lists -* [ ] Archos -* [X] Asus -* [ ] Blackberry -* [ ] Gionee -* [X] LG -* [X] Google -* [ ] iQOO -* [X] Fairphone -* [ ] HTC -* [X] Huawei -* [X] Motorola -* [X] Nokia -* [X] OnePlus -* [X] Oppo -* [X] Realme -* [X] Samsung -* [X] Sony -* [X] Tecno -* [ ] TCL -* [X] Unihertz -* [X] Vivo/iQOO -* [ ] Wiko -* [X] Xiaomi -* [X] ZTE + +- [ ] Archos +- [x] Asus +- [ ] Blackberry +- [ ] Gionee +- [x] LG +- [x] Google +- [ ] iQOO +- [x] Fairphone +- [ ] HTC +- [x] Huawei +- [x] Motorola +- [x] Nokia +- [x] OnePlus +- [x] Oppo +- [x] Realme +- [x] Samsung +- [x] Sony +- [x] Tecno +- [ ] TCL +- [x] Unihertz +- [x] Vivo/iQOO +- [ ] Wiko +- [x] Xiaomi +- [x] ZTE ## Mobile carriers debloat lists -| Country | Carriers | -|-----------------|-----------------------------------| -| France | Orange, SFR, Free, Bouygues | -| USA | T-Mobile, Verizon, Sprint, AT&T | -| Germany | Telekom | -| UK | EE | +| Country | Carriers | +| ------- | ------------------------------- | +| France | Orange, SFR, Free, Bouygues | +| USA | T-Mobile, Verizon, Sprint, AT&T | +| Germany | Telekom | +| UK | EE | ## How to use it + - **Read the [FAQ](https://github.com/0x192/universal-android-debloater/wiki/FAQ)!** - **Do a proper backup of your data! You can never be too careful!** -- Enable *Developer Options* on your smartphone. -- Turn on *USB Debugging* from the developer panel. -- From the settings, disconnect from any OEM accounts (when you delete an OEM account package it could lock you on the lockscreen because the phone can't associate your identity anymore) +- Enable _Developer Options_ on your smartphone. +- Turn on _USB Debugging_ from the developer panel. +- From the settings, disconnect from any OEM accounts (when you delete an OEM + account package it could lock you on the lockscreen because the phone can't + associate your identity anymore) - Install ADB (see the intructions by clicking on your OS below):

LINUX - - Install *Android platform tools* on your PC : + - Install _Android platform tools_ on your PC : Debian Base: + ```bash - $ sudo apt install android-sdk-platform-tools + sudo apt install android-sdk-platform-tools ``` + Arch-Linux Base: + ```bash - $ sudo pacman -S android-tools + sudo pacman -S android-tools ``` + Red Hat Base: + ```bash - $ sudo yum install android-tools + sudo yum install android-tools ``` + OpenSUSE Base: + ```bash - $ sudo zypper install android-tools + sudo zypper install android-tools ``` +

@@ -100,42 +125,55 @@ NB : System apps cannot really be uninstalled without root (see the [FAQ](https: MAC OS - Install [Homebrew](https://brew.sh/) - - Install *Android platform tools* + - Install _Android platform tools_ + ```bash - $ brew install android-platform-tools + brew install android-platform-tools ``` - -

+ + +

WINDOWS - - Download [android platform tools](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) and unzip it somewhere. - - [Add the android platform tools to your PATH](https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/) **OR** make sure to launch UAD from the same directory. + - Download [android platform tools](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) + and unzip it somewhere. + - [Add the android platform tools to your PATH](https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/) + **OR** make sure to launch UAD from the same directory. - [Install USB drivers for your device](https://developer.android.com/studio/run/oem-usb#Drivers) - Check your device is detected: - ```batch - > adb devices + + ```bash + adb devices ``` -
-

+ +

-- Download the latest release of UAD GUI for your Operating System [here](https://github.com/0x192/universal-android-debloater/releases). Take the `opengl` version only if the default version (with a Vulkan backend) doesn't launch. +- Download the latest release of UAD GUI for your Operating System [here](https://github.com/0x192/universal-android-debloater/releases). + Take the `opengl` version only if the default version (with a Vulkan backend) + doesn't launch. -**NOTE:** Chinese phones users may need to use the AOSP list for removing some stock apps because those Chinese manufacturers (especially Xiaomi and Huawei) have been using the name of AOSP packages for their own (modified & closed-source) apps. +**NOTE:** Chinese phones users may need to use the AOSP list for removing some stock +apps because those Chinese manufacturers (especially Xiaomi and Huawei) have been +using the name of AOSP packages for their own (modified & closed-source) apps. -**IMPORTANT NOTE:** You will have to run this software whenever your OEM pushes an update to your phone as some *uninstalled* system apps could be reinstalled. +**IMPORTANT NOTE:** You will have to run this software whenever your OEM pushes +an update to your phone as some _uninstalled_ system apps could be reinstalled. ## How to contribute -Hey-hey-hey! Don't go away so fast! This is a community project. That means I need you! I'm sure you want to make this project better anyway. +Hey-hey-hey! Don't go away so fast! This is a community project. +That means I need you! I'm sure you want to make this project better anyway. ==> [How to contribute](https://github.com/0x192/universal-android-debloater/wiki) ## Special thanks -- [@mawilms](https://github.com/mawilms) for his LotRO plugin manager ([Lembas](https://github.com/mawilms/lembas)) which helped me a lot to understand how to use the [Iced](https://github.com/hecrj/iced) GUI library. +- [@mawilms](https://github.com/mawilms) for his LotRO plugin manager ([Lembas](https://github.com/mawilms/lembas)) + which helped me a lot to understand how to use the [Iced](https://github.com/hecrj/iced) + GUI library. - [@casperstorm](https://github.com/casperstorm) for the UI/UX inspiration. diff --git a/src/core/config.rs b/src/core/config.rs index 7fed6df..1243866 100644 --- a/src/core/config.rs +++ b/src/core/config.rs @@ -55,43 +55,38 @@ static CONFIG_FILE: PathBuf = CONFIG_DIR.join("config.toml"); impl Config { pub fn save_changes(settings: &Settings, device_id: &String) { let mut config = Self::load_configuration_file(); - match config + if let Some(device) = config .devices .iter_mut() .find(|x| x.device_id == *device_id) { - Some(device) => { - *device = settings.device.clone(); - config.general = settings.general.clone(); - } - None => { - debug!("config: New device settings saved"); - config.devices.push(settings.device.clone()); - config.general = settings.general.clone(); - } + *device = settings.device.clone(); + } else { + debug!("config: New device settings saved"); + config.devices.push(settings.device.clone()); } + config.general = settings.general.clone(); let toml = toml::to_string(&config).unwrap(); fs::write(&*CONFIG_FILE, toml).expect("Could not write config file to disk!"); } + #[allow(clippy::option_if_let_else)] pub fn load_configuration_file() -> Self { - match fs::read_to_string(&*CONFIG_FILE) { - Ok(s) => match toml::from_str(&s) { + if let Ok(s) = fs::read_to_string(&*CONFIG_FILE) { + match toml::from_str(&s) { Ok(config) => config, Err(e) => { error!("Invalid config file: `{}`", e); error!("Restoring default config file"); - let toml = toml::to_string(&Config::default()).unwrap(); + let toml = toml::to_string(&Self::default()).unwrap(); fs::write(&*CONFIG_FILE, toml).expect("Could not write config file to disk!"); - Config::default() + Self::default() } - }, - Err(_) => { - let default_conf = toml::to_string(&Config::default()).unwrap(); - fs::write(&*CONFIG_FILE, default_conf) - .expect("Could not write config file to disk!"); - Config::default() } + } else { + let default_conf = toml::to_string(&Self::default()).unwrap(); + fs::write(&*CONFIG_FILE, default_conf).expect("Could not write config file to disk!"); + Self::default() } } } diff --git a/src/core/save.rs b/src/core/save.rs index 222d734..3a6697d 100644 --- a/src/core/save.rs +++ b/src/core/save.rs @@ -44,7 +44,7 @@ pub async fn backup_phone( user_backup.packages.push(CorePackage { name: p.name.clone(), state: p.state, - }) + }); } backup.users.push(user_backup); } @@ -71,6 +71,7 @@ pub async fn backup_phone( } pub fn list_available_backups(dir: &Path) -> Vec { + #[allow(clippy::option_if_let_else)] match fs::read_dir(dir) { Ok(files) => files .filter_map(|e| e.ok()) @@ -129,15 +130,14 @@ pub fn restore_backup( let mut commands = vec![]; for u in phone_backup.users { - let mut _index = 0; - match selected_device.user_list.iter().find(|x| x.id == u.id) { - Some(i) => _index = i.index, + let index = match selected_device.user_list.iter().find(|x| x.id == u.id) { + Some(i) => i.index, None => return Err(format!("user {} doesn't exist", u.id)), }; for (i, backup_package) in u.packages.iter().enumerate() { let package: CorePackage; - match packages[_index] + match packages[index] .iter() .find(|x| x.name == backup_package.name) { @@ -150,8 +150,8 @@ pub fn restore_backup( } } let p_commands = apply_pkg_state_commands( - package, - &backup_package.state, + &package, + backup_package.state, &settings .backup .selected_user diff --git a/src/core/sync.rs b/src/core/sync.rs index 13fbcc4..0ad8b7c 100644 --- a/src/core/sync.rs +++ b/src/core/sync.rs @@ -29,7 +29,7 @@ impl Default for Phone { model: "fetching devices...".to_string(), android_sdk: 0, user_list: vec![], - adb_id: "".to_string(), + adb_id: String::new(), } } } @@ -54,9 +54,10 @@ impl std::fmt::Display for User { } pub fn adb_shell_command(shell: bool, args: &str) -> Result { - let adb_command = match shell { - true => vec!["shell", args], - false => vec![args], + let adb_command = if shell { + vec!["shell", args] + } else { + vec![args] }; #[cfg(target_os = "windows")] @@ -77,7 +78,12 @@ pub fn adb_shell_command(shell: bool, args: &str) -> Result { Err("ADB was not found".to_string()) } Ok(o) => { - if !o.status.success() { + if o.status.success() { + Ok(String::from_utf8(o.stdout) + .map_err(|e| e.to_string())? + .trim_end() + .to_string()) + } else { let stdout = String::from_utf8(o.stdout) .map_err(|e| e.to_string())? .trim_end() @@ -90,11 +96,6 @@ pub fn adb_shell_command(shell: bool, args: &str) -> Result { // ADB does really weird things. Some errors are not redirected to stderr let err = if stdout.is_empty() { stderr } else { stdout }; Err(err) - } else { - Ok(String::from_utf8(o.stdout) - .map_err(|e| e.to_string())? - .trim_end() - .to_string()) } } } @@ -139,26 +140,28 @@ pub async fn perform_adb_commands( } pub fn list_all_system_packages(user_id: Option<&User>) -> String { + #[allow(clippy::option_if_let_else)] let action = match user_id { Some(user_id) => format!("pm list packages -s -u --user {}", user_id.id), None => "pm list packages -s -u".to_string(), }; adb_shell_command(true, &action) - .unwrap_or_else(|_| "".to_string()) + .unwrap_or_else(|_| String::new()) .replace("package:", "") } pub fn hashset_system_packages(state: PackageState, user_id: Option<&User>) -> HashSet { + #[allow(clippy::option_if_let_else)] let user = match user_id { Some(user_id) => format!(" --user {}", user_id.id), - None => "".to_string(), + None => String::new(), }; let action = match state { PackageState::Enabled => format!("pm list packages -s -e{user}"), PackageState::Disabled => format!("pm list package -s -d{user}"), - _ => "".to_string(), // You probably don't need to use this function for anything else + _ => String::new(), // You probably don't need to use this function for anything else }; adb_shell_command(true, &action) @@ -178,7 +181,7 @@ pub struct CorePackage { impl From<&mut PackageRow> for CorePackage { fn from(pr: &mut PackageRow) -> Self { - CorePackage { + Self { name: pr.name.clone(), state: pr.state, } @@ -186,7 +189,7 @@ impl From<&mut PackageRow> for CorePackage { } impl From for CorePackage { fn from(pr: PackageRow) -> Self { - CorePackage { + Self { name: pr.name.clone(), state: pr.state, } @@ -195,7 +198,7 @@ impl From for CorePackage { impl From<&PackageRow> for CorePackage { fn from(pr: &PackageRow) -> Self { - CorePackage { + Self { name: pr.name.clone(), state: pr.state, } @@ -203,8 +206,8 @@ impl From<&PackageRow> for CorePackage { } pub fn apply_pkg_state_commands( - package: CorePackage, - wanted_state: &PackageState, + package: &CorePackage, + wanted_state: PackageState, selected_user: &User, phone: &Phone, ) -> Vec { @@ -242,24 +245,25 @@ pub fn apply_pkg_state_commands( }, _ => vec![], }, - _ => vec![], + PackageState::All => vec![], }; if phone.android_sdk < 21 { - request_builder(commands, &package.name, None) + request_builder(&commands, &package.name, None) } else { - request_builder(commands, &package.name, Some(selected_user)) + request_builder(&commands, &package.name, Some(selected_user)) } } -pub fn request_builder(commands: Vec<&str>, package: &str, user: Option<&User>) -> Vec { - if let Some(u) = user { - commands - .iter() - .map(|c| format!("{} --user {} {}", c, u.id, package)) - .collect() - } else { - commands.iter().map(|c| format!("{c} {package}")).collect() - } +pub fn request_builder(commands: &[&str], package: &str, user: Option<&User>) -> Vec { + user.map_or_else( + || commands.iter().map(|c| format!("{c} {package}")).collect(), + |u| { + commands + .iter() + .map(|c| format!("{} --user {} {}", c, u.id, package)) + .collect() + }, + ) } pub fn get_phone_model() -> String { @@ -277,17 +281,14 @@ pub fn get_phone_model() -> String { } pub fn get_android_sdk() -> u8 { - match adb_shell_command(true, "getprop ro.build.version.sdk") { - Ok(sdk) => sdk.parse().unwrap(), - Err(_) => 0, - } + adb_shell_command(true, "getprop ro.build.version.sdk").map_or(0, |sdk| sdk.parse().unwrap()) } pub fn get_phone_brand() -> String { format!( "{} {}", adb_shell_command(true, "getprop ro.product.brand") - .unwrap_or_else(|_| "".to_string()) + .unwrap_or_else(|_| String::new()) .trim(), get_phone_model() ) @@ -300,6 +301,8 @@ pub fn is_protected_user(user_id: &str) -> bool { pub fn get_user_list() -> Vec { #[dynamic] static RE: Regex = Regex::new(r"\{([0-9]+)").unwrap(); + + #[allow(clippy::option_if_let_else)] match adb_shell_command(true, "pm list users") { Ok(users) => RE .find_iter(&users) @@ -316,7 +319,7 @@ pub fn get_user_list() -> Vec { // getprop ro.serialno pub async fn get_devices_list() -> Vec { - match retry( + retry( Fixed::from_millis(500).take(120), || match adb_shell_command(false, "devices") { Ok(devices) => { @@ -341,8 +344,6 @@ pub async fn get_devices_list() -> Vec { OperationResult::Retry(test) } }, - ) { - Ok(devices) => devices, - Err(_) => vec![], - } + ) + .map_or_else(|_| vec![], |devices| devices) } diff --git a/src/core/theme.rs b/src/core/theme.rs index 7b42780..ffc1379 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -39,7 +39,7 @@ pub struct ColorPalette { impl Theme { pub const ALL: [Self; 3] = [Self::Lupin, Self::Dark, Self::Light]; - pub fn palette(&self) -> ColorPalette { + pub fn palette(self) -> ColorPalette { match self { Self::Dark => ColorPalette { base: BaseColors { @@ -105,9 +105,9 @@ impl std::fmt::Display for Theme { f, "{}", match self { - Theme::Dark => "Dark", - Theme::Light => "Light", - Theme::Lupin => "Lupin", + Self::Dark => "Dark", + Self::Light => "Light", + Self::Lupin => "Lupin", } ) } diff --git a/src/core/uad_lists.rs b/src/core/uad_lists.rs index d169c11..abefa40 100644 --- a/src/core/uad_lists.rs +++ b/src/core/uad_lists.rs @@ -44,24 +44,24 @@ impl std::fmt::Display for UadListState { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let date = last_modified_date(CACHE_DIR.join("uad_lists.json")); let s = match self { - UadListState::Downloading => "Checking updates...".to_string(), - UadListState::Done => format!("Done (last was {})", format_diff_time_from_now(date)), - UadListState::Failed => "Failed to check update!".to_string(), + Self::Downloading => "Checking updates...".to_string(), + Self::Done => format!("Done (last was {})", format_diff_time_from_now(date)), + Self::Failed => "Failed to check update!".to_string(), }; write!(f, "{s}") } } impl UadList { - pub const ALL: [UadList; 8] = [ - UadList::All, - UadList::Aosp, - UadList::Carrier, - UadList::Google, - UadList::Misc, - UadList::Oem, - UadList::Pending, - UadList::Unlisted, + pub const ALL: [Self; 8] = [ + Self::All, + Self::Aosp, + Self::Carrier, + Self::Google, + Self::Misc, + Self::Oem, + Self::Pending, + Self::Unlisted, ]; } @@ -71,14 +71,14 @@ impl std::fmt::Display for UadList { f, "{}", match self { - UadList::All => "All lists", - UadList::Aosp => "aosp", - UadList::Carrier => "carrier", - UadList::Google => "google", - UadList::Misc => "misc", - UadList::Oem => "oem", - UadList::Pending => "pending", - UadList::Unlisted => "unlisted", + Self::All => "All lists", + Self::Aosp => "aosp", + Self::Carrier => "carrier", + Self::Google => "google", + Self::Misc => "misc", + Self::Oem => "oem", + Self::Pending => "pending", + Self::Unlisted => "unlisted", } ) } @@ -94,12 +94,7 @@ pub enum PackageState { } impl PackageState { - pub const ALL: [PackageState; 4] = [ - PackageState::All, - PackageState::Enabled, - PackageState::Uninstalled, - PackageState::Disabled, - ]; + pub const ALL: [Self; 4] = [Self::All, Self::Enabled, Self::Uninstalled, Self::Disabled]; } impl std::fmt::Display for PackageState { @@ -108,10 +103,10 @@ impl std::fmt::Display for PackageState { f, "{}", match self { - PackageState::All => "All packages", - PackageState::Enabled => "Enabled", - PackageState::Uninstalled => "Uninstalled", - PackageState::Disabled => "Disabled", + Self::All => "All packages", + Self::Enabled => "Enabled", + Self::Uninstalled => "Uninstalled", + Self::Disabled => "Disabled", } ) } @@ -122,17 +117,17 @@ pub trait Opposite { } impl Opposite for PackageState { - fn opposite(&self, disable: bool) -> PackageState { + fn opposite(&self, disable: bool) -> Self { match self { - PackageState::Enabled => { + Self::Enabled => { if disable { - PackageState::Disabled + Self::Disabled } else { - PackageState::Uninstalled + Self::Uninstalled } } - PackageState::Uninstalled | PackageState::Disabled => PackageState::Enabled, - PackageState::All => PackageState::All, + Self::Uninstalled | Self::Disabled => Self::Enabled, + Self::All => Self::All, } } } @@ -150,13 +145,13 @@ pub enum Removal { } impl Removal { - pub const ALL: [Removal; 6] = [ - Removal::All, - Removal::Recommended, - Removal::Advanced, - Removal::Expert, - Removal::Unsafe, - Removal::Unlisted, + pub const ALL: [Self; 6] = [ + Self::All, + Self::Recommended, + Self::Advanced, + Self::Expert, + Self::Unsafe, + Self::Unlisted, ]; } @@ -166,12 +161,12 @@ impl std::fmt::Display for Removal { f, "{}", match self { - Removal::All => "All", - Removal::Recommended => "Recommended", - Removal::Advanced => "Advanced", - Removal::Expert => "Expert", - Removal::Unsafe => "Unsafe", - Removal::Unlisted => "Unlisted", + Self::All => "All", + Self::Recommended => "Recommended", + Self::Advanced => "Advanced", + Self::Expert => "Expert", + Self::Unsafe => "Unsafe", + Self::Unlisted => "Unlisted", } ) } @@ -182,10 +177,10 @@ pub fn load_debloat_lists(remote: bool) -> (Result = if remote { - match retry(Fixed::from_millis(1000).take(60), || { + retry(Fixed::from_millis(1000).take(60), || { match ureq::get( "https://raw.githubusercontent.com/0x192/universal-android-debloater/\ - main/resources/assets/uad_lists.json", + main/resources/assets/uad_lists.json", ) .call() { @@ -201,10 +196,8 @@ pub fn load_debloat_lists(remote: bool) -> (Result::new()) } } - }) { - Ok(list) => list, - Err(_) => get_local_lists(), - } + }) + .map_or_else(|_| get_local_lists(), |list| list) } else { warn!("Could not load remote debloat list"); get_local_lists() diff --git a/src/core/update.rs b/src/core/update.rs index ca05c50..3d63469 100644 --- a/src/core/update.rs +++ b/src/core/update.rs @@ -41,10 +41,10 @@ pub enum SelfUpdateStatus { impl std::fmt::Display for SelfUpdateStatus { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let s = match self { - SelfUpdateStatus::Checking => "Checking updates...", - SelfUpdateStatus::Updating => "Updating...", - SelfUpdateStatus::Failed => "Failed to check update!", - SelfUpdateStatus::Done => "Done", + Self::Checking => "Checking updates...", + Self::Updating => "Updating...", + Self::Failed => "Failed to check update!", + Self::Done => "Done", }; write!(f, "{s}") } @@ -52,7 +52,7 @@ impl std::fmt::Display for SelfUpdateStatus { /// Download a file from the internet #[cfg(feature = "self-update")] -pub async fn download_file(url: T, dest_file: PathBuf) -> Result<(), String> { +pub async fn download_file(url: T, dest_file: PathBuf) -> Result<(), String> { let url = url.to_string(); debug!("downloading file from {}", &url); @@ -200,7 +200,7 @@ pub fn get_latest_release() -> Result, ()> { } } -/// Extracts the binary from a `tar.gz` archive to temp_file path +/// Extracts the binary from a `tar.gz` archive to `temp_file` path #[cfg(feature = "self-update")] #[cfg(not(target_os = "windows"))] pub fn extract_binary_from_tar(archive_path: &Path, temp_file: &Path) -> io::Result<()> { diff --git a/src/core/utils.rs b/src/core/utils.rs index 15d4337..5d94734 100644 --- a/src/core/utils.rs +++ b/src/core/utils.rs @@ -31,7 +31,7 @@ pub fn fetch_packages( if uad_lists.contains_key(p_name) { description = &uad_lists.get(p_name).unwrap().description; if description.is_empty() { - description = "[No description] : CONTRIBUTION WELCOMED" + description = "[No description] : CONTRIBUTION WELCOMED"; }; uad_list = uad_lists.get(p_name).unwrap().list; removal = uad_lists.get(p_name).unwrap().removal; @@ -51,8 +51,8 @@ pub fn fetch_packages( user_package } -pub fn string_to_theme(theme: String) -> Theme { - match theme.as_str() { +pub fn string_to_theme(theme: &str) -> Theme { + match theme { "Dark" => Theme::Dark, "Light" => Theme::Light, "Lupin" => Theme::Lupin, @@ -80,21 +80,20 @@ pub fn open_url(dir: PathBuf) { Ok(o) => { if !o.status.success() { let stderr = String::from_utf8(o.stderr).unwrap().trim_end().to_string(); - error!("Can't open the following URL: {}", stderr) + error!("Can't open the following URL: {}", stderr); } } Err(e) => error!("Failed to run command to open the file explorer: {}", e), } } +#[rustfmt::skip] +#[allow(clippy::option_if_let_else)] pub fn last_modified_date(file: PathBuf) -> DateTime { - match fs::metadata(file) { - Ok(metadata) => match metadata.modified() { - Ok(time) => time.into(), - Err(_) => Utc::now(), - }, + fs::metadata(file).map_or_else(|_| Utc::now(), |metadata| match metadata.modified() { + Ok(time) => time.into(), Err(_) => Utc::now(), - } + }) } pub fn format_diff_time_from_now(date: DateTime) -> String { @@ -118,19 +117,20 @@ pub struct DisplayablePath { impl fmt::Display for DisplayablePath { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let stem = match self.path.file_stem() { - Some(p) => match p.to_os_string().into_string() { + let stem = self.path.file_stem().map_or_else( + || { + error!("[PATH STEM]: No file stem found"); + "[File steam not found]".to_string() + }, + |p| match p.to_os_string().into_string() { Ok(stem) => stem, Err(e) => { error!("[PATH ENCODING]: {:?}", e); "[PATH ENCODING ERROR]".to_string() } }, - None => { - error!("[PATH STEM]: No file stem found"); - "[File steam not found]".to_string() - } - }; + ); + write!(f, "{stem}") } } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 6140740..97feb72 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -87,7 +87,7 @@ impl Application for UadGui { } fn theme(&self) -> Theme { - string_to_theme(self.settings_view.general.theme.clone()) + string_to_theme(&self.settings_view.general.theme) } fn title(&self) -> String { @@ -95,6 +95,7 @@ impl Application for UadGui { } fn update(&mut self, msg: Message) -> Command { match msg { + #[allow(clippy::option_if_let_else)] Message::LoadDevices(devices_list) => { self.selected_device = match &self.selected_device { Some(s_device) => { @@ -102,9 +103,9 @@ impl Application for UadGui { devices_list .iter() .find(|phone| phone.adb_id == s_device.adb_id) - .map(|x| x.to_owned()) + .cloned() } - None => devices_list.first().map(|x| x.to_owned()), + None => devices_list.first().cloned(), }; self.devices_list = devices_list; @@ -210,7 +211,7 @@ impl Application for UadGui { AboutMessage::UpdateUadLists => { self.update_state.uad_list = UadListState::Downloading; self.apps_view.loading_state = - ListLoadingState::DownloadingList("".to_string()); + ListLoadingState::DownloadingList(String::new()); self.update(Message::AppsAction(AppsMessage::LoadUadList(true))) } AboutMessage::DoSelfUpdate => { @@ -218,7 +219,7 @@ impl Application for UadGui { if self.update_state.self_update.latest_release.is_some() { self.update_state.self_update.status = SelfUpdateStatus::Updating; self.apps_view.loading_state = - ListLoadingState::_UpdatingUad("".to_string()); + ListLoadingState::_UpdatingUad(String::new()); let bin_name = bin_name().to_owned(); let release = self .update_state @@ -237,7 +238,7 @@ impl Application for UadGui { #[cfg(not(feature = "self-update"))] Command::none() } - _ => Command::none(), + AboutMessage::UrlPressed(_) => Command::none(), } } Message::DeviceSelected(s_device) => { @@ -250,7 +251,7 @@ impl Application for UadGui { s_device.android_sdk, s_device.model ); info!("{:-^65}", "-"); - self.apps_view.loading_state = ListLoadingState::FindingPhones("".to_string()); + self.apps_view.loading_state = ListLoadingState::FindingPhones(String::new()); #[allow(unused_must_use)] { @@ -261,48 +262,46 @@ impl Application for UadGui { UadListState::Done, )))) } - Message::_NewReleaseDownloaded(_res) => { + Message::_NewReleaseDownloaded(res) => { debug!("UAD update has been download!"); - #[cfg(feature = "self-update")] - match _res { - Ok((relaunch_path, cleanup_path)) => { - // Remove first arg, which is path to binary. We don't use this first - // arg as binary path because it's not reliable, per the docs. - let mut args = std::env::args(); - args.next(); - let mut args: Vec<_> = args.collect(); + if let Ok((relaunch_path, cleanup_path)) = res { + // Remove first arg, which is path to binary. We don't use this first + // arg as binary path because it's not reliable, per the docs. + let mut args = std::env::args(); + args.next(); + let mut args: Vec<_> = args.collect(); - // Remove the `--self-update-temp` arg from args if it exists, - // since we need to pass it cleanly. Otherwise new process will - // fail during arg parsing. - if let Some(idx) = args.iter().position(|a| a == "--self-update-temp") { - args.remove(idx); - // Remove path passed after this arg - args.remove(idx); + // Remove the `--self-update-temp` arg from args if it exists, + // since we need to pass it cleanly. Otherwise new process will + // fail during arg parsing. + if let Some(idx) = args.iter().position(|a| a == "--self-update-temp") { + args.remove(idx); + // Remove path passed after this arg + args.remove(idx); + } + + match std::process::Command::new(relaunch_path) + .args(args) + .arg("--self-update-temp") + .arg(&cleanup_path) + .spawn() + { + Ok(_) => { + if let Err(e) = remove_file(cleanup_path) { + error!("Could not remove temp update file: {}", e); + } + std::process::exit(0) } - - match std::process::Command::new(relaunch_path) - .args(args) - .arg("--self-update-temp") - .arg(&cleanup_path) - .spawn() - { - Ok(_) => { - if let Err(e) = remove_file(cleanup_path) { - error!("Could not remove temp update file: {}", e); - } - std::process::exit(0) - } - Err(error) => { - if let Err(e) = remove_file(cleanup_path) { - error!("Could not remove temp update file: {}", e); - } - error!("Failed to update UAD: {}", error) + Err(error) => { + if let Err(e) = remove_file(cleanup_path) { + error!("Could not remove temp update file: {}", e); } + error!("Failed to update UAD: {}", error); } } - Err(()) => error!("Failed to update UAD!"), + } else { + error!("Failed to update UAD!"); } Command::none() } @@ -310,13 +309,13 @@ impl Application for UadGui { match release { Ok(r) => { self.update_state.self_update.status = SelfUpdateStatus::Done; - self.update_state.self_update.latest_release = r + self.update_state.self_update.latest_release = r; } Err(_) => self.update_state.self_update.status = SelfUpdateStatus::Failed, }; Command::none() } - _ => Command::none(), + Message::Nothing => Command::none(), } } diff --git a/src/gui/style.rs b/src/gui/style.rs index 20ae5ba..bb28c54 100644 --- a/src/gui/style.rs +++ b/src/gui/style.rs @@ -102,11 +102,9 @@ impl button::StyleSheet for Theme { }; match style { - Button::Primary => active_appearance(None, p.bright.primary), - Button::Unavailable => active_appearance(None, p.bright.error), - Button::Refresh => active_appearance(None, p.bright.primary), - Button::SelfUpdate => active_appearance(None, p.bright.primary), - Button::UninstallPackage => active_appearance(None, p.bright.error), + Button::Primary | Button::SelfUpdate | Button::Refresh => { + active_appearance(None, p.bright.primary) + } Button::RestorePackage => active_appearance(None, p.bright.secondary), Button::NormalPackage => button::Appearance { background: Some(Background::Color(p.base.foreground)), @@ -127,6 +125,9 @@ impl button::StyleSheet for Theme { border_color: p.normal.primary, ..appearance }, + Button::Unavailable | Button::UninstallPackage => { + active_appearance(None, p.bright.error) + } } } @@ -141,17 +142,22 @@ impl button::StyleSheet for Theme { }; match style { - Button::Primary => hover_appearance(p.bright.primary, None), - Button::Unavailable => hover_appearance(p.bright.error, None), - Button::Refresh => hover_appearance(p.bright.primary, None), - Button::SelfUpdate => hover_appearance(p.bright.primary, None), - Button::UninstallPackage => hover_appearance(p.bright.error, None), - Button::RestorePackage => hover_appearance(p.bright.secondary, None), + Button::Primary | Button::SelfUpdate | Button::Refresh => { + hover_appearance(p.bright.primary, None) + } Button::NormalPackage => hover_appearance(p.normal.primary, Some(p.bright.surface)), Button::SelectedPackage => hover_appearance(p.normal.primary, None), + Button::RestorePackage => hover_appearance(p.bright.secondary, None), + Button::Unavailable | Button::UninstallPackage => { + hover_appearance(p.bright.error, None) + } } } + fn pressed(&self, style: &Self::Style) -> button::Appearance { + self.active(style) + } + fn disabled(&self, style: &Self::Style) -> button::Appearance { let active = self.active(style); let p = self.palette(); @@ -169,13 +175,7 @@ impl button::StyleSheet for Theme { Button::RestorePackage => disabled_appearance(p.normal.primary, Some(p.bright.primary)), Button::UninstallPackage => disabled_appearance(p.bright.error, None), Button::Primary => disabled_appearance(p.bright.primary, Some(p.bright.primary)), - _ => button::Appearance { ..active }, - } - } - - fn pressed(&self, style: &Self::Style) -> button::Appearance { - button::Appearance { - ..self.active(style) + _ => active, } } } @@ -212,9 +212,7 @@ impl scrollable::StyleSheet for Theme { fn hovered(&self, style: &Self::Style, _mouse_over_scrollbar: bool) -> scrollable::Scrollbar { scrollable::Scrollbar { - scroller: scrollable::Scroller { - ..self.active(style).scroller - }, + scroller: self.active(style).scroller, ..self.active(style) } } @@ -222,7 +220,7 @@ impl scrollable::StyleSheet for Theme { fn dragging(&self, style: &Self::Style) -> scrollable::Scrollbar { let hovered = self.hovered(style, true); scrollable::Scrollbar { - scroller: scrollable::Scroller { ..hovered.scroller }, + scroller: hovered.scroller, ..hovered } } @@ -291,10 +289,10 @@ impl checkbox::StyleSheet for Theme { }; match style { - CheckBox::PackageEnabled => from_appearance(), - CheckBox::SettingsEnabled => from_appearance(), - CheckBox::PackageDisabled => self.active(style, is_checked), - CheckBox::SettingsDisabled => self.active(style, is_checked), + CheckBox::PackageEnabled | CheckBox::SettingsEnabled => from_appearance(), + CheckBox::PackageDisabled | CheckBox::SettingsDisabled => { + self.active(style, is_checked) + } } } } @@ -410,7 +408,7 @@ pub enum Text { impl From for Text { fn from(color: Color) -> Self { - Text::Color(color) + Self::Color(color) } } @@ -419,7 +417,7 @@ impl text::StyleSheet for Theme { fn appearance(&self, style: Self::Style) -> text::Appearance { match style { - Text::Default => Default::default(), + Text::Default => text::Appearance::default(), Text::Ok => text::Appearance { color: Some(self.palette().bright.secondary), }, diff --git a/src/gui/views/about.rs b/src/gui/views/about.rs index b685d0b..5a2fffe 100644 --- a/src/gui/views/about.rs +++ b/src/gui/views/about.rs @@ -56,22 +56,17 @@ impl About { text(format!("UAD version: v{}", env!("CARGO_PKG_VERSION"))).width(250); #[cfg(feature = "self-update")] - let self_update_text = match &update_state.self_update.latest_release { - Some(r) => { - if update_state.self_update.status == SelfUpdateStatus::Updating { - update_state.self_update.status.to_string() - } else { - format!("(v{} available)", r.tag_name) - } - } - None => { - if update_state.self_update.status == SelfUpdateStatus::Done { - "(No update available)".to_string() - } else { - update_state.self_update.status.to_string() - } - } - }; + #[rustfmt::skip] + let self_update_text = update_state.self_update.latest_release.as_ref().map_or_else(|| + if update_state.self_update.status == SelfUpdateStatus::Done { + "(No update available)".to_string() + } else { + update_state.self_update.status.to_string() + }, |r| if update_state.self_update.status == SelfUpdateStatus::Updating { + update_state.self_update.status.to_string() + } else { + format!("(v{} available)", r.tag_name) + }); #[cfg(feature = "self-update")] let last_self_update_text = text(self_update_text).style(style::Text::Default); diff --git a/src/gui/views/list.rs b/src/gui/views/list.rs index 766b6ce..1af85c5 100644 --- a/src/gui/views/list.rs +++ b/src/gui/views/list.rs @@ -38,7 +38,7 @@ pub enum LoadingState { impl Default for LoadingState { fn default() -> Self { - Self::FindingPhones("".to_string()) + Self::FindingPhones(String::new()) } } @@ -96,7 +96,7 @@ impl List { } Message::ModalValidate => { let mut commands = vec![]; - self.selected_packages.sort(); + self.selected_packages.sort_unstable(); self.selected_packages.dedup(); for selection in &self.selected_packages { commands.append(&mut build_action_pkg_commands( @@ -114,7 +114,7 @@ impl List { if let CommandType::PackageManager(p) = res { self.loading_state = LoadingState::RestoringDevice( self.phone_packages[i_user][p.index].name.clone(), - ) + ); } } else { self.loading_state = LoadingState::RestoringDevice("Error [TODO]".to_string()); @@ -128,7 +128,7 @@ impl List { selected_device.android_sdk, selected_device.model ); info!("{:-^65}", "-"); - self.loading_state = LoadingState::DownloadingList("".to_string()); + self.loading_state = LoadingState::DownloadingList(String::new()); Command::perform( Self::init_apps_view(remote, selected_device.clone()), Message::LoadPhonePackages, @@ -136,7 +136,7 @@ impl List { } Message::LoadPhonePackages(list_box) => { let (uad_list, list_state) = list_box; - self.loading_state = LoadingState::LoadingPackages("".to_string()); + self.loading_state = LoadingState::LoadingPackages(String::new()); self.uad_lists = uad_list.clone(); *list_update_state = list_state; Command::perform( @@ -152,7 +152,7 @@ impl List { self.selected_list = Some(UadList::All); self.selected_user = Some(User::default()); Self::filter_package_lists(self); - self.loading_state = LoadingState::Ready("".to_string()); + self.loading_state = LoadingState::Ready(String::new()); Command::none() } Message::ToggleAllSelected(selected) => { @@ -193,7 +193,7 @@ impl List { #[allow(unused_must_use)] { self.phone_packages[i_user][i_package] - .update(row_message.clone()) + .update(&row_message) .map(move |row_message| Message::List(i_package, row_message)); } @@ -600,7 +600,7 @@ impl List { text("Enable").style(style::Text::Ok), PackageState::Uninstalled => text("Restore").style(style::Text::Ok), - _ => text("Impossible") + PackageState::All => text("Impossible") .style(style::Text::Danger), },] .width(60), @@ -625,13 +625,7 @@ impl List { .padding([0, 10, 0, 10]); container( - if device - .user_list - .iter() - .filter(|&u| !u.protected) - .collect::>() - .len() - > 1 + if device.user_list.iter().filter(|&u| !u.protected).count() > 1 && settings.device.multi_user_mode { column![ @@ -696,13 +690,13 @@ impl List { let mut phone_packages = vec![]; if user_list.len() <= 1 { - phone_packages.push(fetch_packages(&uad_list, None)) + phone_packages.push(fetch_packages(&uad_list, None)); } else { phone_packages.extend( user_list .iter() .map(|user| fetch_packages(&uad_list, Some(user))), - ) + ); }; phone_packages } @@ -775,10 +769,10 @@ fn build_action_pkg_commands( }) { let u_pkg = packages[u.index][selection.1].clone(); let actions = if settings.multi_user_mode { - apply_pkg_state_commands(u_pkg.into(), &wanted_state, u, device) + apply_pkg_state_commands(&u_pkg.into(), wanted_state, u, device) } else { - let wanted_state = &u_pkg.state.opposite(settings.disable_mode); - apply_pkg_state_commands(u_pkg.into(), wanted_state, u, device) + let wanted_state = u_pkg.state.opposite(settings.disable_mode); + apply_pkg_state_commands(&u_pkg.into(), wanted_state, u, device) }; for (j, action) in actions.into_iter().enumerate() { let p_info = PackageInfo { diff --git a/src/gui/views/settings.rs b/src/gui/views/settings.rs index d796038..761ff00 100644 --- a/src/gui/views/settings.rs +++ b/src/gui/views/settings.rs @@ -96,7 +96,7 @@ impl Settings { selected: backups.first().cloned(), users: phone.user_list.clone(), selected_user: phone.user_list.first().copied(), - backup_state: "".to_string(), + backup_state: String::new(), }; } None => { @@ -109,7 +109,7 @@ impl Settings { selected: backups.first().cloned(), users: phone.user_list.clone(), selected_user: phone.user_list.first().copied(), - backup_state: "".to_string(), + backup_state: String::new(), }, } } @@ -190,7 +190,7 @@ impl Settings { radio( format!("{}", option.clone()), *option, - Some(string_to_theme(self.general.theme.clone())), + Some(string_to_theme(&self.general.theme)), Message::ApplyTheme, ) .size(23), @@ -224,7 +224,7 @@ impl Settings { row![ text("The following settings only affect the currently selected device :") .style(style::Text::Danger), - text(phone.model.to_owned()), + text(phone.model.clone()), Space::new(Length::Fill, Length::Shrink), text(phone.adb_id.clone()).style(style::Text::Commentary) ] @@ -390,20 +390,7 @@ impl Settings { .style(style::Container::BorderedFrame) }; - let content = if !phone.adb_id.clone().is_empty() { - column![ - text("Theme").size(25), - theme_ctn, - text("General").size(25), - general_ctn, - text("Current device").size(25), - warning_ctn, - device_specific_ctn, - backup_restore_ctn, - ] - .width(Length::Fill) - .spacing(20) - } else { + let content = if phone.adb_id.clone().is_empty() { column![ text("Theme").size(25), theme_ctn, @@ -416,6 +403,19 @@ impl Settings { ] .width(Length::Fill) .spacing(20) + } else { + column![ + text("Theme").size(25), + theme_ctn, + text("General").size(25), + general_ctn, + text("Current device").size(25), + warning_ctn, + device_specific_ctn, + backup_restore_ctn, + ] + .width(Length::Fill) + .spacing(20) }; container(content) diff --git a/src/gui/widgets/modal.rs b/src/gui/widgets/modal.rs index 7d46cb5..87e6ace 100644 --- a/src/gui/widgets/modal.rs +++ b/src/gui/widgets/modal.rs @@ -25,6 +25,7 @@ impl<'a, Message, Renderer> Modal<'a, Message, Renderer> { } } + #[allow(clippy::missing_const_for_fn)] /// Sets the message that will be produces when the background /// of the [`Modal`] is pressed pub fn on_blur(self, on_blur: Message) -> Self { @@ -187,6 +188,7 @@ where ) -> event::Status { let content_bounds = layout.children().next().unwrap().bounds(); + #[allow(clippy::equatable_if_let)] if let Some(message) = self.on_blur.as_ref() { if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) = &event { if !content_bounds.contains(cursor_position) { diff --git a/src/gui/widgets/navigation_menu.rs b/src/gui/widgets/navigation_menu.rs index c13354a..bde493c 100644 --- a/src/gui/widgets/navigation_menu.rs +++ b/src/gui/widgets/navigation_menu.rs @@ -34,6 +34,7 @@ pub fn nav_menu<'a>( .padding(5) .style(style::Button::Refresh); + #[allow(clippy::option_if_let_else)] let uad_version_text = if let Some(r) = &self_update_state.latest_release { if self_update_state.status == SelfUpdateStatus::Updating { Text::new("Updating please wait...") @@ -48,17 +49,17 @@ pub fn nav_menu<'a>( Text::new(env!("CARGO_PKG_VERSION")) }; - let mut apps_btn = button("Apps") - .on_press(Message::AppsPress) - .padding(5) - .style(style::Button::Primary); - - if self_update_state.latest_release.is_some() { - apps_btn = button("Update") + let apps_btn = if self_update_state.latest_release.is_some() { + button("Update") .on_press(Message::AboutAction(AboutMessage::DoSelfUpdate)) .padding(5) - .style(style::Button::SelfUpdate); - } + .style(style::Button::SelfUpdate) + } else { + button("Apps") + .on_press(Message::AppsPress) + .padding(5) + .style(style::Button::Primary) + }; let about_btn = button("About") .on_press(Message::AboutPressed) diff --git a/src/gui/widgets/package_row.rs b/src/gui/widgets/package_row.rs index 9a83398..9d94c88 100644 --- a/src/gui/widgets/package_row.rs +++ b/src/gui/widgets/package_row.rs @@ -46,7 +46,7 @@ impl PackageRow { } } - pub fn update(&mut self, _message: Message) -> Command { + pub fn update(&mut self, _message: &Message) -> Command { Command::none() } diff --git a/src/main.rs b/src/main.rs index e24b5bc..8f2b3d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,7 +42,7 @@ pub fn setup_logger() -> Result<(), fern::InitError> { record.file().unwrap_or("?"), record.line().map(|l| l.to_string()).unwrap_or_default(), message - )) + )); } };