diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a80a551a..e05bf8d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ on: - Cargo.lock - Cargo.toml - resources/assets/*.ttf + - resources/assets/uad_lists.json - src/** pull_request: paths: diff --git a/Cargo.lock b/Cargo.lock index a44859f4..388efc2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,6 +141,24 @@ dependencies = [ "libloading 0.7.4", ] +[[package]] +name = "ashpd" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd884d7c72877a94102c3715f3b1cd09ff4fac28221add3e57cfbe25c236d093" +dependencies = [ + "async-fs 2.1.1", + "async-net", + "enumflags2", + "futures-channel", + "futures-util", + "rand", + "serde", + "serde_repr", + "url", + "zbus 4.1.2", +] + [[package]] name = "async-broadcast" version = "0.5.1" @@ -151,6 +169,18 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-broadcast" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258b52a1aa741b9f09783b2d86cf0aeeb617bbf847f6933340a39644227acbdb" +dependencies = [ + "event-listener 5.2.0", + "event-listener-strategy 0.5.0", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-channel" version = "2.2.0" @@ -190,6 +220,17 @@ dependencies = [ "futures-lite 1.13.0", ] +[[package]] +name = "async-fs" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc19683171f287921f2405677dd2ed2549c3b3bda697a563ebc3a121ace2aba1" +dependencies = [ + "async-lock 3.3.0", + "blocking", + "futures-lite 2.3.0", +] + [[package]] name = "async-io" version = "1.13.0" @@ -249,6 +290,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io 2.3.2", + "blocking", + "futures-lite 2.3.0", +] + [[package]] name = "async-process" version = "1.8.1" @@ -266,6 +318,26 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "async-process" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53fc6301894e04a92cb2584fedde80cb25ba8e02d9dc39d4a87d036e22f397d" +dependencies = [ + "async-channel", + "async-io 2.3.2", + "async-lock 3.3.0", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener 5.2.0", + "futures-lite 2.3.0", + "rustix 0.38.32", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "async-recursion" version = "1.1.0" @@ -828,9 +900,9 @@ dependencies = [ "objc", "rust-ini", "web-sys", - "winreg", - "zbus", - "zvariant", + "winreg 0.10.1", + "zbus 3.15.1", + "zvariant 3.15.1", ] [[package]] @@ -979,6 +1051,26 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +[[package]] +name = "embed-resource" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6985554d0688b687c5cb73898a34fbe3ad6c24c58c238a4d91d5e840670ee9d" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml", + "vswhom", + "winreg 0.52.0", +] + +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + [[package]] name = "enumflags2" version = "0.7.9" @@ -2204,6 +2296,19 @@ dependencies = [ "memoffset 0.7.1", ] +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "cfg_aliases 0.1.1", + "libc", + "memoffset 0.9.0", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -2559,6 +2664,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2791,6 +2902,29 @@ dependencies = [ "rand", ] +[[package]] +name = "rfd" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a73a7337fc24366edfca76ec521f51877b114e42dab584008209cca6719251" +dependencies = [ + "ashpd", + "block", + "dispatch", + "js-sys", + "log", + "objc", + "objc-foundation", + "objc_id", + "pollster", + "raw-window-handle", + "urlencoding", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.48.0", +] + [[package]] name = "ring" version = "0.17.8" @@ -2828,6 +2962,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.37.27" @@ -2857,9 +3000,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", "ring", @@ -2949,6 +3092,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba" +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.197" @@ -3482,12 +3631,14 @@ dependencies = [ "chrono", "dark-light", "dirs 5.0.1", + "embed-resource", "fern", "flate2", "iced", "log", "regex", "retry", + "rfd", "serde", "serde_json", "static_init", @@ -3611,14 +3762,41 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "waker-fn" version = "1.1.1" @@ -4325,6 +4503,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "x11-dl" version = "2.21.0" @@ -4423,16 +4611,16 @@ checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1" [[package]] name = "zbus" -version = "3.15.2" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" +checksum = "5acecd3f8422f198b1a2f954bcc812fe89f3fa4281646f3da1da7925db80085d" dependencies = [ - "async-broadcast", + "async-broadcast 0.5.1", "async-executor", - "async-fs", + "async-fs 1.6.0", "async-io 1.13.0", "async-lock 2.8.0", - "async-process", + "async-process 1.8.1", "async-recursion", "async-task", "async-trait", @@ -4445,7 +4633,7 @@ dependencies = [ "futures-sink", "futures-util", "hex", - "nix", + "nix 0.26.4", "once_cell", "ordered-stream", "rand", @@ -4457,16 +4645,55 @@ dependencies = [ "uds_windows", "winapi", "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", + "zbus_macros 3.15.1", + "zbus_names 2.6.1", + "zvariant 3.15.1", +] + +[[package]] +name = "zbus" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9ff46f2a25abd690ed072054733e0bc3157e3d4c45f41bd183dce09c2ff8ab9" +dependencies = [ + "async-broadcast 0.7.0", + "async-executor", + "async-fs 2.1.1", + "async-io 2.3.2", + "async-lock 3.3.0", + "async-process 2.2.2", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "derivative", + "enumflags2", + "event-listener 5.2.0", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.28.0", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.52.0", + "xdg-home", + "zbus_macros 4.1.2", + "zbus_names 3.0.0", + "zvariant 4.0.2", ] [[package]] name = "zbus_macros" -version = "3.15.2" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" +checksum = "2207eb71efebda17221a579ca78b45c4c5f116f074eb745c3a172e688ccf89f5" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", @@ -4476,6 +4703,20 @@ dependencies = [ "zvariant_utils", ] +[[package]] +name = "zbus_macros" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0e3852c93dcdb49c9462afe67a2a468f7bd464150d866e861eaf06208633e0" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils", +] + [[package]] name = "zbus_names" version = "2.6.1" @@ -4484,7 +4725,18 @@ checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" dependencies = [ "serde", "static_assertions", - "zvariant", + "zvariant 3.15.1", +] + +[[package]] +name = "zbus_names" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +dependencies = [ + "serde", + "static_assertions", + "zvariant 4.0.2", ] [[package]] @@ -4530,23 +4782,37 @@ dependencies = [ [[package]] name = "zvariant" -version = "3.15.2" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" +checksum = "c5b4fcf3660d30fc33ae5cd97e2017b23a96e85afd7a1dd014534cd0bf34ba67" dependencies = [ "byteorder", "enumflags2", "libc", "serde", "static_assertions", - "zvariant_derive", + "zvariant_derive 3.15.1", +] + +[[package]] +name = "zvariant" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1b3ca6db667bfada0f1ebfc94b2b1759ba25472ee5373d4551bb892616389a" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "url", + "zvariant_derive 4.0.2", ] [[package]] name = "zvariant_derive" -version = "3.15.2" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" +checksum = "0277758a8a0afc0e573e80ed5bfd9d9c2b48bd3108ffe09384f9f738c83f4a55" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", @@ -4555,11 +4821,24 @@ dependencies = [ "zvariant_utils", ] +[[package]] +name = "zvariant_derive" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a4b236063316163b69039f77ce3117accb41a09567fd24c168e43491e521bc" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils", +] + [[package]] name = "zvariant_utils" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +checksum = "00bedb16a193cc12451873fee2a1bc6550225acece0e36f333e68326c73c8172" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 3fe13d54..8d7e349a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" [features] default = ["wgpu", "self-update"] -wgpu = [] # Iced/wgpu is default +wgpu = [] # Iced/wgpu is default self-update = ["flate2", "tar"] no-self-update = [] @@ -23,7 +23,10 @@ serde = { version = "^1.0", features = ["derive"] } serde_json = "^1.0" static_init = "^1.0" fern = { version = "^0", features = ["colored"] } -chrono = { version = "^0.4", default-features = false, features = ["std", "clock"] } +chrono = { version = "^0.4", default-features = false, features = [ + "std", + "clock", +] } log = "^0.4" regex = "^1.10.2" toml = "^0" @@ -31,6 +34,7 @@ dirs = "^5.0.0" ureq = { version = "*", features = ["json"] } retry = "^2.0.0" iced = { version = "^0.12.0", features = ["advanced", "image"] } +rfd = "^0.14" [target.'cfg(not(target_os = "windows"))'.dependencies] flate2 = { version = "^1", optional = true } @@ -43,3 +47,6 @@ win32console = "^0.1.5" opt-level = "s" lto = true strip = "symbols" + +[build-dependencies] +embed-resource = "2.4.2" diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..cc564fe5 --- /dev/null +++ b/build.rs @@ -0,0 +1,9 @@ +use std::{env, error::Error}; + +fn main() -> Result<(), Box> { + if env::var("CARGO_CFG_TARGET_FAMILY")? == "windows" { + embed_resource::compile("resources/assets/manifest.rc", embed_resource::NONE); + } + + Ok(()) +} diff --git a/resources/assets/icon.ico b/resources/assets/icon.ico new file mode 100644 index 00000000..009c2c0b Binary files /dev/null and b/resources/assets/icon.ico differ diff --git a/resources/assets/icons.json b/resources/assets/icons.json index f5544324..b3c80d25 100644 --- a/resources/assets/icons.json +++ b/resources/assets/icons.json @@ -416,8 +416,11 @@ { "ligatures": "folder-open, directory2", "name": "folder-open", - "order": 0, - "id": 49 + "order": 4, + "id": 49, + "prevSize": 28, + "code": 59696, + "tempChar": "" }, { "ligatures": "folder-plus, directory3", @@ -1016,8 +1019,11 @@ { "ligatures": "cog, gear", "name": "cog", - "order": 0, - "id": 149 + "order": 3, + "id": 149, + "prevSize": 28, + "code": 59796, + "tempChar": "" }, { "ligatures": "cogs, gears", diff --git a/resources/assets/icons.ttf b/resources/assets/icons.ttf index 4df2c688..e7f97f02 100644 Binary files a/resources/assets/icons.ttf and b/resources/assets/icons.ttf differ diff --git a/resources/assets/manifest.rc b/resources/assets/manifest.rc new file mode 100644 index 00000000..4df5c066 --- /dev/null +++ b/resources/assets/manifest.rc @@ -0,0 +1 @@ +MAINICON ICON "icon.ico" \ No newline at end of file diff --git a/resources/assets/uad_lists.json b/resources/assets/uad_lists.json index c6da6053..e48f4b16 100644 --- a/resources/assets/uad_lists.json +++ b/resources/assets/uad_lists.json @@ -1,4 +1,13 @@ { + "com.dti.tracfone": { + "list": "Carrier", + "description": "Installs sponsored apps automatically on Tracfone and affiliated carriers (Straight Talk, Total Wireless, etc) \n", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.sony.tvsideview.videoph": { "list": "Oem", "description": "Video & TV SideView (replaced by https://play.google.com/store/apps/details?id=com.sony.tvsideview.phone)\nLets you use your smartphone or tablet as a TV remote control for the home. \n", @@ -1281,11 +1290,11 @@ }, "com.vzw.apnlib": { "list": "Carrier", - "description": "Kind of library for Verizon APN ?\nREMINDER : https://developer.android.com/reference/android/telephony/data/ApnSetting\n", + "description": "Kind of library for Verizon APN ?\nREMINDER : https://developer.android.com/reference/android/telephony/data/ApnSetting\nAfter uninstall phone won't allow to call or text(breaks WiFi calling), On Auto Optimization it cause auto reboots.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Expert" }, "com.vzw.apnservice": { "list": "Carrier", @@ -2077,7 +2086,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.huawei.android.FloatTasks": { "list": "Oem", @@ -2109,7 +2118,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.huawei.android.hwouc": { "list": "Oem", @@ -2293,7 +2302,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.huawei.desktop.explorer": { "list": "Oem", @@ -2317,7 +2326,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, "com.huawei.filemanager": { "list": "Oem", @@ -2471,7 +2480,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, "com.huawei.hwblockchain": { "list": "Oem", @@ -2543,11 +2552,11 @@ }, "com.huawei.ohos.inputmethod": { "list": "Oem", - "description": "Huawei default Keyboard\nWARNING: Before uninstalling, make sure to have a third-party keyboard installed.\n", + "description": "Huawei default Keyboard\nWARNING: Before uninstalling, make sure to have a third-party keyboard installed.\nDisable instead of uninstalling if you don't want to lose the widget.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Recommended" }, "com.huawei.mycenter": { "list": "Oem", @@ -2575,11 +2584,11 @@ }, "com.huawei.iaware": { "list": "Oem", - "description": "App Prioritizer. Prioritizes apps to avoid slowdown\nUp to you but there is apparently no noticeable difference when deleted.\n", + "description": "App Prioritizer. Prioritizes apps to avoid slowdown\nUp to you but there is apparently no noticeable difference when deleted?\nSystem will start lagging a little bit (you will notice it while scrolling and on some animations, for example scrolling installed apps), battery consumption will become slightly higher and battery stats will disappear soon. At the same time, logcat will be full of errors like: PowerKit: PG Server is not found. calling pid xxxx.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, "com.huawei.ihealth": { "list": "Oem", @@ -2703,11 +2712,11 @@ }, "com.huawei.powergenie": { "list": "Oem", - "description": "Task killer app in EMUI 9+ (Android 9+).\nTask killer apps tend to do more harm than help as they clear cached RAM for no good reason, removing the battery and time savings involved in caching. In addition to the obvious issues with background functionality like notifications.\nFrom issue#104.", + "description": "Task killer app in EMUI 9+ (Android 9+).\nTask killer apps tend to do more harm than help as they clear cached RAM for no good reason, removing the battery and time savings involved in caching. In addition to the obvious issues with background functionality like notifications.\nFrom issue#104.\nSystem will start lagging a little bit (you will notice it while scrolling and on some animations, for example scrolling installed apps), battery consumption will become slightly higher and battery stats will disappear soon. At the same time, logcat will be full of errors like: PowerKit: PG Server is not found. calling pid xxxx.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, "com.huawei.stylus.floatmenu": { "list": "Oem", @@ -2943,11 +2952,11 @@ }, "com.huawei.securitymgr": { "list": "Oem", - "description": "PrivateSpace\nLets you store private information in a hidden space within your device that can only be accessed \nwith your fingerprint or password.\nTODO: Data at rest encryption? If not, this is useless\nhttps://consumer.huawei.com/en/support/content/en-us00754246/\n)\n", + "description": "PrivateSpace\nLets you store private information in a hidden space within your device that can only be accessed \nwith your fingerprint or password.\nTODO: Data at rest encryption? If not, this is useless\nhttps://consumer.huawei.com/en/support/content/en-us00754246/)\nThis is the password vault or password manager too.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Expert" }, "android.autoinstalls.config.motorola.layout": { "list": "Oem", @@ -4818,7 +4827,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, "com.samsung.cmfa.AuthTouch": { "list": "Oem", @@ -6502,7 +6511,7 @@ }, "com.sec.android.provider.badge": { "list": "Oem", - "description": "Provider for the notification badges (which are not very useful IMHO)\nProvides a way for apps to use notifications badges.\nhttps://www.samsung.com/au/support/mobile-devices/what-is-app-icon-badge/\n", + "description": "Provider for the notification badges (which are not very useful IMHO)\nProvides a way for apps to use notifications badges.\nhttps://www.samsung.com/au/support/mobile-devices/what-is-app-icon-badge/\nEmergency Power saving launcher does not start after removing.", "dependencies": [], "neededBy": [], "labels": [], @@ -6714,7 +6723,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Unsafe" + "removal": "Expert" }, "com.samsung.android.sm.policy": { "list": "Oem", @@ -6812,109 +6821,109 @@ "labels": [], "removal": "Expert" }, - "com.android.icon_pack.circular.android": { + "com.android.theme.icon_pack.circular.android": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.circular.launcher": { + "com.android.theme.icon_pack.circular.launcher": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.circular.settings": { + "com.android.theme.icon_pack.circular.settings": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.circular.systemui": { + "com.android.theme.icon_pack.circular.systemui": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.circular.themepicker": { + "com.android.theme.icon_pack.circular.themepicker": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.filled.android": { + "com.android.theme.icon_pack.filled.android": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.filled.launcher": { + "com.android.theme.icon_pack.filled.launcher": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.filled.settings": { + "com.android.theme.icon_pack.filled.settings": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.filled.systemui": { + "com.android.theme.icon_pack.filled.systemui": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.filled.themepicker": { + "com.android.theme.icon_pack.filled.themepicker": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.rounded.android": { + "com.android.theme.icon_pack.rounded.android": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.rounded.launcher": { + "com.android.theme.icon_pack.rounded.launcher": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.icon_pack.rounded.settings": { + "com.android.theme.icon_pack.rounded.settings": { "list": "Oem", "description": "Android icon pack only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, "com.android.magicsmoke": { "list": "Aosp", @@ -7002,7 +7011,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Expert" }, "com.android.soundrecorder": { "list": "Aosp", @@ -7680,7 +7689,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Expert" }, "com.android.certinstaller": { "list": "Aosp", @@ -7756,11 +7765,11 @@ }, "com.android.mms.service": { "list": "Aosp", - "description": "Provides support for sending MMS.\n", + "description": "Provides support for sending MMS.\nIt doesn't cause bootloop.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Unsafe" + "removal": "Expert" }, "com.android.mtp": { "list": "Aosp", @@ -8714,19 +8723,19 @@ }, "com.android.networkstack.inprocess": { "list": "Aosp", - "description": "", + "description": "Related to the Network Stack module, which is an updatable Mainline module that ensures Android can adapt to evolving network standards and allows for interoperability with new implementations\nhttps://source.android.com/docs/core/ota/modular-system/networking", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.android.networkstack.permissionconfig": { "list": "Aosp", - "description": "", + "description": "Network Stack Permission Configuration\nDefines a permission that enables modules to perform network-related tasks.\nhttps://source.android.com/devices/architecture/modular-system/networking", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.android.phone.basiccolorblack.overlay": { "list": "Aosp", @@ -8818,11 +8827,11 @@ }, "com.android.systemui.overlay.common": { "list": "Oem", - "description": "Have something about to wellbeing.", + "description": "Has something related to Google Wellbeing first time setup quick settings. Safe to remove.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Recommended" }, "com.android.theme.icon.circle": { "list": "Aosp", @@ -9550,11 +9559,11 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Advanced" }, "com.qti.pasrservice": { "list": "Misc", - "description": "Have logs, debug, screen filter things.\nalso have something to power but not sure.\nMaybe needed for google fit or mi fit.", + "description": "Has powersaving things, device idle mode changer to screen on/off.", "dependencies": [], "neededBy": [], "labels": [], @@ -9742,7 +9751,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.android.wifi.resources.overlay.common": { "list": "Oem", @@ -9750,7 +9759,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.android.wifi.resources.overlay.target": { "list": "Oem", @@ -10134,7 +10143,7 @@ }, "com.qti.phone": { "list": "Misc", - "description": "dialer, dialing service, for phone calls", + "description": "dialer, dialing service, for phone calls.\nHas IMS things, optimizations?, its weird that calling works after remove, has code related to 'com.qualcomm.qcrilmsgtunnel',\nChina Mobile Communications Corporation(China Mobile) SIM card things.", "dependencies": [], "neededBy": [], "labels": [], @@ -10428,14 +10437,6 @@ "labels": [], "removal": "Recommended" }, - "com.samsung.android.incall.contentprovider": { - "list": "Oem", - "description": "", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Expert" - }, "com.samsung.android.service.tagservice": { "list": "Oem", "description": "Tags in Samsung Gallery app.", @@ -10460,14 +10461,6 @@ "labels": [], "removal": "Expert" }, - "com.samsung.android.wifi.softap.resources": { - "list": "Oem", - "description": "I found only configs value to wifi that can be important", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Unsafe" - }, "com.sec.android.Cdfs": { "list": "Oem", "description": "CDFS MODE Launcher, it's CdfsService Probably needed for usb mtp", @@ -10508,14 +10501,6 @@ "labels": [], "removal": "Expert" }, - "com.samsung.sait.sohservice": { - "list": "Oem", - "description": "FactoryApp to test battery things such as set voltage, Soc, temperature, status, timestamp.", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Recommended" - }, "com.samsung.vklayer.sm8250": { "list": "Oem", "description": "Vulkan GPU DRIVER", @@ -10636,14 +10621,6 @@ "labels": [], "removal": "Advanced" }, - "com.samsung.android.secsoundpicker": { - "list": "Oem", - "description": "", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Expert" - }, "com.samsung.android.service.stplatform": { "list": "Oem", "description": "SmartThings Framework\nI guess it's app for installing sponsored apps. Useless Framework.", @@ -10660,14 +10637,6 @@ "labels": [], "removal": "Expert" }, - "com.samsung.android.singletake.service": { - "list": "Oem", - "description": "", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Expert" - }, "com.samsung.android.sume.nn.service": { "list": "Oem", "description": "Provides the photo remaster feature in the Gallery app. Has the camera permission and can access all your medias but performs its job locally on the device.\n\nhttps://www.samsung.com/au/support/mobile-devices/remastering-photos-on-samsung-phone/", @@ -10692,22 +10661,6 @@ "labels": [], "removal": "Expert" }, - "com.samsung.ims.smk": { - "list": "Oem", - "description": "SimMobilityKit", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Expert" - }, - "com.samsung.internal.systemui.navbar.gestural_no_hint": { - "list": "Oem", - "description": "", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Expert" - }, "com.samsung.internal.systemui.navbar.gestural_no_hint_extra_wide_back": { "list": "Oem", "description": "", @@ -10732,22 +10685,6 @@ "labels": [], "removal": "Expert" }, - "com.samsung.internal.systemui.navbar.sec_gestural": { - "list": "Oem", - "description": "", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Expert" - }, - "com.samsung.internal.systemui.navbar.sec_gestural_no_hint": { - "list": "Oem", - "description": "", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Expert" - }, "com.samsung.pregpudriver.ex2100": { "list": "Oem", "description": "", @@ -12598,7 +12535,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Expert" }, "com.sohu.inputmethod.sogouoem": { "list": "Oem", @@ -12926,7 +12863,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Recommended" }, "com.qualcomm.qti.qcolor": { "list": "Misc", @@ -12994,7 +12931,7 @@ }, "com.qualcomm.qcrilmsgtunnel": { "list": "Misc", - "description": "Message receiving channel (secondary card can't turn on 5g)\nSo if you dont use dual-sim it's safe to remove. Breaks calls after a reboot.", + "description": "Message receiving channel (secondary card can't turn on 5g)\nSo if you dont use dual-sim it's safe to remove. Breaks calls after a reboot on some phones.", "dependencies": [], "neededBy": [], "labels": [], @@ -13150,7 +13087,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Advanced" }, "com.qualcomm.qti.auth.fidocryptoservice": { "list": "Misc", @@ -14632,29 +14569,29 @@ "labels": [], "removal": "Recommended" }, - "com.android.theme.color.roundedrect": { + "com.android.theme.icon.roundedrect": { "list": "Oem", "description": "Android color accent only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.theme.color.squircle": { + "com.android.theme.icon.squircle": { "list": "Oem", "description": "Android color accent only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, - "com.android.theme.color.teardrop": { + "com.android.theme.icon.teardrop": { "list": "Oem", "description": "Android color accent only for google pixel or aosp or motorola", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, "com.monotype.android.font.rosemary": { "list": "Misc", @@ -14888,7 +14825,7 @@ "labels": [], "removal": "Recommended" }, - "android.autoinstalls.config.xiaomi.qssi": { + "android.autoinstalls.config.Xiaomi.qssi": { "list": "Oem", "description": "PlayAutoInstalls\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).", "dependencies": [], @@ -15742,7 +15679,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Expert" }, "com.xiaomi.jr": { "list": "Oem", @@ -16098,7 +16035,7 @@ }, "com.miui.aod": { "list": "Oem", - "description": "Always-on display\nSafe to remove if you don't use \"Always-on display\" features in settings.", + "description": "Always-on display\nSafe to remove if you don't use \"Always-on display\" features in settings.\nRequired for the fingerprint scanner if you want without double-tapping or pressing the power button.", "dependencies": [], "neededBy": [], "labels": [], @@ -16140,7 +16077,7 @@ }, "com.miui.freeform": { "list": "Oem", - "description": "Floating window\nI think the name of the app is pretty straightforward\nYou can make apps appear above other applications\nhttps://forum.xda-developers.com/android/miui/floating-windows-miui-12-t4125661\n", + "description": "Floating window\nI think the name of the app is pretty straightforward\nYou can make apps appear above other applications\nhttps://forum.xda-developers.com/android/miui/floating-windows-miui-12-t4125661\nOn some phones even if you uninstalled it, floating window still works.", "dependencies": [], "neededBy": [], "labels": [], @@ -16156,7 +16093,7 @@ }, "com.mi.globallayout": { "list": "Oem", - "description": "Home Layout\nIt most likely handles the main screen layout (grid size, apps placement...)\n#\nSome people removed this without issue. Can someone try and give feedback?\n", + "description": "Home Layout\nSets the default MIUI launcher to global layout instead of Chinese (or HyperOS) when you first launch the app or when cleaning the launcher data.\nAfter removing this app there are several replacement widgets and no phone/message at the bottom.\nBecause Chinese MUI uses other apps and package names instead of just changing the default layout in the MIUI launcher code, they just threw the app in.", "dependencies": [], "neededBy": [], "labels": [], @@ -16260,7 +16197,7 @@ }, "com.miui.core": { "list": "Oem", - "description": "MIUI SDK\nIt is obiously needed for MIUI to work correctly. FYI, it manages the MIUI Analytics service.\nWill cause bootloop if removed.\nI read you can freeze it without issue. I'm... a bit dubious about this.\nIf someone want to try et report the result:\nadb shell am force-stop com.miui.core && adb shell pm disable-user com.miui.core && adb shell pm clear com.miui.core\nCan be disabled and uninstalled with MIUI 13.0.6, MIUI 14, see\nhttps://github.com/0x192/universal-android-debloater/issues/632\nNOTE: uninstalling/disabling this package causes the Settings app to crash when searching in Settings.", + "description": "MIUI SDK\nIt is obiously needed for MIUI to work correctly. FYI, it manages the MIUI Analytics service (`tracking.miui.com`), autoinstall MIUI apps updates (?). Related to GetApps 'com.xiaomi.market' China Mi App Store), DropboxManager where is temp clean code, a lot of logs. Found things related to Quick Apps 'com.miui.hybrid', DataUpdateManager (related to micloud?). Telocation update, app looks like tracking everything. Can be disabled and uninstalled with MIUI 13.0.6, MIUI 14, see\nhttps://github.com/0x192/universal-android-debloater/issues/632\nNOTE: uninstalling this package causes the Settings app to crash when searching in Settings, so better disable this app instead.\nIf you want to test, disable this app and open an issue if anything isn't working. Another weird thing is normal user can disable this app using hidden Settings to manage app by in Google Play.\nNo effects after disable, but not sure if its required for Miui updates or gestures.", "dependencies": [], "neededBy": [], "labels": [], @@ -17268,11 +17205,11 @@ }, "com.huawei.securityserver": { "list": "Oem", - "description": "HwSecurityServer\nNot needed app without code and useless assets to spying apps.", + "description": "HwSecurityServer\nNot needed app without code and useless assets to spying apps.\nNeeded for face unlock, black screen will be shown if you remove this package (?). Doesn't apply to all devices", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Expert" }, "com.huawei.sos": { "list": "Oem", @@ -19469,7 +19406,7 @@ }, "com.android.theme.color.amethyst": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19477,7 +19414,7 @@ }, "com.android.theme.color.aquamarine": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19485,7 +19422,7 @@ }, "com.android.theme.color.darklake": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19493,7 +19430,7 @@ }, "com.android.theme.color.dorange": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19501,7 +19438,7 @@ }, "com.android.theme.color.dpurple": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19509,7 +19446,7 @@ }, "com.android.theme.color.lgreen": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19517,7 +19454,7 @@ }, "com.android.theme.color.parasailing": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19525,7 +19462,7 @@ }, "com.android.theme.color.saffron": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19533,7 +19470,7 @@ }, "com.android.theme.color.sand": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19541,7 +19478,7 @@ }, "com.android.theme.color.slate": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19549,7 +19486,7 @@ }, "com.android.theme.color.tangerine": { "description": "Android color accent only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19557,7 +19494,7 @@ }, "com.android.theme.icon_pack.kai.android": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19565,7 +19502,7 @@ }, "com.android.theme.icon_pack.kai.launcher": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19573,7 +19510,7 @@ }, "com.android.theme.icon_pack.kai.settings": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19581,7 +19518,7 @@ }, "com.android.theme.icon_pack.kai.systemui": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19589,7 +19526,7 @@ }, "com.android.theme.icon_pack.kai.themepicker": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19597,7 +19534,7 @@ }, "com.android.theme.icon_pack.sam.android": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19605,7 +19542,7 @@ }, "com.android.theme.icon_pack.sam.launcher": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19613,7 +19550,7 @@ }, "com.android.theme.icon_pack.sam.settings": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19621,7 +19558,7 @@ }, "com.android.theme.icon_pack.sam.systemui": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19629,7 +19566,7 @@ }, "com.android.theme.icon_pack.sam.themepicker": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19637,7 +19574,7 @@ }, "com.android.theme.icon_pack.victor.android": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19645,7 +19582,7 @@ }, "com.android.theme.icon_pack.victor.launcher": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19653,7 +19590,7 @@ }, "com.android.theme.icon_pack.victor.settings": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19661,7 +19598,7 @@ }, "com.android.theme.icon_pack.victor.systemui": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19669,7 +19606,7 @@ }, "com.android.theme.icon_pack.victor.themepicker": { "description": "Android icon pack only for Google Pixel or AOSP or Motorola", - "removal": "Recommended", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -19716,16 +19653,16 @@ "labels": [] }, "com.android.providers.telephony.overlay.carriersettings": { - "description": "Useless overlay to (com.google.android.carrier)\nAnyway, this app doesn't exist on your phone I guess.", - "removal": "Recommended", + "description": "Overlay to (com.google.android.carrier)\nAnyway, this app doesn't exist on your phone I guess.", + "removal": "Expert", "list": "Oem", "dependencies": [], "neededBy": [], "labels": [] }, "com.android.phone.overlay.carriersettings": { - "description": "Useless overlay to (com.google.android.carrier)\nAnyway, this app doesn't exist on your phone I guess.", - "removal": "Recommended", + "description": "Overlay to (com.google.android.carrier)\nAnyway, this app doesn't exist on your phone I guess.", + "removal": "Expert", "list": "Oem", "dependencies": [], "neededBy": [], @@ -20030,8 +19967,8 @@ "labels": [] }, "android.overlay.common.all_devices": { - "description": "This overlay has got useless configs", - "removal": "Recommended", + "description": "This overlay has got useless configs (?)", + "removal": "Expert", "list": "Oem", "dependencies": [], "neededBy": [], @@ -21180,8 +21117,8 @@ "labels": [] }, "com.heytap.appplatform": { - "description": "Needed for OTA Updates also can brick phone but not confirmed", - "removal": "Expert", + "description": "Needed for OTA Updates also causes bootloop on some phones after uninstall.", + "removal": "Unsafe", "list": "Oem", "dependencies": [], "neededBy": [], @@ -21526,8 +21463,8 @@ "labels": [] }, "com.coloros.bootreg": { - "description": "Used only on first-boot setup", - "removal": "Recommended", + "description": "Setup Wizard\nCause bootloop after uninstall app.", + "removal": "Unsafe", "list": "Oem", "dependencies": [], "neededBy": [], @@ -22376,7 +22313,7 @@ "labels": [] }, "com.android.bips.auto_generated_rro_product__": { - "description": "Useless color icon code to print service.", + "description": "Unused auto generated code: color icon code to print service.", "removal": "Recommended", "list": "Oem", "dependencies": [], @@ -22384,7 +22321,7 @@ "labels": [] }, "com.android.providers.contacts.auto_generated_rro_product__": { - "description": "Incorrect named thing to sync metadata gms?\nmetadata_sync_pacakge com.google.android.gms\nlmao google. No effects after remove.", + "description": "Incorrect named thing to sync metadata gms?\nmetadata_sync_pacakge com.google.android.gms\nNo effects after remove.", "removal": "Recommended", "list": "Oem", "dependencies": [], @@ -22498,7 +22435,7 @@ "com.android.networkstack.overlay": { "description": "WiFi will not work after remove.", "removal": "Unsafe", - "list": "Oem", + "list": "Aosp", "dependencies": [], "neededBy": [], "labels": [] @@ -22552,8 +22489,8 @@ "labels": [] }, "com.google.android.connectivity.resources.overlay": { - "description": "Useless default configs", - "removal": "Recommended", + "description": "Useless default configs (?)", + "removal": "Expert", "list": "Oem", "dependencies": [], "neededBy": [], @@ -22592,8 +22529,8 @@ "labels": [] }, "com.google.android.networkstack.tethering.overlay2021": { - "description": "Useless hotspot configs", - "removal": "Recommended", + "description": "Useless hotspot configs (?)", + "removal": "Expert", "list": "Oem", "dependencies": [], "neededBy": [], @@ -22776,7 +22713,7 @@ "labels": [] }, "com.google.android.overlay.udfpsoverlay": { - "description": "useless configs to fingerprints FRP auto generated.", + "description": "Configs to fingerprints FRP auto generated.", "removal": "Recommended", "list": "Oem", "dependencies": [], @@ -23554,7 +23491,7 @@ "labels": [] }, "com.facemoji.lite.transsion": { - "description": "Emoji Keyboard\nHave ads and it's not good for privacy.", + "description": "Emoji Keyboard\nHave ads and it's not good for privacy.\nWARNING: On Infinix phones, this package is a hard dependency to show keyboard after initial reboot/startup. Without it, even if you have another keyboard installed, no keyboard will show.\nDon't remove if you're using an Infinix phone and need to enter password after boot.", "removal": "Advanced", "suggestions": "keyboards", "list": "Oem", @@ -23620,8 +23557,8 @@ "labels": [] }, "com.transsion.hilauncher": { - "description": "HiOS Launcher\nIt have google analytics and it's so bloated.", - "removal": "Expert", + "description": "HiOS Launcher\nIt have google analytics and it's so bloated.\nThe recent apps button does not work after uninstallation.", + "removal": "Unsafe", "list": "Oem", "dependencies": [], "neededBy": [], @@ -25285,8 +25222,8 @@ "labels": [] }, "android.miui.home.launcher.res": { - "description": "Useless config to default com.miui.home launcher.\nIt's unused! Like com.mi.globallayout, it's not a joke.", - "removal": "Recommended", + "description": "Config to default icons/placeholder widgets in MIUI launcher.\nIt's used only first time run MIUI launcher app like com.mi.globallayout.", + "removal": "Advanced", "list": "Oem", "dependencies": [], "neededBy": [], @@ -26497,7 +26434,7 @@ }, "com.miui.systemui.overlay.devices.android": { "list": "Oem", - "description": "MIUI User interface for 'device' settings?\n", + "description": "Config doze Component 'com.miui.aod' and ext media ready notification 'Tap to safely remove device'.", "dependencies": [], "neededBy": [], "labels": [], @@ -26561,7 +26498,7 @@ }, "com.miui.securitycenter": { "list": "Oem", - "description": "MIUI Security app\nProvides \"protection and optimization tools\" \nApp lock, Data usage, Security scan, Cleaner, Battery saver, Blocklist and other features.\nThis package is mostly the front-end (UI).\nhttps://beta.pithus.org/report/f8c24ccfc526389ff9084505c60fba3d3463565f92e2015190e2974b370e7c4e\nNOTE: REMOVING THIS WILL MOST LIKELY BOOTLOOP YOUR DEVICE! Uninstalling this on the Redmi Pad is not causing any bootloop, but you will lose some functionality like the battery status/usage page, as well as the app usage/removal page.", + "description": "MIUI Security app\nProvides \"protection and optimization tools\" \nApp lock, Data usage, Security scan, Cleaner, Battery saver, Blocklist and other features.\nThis package is mostly the front-end (UI).\nhttps://beta.pithus.org/report/f8c24ccfc526389ff9084505c60fba3d3463565f92e2015190e2974b370e7c4e\nNOTE: REMOVING THIS WILL MOST LIKELY BOOTLOOP YOUR DEVICE! Uninstalling this on the Redmi Pad or Miui 14 is not causing any bootloop, but you will lose some functionality like the battery status/usage page, as well as the app usage/removal page.", "dependencies": [], "neededBy": [], "labels": [], @@ -26569,7 +26506,7 @@ }, "com.miui.securitycore": { "list": "Oem", - "description": "Core features of the \"com.miui.securitycenter\"\nREMOVING THIS WILL MOST LIKELY BOOTLOOP YOUR DEVICE! This may depend on your MIUI version and device, see\nhttps://github.com/0x192/universal-android-debloater/issues/641", + "description": "Core features of the \"com.miui.securitycenter\"\nREMOVING THIS WILL MOST LIKELY BOOTLOOP YOUR DEVICE! This may depend on your MIUI version and device, see\nhttps://github.com/0x192/universal-android-debloater/issues/641\nOn Miui 14 it doesnt bootloop and looks performance like the same, also this app has annoying notifications when you running new app.", "dependencies": [], "neededBy": [], "labels": [], @@ -27576,7 +27513,7 @@ "removal": "Advanced" }, "com.google.android.carrierconfig": { - "list": "Google", + "list": "Aosp", "description": "Same as com.android.carrierconfig? Here's that description:\nDynamically provides configuration for the carrier network.\nThe config contains: Roaming networks, Voicemail settings, SMS/MMS settings, VoLTE/IMS settings, and more.\nIf a carrier app is installed it will be queried for overrides to these settings.\nSeems to run on boot and when you swap SIM card?\nhttps://source.android.com/devices/tech/config/carrier\nhttps://cs.android.com/android/platform/superproject/+/master:packages/apps/CarrierConfig/src/com/android/carrierconfig/DefaultCarrierConfigService.java", "dependencies": [], "neededBy": [], @@ -27725,7 +27662,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Expert" }, "com.google.android.launcher": { "list": "Google", @@ -27824,7 +27761,7 @@ "removal": "Advanced" }, "com.google.android.captiveportallogin": { - "list": "Google", + "list": "Aosp", "description": "it's the same as (com.android.captiveportallogin). Support for captive portal.\nA captive portal login is a web page where the users have to input their login information or accept the displayed terms of use. \nSome networks (typically public wifi network) use the captive portal login to block access until the user inputs \nsome necessary information\nNOTE : This package is a now a mandatory mainline module\nhttps://en.wikipedia.org/wiki/Captive_portal\nhttps://www.xda-developers.com/android-project-mainline-modules-explanation", "dependencies": [], "neededBy": [], @@ -27832,7 +27769,7 @@ "removal": "Advanced" }, "com.google.android.modulemetadata": { - "list": "Google", + "list": "Aosp", "description": "Module that contains metadata about the list of modules on the device. And that’s about it.\nI wouldn't advise you to mess with it as it could break important modules (see #37)\nGood explanation of what android modules are : https://www.xda-developers.com/android-project-mainline-modules-explanation/", "dependencies": [], "neededBy": [], @@ -27840,7 +27777,7 @@ "removal": "Unsafe" }, "com.google.android.ext.services": { - "list": "Google", + "list": "Aosp", "description": "The ExtServices module updates framework components for core OS functionality such as notification ranking, autofill text-matching strategies, storage cache, package watchdog, and other services that run continually. This module is updatable, meaning it can receive updates to functionality outside of the normal Android release cycle.\nCan run before the user unlocks the device (direct-boot aware) and Android 9+ version have internet and location permissions.\n\nWARNING: Causes bootloop on most Android 11+ phones. This module is related to the Android mainline project (which is a useful project).There is no reason to mess with this.\n\nSources:\nhttps://source.android.com/devices/architecture/modular-system/extservices\nhttps://arstechnica.com/gadgets/2016/11/android-extensions-could-be-googles-plan-to-make-android-updates-suck-less/\nPithus analysis (Android 11): https://beta.pithus.org/report/e5e4a181082b88baf55e19aab0f9cb62e131d612eeaa73cddb510a52e0ff5c1a", "dependencies": [], "neededBy": [], @@ -27858,7 +27795,7 @@ "removal": "Unsafe" }, "com.google.android.networkstack": { - "list": "Google", + "list": "Aosp", "description": "Network Stack Components\nhttps://source.android.com/devices/architecture/modular-system/networking\nProvides common IP services, network connectivity monitoring, and captive login portal detection.\n", "dependencies": [], "neededBy": [], @@ -27866,7 +27803,7 @@ "removal": "Unsafe" }, "com.google.android.networkstack.permissionconfig": { - "list": "Google", + "list": "Aosp", "description": "Network Stack Permission Configuration\nDefines a permission that enables modules to perform network-related tasks.\nhttps://source.android.com/devices/architecture/modular-system/networking\n", "dependencies": [], "neededBy": [], @@ -27874,7 +27811,7 @@ "removal": "Unsafe" }, "com.google.android.packageinstaller": { - "list": "Google", + "list": "Aosp", "description": "Google package installer. Seems to replace com.android.packageinstaller on newer phones. It is strangely not needed on older devices (you can still install APKs without it by using the AOSP package installer) but since Android 9, it also handles permissions control and could bootloop your device if removed.\nOn Android 8.1, disabling the app also disabled the 'Permissions' settings within all the apps. Besides that, I couldn't install an '.apk' file download from outside the Play Store.\nSource: https://source.android.com/docs/core/architecture/modular-system/permissioncontroller.", "dependencies": [], "neededBy": [], @@ -27882,7 +27819,7 @@ "removal": "Unsafe" }, "com.google.android.packageinstaller.a_overlay": { - "list": "Google", + "list": "Aosp", "description": "Gives ability to install, update or remove applications on the device.\nIf you delete this package, your phone will probably bootloop.\n", "dependencies": [], "neededBy": [], @@ -27890,7 +27827,7 @@ "removal": "Unsafe" }, "com.google.android.permissioncontroller": { - "list": "Google", + "list": "Aosp", "description": "Permission controller\nControls app permissions.\nhttps://source.android.com/devices/architecture/modular-system/permissioncontroller", "dependencies": [], "neededBy": [], @@ -28885,13 +28822,13 @@ }, "com.huawei.nearby": { "list": "Oem", - "description": "HwNearby\nNeeded for Huawei Share features. (com.huawei.android.instantshare)\nHuawei Share features may not work after remove.", + "description": "HwNearby\nNeeded for Huawei Share features. (com.huawei.android.instantshare)\nHuawei Share features may not work after remove.\nNeeded to show a preview of recently opened apps in task manager. I agree, makes no sense, but that's what it is.", "dependencies": [ "com.huawei.android.instantshare" ], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Advanced" }, "com.huawei.omacp": { "list": "Oem", @@ -29429,7 +29366,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Unsafe" + "removal": "Expert" }, "com.fairphone.activator": { "list": "Oem", @@ -29886,7 +29823,7 @@ }, "com.huawei.systemmanager": { "list": "Oem", - "description": "System Manager\nHuawei's stock phone cleaner. Consumes a lot of battery power for useless 'security' checks.\nSafe to remove unless you need any anti-virus (while there are better ones to be found). NOTE: breaks the functionality of closing and cleaning background apps.", + "description": "System Manager\nHuawei's stock phone cleaner. Consumes a lot of battery power for useless 'security' checks.\nSafe to remove unless you need any anti-virus (while there are better ones to be found). NOTE: breaks the functionality of closing and cleaning background apps.\nThis is more than a phone cleaner, you will lose a lot of settings like battery and notifications management if you remove this.", "dependencies": [], "neededBy": [], "labels": [], @@ -29894,7 +29831,7 @@ }, "com.huawei.systemserver": { "list": "Oem", - "description": "Huawei System Services\nIt depends on (com.huawei.systemmanager).", + "description": "Huawei System Services\nIt depends on (com.huawei.systemmanager).\nNeeded for navigation with a fingerprint reader that is on Mate 10, but fingerprint unlock will still work if you remove it.", "dependencies": [], "neededBy": [], "labels": [], @@ -29910,19 +29847,19 @@ }, "com.huawei.wifieapsimplmn": { "list": "Oem", - "description": "PredefinedEapSim\nNeeded for WiFi to work properly\nWiFi will not work.", + "description": "PredefinedEapSim\nNeeded for WiFi to work properly? WiFi may not work (?)", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Unsafe" + "removal": "Expert" }, "com.huawei.wifiprobqeservice": { "list": "Oem", - "description": "HwWifiproBqeService\nNeeded for WiFi to work properly\nWiFi will not work.", + "description": "HwWifiproBqeService\nNeeded for WiFi to work properly? WiFi may not work (?)", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Unsafe" + "removal": "Expert" }, "com.qeexo.smartshot": { "list": "Oem", @@ -30212,6 +30149,14 @@ "labels": [], "removal": "Advanced" }, + "com.realme.as.music": { + "list": "Oem", + "description": "Realme Music app\nhttps://play.google.com/store/apps/details?id=com.realme.as.music", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, "com.realme.link": { "list": "Oem", "description": "RealMe Link (https://play.google.com/store/apps/details?id=com.realme.link)\nCompanion app for various realme IoT devices. Useless if you don't have a realme watch/band", @@ -30276,13 +30221,21 @@ "labels": [], "removal": "Advanced" }, + "com.oplus.pantanal.ums": { + "list": "Oem", + "description": "Ubiquitous Manager Service\nA service required for Fluid Cloud (Dynamic Island clone) feature in OxygenOS/ColorOS/RealmeUI (Android 14). Runs in background. After disabling, no issues occurred but there's a little empty space between clock and recent notification icons on the right.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Advanced" + }, "com.oplus.appplatform": { "list": "Oem", - "description": "App Services\nMight be renamed package of com.heytap.appplatform which is related to Oppo's Heytap account services. Provides a RomUpdateService. Probably not safe to remove.\n\nPithus analysis: https://beta.pithus.org/report/2025ceb69d9379a01771de71ff00051eb0f0c7f44226a72c2066db9649b6dcd2", + "description": "App Services\nMight be renamed package of com.heytap.appplatform which is related to Oppo's Heytap account services. Provides a RomUpdateService. Probably not safe to remove.\n\nPithus analysis: https://beta.pithus.org/report/2025ceb69d9379a01771de71ff00051eb0f0c7f44226a72c2066db9649b6dcd2\nCauses bootloop on some phones after uninstall.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.oplus.athena": { "list": "Oem", @@ -31323,7 +31276,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.google.android.apps.safetyhub": { "list": "Google", @@ -31407,7 +31360,7 @@ }, "com.ape.mtbf": { "list": "Oem", - "description": "Named 'MTBF Tools'\nDialer Code: 68238665. Uses SQLite Database. Reads/writes to External Storage. All sorts of permissions (camera, mic, battery, radio, led, sim, gps, nfc).\nFound more details at https://twitter.com/dbauduin/status/940126704261099520\nHardcoded URLs (an api and a book): http://www.andykhan.com/jexcelapi\nhttp://www.amazon.co.uk/exec/obidos/ASIN/0571058086/qid=1099836249/sr=1-3/ref=sr_1_11_3/202-6017285-1620664\nhttps://www.amazon.co.uk/exec/obidos/ASIN/0571058086qid=1099836249/sr=1-3/ref=sr_1_11_3/202-6017285-1620664", + "description": "Named 'MTBF Tools'\nDialer Code: 68238665. Uses SQLite Database. Reads/writes to External Storage. All sorts of permissions (camera, mic, battery, radio, led, sim, gps, nfc).\nFound more details at https://twitter.com/dbauduin/status/940126704261099520 (archive: https://web.archive.org/web/20240330025312/https://twitter.com/dbauduin/status/940126704261099520)\nHardcoded URLs (an api and a book): http://www.andykhan.com/jexcelapi\nhttp://www.amazon.co.uk/exec/obidos/ASIN/0571058086/qid=1099836249/sr=1-3/ref=sr_1_11_3/202-6017285-1620664\nhttps://www.amazon.co.uk/exec/obidos/ASIN/0571058086qid=1099836249/sr=1-3/ref=sr_1_11_3/202-6017285-1620664", "dependencies": [], "neededBy": [], "labels": [], @@ -31479,7 +31432,7 @@ }, "com.miui.core.internal.editor.services": { "list": "Oem", - "description": "I only found: config_enableHapticTextHandle true\nWhat is this mean? it's used to permission MIUIOP 10008 in some apps.\nMIUIOP = miui optimization? it's useless or important?", + "description": "I only found: config_enableHapticTextHandle true\nWhat is this mean? it's used to permission MIUIOP 10008 in some apps.\nMIUIOP = miui optimization? it's useless or important?\nNo effects after removing, it's probably a feature of Touch Assistant, but its used on 'com.miui.core'?", "dependencies": [], "neededBy": [], "labels": [], @@ -31487,7 +31440,7 @@ }, "com.miui.core.internal.services": { "list": "Oem", - "description": "I only found: array name= config_deviceSpecificSystemServices\nitem: com.miui.me.server.auto_install.InstallService\nWhat is this mean? I have must to check com.miui.core what it does\nand it's for ota updates but I'm not sure. (yes miui core have ota updates components)", + "description": "I only found: array name= config_deviceSpecificSystemServices\nitem: com.miui.me.server.auto_install.InstallService\nWhat does this mean? I have to check com.miui.core what it does and it's for autoinstall miui apps updates from GetApps 'com.xiaomi.market'.", "dependencies": [], "neededBy": [], "labels": [], @@ -31515,7 +31468,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.android.wifi.resources.overlay": { "list": "Aosp", @@ -31523,7 +31476,7 @@ "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.android.wifi.resources.xiaomi": { "list": "Oem", @@ -31839,11 +31792,11 @@ }, "android.miui.poco.launcher.res": { "list": "Oem", - "description": "Useless config to default com.miui.home launcher.\nIt's unused! Like com.mi.globallayout, it's not a joke.", + "description": "Config to default icons/placeholder widgets in MIUI launcher.\nIt's used only first time run MIUI launcher app like com.mi.globallayout.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Advanced" }, "com.android.uwb.resources": { "list": "Aosp", @@ -33079,7 +33032,7 @@ }, "com.huawei.coauthservice": { "list": "Oem", - "description": "HwCoAuthService\nApplock, lockscreen password, face recognition things, fingerprint, not sure if it's worth removing it", + "description": "HwCoAuthService\nApplock, lockscreen password, face recognition things, fingerprint, not sure if it's worth removing it.\nNeeded for manual apk installation.", "dependencies": [], "neededBy": [], "labels": [], @@ -33095,7 +33048,7 @@ }, "com.huawei.controlcenter": { "list": "Oem", - "description": "Smart Collaboration\nCollaboration between devices. Needed for Multi-Screen, Wireless Projection.", + "description": "Smart Collaboration\nCollaboration between devices. Needed for Multi-Screen, Wireless Projection?\nNeeded for Super Device or Device+, safe to remove if you don't use this, it will also declutter action center.", "dependencies": [], "neededBy": [], "labels": [], @@ -33167,7 +33120,7 @@ }, "com.huawei.harmonyos.foundation": { "list": "Oem", - "description": "foundation\nHas hwid, vehicle things, Aosp In Call Service permissions.\nDisable app instead of uninstalling, because breaks calling.", + "description": "foundation\nHas hwid, vehicle things, Aosp In Call Service permissions.\nDisable app instead of uninstalling, because breaks calling.\nSettings app and APK installation will become slow if you uninstall this.", "dependencies": [], "neededBy": [], "labels": [], @@ -33183,7 +33136,7 @@ }, "com.huawei.hwddmp": { "list": "Oem", - "description": "HwDDMP\nHas a lot frameworks.\nUninstalling breaks calling app even if you disable.\nIt does not cause bootloop but removing is highly not recommended.", + "description": "HwDDMP\nHas a lot frameworks.\nUninstalling breaks calling app even if you disable.\nIt does not cause bootloop but removing is highly not recommended.\nNot only breaks the dialer app, but causes lag in whole system too.", "dependencies": [], "neededBy": [], "labels": [], @@ -33223,7 +33176,7 @@ }, "com.huawei.ohos.famanager": { "list": "Oem", - "description": "Service Center\nProvides a space for you to view and manage services.\nThis app and its underlying services (which provide searches and AI-based services). A lot tracking.", + "description": "Service Center\nProvides a space for you to view and manage services.\nThis app and its underlying services (which provide searches and AI-based services). A lot tracking.\nDisable instead of uninstalling if you don't want to lose the widget.", "dependencies": [], "neededBy": [], "labels": [], @@ -33231,7 +33184,7 @@ }, "com.huawei.ohos.hiwindow": { "list": "Oem", - "description": "HiWindow\nHave loading, waiting png files\ncollaboration devices, hardware things, screen projection on activities shows Window Shell.\nAfter remove you will lose animations and loading screen.", + "description": "HiWindow\nHave loading, waiting png files\ncollaboration devices, hardware things, screen projection on activities shows Window Shell.\nAfter remove you will lose animations and loading screen.\nDisable instead of uninstalling if you don't want to lose the widget.", "dependencies": [], "neededBy": [], "labels": [], @@ -33727,11 +33680,11 @@ }, "com.google.android.carrier": { "list": "Oem", - "description": "Carrier Settings\nGoogle Api Activity, requires GMS, totally random api's.\nNot needed app, a lot metrics or telemetry frameworks.", + "description": "Carrier Settings\nGoogle Api Activity, requires GMS, totally random api's.\nRequired for 4G, but does not cause bootloop after removal.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Unsafe" }, "android.autoinstalls.config.xioami.mibox3": { "list": "Oem", @@ -34023,11 +33976,11 @@ }, "com.oplus.nas": { "list": "Oem", - "description": "NetworkAssistSys\nNeeded for network I guess by dialogs found in code.", + "description": "NetworkAssistSys\nNeeded for network I guess by dialogs found in code. Has location & phone permission, can read your call logs. Runs in background. After disabling, no issues occured (OxygenOS 14, OnePlus 11).", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Unsafe" + "removal": "Advanced" }, "com.oplus.notificationmanager": { "list": "Oem", @@ -34159,7 +34112,7 @@ }, "com.oplus.safecenter": { "list": "Oem", - "description": "Security Center\nIt breaks 'display over other apps' permission!", + "description": "Security Center\nIt breaks 'display over other apps' permission and also breaks screen lock on OnePlus Android 14", "dependencies": [], "neededBy": [], "labels": [], @@ -34677,14 +34630,6 @@ "labels": [], "removal": "Advanced" }, - "com.android.settings.os.overlay": { - "list": "Oem", - "description": "Icon user found, overlay to 'com.android.settings'.", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Expert" - }, "com.android.systemui.os.overlay": { "list": "Oem", "description": "Icon user found, overlay to 'com.android.systemui'.", @@ -34719,11 +34664,11 @@ }, "com.google.android.networkstack.overlay": { "list": "Aosp", - "description": "Needed for Network.", + "description": "WiFi will not work after remove.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Expert" + "removal": "Unsafe" }, "com.infinix": { "list": "Oem", @@ -34983,11 +34928,11 @@ }, "com.huawei.ohos.collaborationcenter": { "list": "Oem", - "description": "Sometimes ohos apps is configuration app before building.\nIn code I found it's for app cast transfer.", + "description": "Sometimes ohos apps is configuration app before building.\nIn code I found it's for app cast transfer.\nDisable instead of uninstalling if you don't want to lose the widget.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Recommended" }, "com.huawei.tipsove": { "list": "Oem", @@ -34999,11 +34944,11 @@ }, "com.huawei.ohos.security.privacycenter": { "list": "Oem", - "description": "It's shell to app 'com.huawei.security.privacycenter'.", + "description": "It's shell to app 'com.huawei.security.privacycenter'?\nDisable instead of uninstalling if you don't want to lose the widget.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Recommended" }, "com.huawei.android.findmyphone": { "list": "Oem", @@ -35223,7 +35168,7 @@ }, "com.huawei.featurelayer.sharedfeature.map": { "list": "Oem", - "description": "Huawei Map Service\nRequire FeatureFramework.\nOnly uses Chinese AMap to get location.", + "description": "Huawei Map Service\nRequire FeatureFramework.\nOnly uses Chinese AMap to get location.\nUsed to show maps inside Calendar and Gallery, they will complain if you uninstall it, disable instead.", "dependencies": [], "neededBy": [], "labels": [], @@ -35287,11 +35232,11 @@ }, "com.huawei.security.privacycenter": { "list": "Oem", - "description": "Protect your privacy by preventing apps from accessing sensitive data stored within images,\nsuch as location info and time stamps. This restriction does not apply to system apps such as Gallery and Cloud.\nI don't think this app values privacy a lot.", + "description": "Protect your privacy by preventing apps from accessing sensitive data stored within images,\nsuch as location info and time stamps. This restriction does not apply to system apps such as Gallery and Cloud.\nI don't think this app values privacy a lot.\nNeeded for Permission Manager to open.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Advanced" + "removal": "Expert" }, "com.huawei.smartlocation": { "list": "Oem", @@ -35879,7 +35824,7 @@ }, "com.google.android.overlay.healthconnect": { "list": "Oem", - "description": "Useless overlay to 'com.google.android.apps.healthdata'.", + "description": "Overlay to 'com.google.android.apps.healthdata'.", "dependencies": [], "neededBy": [], "labels": [], @@ -36285,14 +36230,6 @@ "labels": [], "removal": "Unsafe" }, - "com.samsung.attribution": { - "list": "Oem", - "description": "Attribution\nApp for auto updates I don't know what.", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Expert" - }, "com.samsung.android.bixbyhelper": { "list": "Oem", "description": "QQ music plugin\nRequire QQ Music and it's Chinese.", @@ -36389,6 +36326,14 @@ "labels": [], "removal": "Advanced" }, + "com.samsung.android.dbsc": { + "list": "Oem", + "description": "Galaxy Service Setup\nDevice-Based Service Consent. Pairs with `com.sec.spp.push` to broadcast new service consent requests to your device.\nReally slimey move by Samsung to name it this in the wake of Google announcing their own DBSC (Device Bound Session Credentials) which will phase out third-party cookies and help secure browsers against cookie theft.\nhttps://blog.chromium.org/2024/04/fighting-cookie-theft-using-device.html\n", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, "com.samsung.android.deviceidservice": { "list": "Oem", "description": "DeviceIdService\nCollects device id but it is not known what it is used for.\nTake's OAID, VAID, AAID.", @@ -36421,14 +36366,6 @@ "labels": [], "removal": "Recommended" }, - "com.samsung.android.widget.pictureframe": { - "list": "Oem", - "description": "Gallery\nHas something like restore image.\nIt's not gallery app but provides some features to this app.", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Advanced" - }, "com.samsung.gamedriver.sm8550": { "list": "Oem", "description": "Samsung SM8550 GameDriver.", @@ -36439,11 +36376,11 @@ }, "com.samsung.android.globalpostprocmgr": { "list": "Oem", - "description": "GlobalPostProcMgr\nUnknown app, has Draft Recovery.", + "description": "GlobalPostProcMgr\nUnknown app, has Draft Recovery.\nUninstalling breaks camera functionality.", "dependencies": [], "neededBy": [], "labels": [], - "removal": "Recommended" + "removal": "Expert" }, "com.samsung.hongbaoassistant": { "list": "Oem", @@ -36557,14 +36494,6 @@ "labels": [], "removal": "Recommended" }, - "com.samsung.android.photoremasterservice": { - "list": "Oem", - "description": "Photo remaster will not work after remove, if this feature exist, still unknown.", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Advanced" - }, "com.samsung.preloadapp": { "list": "Oem", "description": "Install app\nInstalls recommended apps.", @@ -36685,14 +36614,6 @@ "labels": [], "removal": "Advanced" }, - "com.samsung.android.sm_cn": { - "list": "Oem", - "description": "Smart Manager\nTests hardware things.", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Recommended" - }, "com.samsung.android.sm.devicesecurity.tcm": { "list": "Oem", "description": "Device security\nChinese scanning app for searching viruses.", @@ -36719,7 +36640,7 @@ }, "com.samsung.sait.sohservice": { "list": "Oem", - "description": "This weird app collects battery data and probably others, who knows?", + "description": "FactoryApp\nThis weird app collects battery data and probably others, who knows? Also to test battery things such as set voltage, Soc, temperature, status, timestamp.", "dependencies": [], "neededBy": [], "labels": [], @@ -36765,14 +36686,6 @@ "labels": [], "removal": "Recommended" }, - "com.samsung.android.wallpaper.res": { - "list": "Oem", - "description": "Video Wallpaper .webp resources.", - "dependencies": [], - "neededBy": [], - "labels": [], - "removal": "Advanced" - }, "com.samsung.android.wifi.ai": { "list": "Oem", "description": "No activities, provides WiFi diagnostics, has several ai models that it is not clear how useful they are.", @@ -36868,5 +36781,269 @@ "neededBy": [], "labels": [], "removal": "Advanced" + }, + "com.transsion.manualguide": { + "list": "Oem", + "description": "Digital version of your phone manual.\nYou can view it from (Settings > System > Manual Guide)\nCan be safely removed if you don't need it.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.transsion.aiwallpaper": { + "list": "Oem", + "description": "Mediocre AI Wallpaper Generator.\nCan be accessed from (Settings > Personalization).\nYou can safely remove this without any issues if you don't use it.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.transsion.aivoiceassistant": { + "list": "Oem", + "description": "Very shady voice assistant called 'Folax' that comes preinstalled in Infinix phones, and is also packed with ads in the main ui. It needs every permission, and access to everything on your phone to run. It uses OpenAI as its backend.\nIt constantly runs in the background after boot, and periodically phones home.\nYou don't want this on your phone.\nThis can be safely removed without issues.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.transsion.aisettings": { + "list": "Oem", + "description": "Adds a shortcut on the Settings app that lets you manage your Folax AI (com.transsion.aivoiceassistant) settings. If you have already removed that package, it just displays a blank page.\nThis can also be safely removed without issues.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.miui.phone.carriers.overlay": { + "description": "Preferred network type to Vodafone 5G/4G/3G/2G auto.\nIt's unused.", + "removal": "Recommended", + "list": "Oem", + "dependencies": [], + "neededBy": [], + "labels": [] + }, + "com.tracfone.preload.accountservices": { + "list": "Carrier", + "description": "TracPhone / StraightTalk application. It just shows IMEI, SIM, and phone number, as well as a way to see device properties.\nComes preinstalled with any TracPhone or StraightTalk device. It can be downloaded from the playstore if needed for whatever reason.\nHas Approximate and Precise location permissions, and Device ID permission.\nRuns in the background for them to collect data.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "org.chromium.webview_shell": { + "list": "Aosp", + "description": "Simple Browser for WebView tester used in AOSP.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.sonymobile.telephony.extension": { + "description": "I have uninstalled it for the user 0 on my phone, and since then I haven't noticed any functionality drop.\nCell signal is similar as before, also calls, SMSs and mobile data. I think it is not worth having this package installed because it uses a lot of wakelock time, but I cannot see any cell signal drop since I uninstalled it.\nIn the code found some things: omadm, wifi calling, IMS. Its app for dual SIM reachability? Not sure if its app for debugging.", + "removal": "Advanced", + "list": "Oem", + "dependencies": [], + "neededBy": [], + "labels": [] + }, + "com.microsoft.deviceintegrationservice": { + "description": "Device Integration Service\nMight be needed for Microsoft Link to Windows (com.microsoft.appmanager) which is preinstalled with OxygenOS 14.\nAfter Uninstalling, no issues occurred.", + "removal": "Recommended", + "list": "Oem", + "dependencies": [], + "neededBy": [], + "labels": [] + }, + "com.microsoftsdk.crossdeviceservicebroker": { + "description": "Cross Device Broker\nMight be needed for Microsoft Link to Windows (com.microsoft.appmanager) which is preinstalled with OxygenOS 14.\nAfter Uninstalling, no issues occurred.", + "removal": "Recommended", + "list": "Oem", + "dependencies": [], + "neededBy": [], + "labels": [] + }, + "com.samsung.android.app.notes.addons": { + "list": "Oem", + "description": "Allows for marking up/drawing on notes in the Samsung Notes app (designed for use with S Pen).\nRemoval likely breaks com.samsung.android.app.notes. Safe to remove otherwise.\nMay reinstall itself automatically (removal has persisted for me this time around, and through multiple reboots).\nhttps://galaxystore.samsung.com/prepost/000005769652?appId=com.samsung.android.app.notes.addons", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Advanced" + }, + "com.aura.jet.att": { + "list": "Carrier", + "description": "AT&T Hub\nApp from AT&T. Installs apps on oobe and its maded by advertising company 'ironSource'.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.aura.oobe.att": { + "list": "Carrier", + "description": "AppCloud\nApp from AT&T. Installs apps on oobe and its maded by advertising company 'ironSource'.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.samsung.android.app.interpreter": { + "list": "Oem", + "description": "Samsung Interpreter app, enables Live translation of foreign languages", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Advanced" + }, + "com.samsung.android.inputshare": { + "list": "Oem", + "description": "Samsung Multi-Control, allows certain apps to be continued on multiple Galaxy devices (like Internet or Notes)", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.samsung.android.audiomirroring": { + "list": "Oem", + "description": "AudioMirroring\nAudio Mirroring to Cast other devices will not work after remove.\nAlso this app running in the background.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Advanced" + }, + "com.android.connectivity.resources.overlay": { + "list": "Oem", + "description": "Cause bootloop?\nFound in TECNO phone, in overlay there's a notification saying 'No Internet As Dialog When High Priority'.\nCan someone test it?", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Unsafe" + }, + "com.hilauncherconfig": { + "list": "Oem", + "description": "Configures app icons and folders on first run HiOS Launcher.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Advanced" + }, + "com.theme.icondefaultshape": { + "list": "Oem", + "description": "The shape of the icons can be uninstalled or left alone, it's just the look of the icon.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Advanced" + }, + "com.itc.autotest": { + "list": "Oem", + "description": "ITC_Base\nHidden camera testing, also its Chinese.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.transsnet.moreplus": { + "list": "Oem", + "description": "More+ is a social app with massive videos, images, opinions and tribes, where you can post your personal blogs, share funny moments, chat and make friends.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.android.bluetooth.auto_generated_rro_product__": { + "list": "Oem", + "description": "Random generated code app, in TECNO Phone found headphones images in the app to Settings.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Advanced" + }, + "com.transsion.nephilim": { + "list": "Oem", + "description": "App provides custom quality settings to game: pubg, call of duty.\nNot very useful.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.transsion.phoenix": { + "list": "Oem", + "description": "Phoenix Browser\nhttps://play.google.com/store/apps/details?id=com.transsion.phoenix&hl=en", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.mediatek.ppl": { + "list": "Oem", + "description": "Mobile anti-theft\nIt seems that people don't even have access to it, its app to remote phone lock, wipe data, fetch back anti-theft PIN.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.android.settings.os.overlay": { + "list": "Oem", + "description": "Looks unused, but not confirmed. Found in app 'icon file download', Vibration switch. Icon user found, overlay to 'com.android.settings'.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Expert" + }, + "com.android.soundpicker.auto_generated_rro_product__": { + "list": "Oem", + "description": "Has colors, dialog things, autogenerated code, but someone can confirm that app is safe to remove?", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Expert" + }, + "com.google.android.overlay.modules.packageinstaller": { + "list": "Oem", + "description": "Package installer ui changes to the classic after uninstallation.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Advanced" + }, + "com.transsion.bluetooth": { + "list": "Oem", + "description": "Airlink\nBluetooth still work without this.\n(not sure if its needed for transfer files using bluetooth)", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Advanced" + }, + "com.infinix.xshare": { + "list": "Oem", + "description": "XShare\nIts app for Transfer & Share files, also has ads.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.android.opasuwintegrationsample": { + "list": "Oem", + "description": "Optimized Setup Wizard Integration Sample code.\nCan be used to create a custom setup wizard, such as one created by a manufacturer that runs after the initial Android Setup Wizard.\nDoes not appear to actually run. It is sample code and should be able to be removed safely.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Recommended" + }, + "com.android.settings.resoverlay": { + "list": "Oem", + "description": "Found in the code \"Declaration of Conformity\" on the TECNO phone, is probably unused, as it cannot be found in the Settings or anywhere else.\nIt can be safely removed, the Settings still work without this app.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Advanced" + }, + "me.phh.treble.app": { + "list": "Oem", + "description": "Used for settings GSI rom that based by Phh Treble. This should not be remove.", + "dependencies": [], + "neededBy": [], + "labels": [], + "removal": "Unsafe" } } diff --git a/src/core/config.rs b/src/core/config.rs index ed015f46..9a084bbd 100644 --- a/src/core/config.rs +++ b/src/core/config.rs @@ -1,6 +1,7 @@ use crate::core::sync::{get_android_sdk, User}; use crate::core::utils::DisplayablePath; use crate::gui::views::settings::Settings; +use crate::CACHE_DIR; use crate::CONFIG_DIR; use serde::{Deserialize, Serialize}; use static_init::dynamic; @@ -14,10 +15,11 @@ pub struct Config { pub devices: Vec, } -#[derive(Default, Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct GeneralSettings { pub theme: String, pub expert_mode: bool, + pub backup_folder: PathBuf, } #[derive(Default, Debug, Clone)] @@ -38,6 +40,16 @@ pub struct DeviceSettings { pub backup: BackupSettings, } +impl Default for GeneralSettings { + fn default() -> Self { + Self { + theme: String::from("Dark"), + expert_mode: false, + backup_folder: CACHE_DIR.join("backups"), + } + } +} + impl Default for DeviceSettings { fn default() -> Self { Self { @@ -65,7 +77,7 @@ impl Config { debug!("config: New device settings saved"); config.devices.push(settings.device.clone()); } - config.general = settings.general.clone(); + config.general.clone_from(&settings.general); let toml = toml::to_string(&config).unwrap(); fs::write(&*CONFIG_FILE, toml).expect("Could not write config file to disk!"); } diff --git a/src/core/helpers.rs b/src/core/helpers.rs new file mode 100644 index 00000000..7824b7b8 --- /dev/null +++ b/src/core/helpers.rs @@ -0,0 +1,14 @@ +use crate::core::theme::Theme; +use crate::gui::style; +use iced::widget::button; +use iced::widget::button::Button; +use iced::{Element, Renderer}; + +/// Wrapper function for iced::widget::button with padding and style applied +pub fn button_primary<'a, Message>( + content: impl Into>, +) -> Button<'a, Message, Theme, Renderer> { + button(content) + .padding([5, 10]) + .style(style::Button::Primary) +} diff --git a/src/core/mod.rs b/src/core/mod.rs index 116c9b2a..321c5804 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,4 +1,5 @@ pub mod config; +pub mod helpers; pub mod save; pub mod sync; pub mod theme; diff --git a/src/core/save.rs b/src/core/save.rs index 3a6697d3..21f172e1 100644 --- a/src/core/save.rs +++ b/src/core/save.rs @@ -1,4 +1,4 @@ -use crate::core::config::DeviceSettings; +use crate::core::config::{Config, DeviceSettings}; use crate::core::sync::{apply_pkg_state_commands, CorePackage, Phone, User}; use crate::core::utils::DisplayablePath; use crate::gui::widgets::package_row::PackageRow; @@ -51,7 +51,8 @@ pub async fn backup_phone( match serde_json::to_string_pretty(&backup) { Ok(json) => { - let backup_path = &*BACKUP_DIR.join(device_id); + let backup_dir: PathBuf = Config::load_configuration_file().general.backup_folder; + let backup_path = &*backup_dir.join(device_id); if let Err(e) = fs::create_dir_all(backup_path) { error!("BACKUP: could not create backup dir: {}", e); diff --git a/src/core/sync.rs b/src/core/sync.rs index 776efbef..482e025e 100644 --- a/src/core/sync.rs +++ b/src/core/sync.rs @@ -1,4 +1,5 @@ use crate::core::uad_lists::PackageState; +use crate::core::utils::ANDROID_SERIAL; use crate::gui::views::list::PackageInfo; use crate::gui::widgets::package_row::PackageRow; use regex::Regex; @@ -322,7 +323,7 @@ pub async fn get_devices_list() -> Vec { return OperationResult::Retry(vec![]); } for device in RE.captures_iter(&devices) { - env::set_var("ANDROID_SERIAL", &device[1]); + env::set_var(ANDROID_SERIAL, &device[1]); device_list.push(Phone { model: get_phone_brand(), android_sdk: get_android_sdk(), diff --git a/src/core/utils.rs b/src/core/utils.rs index b95d8816..f56cddaa 100644 --- a/src/core/utils.rs +++ b/src/core/utils.rs @@ -8,6 +8,16 @@ use std::path::PathBuf; use std::process::Command; use std::{fmt, fs}; +/// Global environment variable to keep +/// track of the current device serial. +pub const ANDROID_SERIAL: &str = "ANDROID_SERIAL"; +pub const EXPORT_FILE_NAME: &str = "selection_export.txt"; + +#[derive(Debug, Clone)] +pub enum Error { + DialogClosed, +} + pub fn fetch_packages(uad_lists: &PackageHashMap, 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); @@ -105,6 +115,20 @@ pub fn format_diff_time_from_now(date: DateTime) -> String { } } +pub async fn export_selection(packages: Vec) -> Result { + let selected = packages + .iter() + .filter(|p| p.selected) + .map(|p| p.name.clone()) + .collect::>() + .join("\n"); + + match fs::write(EXPORT_FILE_NAME, selected) { + Ok(_) => Ok(true), + Err(err) => Err(err.to_string()), + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct DisplayablePath { pub path: PathBuf, @@ -129,3 +153,12 @@ impl fmt::Display for DisplayablePath { write!(f, "{stem}") } } + +pub async fn open_folder() -> Result { + let picked_folder = rfd::AsyncFileDialog::new() + .pick_folder() + .await + .ok_or(Error::DialogClosed)?; + + Ok(picked_folder.path().to_owned()) +} diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 9fda70c5..5ea7966c 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -6,7 +6,7 @@ use crate::core::sync::{get_devices_list, initial_load, perform_adb_commands, Co use crate::core::theme::Theme; use crate::core::uad_lists::UadListState; use crate::core::update::{get_latest_release, Release, SelfUpdateState, SelfUpdateStatus}; -use crate::core::utils::string_to_theme; +use crate::core::utils::{string_to_theme, ANDROID_SERIAL}; use iced::advanced::graphics::image::image_rs::ImageFormat; use iced::font; @@ -261,7 +261,7 @@ impl Application for UadGui { Message::DeviceSelected(s_device) => { self.selected_device = Some(s_device.clone()); self.view = View::List; - env::set_var("ANDROID_SERIAL", s_device.adb_id); + env::set_var(ANDROID_SERIAL, s_device.adb_id); info!("{:-^65}", "-"); info!( "ANDROID_SDK: {} | DEVICE: {}", diff --git a/src/gui/style.rs b/src/gui/style.rs index ee17a126..ac329427 100644 --- a/src/gui/style.rs +++ b/src/gui/style.rs @@ -89,7 +89,6 @@ pub enum Button { Primary, Unavailable, SelfUpdate, - Refresh, UninstallPackage, RestorePackage, NormalPackage, @@ -124,9 +123,7 @@ impl button::StyleSheet for Theme { }; match style { - Button::Primary | Button::SelfUpdate | Button::Refresh => { - active_appearance(None, p.bright.primary) - } + Button::Primary | Button::SelfUpdate => 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)), @@ -178,9 +175,7 @@ impl button::StyleSheet for Theme { }; match style { - Button::Primary | Button::SelfUpdate | Button::Refresh => { - hover_appearance(p.bright.primary, None) - } + Button::Primary | Button::SelfUpdate => 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), diff --git a/src/gui/views/about.rs b/src/gui/views/about.rs index ef2a4343..b410e3e1 100644 --- a/src/gui/views/about.rs +++ b/src/gui/views/about.rs @@ -1,8 +1,9 @@ +use crate::core::helpers::button_primary; use crate::core::theme::Theme; use crate::core::utils::{last_modified_date, open_url}; use crate::gui::{style, UpdateState}; use crate::CACHE_DIR; -use iced::widget::{button, column, container, row, text, Space}; +use iced::widget::{column, container, row, text, Space}; use iced::{Alignment, Element, Length, Renderer}; use std::path::PathBuf; @@ -38,16 +39,10 @@ impl About { let uad_list_text = text(format!("UAD-ng package list: v{}", date.format("%Y%m%d"))).width(250); let last_update_text = text(update_state.uad_list.to_string()); - let uad_lists_btn = button("Update") - .on_press(Message::UpdateUadLists) - .padding([5, 10]) - .style(style::Button::Primary); + let uad_lists_btn = button_primary("Update").on_press(Message::UpdateUadLists); #[cfg(feature = "self-update")] - let self_update_btn = button("Update") - .on_press(Message::DoSelfUpdate) - .padding([5, 10]) - .style(style::Button::Primary); + let self_update_btn = button_primary("Update").on_press(Message::DoSelfUpdate); #[cfg(feature = "self-update")] let uad_version_text = @@ -96,31 +91,22 @@ impl About { .padding(10) .style(style::Container::Frame); - let website_btn = button("GitHub page") - .on_press(Message::UrlPressed(PathBuf::from( + let website_btn = + button_primary("GitHub page").on_press(Message::UrlPressed(PathBuf::from( "https://github.com/Universal-Debloater-Alliance/universal-android-debloater", - ))) - .padding([5, 10]) - .style(style::Button::Primary); + ))); - let issue_btn = button("Have an issue?") + let issue_btn = button_primary("Have an issue?") .on_press(Message::UrlPressed(PathBuf::from( - "https://github.com/Universal-Debloater-Alliance/universal-android-debloater/issues", - ))) - .padding([5, 10]) - .style(style::Button::Primary); + "https://github.com/Universal-Debloater-Alliance/universal-android-debloater/issues", + ))); - let log_btn = button("Locate the logfiles") - .on_press(Message::UrlPressed(CACHE_DIR.to_path_buf())) - .padding([5, 10]) - .style(style::Button::Primary); + let log_btn = button_primary("Locate the logfiles") + .on_press(Message::UrlPressed(CACHE_DIR.to_path_buf())); - let wiki_btn = button("Wiki") - .on_press(Message::UrlPressed(PathBuf::from( - "https://github.com/Universal-Debloater-Alliance/universal-android-debloater/wiki", - ))) - .padding([5, 10]) - .style(style::Button::Primary); + let wiki_btn = button_primary("Wiki").on_press(Message::UrlPressed(PathBuf::from( + "https://github.com/Universal-Debloater-Alliance/universal-android-debloater/wiki", + ))); let row = row![website_btn, wiki_btn, issue_btn, log_btn,].spacing(20); diff --git a/src/gui/views/list.rs b/src/gui/views/list.rs index 05a33aeb..87267469 100644 --- a/src/gui/views/list.rs +++ b/src/gui/views/list.rs @@ -1,4 +1,5 @@ use crate::core::config::DeviceSettings; +use crate::core::helpers::button_primary; use crate::core::sync::{ apply_pkg_state_commands, perform_adb_commands, AdbError, CommandType, Phone, User, }; @@ -6,8 +7,9 @@ use crate::core::theme::Theme; use crate::core::uad_lists::{ load_debloat_lists, Opposite, PackageHashMap, PackageState, Removal, UadList, UadListState, }; -use crate::core::utils::fetch_packages; -use crate::core::utils::open_url; +use crate::core::utils::{ + export_selection, fetch_packages, open_url, ANDROID_SERIAL, EXPORT_FILE_NAME, +}; use crate::gui::style; use crate::gui::widgets::navigation_menu::ICONS; use std::env; @@ -18,7 +20,7 @@ use crate::gui::widgets::modal::Modal; use crate::gui::widgets::package_row::{Message as RowMessage, PackageRow}; use iced::widget::{ button, checkbox, column, container, horizontal_space, pick_list, radio, row, scrollable, text, - text_input, tooltip, vertical_rule, Space, + text_input, tooltip, vertical_rule, Column, Space, }; use iced::{alignment, Alignment, Command, Element, Length, Renderer}; @@ -57,6 +59,7 @@ pub struct List { description: String, selection_modal: bool, error_modal: Option, + export_modal: bool, current_package_index: usize, is_adb_satisfied: bool, } @@ -84,6 +87,8 @@ pub enum Message { ADBSatisfied(bool), UpdateFailed, GoToUrl(PathBuf), + ExportSelection, + SelectionExported(Result), } pub struct SummaryEntry { @@ -115,6 +120,7 @@ impl List { Message::ModalHide => { self.selection_modal = false; self.error_modal = None; + self.export_modal = false; Command::none() } Message::ModalValidate => { @@ -160,7 +166,7 @@ impl List { Message::LoadPhonePackages(list_box) => { let (uad_list, list_state) = list_box; self.loading_state = LoadingState::LoadingPackages; - self.uad_lists = uad_list.clone(); + self.uad_lists.clone_from(&uad_list); *list_update_state = list_state; Command::perform( Self::load_packages(uad_list, selected_device.user_list.clone()), @@ -323,10 +329,22 @@ impl List { open_url(url); Command::none() } + Message::ExportSelection => Command::perform( + export_selection(self.phone_packages[i_user].clone()), + Message::SelectionExported, + ), + Message::SelectionExported(export) => { + match export { + Ok(_) => self.export_modal = true, + Err(err) => error!("Failed to export current selection: {:?}", err), + }; + Command::none() + } Message::Nothing => Command::none(), } } + /// Builds the main view for the app list interface pub fn view( &self, settings: &Settings, @@ -334,22 +352,15 @@ impl List { ) -> Element { match &self.loading_state { LoadingState::DownloadingList => waiting_view( - settings, "Downloading latest UAD-ng lists from GitHub. Please wait...", Some(button("No internet?").on_press(Message::LoadUadList(false))), style::Text::Default, ), LoadingState::FindingPhones => { if self.is_adb_satisfied { - waiting_view( - settings, - "Finding connected devices...", - None, - style::Text::Default, - ) + waiting_view("Finding connected devices...", None, style::Text::Default) } else { waiting_view( - settings, "ADB is not installed on your system, install ADB and relaunch application.", Some(button("Read on how to get started.") .on_press(Message::GoToUrl(PathBuf::from( @@ -360,127 +371,157 @@ impl List { } } LoadingState::LoadingPackages => waiting_view( - settings, "Pulling packages from the device. Please wait...", None, style::Text::Default, ), LoadingState::_UpdatingUad => waiting_view( - settings, "Updating UAD-ng. Please wait...", None, style::Text::Default, ), LoadingState::RestoringDevice(device) => waiting_view( - settings, &format!("Restoring device: {device}"), None, style::Text::Default, ), - LoadingState::Ready => { - let search_packages = text_input("Search packages...", &self.input_value) - .width(Length::Fill) - .on_input(Message::SearchInputChanged) - .padding([5, 10]); - - let select_all_checkbox = checkbox("", self.all_selected) - .on_toggle(Message::ToggleAllSelected) - .style(style::CheckBox::SettingsEnabled) - .spacing(0); // no label, so remove space entirely - - let col_sel_all = row![tooltip( - select_all_checkbox, - if self.all_selected { - "Deselect all" - } else { - "Select all" - }, - tooltip::Position::Top, - ) - .style(style::Container::Tooltip) - .gap(4)] - .padding(8); + LoadingState::Ready => self.ready_view(settings, selected_device), + LoadingState::FailedToUpdate => waiting_view( + "Failed to download update", + Some(button("Go back").on_press(Message::LoadUadList(false))), + style::Text::Danger, + ), + } + } + + fn control_panel(&self, selected_device: &Phone) -> Element { + let search_packages = text_input("Search packages...", &self.input_value) + .width(Length::Fill) + .on_input(Message::SearchInputChanged) + .padding([5, 10]); + + let select_all_checkbox = checkbox("", self.all_selected) + .on_toggle(Message::ToggleAllSelected) + .style(style::CheckBox::SettingsEnabled) + .spacing(0); // no label, so remove space entirely + + let col_sel_all = row![tooltip( + select_all_checkbox, + if self.all_selected { + "Deselect all" + } else { + "Select all" + }, + tooltip::Position::Top, + ) + .style(style::Container::Tooltip) + .gap(4)] + .padding(8); + + let user_picklist = pick_list( + selected_device.user_list.clone(), + self.selected_user, + Message::UserSelected, + ) + .width(85); + + let list_picklist = pick_list(UadList::ALL, self.selected_list, Message::ListSelected); + let package_state_picklist = pick_list( + PackageState::ALL, + self.selected_package_state, + Message::PackageStateSelected, + ); + + let removal_picklist = pick_list( + Removal::ALL, + self.selected_removal, + Message::RemovalSelected, + ); + + row![ + col_sel_all, + search_packages, + user_picklist, + removal_picklist, + package_state_picklist, + list_picklist, + ] + .width(Length::Fill) + .align_items(Alignment::Center) + .spacing(6) + .padding([0, 16, 0, 0]) + .into() + } - let user_picklist = pick_list( - selected_device.user_list.clone(), - self.selected_user, - Message::UserSelected, + fn ready_view( + &self, + settings: &Settings, + selected_device: &Phone, + ) -> Element { + let packages = self + .filtered_packages + .iter() + .fold(column![].spacing(6), |col, &i| { + col.push( + self.phone_packages[self.selected_user.unwrap().index][i] + .view(settings, selected_device) + .map(move |msg| Message::List(i, msg)), ) - .width(85); - - let list_picklist = - pick_list(UadList::ALL, self.selected_list, Message::ListSelected); - let package_state_picklist = pick_list( - PackageState::ALL, - self.selected_package_state, - Message::PackageStateSelected, - ); + }); - let removal_picklist = pick_list( - Removal::ALL, - self.selected_removal, - Message::RemovalSelected, - ); + let packages_scrollable = scrollable(packages) + .height(Length::FillPortion(6)) + .style(style::Scrollable::Packages); - let control_panel = row![ - col_sel_all, - search_packages, - user_picklist, - removal_picklist, - package_state_picklist, - list_picklist, - ] - .width(Length::Fill) - .align_items(Alignment::Center) - .spacing(6) - .padding([0, 16, 0, 0]); - - let packages = - self.filtered_packages - .iter() - .fold(column![].spacing(6), |col, &i| { - col.push( - self.phone_packages[self.selected_user.unwrap().index][i] - .view(settings, selected_device) - .map(move |msg| Message::List(i, msg)), - ) - }); - - let packages_scrollable = scrollable(packages) - .height(Length::FillPortion(6)) - .style(style::Scrollable::Packages); - - let description_scroll = scrollable(text(&self.description).width(Length::Fill)) - .style(style::Scrollable::Description); - - let description_panel = container(description_scroll) - .padding(6) - .height(Length::FillPortion(2)) - .width(Length::Fill) - .style(style::Container::Frame); - - let review_selection = if !self.selected_packages.is_empty() { - button(text(format!( - "Review selection ({})", - self.selected_packages.len() - ))) - .on_press(Message::ApplyActionOnSelection) - .padding([5, 10]) - .style(style::Button::Primary) - } else { - button(text(format!( - "Review selection ({})", - self.selected_packages.len() - ))) - .padding([5, 10]) - }; + let description_scroll = scrollable(text(&self.description).width(Length::Fill)) + .style(style::Scrollable::Description); - let action_row = row![Space::new(Length::Fill, Length::Shrink), review_selection] - .width(Length::Fill) - .spacing(10) - .align_items(Alignment::Center); + let description_panel = container(description_scroll) + .padding(6) + .height(Length::FillPortion(2)) + .width(Length::Fill) + .style(style::Container::Frame); + + let review_selection = if !self.selected_packages.is_empty() { + button_primary(text(format!( + "Review selection ({})", + self.selected_packages.len() + ))) + .on_press(Message::ApplyActionOnSelection) + } else { + button(text(format!( + "Review selection ({})", + self.selected_packages.len() + ))) + .padding([5, 10]) + }; + + let export_selection = if !self.selected_packages.is_empty() { + button(text(format!( + "Export current selection ({})", + self.selected_packages.len() + ))) + .on_press(Message::ExportSelection) + .padding([5, 10]) + .style(style::Button::Primary) + } else { + button(text(format!( + "Export current selection ({})", + self.selected_packages.len() + ))) + .padding([5, 10]) + }; - let unavailable = container( + let action_row = row![ + export_selection, + Space::new(Length::Fill, Length::Shrink), + review_selection + ] + .width(Length::Fill) + .spacing(10) + .align_items(Alignment::Center); + + let unavailable = container( column![ text("ADB is not authorized to access this user!").size(20) .style(style::Text::Danger), @@ -495,79 +536,76 @@ impl List { .center_x() .style(style::Container::BorderedFrame); - let content = if selected_device.user_list.is_empty() - || !self.phone_packages[self.selected_user.unwrap().index].is_empty() - { - column![ - control_panel, - packages_scrollable, - description_panel, - action_row, - ] - .width(Length::Fill) - .spacing(10) - .align_items(Alignment::Center) - } else { - column![ - control_panel, - container(unavailable).height(Length::Fill).center_y(), - ] - .width(Length::Fill) - .spacing(10) - .align_items(Alignment::Center) - }; - if self.selection_modal { - return Modal::new( - content.padding(10), - self.apply_selection_modal( - selected_device, - settings, - &self.phone_packages[self.selected_user.unwrap().index], - ), - ) - .on_blur(Message::ModalHide) - .into(); - } - if let Some(err) = &self.error_modal { - let title_ctn = container( - row![text("Failed to perform ADB operation").size(24)] - .align_items(Alignment::Center), - ) - .width(Length::Fill) - .style(style::Container::Frame) - .padding([10, 0, 10, 0]) - .center_y() - .center_x(); - - let modal_btn_row = row![button( - text("Close") - .width(Length::Fill) - .horizontal_alignment(alignment::Horizontal::Center), - ) - .width(Length::Fill) - .padding(10) - .on_press(Message::ModalHide)] - .padding([10, 0, 0, 0]); + let control_panel = self.control_panel(selected_device); + let content = if selected_device.user_list.is_empty() + || !self.phone_packages[self.selected_user.unwrap().index].is_empty() + { + column![ + control_panel, + packages_scrollable, + description_panel, + action_row, + ] + } else { + column![ + control_panel, + container(unavailable).height(Length::Fill).center_y(), + ] + } + .width(Length::Fill) + .spacing(10) + .align_items(Alignment::Center); - let text_box = scrollable(text(err).width(Length::Fill)).height(400); + if self.selection_modal { + return Modal::new( + content.padding(10), + self.apply_selection_modal( + selected_device, + settings, + &self.phone_packages[self.selected_user.unwrap().index], + ), + ) + .on_blur(Message::ModalHide) + .into(); + } - let ctn = container(column![title_ctn, text_box, modal_btn_row]) - .height(Length::Shrink) - .max_height(700) - .padding(10) - .style(style::Container::Frame); + if self.export_modal { + let title = container(row![text("Success").size(24)].align_items(Alignment::Center)) + .width(Length::Fill) + .style(style::Container::Frame) + .padding([10, 0, 10, 0]) + .center_y() + .center_x(); - Modal::new(content, ctn).on_blur(Message::ModalHide).into() - } else { - container(content).height(Length::Fill).padding(10).into() - } - } - LoadingState::FailedToUpdate => waiting_view( - settings, - "Failed to download update", - Some(button("Go back").on_press(Message::LoadUadList(false))), - style::Text::Danger, - ), + let text_box = row![ + text("Exported current selection into file.\nFile is exported in same directory where UAD-ng is located.").width(Length::Fill), + ].padding(20); + + let file_row = row![text(EXPORT_FILE_NAME).style(style::Text::Commentary)].padding(20); + + let modal_btn_row = row![ + Space::new(Length::Fill, Length::Shrink), + button(text("Close").width(Length::Shrink)) + .width(Length::Shrink) + .on_press(Message::ModalHide), + Space::new(Length::Fill, Length::Shrink), + ]; + + let ctn = container(column![title, text_box, file_row, modal_btn_row]) + .height(Length::Shrink) + .width(500) + .padding(10) + .style(style::Container::Frame); + + return Modal::new(content.padding(10), ctn) + .on_blur(Message::ModalHide) + .into(); + } + + if let Some(err) = &self.error_modal { + error_view(err, content).into() + } else { + container(content).height(Length::Fill).padding(10).into() } } @@ -683,12 +721,13 @@ impl List { self.phone_packages[selection.0][selection.1] .uad_list )] - .width(70), + .width(50), row![text( self.phone_packages[selection.0][selection.1] .name .clone() - ),], + ),] + .width(540), horizontal_space(), row![match self.phone_packages[selection.0] [selection.1] @@ -709,7 +748,7 @@ impl List { PackageState::All => text("Impossible") .style(style::Text::Danger), },] - .width(80), + .width(70), ] .width(Length::Fill) .spacing(20), @@ -765,7 +804,7 @@ impl List { .align_items(Alignment::Center) }, ) - .width(800) + .width(900) .height(Length::Shrink) .max_height(700) .style(style::Container::Background) @@ -804,7 +843,7 @@ impl List { let (uad_lists, _) = load_debloat_lists(remote); match uad_lists { Ok(list) => { - env::set_var("ANDROID_SERIAL", phone.adb_id.clone()); + env::set_var(ANDROID_SERIAL, phone.adb_id.clone()); if phone.adb_id.is_empty() { error!("AppsView ready but no phone found"); } @@ -818,8 +857,40 @@ impl List { } } +fn error_view<'a>( + error: &'a str, + content: Column<'a, Message, Theme, Renderer>, +) -> Modal<'a, Message, Theme, Renderer> { + let title_ctn = container( + row![text("Failed to perform ADB operation").size(24)].align_items(Alignment::Center), + ) + .width(Length::Fill) + .style(style::Container::Frame) + .padding([10, 0, 10, 0]) + .center_y() + .center_x(); + + let modal_btn_row = row![button( + text("Close") + .width(Length::Fill) + .horizontal_alignment(alignment::Horizontal::Center), + ) + .width(Length::Fill) + .on_press(Message::ModalHide)] + .padding([10, 0, 0, 0]); + + let text_box = scrollable(text(error).width(Length::Fill)).height(400); + + let ctn = container(column![title_ctn, text_box, modal_btn_row]) + .height(Length::Shrink) + .max_height(700) + .padding(10) + .style(style::Container::Frame); + + Modal::new(content, ctn).on_blur(Message::ModalHide) +} + fn waiting_view<'a>( - _settings: &Settings, displayed_text: &str, btn: Option>, text_style: style::Text, diff --git a/src/gui/views/settings.rs b/src/gui/views/settings.rs index 29b57a76..8586c150 100644 --- a/src/gui/views/settings.rs +++ b/src/gui/views/settings.rs @@ -1,26 +1,31 @@ +use crate::core::helpers::button_primary; use crate::core::sync::AdbError; use crate::core::config::{BackupSettings, Config, DeviceSettings, GeneralSettings}; use crate::core::save::{ - backup_phone, list_available_backup_user, list_available_backups, restore_backup, BACKUP_DIR, + backup_phone, list_available_backup_user, list_available_backups, restore_backup, }; use crate::core::sync::{get_android_sdk, perform_adb_commands, CommandType, Phone}; use crate::core::theme::Theme; -use crate::core::utils::{open_url, string_to_theme, DisplayablePath}; +use crate::core::utils::{open_folder, open_url, string_to_theme, DisplayablePath}; use crate::gui::style; use crate::gui::views::list::PackageInfo; +use crate::gui::widgets::navigation_menu::ICONS; use crate::gui::widgets::package_row::PackageRow; use iced::widget::{ - button, checkbox, column, container, pick_list, radio, row, scrollable, text, Space, + button, checkbox, column, container, pick_list, radio, row, scrollable, text, Space, Text, }; use iced::{alignment, Alignment, Command, Element, Length, Renderer}; use std::path::PathBuf; +use crate::core::utils::Error; + #[derive(Debug, Clone)] pub struct Settings { pub general: GeneralSettings, pub device: DeviceSettings, + is_loading: bool, } impl Default for Settings { @@ -28,6 +33,7 @@ impl Default for Settings { Self { general: Config::load_configuration_file().general, device: DeviceSettings::default(), + is_loading: false, } } } @@ -45,6 +51,8 @@ pub enum Message { RestoreDevice, RestoringDevice(Result), DeviceBackedUp(Result<(), String>), + ChooseBackUpFolder, + FolderChosen(Result), } impl Settings { @@ -87,7 +95,8 @@ impl Settings { Command::none() } Message::LoadDeviceSettings => { - let backups = list_available_backups(&BACKUP_DIR.join(&phone.adb_id)); + let backups = + list_available_backups(&self.general.backup_folder.join(&phone.adb_id)); let backup = BackupSettings { backups: backups.clone(), selected: backups.first().cloned(), @@ -101,7 +110,7 @@ impl Settings { .find(|d| d.device_id == phone.adb_id) { Some(device) => { - self.device = device.clone(); + self.device.clone_from(device); self.device.backup = backup; } None => { @@ -131,7 +140,7 @@ impl Settings { Message::DeviceBackedUp(_) => { info!("[BACKUP] Backup successfully created"); self.device.backup.backups = - list_available_backups(&BACKUP_DIR.join(phone.adb_id.clone())); + list_available_backups(&self.general.backup_folder.join(phone.adb_id.clone())); self.device.backup.selected = self.device.backup.backups.first().cloned(); Command::none() } @@ -178,6 +187,32 @@ impl Settings { }, // Trigger an action in mod.rs (Message::SettingsAction(msg)) Message::RestoringDevice(_) => Command::none(), + Message::FolderChosen(result) => { + self.is_loading = false; + + if let Ok(path) = result { + self.general.backup_folder = path; + Config::save_changes(self, &phone.adb_id); + #[allow(unused_must_use)] + { + self.update( + phone, + packages, + nb_running_async_adb_commands, + Message::LoadDeviceSettings, + ); + } + } + Command::none() + } + Message::ChooseBackUpFolder => { + if self.is_loading { + Command::none() + } else { + self.is_loading = true; + Command::perform(open_folder(), Message::FolderChosen) + } + } } } @@ -212,11 +247,37 @@ impl Settings { text("Most unsafe packages are known to bootloop the device if removed.") .style(style::Text::Commentary); - let general_ctn = container(column![expert_mode_checkbox, expert_mode_descr].spacing(10)) - .padding(10) - .width(Length::Fill) - .height(Length::Shrink) - .style(style::Container::Frame); + let choose_backup_descr = text("Note: If you have previous backups, you will need to transfer them manually to newly changed backup folder to be able to use Restore functionality") + .style(style::Text::Commentary); + + let choose_backup_btn = button(Text::new("\u{E930}").font(ICONS)) + .padding([5, 10]) + .on_press(Message::ChooseBackUpFolder) + .style(style::Button::Primary); + + let choose_backup_row = row![ + choose_backup_btn, + "Choose backup folder", + Space::new(Length::Fill, Length::Shrink), + "Current folder: ", + Text::new(self.general.backup_folder.to_string_lossy()) + ] + .spacing(10) + .align_items(Alignment::Center); + + let general_ctn = container( + column![ + expert_mode_checkbox, + expert_mode_descr, + choose_backup_row, + choose_backup_descr, + ] + .spacing(10), + ) + .padding(10) + .width(Length::Fill) + .height(Length::Shrink) + .style(style::Container::Frame); let warning_ctn = container( row![ @@ -317,11 +378,10 @@ impl Settings { ) .padding(6); - let backup_btn = button(text("Backup").horizontal_alignment(alignment::Horizontal::Center)) - .padding([5, 10]) - .on_press(Message::BackupDevice) - .style(style::Button::Primary) - .width(77); + let backup_btn = + button_primary(text("Backup").horizontal_alignment(alignment::Horizontal::Center)) + .on_press(Message::BackupDevice) + .width(77); let restore_btn = |enabled| { if enabled { @@ -341,14 +401,11 @@ impl Settings { }; let locate_backup_btn = if self.device.backup.backups.is_empty() { - button("Open backup directory") - .padding([5, 10]) - .style(style::Button::Primary) + button_primary("Open backup directory") } else { - button("Open backup directory") - .on_press(Message::UrlPressed(BACKUP_DIR.join(phone.adb_id.clone()))) - .padding([5, 10]) - .style(style::Button::Primary) + button_primary("Open backup directory").on_press(Message::UrlPressed( + self.general.backup_folder.join(phone.adb_id.clone()), + )) }; let backup_row = row![ @@ -409,6 +466,7 @@ impl Settings { text("Current device").size(26), warning_ctn, device_specific_ctn, + text("Backup / Restore").size(26), backup_restore_ctn, ] .width(Length::Fill) diff --git a/src/gui/widgets/navigation_menu.rs b/src/gui/widgets/navigation_menu.rs index c9210fae..a7c5b97c 100644 --- a/src/gui/widgets/navigation_menu.rs +++ b/src/gui/widgets/navigation_menu.rs @@ -1,3 +1,4 @@ +use crate::core::helpers::button_primary; pub use crate::core::sync::Phone; use crate::core::theme::Theme; use crate::core::update::{SelfUpdateState, SelfUpdateStatus}; @@ -19,24 +20,19 @@ pub fn nav_menu<'a>( apps_view: &AppsView, self_update_state: &SelfUpdateState, ) -> Element<'a, Message, Theme, Renderer> { - let apps_refresh_btn = button( + let apps_refresh_btn = button_primary( Text::new("\u{E900}") .font(ICONS) .width(22) .horizontal_alignment(alignment::Horizontal::Center), ) - .on_press(Message::RefreshButtonPressed) - .padding([5, 10]) - .style(style::Button::Refresh); + .on_press(Message::RefreshButtonPressed); let apps_refresh_tooltip = tooltip(apps_refresh_btn, "Refresh apps", tooltip::Position::Bottom) .style(style::Container::Tooltip) .gap(4); - let reboot_btn = button("Reboot") - .on_press(Message::RebootButtonPressed) - .padding([5, 10]) - .style(style::Button::Refresh); + let reboot_btn = button_primary("Reboot").on_press(Message::RebootButtonPressed); #[allow(clippy::option_if_let_else)] let uad_version_text = if let Some(r) = &self_update_state.latest_release { @@ -63,25 +59,17 @@ pub fn nav_menu<'a>( button("").height(0).width(0).style(style::Button::Hidden) }; - let apps_btn = button("Apps") - .on_press(Message::AppsPress) - .padding([5, 10]) - .style(style::Button::Primary); + let apps_btn = button_primary("Apps").on_press(Message::AppsPress); - let about_btn = button("About") - .on_press(Message::AboutPressed) - .padding([5, 10]) - .style(style::Button::Primary); + let about_btn = button_primary("About").on_press(Message::AboutPressed); - let settings_btn = button( + let settings_btn = button_primary( Text::new("\u{E994}") .font(ICONS) .width(22) .horizontal_alignment(alignment::Horizontal::Center), ) - .on_press(Message::SettingsPressed) - .padding([5, 10]) - .style(style::Button::Primary); + .on_press(Message::SettingsPressed); let device_list_text = match apps_view.loading_state { ListLoadingState::FindingPhones => text("Finding connected devices..."),