mirror of
https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation.git
synced 2026-08-24 06:24:19 +02:00
Compare commits
3 commits
main
...
feature/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16a0217b7f |
||
|
|
08578514db |
||
|
|
34df8d2296 |
20 changed files with 2603 additions and 359 deletions
2
.github/workflows/build_artifacts.yml
vendored
2
.github/workflows/build_artifacts.yml
vendored
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
restore-keys: ${{ runner.OS }}-release-
|
restore-keys: ${{ runner.OS }}-release-
|
||||||
if: matrix.os == 'ubuntu-22.04'
|
if: matrix.os == 'ubuntu-22.04'
|
||||||
- name: Building
|
- name: Building
|
||||||
run: cargo build --release -p uad-gui --no-default-features --features wgpu,${{ matrix.update_feature }},img
|
run: cargo build --release -p uad-gui --no-default-features --features wgpu,${{ matrix.update_feature }},img,builtin-adb
|
||||||
- name: Renaming binaries [Windows]
|
- name: Renaming binaries [Windows]
|
||||||
if: matrix.os == 'windows-2022'
|
if: matrix.os == 'windows-2022'
|
||||||
run: mv target/release/uad-ng.exe uad-ng-${{ matrix.build_target }}.exe
|
run: mv target/release/uad-ng.exe uad-ng-${{ matrix.build_target }}.exe
|
||||||
|
|
|
||||||
569
Cargo.lock
generated
569
Cargo.lock
generated
|
|
@ -18,6 +18,31 @@ version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
|
checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adb_client"
|
||||||
|
version = "3.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773b25a440e72829bbb1b96435ee0e65ef0f14a3da545590930ca881a68e59d7"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"byteorder",
|
||||||
|
"chrono",
|
||||||
|
"log",
|
||||||
|
"num-bigint-dig",
|
||||||
|
"num-traits",
|
||||||
|
"num_enum",
|
||||||
|
"quick-protobuf",
|
||||||
|
"rand 0.10.1",
|
||||||
|
"rcgen",
|
||||||
|
"regex",
|
||||||
|
"rsa",
|
||||||
|
"rusb",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"sha1",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler2"
|
name = "adler2"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
|
|
@ -37,6 +62,15 @@ dependencies = [
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aligned"
|
name = "aligned"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
|
@ -227,6 +261,45 @@ dependencies = [
|
||||||
"zbus",
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "asn1-rs"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60"
|
||||||
|
dependencies = [
|
||||||
|
"asn1-rs-derive",
|
||||||
|
"asn1-rs-impl",
|
||||||
|
"displaydoc",
|
||||||
|
"nom 7.1.3",
|
||||||
|
"num-traits",
|
||||||
|
"rusticata-macros",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "asn1-rs-derive"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"synstructure",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "asn1-rs-impl"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-broadcast"
|
name = "async-broadcast"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
|
|
@ -473,7 +546,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"log",
|
"log",
|
||||||
"nom",
|
"nom 8.0.0",
|
||||||
"num-rational",
|
"num-rational",
|
||||||
"v_frame",
|
"v_frame",
|
||||||
]
|
]
|
||||||
|
|
@ -493,13 +566,19 @@ version = "0.22.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64ct"
|
||||||
|
version = "1.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-vec",
|
"bit-vec 0.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -508,6 +587,15 @@ version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-vec"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit_field"
|
name = "bit_field"
|
||||||
version = "0.10.3"
|
version = "0.10.3"
|
||||||
|
|
@ -541,6 +629,15 @@ version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block2"
|
name = "block2"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
@ -604,6 +701,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder-lite"
|
name = "byteorder-lite"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -704,10 +807,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chacha20"
|
||||||
version = "0.4.43"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
|
checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures 0.3.0",
|
||||||
|
"rand_core 0.10.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
|
@ -854,6 +968,12 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-oid"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cookie"
|
name = "cookie"
|
||||||
version = "0.18.1"
|
version = "0.18.1"
|
||||||
|
|
@ -986,6 +1106,24 @@ dependencies = [
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
@ -1039,6 +1177,16 @@ dependencies = [
|
||||||
"wgpu",
|
"wgpu",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "csv"
|
name = "csv"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
@ -1086,6 +1234,37 @@ dependencies = [
|
||||||
"winreg 0.52.0",
|
"winreg 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "data-encoding"
|
||||||
|
version = "2.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "der"
|
||||||
|
version = "0.7.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
||||||
|
dependencies = [
|
||||||
|
"const-oid",
|
||||||
|
"pem-rfc7468",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "der-parser"
|
||||||
|
version = "10.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6"
|
||||||
|
dependencies = [
|
||||||
|
"asn1-rs",
|
||||||
|
"displaydoc",
|
||||||
|
"nom 7.1.3",
|
||||||
|
"num-bigint",
|
||||||
|
"num-traits",
|
||||||
|
"rusticata-macros",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.5.6"
|
version = "0.5.6"
|
||||||
|
|
@ -1095,6 +1274,17 @@ dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"const-oid",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
|
|
@ -1597,6 +1787,16 @@ dependencies = [
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gethostname"
|
name = "gethostname"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -1639,6 +1839,7 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi",
|
"r-efi",
|
||||||
|
"rand_core 0.10.1",
|
||||||
"wasip2",
|
"wasip2",
|
||||||
"wasip3",
|
"wasip3",
|
||||||
]
|
]
|
||||||
|
|
@ -2177,9 +2378,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.9"
|
version = "0.25.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a"
|
checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder-lite",
|
"byteorder-lite",
|
||||||
|
|
@ -2195,8 +2396,8 @@ dependencies = [
|
||||||
"rayon",
|
"rayon",
|
||||||
"rgb",
|
"rgb",
|
||||||
"tiff",
|
"tiff",
|
||||||
"zune-core 0.5.1",
|
"zune-core",
|
||||||
"zune-jpeg 0.5.12",
|
"zune-jpeg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2351,6 +2552,9 @@ name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
dependencies = [
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "leb128fmt"
|
name = "leb128fmt"
|
||||||
|
|
@ -2407,6 +2611,18 @@ dependencies = [
|
||||||
"redox_syscall 0.7.1",
|
"redox_syscall 0.7.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libusb1-sys"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da050ade7ac4ff1ba5379af847a10a10a8e284181e060105bf8d86960ce9ce0f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lilt"
|
name = "lilt"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
|
@ -2457,9 +2673,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.29"
|
version = "0.4.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"value-bag",
|
"value-bag",
|
||||||
]
|
]
|
||||||
|
|
@ -2537,6 +2753,12 @@ dependencies = [
|
||||||
"paste",
|
"paste",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.9"
|
version = "0.8.9"
|
||||||
|
|
@ -2560,9 +2782,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moxcms"
|
name = "moxcms"
|
||||||
version = "0.7.11"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
|
checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"pxfm",
|
"pxfm",
|
||||||
|
|
@ -2682,6 +2904,16 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "8.0.0"
|
version = "8.0.0"
|
||||||
|
|
@ -2707,6 +2939,23 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint-dig"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"libm",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-traits",
|
||||||
|
"rand 0.8.6",
|
||||||
|
"serde",
|
||||||
|
"smallvec",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-conv"
|
name = "num-conv"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
@ -2733,6 +2982,17 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-rational"
|
name = "num-rational"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
|
@ -2766,9 +3026,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum"
|
name = "num_enum"
|
||||||
version = "0.7.5"
|
version = "0.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c"
|
checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num_enum_derive",
|
"num_enum_derive",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
|
|
@ -2776,9 +3036,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum_derive"
|
name = "num_enum_derive"
|
||||||
version = "0.7.5"
|
version = "0.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7"
|
checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|
@ -3145,6 +3405,15 @@ dependencies = [
|
||||||
"objc2-foundation 0.2.2",
|
"objc2-foundation 0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oid-registry"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7"
|
||||||
|
dependencies = [
|
||||||
|
"asn1-rs",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.3"
|
||||||
|
|
@ -3242,6 +3511,25 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
|
checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pem"
|
||||||
|
version = "3.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pem-rfc7468"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
|
|
@ -3291,6 +3579,27 @@ dependencies = [
|
||||||
"futures-io",
|
"futures-io",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkcs1"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"pkcs8",
|
||||||
|
"spki",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkcs8"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"spki",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
|
|
@ -3446,6 +3755,15 @@ version = "2.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-protobuf"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.38.4"
|
version = "0.38.4"
|
||||||
|
|
@ -3501,6 +3819,17 @@ dependencies = [
|
||||||
"rand_core 0.9.5",
|
"rand_core 0.9.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
|
||||||
|
dependencies = [
|
||||||
|
"chacha20",
|
||||||
|
"getrandom 0.4.1",
|
||||||
|
"rand_core 0.10.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_chacha"
|
name = "rand_chacha"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|
@ -3539,6 +3868,12 @@ dependencies = [
|
||||||
"getrandom 0.3.4",
|
"getrandom 0.3.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "range-alloc"
|
name = "range-alloc"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
|
|
@ -3588,9 +3923,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ravif"
|
name = "ravif"
|
||||||
version = "0.12.0"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285"
|
checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"avif-serialize",
|
"avif-serialize",
|
||||||
"imgref",
|
"imgref",
|
||||||
|
|
@ -3627,6 +3962,20 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rcgen"
|
||||||
|
version = "0.14.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57f6d249aad744e274e682777a50283a225a32705394ee6d5fcc01efa25e4055"
|
||||||
|
dependencies = [
|
||||||
|
"pem",
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"time",
|
||||||
|
"x509-parser",
|
||||||
|
"yasna",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "read-fonts"
|
name = "read-fonts"
|
||||||
version = "0.35.0"
|
version = "0.35.0"
|
||||||
|
|
@ -3676,6 +4025,35 @@ dependencies = [
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "renderdoc-sys"
|
name = "renderdoc-sys"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -3744,6 +4122,36 @@ version = "0.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
|
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rsa"
|
||||||
|
version = "0.9.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d"
|
||||||
|
dependencies = [
|
||||||
|
"const-oid",
|
||||||
|
"digest",
|
||||||
|
"num-bigint-dig",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"pkcs1",
|
||||||
|
"pkcs8",
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
"signature",
|
||||||
|
"spki",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusb"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab9f9ff05b63a786553a4c02943b74b34a988448671001e9a27e2f0565cc05a4"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"libusb1-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -3765,6 +4173,15 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusticata-macros"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
|
||||||
|
dependencies = [
|
||||||
|
"nom 7.1.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.44"
|
version = "0.38.44"
|
||||||
|
|
@ -3793,9 +4210,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.36"
|
version = "0.23.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b"
|
checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -3808,9 +4225,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.14.0"
|
version = "1.14.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
|
checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
@ -3969,6 +4386,17 @@ dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha1"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures 0.2.17",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
|
@ -3985,6 +4413,16 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signature"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simd-adler32"
|
name = "simd-adler32"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
|
@ -4144,6 +4582,12 @@ dependencies = [
|
||||||
"x11rb",
|
"x11rb",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spirv"
|
name = "spirv"
|
||||||
version = "0.3.0+sdk-1.3.268.0"
|
version = "0.3.0+sdk-1.3.268.0"
|
||||||
|
|
@ -4153,6 +4597,16 @@ dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spki"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"der",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
|
|
@ -4306,16 +4760,16 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiff"
|
name = "tiff"
|
||||||
version = "0.10.3"
|
version = "0.11.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f"
|
checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fax",
|
"fax",
|
||||||
"flate2",
|
"flate2",
|
||||||
"half",
|
"half",
|
||||||
"quick-error",
|
"quick-error",
|
||||||
"weezl",
|
"weezl",
|
||||||
"zune-jpeg 0.4.21",
|
"zune-jpeg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -4532,6 +4986,12 @@ dependencies = [
|
||||||
"core_maths",
|
"core_maths",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uad-cli"
|
name = "uad-cli"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
|
@ -4556,15 +5016,19 @@ dependencies = [
|
||||||
name = "uad-core"
|
name = "uad-core"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"adb_client",
|
||||||
"chrono",
|
"chrono",
|
||||||
"csv",
|
"csv",
|
||||||
"dirs",
|
"dirs",
|
||||||
"flate2",
|
"flate2",
|
||||||
"log",
|
"log",
|
||||||
"retry",
|
"retry",
|
||||||
|
"rsa",
|
||||||
|
"rusb",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tar",
|
"tar",
|
||||||
|
"tempfile",
|
||||||
"toml",
|
"toml",
|
||||||
"ureq",
|
"ureq",
|
||||||
"win32console",
|
"win32console",
|
||||||
|
|
@ -4745,6 +5209,12 @@ version = "1.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0"
|
checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
|
|
@ -5119,7 +5589,7 @@ checksum = "27a75de515543b1897b26119f93731b385a19aea165a1ec5f0e3acecc229cae7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-set",
|
"bit-set",
|
||||||
"bit-vec",
|
"bit-vec 0.8.0",
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg_aliases 0.2.1",
|
"cfg_aliases 0.2.1",
|
||||||
|
|
@ -5891,6 +6361,24 @@ version = "0.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
|
checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x509-parser"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202"
|
||||||
|
dependencies = [
|
||||||
|
"asn1-rs",
|
||||||
|
"data-encoding",
|
||||||
|
"der-parser",
|
||||||
|
"lazy_static",
|
||||||
|
"nom 7.1.3",
|
||||||
|
"oid-registry",
|
||||||
|
"ring",
|
||||||
|
"rusticata-macros",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xattr"
|
name = "xattr"
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
|
|
@ -5938,6 +6426,16 @@ version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448"
|
checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yasna"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282"
|
||||||
|
dependencies = [
|
||||||
|
"bit-vec 0.9.1",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yazi"
|
name = "yazi"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
|
@ -6120,12 +6618,6 @@ version = "1.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zune-core"
|
|
||||||
version = "0.4.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-core"
|
name = "zune-core"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
@ -6141,22 +6633,13 @@ dependencies = [
|
||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zune-jpeg"
|
|
||||||
version = "0.4.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713"
|
|
||||||
dependencies = [
|
|
||||||
"zune-core 0.4.12",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-jpeg"
|
name = "zune-jpeg"
|
||||||
version = "0.5.12"
|
version = "0.5.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "410e9ecef634c709e3831c2cfdb8d9c32164fae1c67496d5b68fff728eec37fe"
|
checksum = "410e9ecef634c709e3831c2cfdb8d9c32164fae1c67496d5b68fff728eec37fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zune-core 0.5.1",
|
"zune-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ edition = "2024"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
# Core dependencies
|
# Core dependencies
|
||||||
|
adb_client = { version = "3.2.3", default-features = false }
|
||||||
|
rusb = { version = "0.9.4", features = ["vendored"] }
|
||||||
|
rsa = { version = "0.9.10", features = ["pem"] }
|
||||||
|
tempfile = "3.25.0"
|
||||||
serde = { version = "^1.0", features = ["derive"] }
|
serde = { version = "^1.0", features = ["derive"] }
|
||||||
serde_json = "^1.0"
|
serde_json = "^1.0"
|
||||||
log = "^0.4"
|
log = "^0.4"
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,12 @@ edition.workspace = true
|
||||||
name = "uad"
|
name = "uad"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["builtin-adb"]
|
||||||
|
builtin-adb = ["uad-core/builtin-adb"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
uad-core = { path = "../uad-core" }
|
uad-core = { path = "../uad-core", default-features = false }
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
clap_complete = "4.4"
|
clap_complete = "4.4"
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::collections::{HashMap, HashSet};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use uad_core::adb::{ACommand, PmListPacksFlag};
|
use uad_core::adb::{ACommand, PmListPacksFlag};
|
||||||
use uad_core::sync::{
|
use uad_core::sync::{
|
||||||
CorePackage, Phone, User, apply_pkg_state_commands, get_devices_list, get_package_state,
|
CorePackage, Phone, User, apply_pkg_state_commands, discover_devices, get_package_state,
|
||||||
run_adb_shell_action,
|
run_adb_shell_action,
|
||||||
};
|
};
|
||||||
use uad_core::uad_lists::{Package, PackageState, Removal, UadList, load_debloat_lists};
|
use uad_core::uad_lists::{Package, PackageState, Removal, UadList, load_debloat_lists};
|
||||||
|
|
@ -17,10 +17,14 @@ use crate::{Cli, print_or_exit, println_or_exit};
|
||||||
/// List all connected Android devices
|
/// List all connected Android devices
|
||||||
pub fn list_devices() -> Result<(), Box<dyn std::error::Error>> {
|
pub fn list_devices() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
println_or_exit!("Scanning for connected devices...");
|
println_or_exit!("Scanning for connected devices...");
|
||||||
let devices = get_devices_list();
|
let discovery = discover_devices();
|
||||||
|
let devices = discovery.devices;
|
||||||
|
|
||||||
if devices.is_empty() {
|
if devices.is_empty() {
|
||||||
return Err(NO_DEVICES_FOUND.into());
|
return Err(discovery
|
||||||
|
.issue
|
||||||
|
.map_or_else(|| NO_DEVICES_FOUND.to_string(), |issue| issue.to_string())
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
println_or_exit!("\nFound {} device(s):\n", devices.len());
|
println_or_exit!("\nFound {} device(s):\n", devices.len());
|
||||||
|
|
@ -104,6 +108,15 @@ pub struct DisplayConfig {
|
||||||
pub show_removal: bool,
|
pub show_removal: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve_pm_flag(state_filter: Option<StateFilter>) -> Option<PmListPacksFlag> {
|
||||||
|
match state_filter {
|
||||||
|
Some(StateFilter::Enabled | StateFilter::Disabled) => {
|
||||||
|
state_filter.and_then(StateFilter::to_pm_flag)
|
||||||
|
}
|
||||||
|
_ => Some(PmListPacksFlag::IncludeUninstalled),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// List packages on a device with filtering
|
/// List packages on a device with filtering
|
||||||
pub fn list_packages(
|
pub fn list_packages(
|
||||||
device: Option<String>,
|
device: Option<String>,
|
||||||
|
|
@ -129,7 +142,7 @@ pub fn list_packages(
|
||||||
search,
|
search,
|
||||||
};
|
};
|
||||||
|
|
||||||
let pm_flag = state_filter.and_then(StateFilter::to_pm_flag);
|
let pm_flag = resolve_pm_flag(state_filter);
|
||||||
let system_packages = ACommand::new()
|
let system_packages = ACommand::new()
|
||||||
.shell(&target_device.adb_id)
|
.shell(&target_device.adb_id)
|
||||||
.pm()
|
.pm()
|
||||||
|
|
@ -468,3 +481,37 @@ pub fn generate_completions(shell: Shell) {
|
||||||
let name = cmd.get_name().to_string();
|
let name = cmd.get_name().to_string();
|
||||||
generate(shell, &mut cmd, name, &mut std::io::stdout());
|
generate(shell, &mut cmd, name, &mut std::io::stdout());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Show ADB backend and version information
|
||||||
|
pub fn show_adb_info() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let backend = uad_core::adb::AdbBackend::current();
|
||||||
|
println!("ADB Backend: {}\n", backend);
|
||||||
|
|
||||||
|
match ACommand::new().version() {
|
||||||
|
Ok(version) => {
|
||||||
|
println!("{version}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to get ADB version: {e}");
|
||||||
|
Err(e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_and_uninstalled_lists_include_removed_packages() {
|
||||||
|
assert_eq!(
|
||||||
|
resolve_pm_flag(None),
|
||||||
|
Some(PmListPacksFlag::IncludeUninstalled)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
resolve_pm_flag(Some(StateFilter::Uninstalled)),
|
||||||
|
Some(PmListPacksFlag::IncludeUninstalled)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
use uad_core::sync::{Phone, User, get_devices_list};
|
use uad_core::sync::{Phone, User, discover_devices};
|
||||||
|
|
||||||
pub const NO_DEVICES_FOUND: &str =
|
pub const NO_DEVICES_FOUND: &str =
|
||||||
"No devices found. Make sure ADB is installed and devices are connected.";
|
"No devices found. Make sure ADB is installed and devices are connected.";
|
||||||
|
|
||||||
/// Get target device, either by serial or first available
|
/// Get target device, either by serial or first available
|
||||||
pub fn get_target_device(device: Option<String>) -> Result<Phone, Box<dyn std::error::Error>> {
|
pub fn get_target_device(device: Option<String>) -> Result<Phone, Box<dyn std::error::Error>> {
|
||||||
let devices = get_devices_list();
|
let discovery = discover_devices();
|
||||||
|
let devices = discovery.devices;
|
||||||
|
|
||||||
if devices.is_empty() {
|
if devices.is_empty() {
|
||||||
return Err(NO_DEVICES_FOUND.into());
|
return Err(discovery
|
||||||
|
.issue
|
||||||
|
.map_or_else(|| NO_DEVICES_FOUND.to_string(), |issue| issue.to_string())
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_device = if let Some(device_id) = device {
|
let target_device = if let Some(device_id) = device {
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,15 @@
|
||||||
clippy::uninlined_format_args,
|
clippy::uninlined_format_args,
|
||||||
clippy::map_unwrap_or,
|
clippy::map_unwrap_or,
|
||||||
clippy::unnecessary_wraps,
|
clippy::unnecessary_wraps,
|
||||||
|
clippy::exit,
|
||||||
reason = "Suppress non-critical pedantic/style lints to keep build green"
|
reason = "Suppress non-critical pedantic/style lints to keep build green"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
use clap_complete::Shell;
|
use clap_complete::Shell;
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
|
use uad_core::adb::{ACommand, AdbBackend, AdbDeviceStatus};
|
||||||
|
use uad_core::sync::{DeviceDiscoveryIssue, classify_device_issue};
|
||||||
use uad_core::uad_lists::PackageState;
|
use uad_core::uad_lists::PackageState;
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
|
|
@ -20,12 +23,46 @@ mod repl;
|
||||||
|
|
||||||
use filters::{ListFilter, RemovalFilter, StateFilter};
|
use filters::{ListFilter, RemovalFilter, StateFilter};
|
||||||
|
|
||||||
|
/// CLI-compatible ADB backend selection
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
|
||||||
|
pub enum AdbBackendArg {
|
||||||
|
/// Embedded ADB over USB
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
Builtin,
|
||||||
|
/// Use system-installed adb binary
|
||||||
|
System,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AdbBackendArg> for AdbBackend {
|
||||||
|
fn from(arg: AdbBackendArg) -> Self {
|
||||||
|
match arg {
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
AdbBackendArg::Builtin => AdbBackend::Builtin,
|
||||||
|
AdbBackendArg::System => AdbBackend::System,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "uad")]
|
#[command(name = "uad")]
|
||||||
#[command(about = "Universal Android Debloater - Command Line Interface", long_about = None)]
|
#[command(about = "Universal Android Debloater - Command Line Interface", long_about = None)]
|
||||||
#[command(version)]
|
#[command(version)]
|
||||||
#[command(propagate_version = true)]
|
#[command(propagate_version = true)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
|
/// ADB backend to use
|
||||||
|
#[arg(
|
||||||
|
short = 'B',
|
||||||
|
long = "backend",
|
||||||
|
value_enum,
|
||||||
|
global = true,
|
||||||
|
default_value = "system"
|
||||||
|
)]
|
||||||
|
backend: AdbBackendArg,
|
||||||
|
|
||||||
|
/// Stop the system ADB server before using the Builtin backend
|
||||||
|
#[arg(long, global = true)]
|
||||||
|
kill_adb_server: bool,
|
||||||
|
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Commands,
|
command: Commands,
|
||||||
}
|
}
|
||||||
|
|
@ -136,6 +173,9 @@ enum Commands {
|
||||||
/// Update UAD package lists from remote repository
|
/// Update UAD package lists from remote repository
|
||||||
Update,
|
Update,
|
||||||
|
|
||||||
|
/// Show ADB backend and version information
|
||||||
|
Adb,
|
||||||
|
|
||||||
/// Generate shell completion script
|
/// Generate shell completion script
|
||||||
Completions {
|
Completions {
|
||||||
/// Shell to generate completions for
|
/// Shell to generate completions for
|
||||||
|
|
@ -169,6 +209,7 @@ async fn main() -> ExitCode {
|
||||||
|
|
||||||
fn run() -> Result<(), Box<dyn std::error::Error>> {
|
fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
configure_adb(&cli)?;
|
||||||
|
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Commands::Devices => {
|
Commands::Devices => {
|
||||||
|
|
@ -239,6 +280,9 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
Commands::Update => {
|
Commands::Update => {
|
||||||
commands::update_lists()?;
|
commands::update_lists()?;
|
||||||
}
|
}
|
||||||
|
Commands::Adb => {
|
||||||
|
commands::show_adb_info()?;
|
||||||
|
}
|
||||||
Commands::Completions { shell } => {
|
Commands::Completions { shell } => {
|
||||||
commands::generate_completions(shell);
|
commands::generate_completions(shell);
|
||||||
}
|
}
|
||||||
|
|
@ -249,3 +293,123 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn configure_adb(cli: &Cli) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let backend: AdbBackend = cli.backend.into();
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
let using_builtin = backend == AdbBackend::Builtin;
|
||||||
|
#[cfg(not(feature = "builtin-adb"))]
|
||||||
|
let using_builtin = false;
|
||||||
|
|
||||||
|
if cli.kill_adb_server && !using_builtin {
|
||||||
|
return Err("--kill-adb-server requires --backend builtin".into());
|
||||||
|
}
|
||||||
|
if cli.kill_adb_server {
|
||||||
|
ACommand::kill_system_server()
|
||||||
|
.map_err(|err| format!("Failed to stop the system ADB server: {err}"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
backend.set_current();
|
||||||
|
|
||||||
|
if using_builtin && !cli.kill_adb_server && command_uses_device(&cli.command) {
|
||||||
|
let devices = ACommand::new().devices()?;
|
||||||
|
match builtin_preflight_issue(&devices) {
|
||||||
|
Some(DeviceDiscoveryIssue::Busy) => {
|
||||||
|
return Err(
|
||||||
|
"The system ADB server is using the USB device. Stop it with `adb kill-server` \
|
||||||
|
or rerun with `--kill-adb-server`."
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Some(issue @ DeviceDiscoveryIssue::NoPermissions) => {
|
||||||
|
return Err(issue.to_string().into());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn builtin_preflight_issue(devices: &[(String, AdbDeviceStatus)]) -> Option<DeviceDiscoveryIssue> {
|
||||||
|
if devices
|
||||||
|
.iter()
|
||||||
|
.any(|(_, status)| status == &AdbDeviceStatus::Device)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
classify_device_issue(devices).filter(|issue| {
|
||||||
|
matches!(
|
||||||
|
issue,
|
||||||
|
DeviceDiscoveryIssue::Busy | DeviceDiscoveryIssue::NoPermissions
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command_uses_device(command: &Commands) -> bool {
|
||||||
|
match command {
|
||||||
|
Commands::Devices
|
||||||
|
| Commands::List { .. }
|
||||||
|
| Commands::Uninstall { .. }
|
||||||
|
| Commands::Enable { .. }
|
||||||
|
| Commands::Disable { .. }
|
||||||
|
| Commands::Repl { .. } => true,
|
||||||
|
Commands::Info { device, .. } => device.is_some(),
|
||||||
|
Commands::Update | Commands::Adb | Commands::Completions { .. } => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
#[test]
|
||||||
|
fn builtin_server_shutdown_is_explicitly_opted_in() {
|
||||||
|
let cli = Cli::try_parse_from([
|
||||||
|
"uad",
|
||||||
|
"--backend",
|
||||||
|
"builtin",
|
||||||
|
"--kill-adb-server",
|
||||||
|
"devices",
|
||||||
|
])
|
||||||
|
.expect("valid Builtin CLI arguments");
|
||||||
|
|
||||||
|
assert_eq!(cli.backend, AdbBackendArg::Builtin);
|
||||||
|
assert!(cli.kill_adb_server);
|
||||||
|
assert!(command_uses_device(&cli.command));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn non_device_commands_skip_usb_preflight() {
|
||||||
|
assert!(!command_uses_device(&Commands::Update));
|
||||||
|
assert!(!command_uses_device(&Commands::Adb));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builtin_preflight_allows_any_ready_device() {
|
||||||
|
let devices = vec![
|
||||||
|
("ready".to_string(), AdbDeviceStatus::Device),
|
||||||
|
("busy".to_string(), AdbDeviceStatus::Busy),
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(builtin_preflight_issue(&devices), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builtin_preflight_reports_blocking_issues_without_a_ready_device() {
|
||||||
|
assert_eq!(
|
||||||
|
builtin_preflight_issue(&[("busy".to_string(), AdbDeviceStatus::Busy)]),
|
||||||
|
Some(DeviceDiscoveryIssue::Busy)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
builtin_preflight_issue(&[("denied".to_string(), AdbDeviceStatus::NoPermissions,)]),
|
||||||
|
Some(DeviceDiscoveryIssue::NoPermissions)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
builtin_preflight_issue(&[("pending".to_string(), AdbDeviceStatus::Unauthorized,)]),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,22 @@
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! println_or_exit {
|
macro_rules! println_or_exit {
|
||||||
() => {
|
() => {
|
||||||
let _ = writeln!(std::io::stdout());
|
if writeln!(std::io::stdout()).is_err() {
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
($($arg:tt)*) => {
|
($($arg:tt)*) => {
|
||||||
let _ = writeln!(std::io::stdout(), $($arg)*);
|
if writeln!(std::io::stdout(), $($arg)*).is_err() {
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! print_or_exit {
|
macro_rules! print_or_exit {
|
||||||
($($arg:tt)*) => {
|
($($arg:tt)*) => {
|
||||||
let _ = write!(std::io::stdout(), $($arg)*);
|
if write!(std::io::stdout(), $($arg)*).is_err() {
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ use rustyline::DefaultEditor;
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use uad_core::adb::ACommand;
|
use uad_core::adb::{ACommand, AdbBackend};
|
||||||
use uad_core::sync::{CorePackage, Phone, User, apply_pkg_state_commands, get_package_state};
|
use uad_core::sync::{CorePackage, Phone, User, apply_pkg_state_commands, get_package_state};
|
||||||
use uad_core::uad_lists::{Package, PackageState, Removal, UadList, load_debloat_lists};
|
use uad_core::uad_lists::{Package, PackageState, Removal, UadList, load_debloat_lists};
|
||||||
|
|
||||||
use crate::commands::{PackageListContext, display_package_list, execute_with_fallback};
|
use crate::commands::{
|
||||||
|
PackageListContext, display_package_list, execute_with_fallback, resolve_pm_flag,
|
||||||
|
};
|
||||||
use crate::device::{get_target_device, get_user};
|
use crate::device::{get_target_device, get_user};
|
||||||
use crate::filters::StateFilter;
|
use crate::filters::StateFilter;
|
||||||
use crate::println_or_exit;
|
use crate::println_or_exit;
|
||||||
|
|
@ -21,7 +23,9 @@ pub fn repl_mode(
|
||||||
device: Option<String>,
|
device: Option<String>,
|
||||||
user_id: Option<u16>,
|
user_id: Option<u16>,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let backend = AdbBackend::current();
|
||||||
println!("Universal Android Debloater - Interactive Mode");
|
println!("Universal Android Debloater - Interactive Mode");
|
||||||
|
println!("Using {} ADB backend", backend);
|
||||||
println!("Type 'help' for available commands, 'exit' or 'quit' to leave\n");
|
println!("Type 'help' for available commands, 'exit' or 'quit' to leave\n");
|
||||||
|
|
||||||
let target_device = get_target_device(device)?;
|
let target_device = get_target_device(device)?;
|
||||||
|
|
@ -145,8 +149,12 @@ fn handle_repl_line(
|
||||||
}
|
}
|
||||||
"device" => {
|
"device" => {
|
||||||
println!(
|
println!(
|
||||||
"Device: {} ({}), Android SDK: {}, User: {}",
|
"Device: {} ({}), Android SDK: {}, User: {}, Backend: {}",
|
||||||
device.model, device.adb_id, device.android_sdk, user.id
|
device.model,
|
||||||
|
device.adb_id,
|
||||||
|
device.android_sdk,
|
||||||
|
user.id,
|
||||||
|
AdbBackend::current()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"clear" => {
|
"clear" => {
|
||||||
|
|
@ -219,7 +227,7 @@ fn handle_list_command(
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let parsed = ReplListArgs::parse(args)?;
|
let parsed = ReplListArgs::parse(args)?;
|
||||||
|
|
||||||
let pm_flag = parsed.state_filter.and_then(StateFilter::to_pm_flag);
|
let pm_flag = resolve_pm_flag(parsed.state_filter);
|
||||||
let system_packages = ACommand::new()
|
let system_packages = ACommand::new()
|
||||||
.shell(&device.adb_id)
|
.shell(&device.adb_id)
|
||||||
.pm()
|
.pm()
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,21 @@ categories = ["command-line-utilities"]
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = ["builtin-adb"]
|
||||||
|
builtin-adb = [
|
||||||
|
"dep:adb_client",
|
||||||
|
"adb_client/usb",
|
||||||
|
"dep:rusb",
|
||||||
|
"dep:rsa",
|
||||||
|
"dep:tempfile",
|
||||||
|
]
|
||||||
self-update = ["dep:flate2", "dep:tar"]
|
self-update = ["dep:flate2", "dep:tar"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
adb_client = { workspace = true, optional = true }
|
||||||
|
rusb = { workspace = true, optional = true }
|
||||||
|
rsa = { workspace = true, optional = true }
|
||||||
|
tempfile = { workspace = true, optional = true }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::CACHE_DIR;
|
use crate::CACHE_DIR;
|
||||||
use crate::CONFIG_DIR;
|
use crate::CONFIG_DIR;
|
||||||
|
use crate::adb::AdbBackend;
|
||||||
use crate::sync::User;
|
use crate::sync::User;
|
||||||
use crate::utils::DisplayablePath;
|
use crate::utils::DisplayablePath;
|
||||||
use log::error;
|
use log::error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
@ -22,6 +23,28 @@ pub struct GeneralSettings {
|
||||||
pub theme: String,
|
pub theme: String,
|
||||||
pub expert_mode: bool,
|
pub expert_mode: bool,
|
||||||
pub backup_folder: PathBuf,
|
pub backup_folder: PathBuf,
|
||||||
|
/// ADB backend to use: Builtin (direct USB) or System (installed adb)
|
||||||
|
#[serde(default, deserialize_with = "deserialize_adb_backend")]
|
||||||
|
pub adb_backend: AdbBackend,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
enum PersistedAdbBackend {
|
||||||
|
Builtin,
|
||||||
|
System,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_adb_backend<'de, D>(deserializer: D) -> Result<AdbBackend, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
match PersistedAdbBackend::deserialize(deserializer)? {
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
PersistedAdbBackend::Builtin => Ok(AdbBackend::Builtin),
|
||||||
|
#[cfg(not(feature = "builtin-adb"))]
|
||||||
|
PersistedAdbBackend::Builtin => Ok(AdbBackend::System),
|
||||||
|
PersistedAdbBackend::System => Ok(AdbBackend::System),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
|
|
@ -49,6 +72,7 @@ impl Default for GeneralSettings {
|
||||||
theme: DEFAULT_THEME.to_string(),
|
theme: DEFAULT_THEME.to_string(),
|
||||||
expert_mode: false,
|
expert_mode: false,
|
||||||
backup_folder: CACHE_DIR.join("backups"),
|
backup_folder: CACHE_DIR.join("backups"),
|
||||||
|
adb_backend: AdbBackend::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -121,6 +145,27 @@ mod tests {
|
||||||
assert_eq!(config.general.backup_folder, CACHE_DIR.join("backups"));
|
assert_eq!(config.general.backup_folder, CACHE_DIR.join("backups"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builtin_backend_config_is_preserved_or_safely_downgraded() {
|
||||||
|
let config: Config = toml::from_str(
|
||||||
|
r#"
|
||||||
|
[general]
|
||||||
|
theme = "Custom"
|
||||||
|
expert_mode = true
|
||||||
|
backup_folder = "/tmp/uad-backups"
|
||||||
|
adb_backend = "Builtin"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.expect("Builtin backend config should remain readable");
|
||||||
|
|
||||||
|
assert_eq!(config.general.theme, "Custom");
|
||||||
|
assert!(config.general.expert_mode);
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
assert_eq!(config.general.adb_backend, AdbBackend::Builtin);
|
||||||
|
#[cfg(not(feature = "builtin-adb"))]
|
||||||
|
assert_eq!(config.general.adb_backend, AdbBackend::System);
|
||||||
|
}
|
||||||
|
|
||||||
// non-deterministic
|
// non-deterministic
|
||||||
/*
|
/*
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
adb::{ACommand as AdbCommand, PM_CLEAR_PACK, PackageId},
|
adb::{ACommand as AdbCommand, AdbBackend, AdbDeviceStatus, PM_CLEAR_PACK, PackageId},
|
||||||
uad_lists::PackageState,
|
uad_lists::PackageState,
|
||||||
};
|
};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
|
|
@ -37,6 +37,96 @@ impl std::fmt::Display for Phone {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Why device discovery found no ready devices.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum DeviceDiscoveryIssue {
|
||||||
|
Busy,
|
||||||
|
Unauthorized,
|
||||||
|
NoPermissions,
|
||||||
|
Offline,
|
||||||
|
Backend(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceDiscoveryIssue {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn is_terminal_for(&self, backend: AdbBackend) -> bool {
|
||||||
|
if matches!(self, Self::Busy | Self::NoPermissions) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
return matches!((self, backend), (Self::Backend(_), AdbBackend::Builtin));
|
||||||
|
#[cfg(not(feature = "builtin-adb"))]
|
||||||
|
{
|
||||||
|
let _ = backend;
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for DeviceDiscoveryIssue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Busy => write!(
|
||||||
|
f,
|
||||||
|
"The system ADB server is using the USB device. Stop it and retry."
|
||||||
|
),
|
||||||
|
Self::Unauthorized => write!(
|
||||||
|
f,
|
||||||
|
"USB debugging authorization is pending. Accept the prompt on the device."
|
||||||
|
),
|
||||||
|
Self::NoPermissions => write!(
|
||||||
|
f,
|
||||||
|
"USB access was denied. Check the host's USB permissions or udev rules."
|
||||||
|
),
|
||||||
|
Self::Offline => write!(f, "The device is offline. Reconnect it and retry."),
|
||||||
|
Self::Backend(err) => write!(f, "ADB device discovery failed: {err}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ready devices plus the reason no device was ready.
|
||||||
|
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||||
|
pub struct DeviceDiscovery {
|
||||||
|
pub devices: Vec<Phone>,
|
||||||
|
pub issue: Option<DeviceDiscoveryIssue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Classify statuses returned by `adb devices`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn classify_device_issue(
|
||||||
|
devices: &[(String, AdbDeviceStatus)],
|
||||||
|
) -> Option<DeviceDiscoveryIssue> {
|
||||||
|
let mut statuses = devices.iter().map(|(_, status)| status);
|
||||||
|
if statuses
|
||||||
|
.clone()
|
||||||
|
.any(|status| matches!(status, AdbDeviceStatus::Busy))
|
||||||
|
{
|
||||||
|
Some(DeviceDiscoveryIssue::Busy)
|
||||||
|
} else if statuses
|
||||||
|
.clone()
|
||||||
|
.any(|status| matches!(status, AdbDeviceStatus::Unauthorized))
|
||||||
|
{
|
||||||
|
Some(DeviceDiscoveryIssue::Unauthorized)
|
||||||
|
} else if statuses
|
||||||
|
.clone()
|
||||||
|
.any(|status| matches!(status, AdbDeviceStatus::NoPermissions))
|
||||||
|
{
|
||||||
|
Some(DeviceDiscoveryIssue::NoPermissions)
|
||||||
|
} else if statuses
|
||||||
|
.clone()
|
||||||
|
.any(|status| matches!(status, AdbDeviceStatus::Offline))
|
||||||
|
{
|
||||||
|
Some(DeviceDiscoveryIssue::Offline)
|
||||||
|
} else {
|
||||||
|
statuses
|
||||||
|
.find_map(|status| match status {
|
||||||
|
AdbDeviceStatus::BackendError(error) => Some(error.clone()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(DeviceDiscoveryIssue::Backend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `UserInfo` but relevant to UAD
|
/// `UserInfo` but relevant to UAD
|
||||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
|
|
@ -61,6 +151,7 @@ pub enum AdbError {
|
||||||
/// This replaces the deprecated `adb_shell_command`.
|
/// This replaces the deprecated `adb_shell_command`.
|
||||||
///
|
///
|
||||||
/// If `serial` is empty, it lets ADB choose the default device.
|
/// If `serial` is empty, it lets ADB choose the default device.
|
||||||
|
/// Uses the process-wide selected ADB backend.
|
||||||
pub fn run_adb_shell_action<S: AsRef<str>>(
|
pub fn run_adb_shell_action<S: AsRef<str>>(
|
||||||
device_serial: S,
|
device_serial: S,
|
||||||
action: &str,
|
action: &str,
|
||||||
|
|
@ -227,23 +318,48 @@ pub fn request_builder(commands: &[&str], package: &str, user: Option<User>) ->
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn sanitize_device_prop(raw: &str) -> String {
|
||||||
|
raw.chars()
|
||||||
|
.filter(|c| !c.is_control())
|
||||||
|
.collect::<String>()
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn parse_sdk_version(raw: &str) -> Option<u8> {
|
||||||
|
let sanitized = sanitize_device_prop(raw);
|
||||||
|
let digits: String = sanitized
|
||||||
|
.chars()
|
||||||
|
.skip_while(|c| !c.is_ascii_digit())
|
||||||
|
.take_while(char::is_ascii_digit)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if digits.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
digits.parse().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the model by querying the `ro.product.model` property.
|
/// Get the model by querying the `ro.product.model` property.
|
||||||
///
|
///
|
||||||
/// If `serial` is empty, it lets ADB choose the default device.
|
/// If `serial` is empty, it lets ADB choose the default device.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_device_model(serial: &str) -> String {
|
pub fn get_device_model(serial: &str) -> String {
|
||||||
AdbCommand::new()
|
match AdbCommand::new().shell(serial).getprop("ro.product.model") {
|
||||||
.shell(serial)
|
Ok(model) => sanitize_device_prop(&model),
|
||||||
.getprop("ro.product.model")
|
Err(err) => {
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
eprintln!("ERROR: {err}");
|
eprintln!("ERROR: {err}");
|
||||||
error!("{err}");
|
error!("{err}");
|
||||||
if err.contains("adb: no devices/emulators found") {
|
if err.contains("adb: no devices/emulators found") {
|
||||||
"no devices/emulators found".to_string()
|
"no devices/emulators found".to_string()
|
||||||
} else {
|
} else {
|
||||||
err
|
sanitize_device_prop(&err)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the brand by querying the `ro.product.brand` property.
|
/// Get the brand by querying the `ro.product.brand` property.
|
||||||
|
|
@ -254,8 +370,7 @@ pub fn get_device_brand(serial: &str) -> String {
|
||||||
AdbCommand::new()
|
AdbCommand::new()
|
||||||
.shell(serial)
|
.shell(serial)
|
||||||
.getprop("ro.product.brand")
|
.getprop("ro.product.brand")
|
||||||
// `trim` is just-in-case
|
.map(|s| sanitize_device_prop(&s))
|
||||||
.map(|s| s.trim().to_string())
|
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,7 +384,14 @@ pub fn get_android_sdk(device_serial: &str) -> u8 {
|
||||||
.shell(device_serial)
|
.shell(device_serial)
|
||||||
.getprop("ro.build.version.sdk")
|
.getprop("ro.build.version.sdk")
|
||||||
.map_or(0, |sdk| {
|
.map_or(0, |sdk| {
|
||||||
sdk.parse().expect("SDK version numeral must be valid")
|
if let Some(v) = parse_sdk_version(&sdk) {
|
||||||
|
v
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"Invalid SDK version {sdk:?} for device '{device_serial}'. Falling back to 0"
|
||||||
|
);
|
||||||
|
0
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -457,44 +579,81 @@ pub fn list_users_idx_prot(device_serial: &str) -> Vec<User> {
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This matches serials (`getprop ro.serialno`)
|
/// Discover connected devices using the selected ADB backend.
|
||||||
/// that are authorized by the user.
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_devices_list() -> Vec<Phone> {
|
pub fn discover_devices() -> DeviceDiscovery {
|
||||||
|
let backend = AdbBackend::current();
|
||||||
retry(
|
retry(
|
||||||
Fixed::from_millis(500).take(if cfg!(debug_assertions) { 3 } else { 10 }),
|
Fixed::from_millis(500).take(if cfg!(debug_assertions) { 3 } else { 10 }),
|
||||||
|| match AdbCommand::new().devices() {
|
|| match AdbCommand::new().devices() {
|
||||||
Ok(devices) => {
|
Ok(devices) => {
|
||||||
|
let issue = classify_device_issue(&devices);
|
||||||
let mut device_list: Vec<Phone> = vec![];
|
let mut device_list: Vec<Phone> = vec![];
|
||||||
if devices.iter().all(|(_, stat)| stat != "device") {
|
for (serial, status) in devices {
|
||||||
return OperationResult::Retry(vec![]);
|
if status != AdbDeviceStatus::Device {
|
||||||
}
|
continue;
|
||||||
for device in devices {
|
}
|
||||||
let serial = &device.0;
|
|
||||||
device_list.push(Phone {
|
device_list.push(Phone {
|
||||||
model: format!("{} {}", get_device_brand(serial), get_device_model(serial)),
|
model: format!(
|
||||||
android_sdk: get_android_sdk(serial),
|
"{} {}",
|
||||||
user_list: list_users_idx_prot(serial),
|
get_device_brand(&serial),
|
||||||
adb_id: serial.clone(),
|
get_device_model(&serial)
|
||||||
|
),
|
||||||
|
android_sdk: get_android_sdk(&serial),
|
||||||
|
user_list: list_users_idx_prot(&serial),
|
||||||
|
adb_id: serial,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
OperationResult::Ok(device_list)
|
|
||||||
|
if !device_list.is_empty() {
|
||||||
|
return OperationResult::Ok(DeviceDiscovery {
|
||||||
|
devices: device_list,
|
||||||
|
issue: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let discovery = DeviceDiscovery {
|
||||||
|
devices: vec![],
|
||||||
|
issue,
|
||||||
|
};
|
||||||
|
if discovery
|
||||||
|
.issue
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|current_issue| current_issue.is_terminal_for(backend))
|
||||||
|
{
|
||||||
|
OperationResult::Ok(discovery)
|
||||||
|
} else {
|
||||||
|
OperationResult::Retry(discovery)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("get_devices_list() -> {err}");
|
error!("get_devices_list() -> {err}");
|
||||||
let test: Vec<Phone> = vec![];
|
OperationResult::Retry(DeviceDiscovery {
|
||||||
OperationResult::Retry(test)
|
devices: vec![],
|
||||||
|
issue: Some(DeviceDiscoveryIssue::Backend(err)),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap_or_default()
|
.unwrap_or_else(|last_attempt| last_attempt.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get ready connected devices using the selected ADB backend.
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_devices_list() -> Vec<Phone> {
|
||||||
|
discover_devices().devices
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn initial_load() -> bool {
|
pub fn initial_load() -> bool {
|
||||||
match AdbCommand::new().devices() {
|
match AdbCommand::new().devices() {
|
||||||
Ok(_devices) => true,
|
// A successful query means the selected backend is available. Device
|
||||||
Err(_err) => false,
|
// presence and authorization are handled by get_devices_list().
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(err) => {
|
||||||
|
error!("initial_load() -> {err}");
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -661,3 +820,59 @@ pub fn attempt_fallback(
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn statuses(values: &[AdbDeviceStatus]) -> Vec<(String, AdbDeviceStatus)> {
|
||||||
|
values
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, status)| (format!("device-{index}"), status.clone()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn discovery_issue_classification_is_specific_and_prioritized() {
|
||||||
|
assert_eq!(
|
||||||
|
classify_device_issue(&statuses(&[
|
||||||
|
AdbDeviceStatus::Offline,
|
||||||
|
AdbDeviceStatus::Busy,
|
||||||
|
AdbDeviceStatus::Unauthorized,
|
||||||
|
])),
|
||||||
|
Some(DeviceDiscoveryIssue::Busy)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
classify_device_issue(&statuses(&[AdbDeviceStatus::NoPermissions])),
|
||||||
|
Some(DeviceDiscoveryIssue::NoPermissions)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
classify_device_issue(&statuses(&[AdbDeviceStatus::BackendError(
|
||||||
|
"invalid key".to_string(),
|
||||||
|
)])),
|
||||||
|
Some(DeviceDiscoveryIssue::Backend("invalid key".to_string()))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
classify_device_issue(&statuses(&[AdbDeviceStatus::Device])),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn terminal_discovery_issues_are_backend_aware() {
|
||||||
|
assert!(DeviceDiscoveryIssue::Busy.is_terminal_for(AdbBackend::System));
|
||||||
|
assert!(DeviceDiscoveryIssue::NoPermissions.is_terminal_for(AdbBackend::System));
|
||||||
|
assert!(!DeviceDiscoveryIssue::Unauthorized.is_terminal_for(AdbBackend::System));
|
||||||
|
assert!(!DeviceDiscoveryIssue::Offline.is_terminal_for(AdbBackend::System));
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
{
|
||||||
|
assert!(!DeviceDiscoveryIssue::Unauthorized.is_terminal_for(AdbBackend::Builtin));
|
||||||
|
assert!(!DeviceDiscoveryIssue::Offline.is_terminal_for(AdbBackend::Builtin));
|
||||||
|
assert!(
|
||||||
|
DeviceDiscoveryIssue::Backend("invalid key".to_string())
|
||||||
|
.is_terminal_for(AdbBackend::Builtin)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,15 @@ name = "uad-ng"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["wgpu", "self-update", "img"]
|
default = ["wgpu", "self-update", "img", "builtin-adb"]
|
||||||
wgpu = [] # Iced/wgpu is default
|
builtin-adb = ["uad-core/builtin-adb"]
|
||||||
self-update = ["flate2", "tar"]
|
self-update = ["flate2", "tar", "uad-core/self-update"]
|
||||||
no-self-update = []
|
no-self-update = []
|
||||||
|
wgpu = [] # Iced/wgpu is default
|
||||||
img = ["image", "iced/image"]
|
img = ["image", "iced/image"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
uad-core = { path = "../uad-core", features = ["self-update"] }
|
uad-core = { path = "../uad-core", default-features = false }
|
||||||
iced.workspace = true
|
iced.workspace = true
|
||||||
image = { workspace = true, optional = true }
|
image = { workspace = true, optional = true }
|
||||||
rfd.workspace = true
|
rfd.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,13 @@ use iced::{Alignment, Element, Length, Settings, Task, window::Settings as Windo
|
||||||
use iced::{Subscription, event, keyboard};
|
use iced::{Subscription, event, keyboard};
|
||||||
#[cfg(feature = "img")]
|
#[cfg(feature = "img")]
|
||||||
use image::ImageFormat;
|
use image::ImageFormat;
|
||||||
use log::{debug, error, info};
|
#[cfg(feature = "self-update")]
|
||||||
|
use log::debug;
|
||||||
|
use log::{error, info};
|
||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use uad_core::adb;
|
use uad_core::adb;
|
||||||
use uad_core::sync::{Phone, get_devices_list, initial_load};
|
use uad_core::sync::{DeviceDiscovery, Phone, discover_devices, initial_load};
|
||||||
use uad_core::uad_lists::UadListState;
|
use uad_core::uad_lists::UadListState;
|
||||||
use uad_core::update::{Release, SelfUpdateState, SelfUpdateStatus, get_latest_release};
|
use uad_core::update::{Release, SelfUpdateState, SelfUpdateStatus, get_latest_release};
|
||||||
use uad_core::utils::{FULL_NAME, NAME};
|
use uad_core::utils::{FULL_NAME, NAME};
|
||||||
|
|
@ -68,7 +70,7 @@ pub enum Message {
|
||||||
SettingsAction(SettingsMessage),
|
SettingsAction(SettingsMessage),
|
||||||
RefreshButtonPressed,
|
RefreshButtonPressed,
|
||||||
RebootButtonPressed,
|
RebootButtonPressed,
|
||||||
LoadDevices(Vec<Phone>),
|
LoadDevices(DeviceDiscovery),
|
||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
_NewReleaseDownloaded(Result<(PathBuf, PathBuf), ()>),
|
_NewReleaseDownloaded(Result<(PathBuf, PathBuf), ()>),
|
||||||
GetLatestRelease(Result<Option<Release>, ()>),
|
GetLatestRelease(Result<Option<Release>, ()>),
|
||||||
|
|
@ -83,21 +85,24 @@ impl UadGui {
|
||||||
reason = "required by iced's Application trait interface"
|
reason = "required by iced's Application trait interface"
|
||||||
)]
|
)]
|
||||||
fn title(&self) -> String {
|
fn title(&self) -> String {
|
||||||
self.selected_device.as_ref().map_or_else(
|
if self.selected_device.is_some() {
|
||||||
|| FULL_NAME.to_string(),
|
format!("{FULL_NAME} - device connected")
|
||||||
|device| format!("{FULL_NAME} - {}", device.model),
|
} else {
|
||||||
)
|
FULL_NAME.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> (Self, Task<Message>) {
|
fn new() -> (Self, Task<Message>) {
|
||||||
|
let app = Self::default();
|
||||||
|
let backend = app.settings_view.general.adb_backend;
|
||||||
|
backend.set_current();
|
||||||
(
|
(
|
||||||
Self::default(),
|
app,
|
||||||
Task::batch([
|
Task::batch([
|
||||||
// Used in crate::widgets::navigation_menu::ICONS. Name is `icomoon`.
|
// Used in crate::widgets::navigation_menu::ICONS. Name is `icomoon`.
|
||||||
font::load(include_bytes!("../../../resources/assets/icons.ttf").as_slice())
|
font::load(include_bytes!("../../../resources/assets/icons.ttf").as_slice())
|
||||||
.map(Message::FontLoaded),
|
.map(Message::FontLoaded),
|
||||||
Task::perform(async { initial_load() }, Message::ADBSatisfied),
|
Task::perform(async move { initial_load() }, Message::ADBSatisfied),
|
||||||
Task::perform(async { get_devices_list() }, Message::LoadDevices),
|
|
||||||
Task::perform(
|
Task::perform(
|
||||||
async move { get_latest_release() },
|
async move { get_latest_release() },
|
||||||
Message::GetLatestRelease,
|
Message::GetLatestRelease,
|
||||||
|
|
@ -158,7 +163,12 @@ impl UadGui {
|
||||||
)]
|
)]
|
||||||
fn update(&mut self, msg: Message) -> Task<Message> {
|
fn update(&mut self, msg: Message) -> Task<Message> {
|
||||||
match msg {
|
match msg {
|
||||||
Message::LoadDevices(devices_list) => {
|
Message::LoadDevices(discovery) => {
|
||||||
|
let DeviceDiscovery {
|
||||||
|
devices: devices_list,
|
||||||
|
issue,
|
||||||
|
} = discovery;
|
||||||
|
self.apps_view.discovery_issue = issue;
|
||||||
self.selected_device = match &self.selected_device {
|
self.selected_device = match &self.selected_device {
|
||||||
Some(s_device) => {
|
Some(s_device) => {
|
||||||
// Try to reload last selected phone
|
// Try to reload last selected phone
|
||||||
|
|
@ -171,6 +181,11 @@ impl UadGui {
|
||||||
};
|
};
|
||||||
self.devices_list = devices_list;
|
self.devices_list = devices_list;
|
||||||
|
|
||||||
|
if self.devices_list.is_empty() {
|
||||||
|
self.apps_view.loading_state = ListLoadingState::FindingPhones;
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
|
||||||
#[expect(unused_must_use, reason = "side-effect")]
|
#[expect(unused_must_use, reason = "side-effect")]
|
||||||
{
|
{
|
||||||
self.update(Message::SettingsAction(SettingsMessage::LoadDeviceSettings));
|
self.update(Message::SettingsAction(SettingsMessage::LoadDeviceSettings));
|
||||||
|
|
@ -202,7 +217,7 @@ impl UadGui {
|
||||||
self.adb_satisfied,
|
self.adb_satisfied,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Task::perform(async { get_devices_list() }, Message::LoadDevices)
|
Task::perform(async move { discover_devices() }, Message::LoadDevices)
|
||||||
}
|
}
|
||||||
Message::RebootButtonPressed => {
|
Message::RebootButtonPressed => {
|
||||||
self.apps_view = AppsView::default();
|
self.apps_view = AppsView::default();
|
||||||
|
|
@ -213,10 +228,14 @@ impl UadGui {
|
||||||
self.selected_device = None;
|
self.selected_device = None;
|
||||||
self.devices_list = vec![];
|
self.devices_list = vec![];
|
||||||
Task::perform(
|
Task::perform(
|
||||||
async { adb::ACommand::new().shell(serial).reboot() },
|
async move { adb::ACommand::new().shell(serial).reboot() },
|
||||||
|_| Message::Nothing,
|
|_| Message::Nothing,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Message::AppsAction(AppsMessage::OpenAdbSettings) => {
|
||||||
|
self.view = View::Settings;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
Message::AppsAction(msg) => self
|
Message::AppsAction(msg) => self
|
||||||
.apps_view
|
.apps_view
|
||||||
.update(
|
.update(
|
||||||
|
|
@ -261,6 +280,15 @@ impl UadGui {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SettingsMessage::AdbBackendApplied(backend) => {
|
||||||
|
backend.set_current();
|
||||||
|
self.apps_view = AppsView::default();
|
||||||
|
self.selected_device = None;
|
||||||
|
self.devices_list.clear();
|
||||||
|
self.adb_satisfied = false;
|
||||||
|
|
||||||
|
return Task::perform(async move { initial_load() }, Message::ADBSatisfied);
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
self.settings_view
|
self.settings_view
|
||||||
|
|
@ -387,9 +415,17 @@ impl UadGui {
|
||||||
}
|
}
|
||||||
Message::ADBSatisfied(result) => {
|
Message::ADBSatisfied(result) => {
|
||||||
self.adb_satisfied = result;
|
self.adb_satisfied = result;
|
||||||
self.update(Message::AppsAction(AppsMessage::ADBSatisfied(
|
let update_view = self.update(Message::AppsAction(AppsMessage::ADBSatisfied(
|
||||||
self.adb_satisfied,
|
self.adb_satisfied,
|
||||||
)))
|
)));
|
||||||
|
if result {
|
||||||
|
Task::batch([
|
||||||
|
update_view,
|
||||||
|
Task::perform(async move { discover_devices() }, Message::LoadDevices),
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
update_view
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Message::Nothing => Task::none(),
|
Message::Nothing => Task::none(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,8 @@ use crate::theme::Theme;
|
||||||
use crate::{gui::UpdateState, style, widgets::text};
|
use crate::{gui::UpdateState, style, widgets::text};
|
||||||
use iced::widget::{Space, column, container, row};
|
use iced::widget::{Space, column, container, row};
|
||||||
use iced::{Alignment, Element, Length, Renderer};
|
use iced::{Alignment, Element, Length, Renderer};
|
||||||
use log::error;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use uad_core::CACHE_DIR;
|
use uad_core::CACHE_DIR;
|
||||||
use uad_core::adb;
|
|
||||||
use uad_core::uad_lists::LIST_FNAME;
|
use uad_core::uad_lists::LIST_FNAME;
|
||||||
use uad_core::utils::{FULL_NAME, NAME, last_modified_date, open_url};
|
use uad_core::utils::{FULL_NAME, NAME, last_modified_date, open_url};
|
||||||
|
|
||||||
|
|
@ -95,38 +93,10 @@ impl About {
|
||||||
.spacing(10)
|
.spacing(10)
|
||||||
.width(550);
|
.width(550);
|
||||||
|
|
||||||
/*
|
|
||||||
There's no need to fetch this info every time the view is updated,
|
|
||||||
we could cache it in a `static` `LazyLock`.
|
|
||||||
|
|
||||||
But what if the system updates ADB while the app is running?
|
|
||||||
the numbers will be out of sync!
|
|
||||||
|
|
||||||
However, the server will still be the "old" version
|
|
||||||
until it's killed
|
|
||||||
*/
|
|
||||||
let adb_version_text = text(match adb::ACommand::new().version() {
|
|
||||||
Ok(s) => s
|
|
||||||
.lines()
|
|
||||||
.nth(0)
|
|
||||||
.unwrap_or_else(|| unreachable!())
|
|
||||||
// This allocation is good.
|
|
||||||
// If it was a ref, the app would hold the entire string
|
|
||||||
// instead of the relevant slice.
|
|
||||||
.to_string(),
|
|
||||||
Err(e) => {
|
|
||||||
error!("{e}");
|
|
||||||
"Couldn't fetch ADB version. Is it installed?".into()
|
|
||||||
// satisfy `match` by inferring the type of the `Ok` arm
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.width(250);
|
|
||||||
let adb_version_row = row![adb_version_text].align_y(Alignment::Center).width(550);
|
|
||||||
|
|
||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
let update_column = column![uad_list_row, self_update_row, adb_version_row];
|
let update_column = column![uad_list_row, self_update_row];
|
||||||
#[cfg(not(feature = "self-update"))]
|
#[cfg(not(feature = "self-update"))]
|
||||||
let update_column = column![uad_list_row, adb_version_row];
|
let update_column = column![uad_list_row];
|
||||||
|
|
||||||
let update_column = update_column.align_x(Alignment::Center).spacing(10);
|
let update_column = update_column.align_x(Alignment::Center).spacing(10);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,11 @@ use crate::theme::Theme;
|
||||||
use crate::widgets::navigation_menu::ICONS;
|
use crate::widgets::navigation_menu::ICONS;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use uad_core::adb::AdbBackend;
|
||||||
use uad_core::config::DeviceSettings;
|
use uad_core::config::DeviceSettings;
|
||||||
use uad_core::sync::{AdbError, Phone, User, apply_pkg_state_commands};
|
use uad_core::sync::{
|
||||||
|
AdbError, CorePackage, DeviceDiscoveryIssue, Phone, User, apply_pkg_state_commands,
|
||||||
|
};
|
||||||
use uad_core::uad_lists::{
|
use uad_core::uad_lists::{
|
||||||
Opposite, PackageHashMap, PackageState, Removal, UadList, UadListState, load_debloat_lists,
|
Opposite, PackageHashMap, PackageState, Removal, UadList, UadListState, load_debloat_lists,
|
||||||
};
|
};
|
||||||
|
|
@ -68,6 +71,7 @@ pub struct List {
|
||||||
export_modal: bool,
|
export_modal: bool,
|
||||||
current_package_index: usize,
|
current_package_index: usize,
|
||||||
is_adb_satisfied: bool,
|
is_adb_satisfied: bool,
|
||||||
|
pub discovery_issue: Option<DeviceDiscoveryIssue>,
|
||||||
copy_confirmation: bool,
|
copy_confirmation: bool,
|
||||||
fallback_notifications: Vec<String>,
|
fallback_notifications: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
@ -102,6 +106,7 @@ pub enum Message {
|
||||||
DescriptionEdit(text_editor::Action),
|
DescriptionEdit(text_editor::Action),
|
||||||
CopyError(String),
|
CopyError(String),
|
||||||
HideCopyConfirmation,
|
HideCopyConfirmation,
|
||||||
|
OpenAdbSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SummaryEntry {
|
pub struct SummaryEntry {
|
||||||
|
|
@ -130,6 +135,33 @@ impl From<Removal> for SummaryEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl List {
|
impl List {
|
||||||
|
#[inline]
|
||||||
|
fn current_user_index(&self) -> usize {
|
||||||
|
self.selected_user.unwrap_or_default().index
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn refilter(&mut self) -> Task<Message> {
|
||||||
|
Self::filter_package_lists(self);
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn map_core_to_row(uad_list: &PackageHashMap, core: &CorePackage) -> PackageRow {
|
||||||
|
let list = uad_list
|
||||||
|
.get(&core.name)
|
||||||
|
.map_or(UadList::Unlisted, |p| p.list);
|
||||||
|
PackageRow::new(
|
||||||
|
&core.name,
|
||||||
|
&core.description,
|
||||||
|
core.removal,
|
||||||
|
core.state,
|
||||||
|
list,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update(
|
pub fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
settings: &mut Settings,
|
settings: &mut Settings,
|
||||||
|
|
@ -172,7 +204,7 @@ impl List {
|
||||||
Message::GoToUrl(url) => Self::on_go_to_url(url),
|
Message::GoToUrl(url) => Self::on_go_to_url(url),
|
||||||
Message::ExportSelection => self.on_export_selection(),
|
Message::ExportSelection => self.on_export_selection(),
|
||||||
Message::SelectionExported(res) => self.on_selection_exported(res),
|
Message::SelectionExported(res) => self.on_selection_exported(res),
|
||||||
Message::Nothing => Task::none(),
|
Message::Nothing | Message::OpenAdbSettings => Task::none(),
|
||||||
Message::DescriptionEdit(action) => self.on_description_edit(action),
|
Message::DescriptionEdit(action) => self.on_description_edit(action),
|
||||||
Message::CopyError(err) => self.on_copy_error(err),
|
Message::CopyError(err) => self.on_copy_error(err),
|
||||||
Message::HideCopyConfirmation => self.on_hide_copy_confirmation(),
|
Message::HideCopyConfirmation => self.on_hide_copy_confirmation(),
|
||||||
|
|
@ -213,10 +245,36 @@ impl List {
|
||||||
),
|
),
|
||||||
LoadingState::FindingPhones => {
|
LoadingState::FindingPhones => {
|
||||||
if self.is_adb_satisfied {
|
if self.is_adb_satisfied {
|
||||||
waiting_view("Finding connected devices...", None, style::Text::Default)
|
if let Some(issue) = &self.discovery_issue {
|
||||||
|
let action = if matches!(issue, DeviceDiscoveryIssue::Busy) {
|
||||||
|
Some(button("Open ADB settings").on_press(Message::OpenAdbSettings))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
return waiting_view(&issue.to_string(), action, style::Text::Danger);
|
||||||
|
}
|
||||||
|
let waiting_message = match AdbBackend::current() {
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
AdbBackend::Builtin => {
|
||||||
|
"Waiting for a USB device and USB debugging authorization..."
|
||||||
|
}
|
||||||
|
AdbBackend::System => "Finding connected devices...",
|
||||||
|
};
|
||||||
|
waiting_view(waiting_message, None, style::Text::Default)
|
||||||
} else {
|
} else {
|
||||||
|
let connection_help = match AdbBackend::current() {
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
AdbBackend::Builtin => {
|
||||||
|
"Builtin ADB could not initialize USB access. Check USB permissions \
|
||||||
|
and reconnect the device."
|
||||||
|
}
|
||||||
|
AdbBackend::System => {
|
||||||
|
"ADB is not installed or could not be started. Install Android \
|
||||||
|
platform-tools and relaunch the application."
|
||||||
|
}
|
||||||
|
};
|
||||||
waiting_view(
|
waiting_view(
|
||||||
"ADB is not installed on your system, install ADB and relaunch application.",
|
connection_help,
|
||||||
Some(button("Read on how to get started.")
|
Some(button("Read on how to get started.")
|
||||||
.on_press(Message::GoToUrl(PathBuf::from(
|
.on_press(Message::GoToUrl(PathBuf::from(
|
||||||
"https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Getting-started",
|
"https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/wiki/Getting-started",
|
||||||
|
|
@ -329,12 +387,13 @@ impl List {
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
selected_device: &Phone,
|
selected_device: &Phone,
|
||||||
) -> Element<'_, Message, Theme, Renderer> {
|
) -> Element<'_, Message, Theme, Renderer> {
|
||||||
|
let i_user = self.current_user_index();
|
||||||
let packages = self
|
let packages = self
|
||||||
.filtered_packages
|
.filtered_packages
|
||||||
.iter()
|
.iter()
|
||||||
.fold(column![].spacing(6), |col, &i| {
|
.fold(column![].spacing(6), |col, &i| {
|
||||||
col.push(
|
col.push(
|
||||||
self.phone_packages[self.selected_user.unwrap_or_default().index][i]
|
self.phone_packages[i_user][i]
|
||||||
.view(settings, selected_device)
|
.view(settings, selected_device)
|
||||||
.map(move |msg| Message::List(i, msg)),
|
.map(move |msg| Message::List(i, msg)),
|
||||||
)
|
)
|
||||||
|
|
@ -748,8 +807,7 @@ impl List {
|
||||||
.selected_removal
|
.selected_removal
|
||||||
.expect("removal recommendation must be selected");
|
.expect("removal recommendation must be selected");
|
||||||
|
|
||||||
self.filtered_packages = self.phone_packages
|
self.filtered_packages = self.phone_packages[self.current_user_index()]
|
||||||
[self.selected_user.expect("User must be selected").index]
|
|
||||||
.iter()
|
.iter()
|
||||||
// we must filter the indices associated with pack-rows,
|
// we must filter the indices associated with pack-rows,
|
||||||
// that's why `enumerate` is before `filter`.
|
// that's why `enumerate` is before `filter`.
|
||||||
|
|
@ -776,7 +834,7 @@ impl List {
|
||||||
vec![
|
vec![
|
||||||
fetch_packages(&uad_list, serial, None)
|
fetch_packages(&uad_list, serial, None)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(PackageRow::from)
|
.map(|core| Self::map_core_to_row(&uad_list, &core))
|
||||||
.collect(),
|
.collect(),
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -785,7 +843,7 @@ impl List {
|
||||||
.map(|user| {
|
.map(|user| {
|
||||||
fetch_packages(&uad_list, serial, Some(user.id))
|
fetch_packages(&uad_list, serial, Some(user.id))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(PackageRow::from)
|
.map(|core| Self::map_core_to_row(&uad_list, &core))
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
@ -841,7 +899,7 @@ impl List {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_restoring_device(&mut self, output: Result<PackageInfo, AdbError>) -> Task<Message> {
|
fn on_restoring_device(&mut self, output: Result<PackageInfo, AdbError>) -> Task<Message> {
|
||||||
let i_user = self.selected_user.unwrap_or_default().index;
|
let i_user = self.current_user_index();
|
||||||
if let Ok(p) = output {
|
if let Ok(p) = output {
|
||||||
self.loading_state =
|
self.loading_state =
|
||||||
LoadingState::RestoringDevice(self.phone_packages[i_user][p.index].name.clone());
|
LoadingState::RestoringDevice(self.phone_packages[i_user][p.index].name.clone());
|
||||||
|
|
@ -886,7 +944,7 @@ impl List {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_apply_filters(&mut self, packages: Vec<Vec<PackageRow>>) -> Task<Message> {
|
fn on_apply_filters(&mut self, packages: Vec<Vec<PackageRow>>) -> Task<Message> {
|
||||||
let i_user = self.selected_user.unwrap_or_default().index;
|
let i_user = self.current_user_index();
|
||||||
self.phone_packages = packages;
|
self.phone_packages = packages;
|
||||||
self.filtered_packages = (0..self.phone_packages[i_user].len()).collect();
|
self.filtered_packages = (0..self.phone_packages[i_user].len()).collect();
|
||||||
self.selected_removal = Some(Removal::Recommended);
|
self.selected_removal = Some(Removal::Recommended);
|
||||||
|
|
@ -906,7 +964,7 @@ impl List {
|
||||||
selected_device: &mut Phone,
|
selected_device: &mut Phone,
|
||||||
list_update_state: &mut UadListState,
|
list_update_state: &mut UadListState,
|
||||||
) -> Task<Message> {
|
) -> Task<Message> {
|
||||||
let i_user = self.selected_user.unwrap_or_default().index;
|
let i_user = self.current_user_index();
|
||||||
for i in self.filtered_packages.clone() {
|
for i in self.filtered_packages.clone() {
|
||||||
if self.phone_packages[i_user][i].selected != selected {
|
if self.phone_packages[i_user][i].selected != selected {
|
||||||
#[expect(unused_must_use, reason = "side-effect")]
|
#[expect(unused_must_use, reason = "side-effect")]
|
||||||
|
|
@ -924,26 +982,22 @@ impl List {
|
||||||
|
|
||||||
fn on_search_input_changed(&mut self, letter: String) -> Task<Message> {
|
fn on_search_input_changed(&mut self, letter: String) -> Task<Message> {
|
||||||
self.input_value = letter;
|
self.input_value = letter;
|
||||||
Self::filter_package_lists(self);
|
self.refilter()
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_list_selected(&mut self, list: UadList) -> Task<Message> {
|
fn on_list_selected(&mut self, list: UadList) -> Task<Message> {
|
||||||
self.selected_list = Some(list);
|
self.selected_list = Some(list);
|
||||||
Self::filter_package_lists(self);
|
self.refilter()
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_package_state_selected(&mut self, package_state: PackageState) -> Task<Message> {
|
fn on_package_state_selected(&mut self, package_state: PackageState) -> Task<Message> {
|
||||||
self.selected_package_state = Some(package_state);
|
self.selected_package_state = Some(package_state);
|
||||||
Self::filter_package_lists(self);
|
self.refilter()
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_removal_selected(&mut self, removal: Removal) -> Task<Message> {
|
fn on_removal_selected(&mut self, removal: Removal) -> Task<Message> {
|
||||||
self.selected_removal = Some(removal);
|
self.selected_removal = Some(removal);
|
||||||
Self::filter_package_lists(self);
|
self.refilter()
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_list_row(
|
fn on_list_row(
|
||||||
|
|
@ -953,7 +1007,7 @@ impl List {
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
selected_device: &mut Phone,
|
selected_device: &mut Phone,
|
||||||
) -> Task<Message> {
|
) -> Task<Message> {
|
||||||
let i_user = self.selected_user.unwrap_or_default().index;
|
let i_user = self.current_user_index();
|
||||||
#[expect(unused_must_use, reason = "side-effect")]
|
#[expect(unused_must_use, reason = "side-effect")]
|
||||||
{
|
{
|
||||||
self.phone_packages[i_user][i_package]
|
self.phone_packages[i_user][i_package]
|
||||||
|
|
@ -1031,8 +1085,7 @@ impl List {
|
||||||
self.selected_user = Some(user);
|
self.selected_user = Some(user);
|
||||||
self.fallback_notifications.clear();
|
self.fallback_notifications.clear();
|
||||||
self.filtered_packages = (0..self.phone_packages[user.index].len()).collect();
|
self.filtered_packages = (0..self.phone_packages[user.index].len()).collect();
|
||||||
Self::filter_package_lists(self);
|
self.refilter()
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(
|
#[allow(
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ use iced::{Alignment, Element, Length, Renderer, Task, alignment};
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use uad_core::{
|
use uad_core::{
|
||||||
|
adb::{ACommand, AdbBackend},
|
||||||
config::{BackupSettings, Config, DeviceSettings, GeneralSettings},
|
config::{BackupSettings, Config, DeviceSettings, GeneralSettings},
|
||||||
save::{backup_phone, list_available_backup_user, list_available_backups, restore_backup},
|
save::{backup_phone, list_available_backup_user, list_available_backups, restore_backup},
|
||||||
sync::{
|
sync::{
|
||||||
|
|
@ -27,6 +28,9 @@ use uad_core::{
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PopUpModal {
|
pub enum PopUpModal {
|
||||||
ExportUninstalled,
|
ExportUninstalled,
|
||||||
|
ConfirmAdbServerStop,
|
||||||
|
StoppingAdbServer,
|
||||||
|
AdbBackendError,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -35,15 +39,28 @@ pub struct Settings {
|
||||||
pub device: DeviceSettings,
|
pub device: DeviceSettings,
|
||||||
is_loading: bool,
|
is_loading: bool,
|
||||||
modal: Option<PopUpModal>,
|
modal: Option<PopUpModal>,
|
||||||
|
/// Cached ADB version string for display
|
||||||
|
adb_version: String,
|
||||||
|
pending_adb_backend: Option<AdbBackend>,
|
||||||
|
adb_backend_error: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Settings {
|
impl Default for Settings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let general = Config::load_configuration_file().general;
|
||||||
|
general.adb_backend.set_current();
|
||||||
|
// Fetch initial ADB version
|
||||||
|
let adb_version = ACommand::new()
|
||||||
|
.version()
|
||||||
|
.unwrap_or_else(|e| format!("Error: {e}"));
|
||||||
Self {
|
Self {
|
||||||
general: Config::load_configuration_file().general,
|
general,
|
||||||
device: DeviceSettings::default(),
|
device: DeviceSettings::default(),
|
||||||
is_loading: false,
|
is_loading: false,
|
||||||
modal: None,
|
modal: None,
|
||||||
|
adb_version,
|
||||||
|
pending_adb_backend: None,
|
||||||
|
adb_backend_error: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -55,6 +72,13 @@ pub enum Message {
|
||||||
DisableMode(bool),
|
DisableMode(bool),
|
||||||
MultiUserMode(bool),
|
MultiUserMode(bool),
|
||||||
ApplyTheme(Theme),
|
ApplyTheme(Theme),
|
||||||
|
ApplyAdbBackend(AdbBackend),
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
RetryBuiltinAdb,
|
||||||
|
ConfirmAdbBackendSwitch,
|
||||||
|
AdbServerStopped(Result<String, String>),
|
||||||
|
AdbBackendApplied(AdbBackend),
|
||||||
|
AdbVersionFetched(Result<String, String>),
|
||||||
UrlPressed(PathBuf),
|
UrlPressed(PathBuf),
|
||||||
BackupSelected(DisplayablePath),
|
BackupSelected(DisplayablePath),
|
||||||
BackupDevice,
|
BackupDevice,
|
||||||
|
|
@ -83,6 +107,12 @@ impl Settings {
|
||||||
Message::DisableMode(toggled) => self.handle_disable_mode(phone, toggled),
|
Message::DisableMode(toggled) => self.handle_disable_mode(phone, toggled),
|
||||||
Message::MultiUserMode(toggled) => self.handle_multi_user_mode(phone, toggled),
|
Message::MultiUserMode(toggled) => self.handle_multi_user_mode(phone, toggled),
|
||||||
Message::ApplyTheme(theme) => self.handle_apply_theme(phone, theme),
|
Message::ApplyTheme(theme) => self.handle_apply_theme(phone, theme),
|
||||||
|
Message::ApplyAdbBackend(backend) => self.handle_apply_adb_backend(backend),
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
Message::RetryBuiltinAdb => self.handle_retry_builtin_adb(),
|
||||||
|
Message::ConfirmAdbBackendSwitch => self.handle_confirm_adb_backend_switch(),
|
||||||
|
Message::AdbServerStopped(result) => self.handle_adb_server_stopped(result),
|
||||||
|
Message::AdbVersionFetched(result) => self.handle_adb_version_fetched(result),
|
||||||
Message::UrlPressed(url) => Self::handle_url_pressed(url),
|
Message::UrlPressed(url) => Self::handle_url_pressed(url),
|
||||||
Message::LoadDeviceSettings => self.handle_load_device_settings(phone),
|
Message::LoadDeviceSettings => self.handle_load_device_settings(phone),
|
||||||
Message::BackupSelected(d_path) => self.handle_backup_selected(d_path),
|
Message::BackupSelected(d_path) => self.handle_backup_selected(d_path),
|
||||||
|
|
@ -91,7 +121,7 @@ impl Settings {
|
||||||
Message::RestoreDevice => {
|
Message::RestoreDevice => {
|
||||||
self.handle_restore_device(phone, packages, nb_running_async_adb_commands)
|
self.handle_restore_device(phone, packages, nb_running_async_adb_commands)
|
||||||
}
|
}
|
||||||
Message::RestoringDevice(_) => Task::none(),
|
Message::RestoringDevice(_) | Message::AdbBackendApplied(_) => Task::none(),
|
||||||
Message::FolderChosen(result) => self.handle_folder_chosen(phone, result),
|
Message::FolderChosen(result) => self.handle_folder_chosen(phone, result),
|
||||||
Message::ChooseBackUpFolder => self.handle_choose_backup_folder(),
|
Message::ChooseBackUpFolder => self.handle_choose_backup_folder(),
|
||||||
Message::ExportPackages => Self::handle_export_packages(selected_user, packages),
|
Message::ExportPackages => Self::handle_export_packages(selected_user, packages),
|
||||||
|
|
@ -101,6 +131,8 @@ impl Settings {
|
||||||
|
|
||||||
fn handle_modal_hide(&mut self) -> Task<Message> {
|
fn handle_modal_hide(&mut self) -> Task<Message> {
|
||||||
self.modal = None;
|
self.modal = None;
|
||||||
|
self.pending_adb_backend = None;
|
||||||
|
self.adb_backend_error = None;
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,6 +170,85 @@ impl Settings {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_apply_adb_backend(&mut self, backend: AdbBackend) -> Task<Message> {
|
||||||
|
if backend == self.general.adb_backend {
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
if backend == AdbBackend::Builtin {
|
||||||
|
self.pending_adb_backend = Some(backend);
|
||||||
|
self.adb_backend_error = None;
|
||||||
|
self.modal = Some(PopUpModal::ConfirmAdbServerStop);
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.commit_adb_backend(backend)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
fn handle_retry_builtin_adb(&mut self) -> Task<Message> {
|
||||||
|
self.pending_adb_backend = Some(AdbBackend::Builtin);
|
||||||
|
self.adb_backend_error = None;
|
||||||
|
self.modal = Some(PopUpModal::ConfirmAdbServerStop);
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_confirm_adb_backend_switch(&mut self) -> Task<Message> {
|
||||||
|
self.modal = Some(PopUpModal::StoppingAdbServer);
|
||||||
|
Task::perform(
|
||||||
|
async { ACommand::kill_system_server() },
|
||||||
|
Message::AdbServerStopped,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_adb_server_stopped(&mut self, result: Result<String, String>) -> Task<Message> {
|
||||||
|
match result {
|
||||||
|
Ok(_) => {
|
||||||
|
let Some(backend) = self.pending_adb_backend.take() else {
|
||||||
|
self.modal = None;
|
||||||
|
return Task::none();
|
||||||
|
};
|
||||||
|
self.modal = None;
|
||||||
|
self.commit_adb_backend(backend)
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
self.pending_adb_backend = None;
|
||||||
|
self.adb_backend_error = Some(format!(
|
||||||
|
"Could not stop the system ADB server: {err}\n\
|
||||||
|
Builtin ADB was not enabled."
|
||||||
|
));
|
||||||
|
self.modal = Some(PopUpModal::AdbBackendError);
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commit_adb_backend(&mut self, backend: AdbBackend) -> Task<Message> {
|
||||||
|
self.general.adb_backend = backend;
|
||||||
|
backend.set_current();
|
||||||
|
self.adb_version = "Fetching...".to_string();
|
||||||
|
debug!("Config change: {self:?}");
|
||||||
|
let mut config = Config::load_configuration_file();
|
||||||
|
config.save_device_settings(self.device.clone(), self.general.clone());
|
||||||
|
info!("ADB backend changed to: {backend}");
|
||||||
|
Task::batch([
|
||||||
|
Task::perform(
|
||||||
|
async move { ACommand::new().version() },
|
||||||
|
Message::AdbVersionFetched,
|
||||||
|
),
|
||||||
|
Task::done(Message::AdbBackendApplied(backend)),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_adb_version_fetched(&mut self, result: Result<String, String>) -> Task<Message> {
|
||||||
|
self.adb_version = match result {
|
||||||
|
Ok(version) => version,
|
||||||
|
Err(e) => format!("Error: {e}"),
|
||||||
|
};
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_url_pressed(url: PathBuf) -> Task<Message> {
|
fn handle_url_pressed(url: PathBuf) -> Task<Message> {
|
||||||
open_url(url);
|
open_url(url);
|
||||||
Task::none()
|
Task::none()
|
||||||
|
|
@ -344,8 +455,18 @@ impl Settings {
|
||||||
self.build_device_content(phone, apps_view)
|
self.build_device_content(phone, apps_view)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(PopUpModal::ExportUninstalled) = self.modal {
|
match self.modal.as_ref() {
|
||||||
return Self::render_export_modal(content);
|
Some(PopUpModal::ExportUninstalled) => return Self::render_export_modal(content),
|
||||||
|
Some(PopUpModal::ConfirmAdbServerStop) => {
|
||||||
|
return Self::render_adb_server_confirmation_modal(content);
|
||||||
|
}
|
||||||
|
Some(PopUpModal::StoppingAdbServer) => {
|
||||||
|
return Self::render_adb_server_stopping_modal(content);
|
||||||
|
}
|
||||||
|
Some(PopUpModal::AdbBackendError) => {
|
||||||
|
return self.render_adb_backend_error_modal(content);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
container(scrollable(content))
|
container(scrollable(content))
|
||||||
|
|
@ -361,6 +482,8 @@ impl Settings {
|
||||||
self.theme_container(),
|
self.theme_container(),
|
||||||
text("General").size(26),
|
text("General").size(26),
|
||||||
self.general_container(),
|
self.general_container(),
|
||||||
|
text("ADB").size(26),
|
||||||
|
self.adb_container(),
|
||||||
text("Current device").size(26),
|
text("Current device").size(26),
|
||||||
Self::no_device_container(),
|
Self::no_device_container(),
|
||||||
text("Backup / Restore").size(26),
|
text("Backup / Restore").size(26),
|
||||||
|
|
@ -381,6 +504,8 @@ impl Settings {
|
||||||
self.theme_container(),
|
self.theme_container(),
|
||||||
text("General").size(26),
|
text("General").size(26),
|
||||||
self.general_container(),
|
self.general_container(),
|
||||||
|
text("ADB").size(26),
|
||||||
|
self.adb_container(),
|
||||||
text("Current device").size(26),
|
text("Current device").size(26),
|
||||||
Self::warning_container(phone),
|
Self::warning_container(phone),
|
||||||
self.device_specific_container(phone),
|
self.device_specific_container(phone),
|
||||||
|
|
@ -460,6 +585,62 @@ impl Settings {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn adb_container(&self) -> Element<'_, Message, Theme, Renderer> {
|
||||||
|
let backend_label = text("Backend:").size(16);
|
||||||
|
let radio_btn_backend =
|
||||||
|
AdbBackend::ALL
|
||||||
|
.iter()
|
||||||
|
.fold(row![].spacing(10), |row_content, option| {
|
||||||
|
row_content.push(
|
||||||
|
radio(
|
||||||
|
format!("{option}"),
|
||||||
|
*option,
|
||||||
|
Some(self.general.adb_backend),
|
||||||
|
Message::ApplyAdbBackend,
|
||||||
|
)
|
||||||
|
.size(20),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let backend_row = row![backend_label, radio_btn_backend]
|
||||||
|
.spacing(10)
|
||||||
|
.align_y(Alignment::Center);
|
||||||
|
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
let backend_description =
|
||||||
|
"System: Uses your installed adb binary. Builtin: Embedded ADB over USB.";
|
||||||
|
#[cfg(not(feature = "builtin-adb"))]
|
||||||
|
let backend_description = "System: Uses your installed adb binary.";
|
||||||
|
let backend_descr = text(backend_description).style(style::Text::Commentary);
|
||||||
|
|
||||||
|
let version_row = row![
|
||||||
|
text("Version: ").size(14),
|
||||||
|
text(&self.adb_version)
|
||||||
|
.size(14)
|
||||||
|
.style(style::Text::Commentary),
|
||||||
|
]
|
||||||
|
.spacing(5)
|
||||||
|
.align_y(Alignment::Center);
|
||||||
|
|
||||||
|
let content = column![backend_row, backend_descr, version_row].spacing(10);
|
||||||
|
#[cfg(feature = "builtin-adb")]
|
||||||
|
let content = if self.general.adb_backend == AdbBackend::Builtin {
|
||||||
|
content.push(
|
||||||
|
button_primary(text("Stop system ADB and retry"))
|
||||||
|
.on_press(Message::RetryBuiltinAdb),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
};
|
||||||
|
|
||||||
|
container(content)
|
||||||
|
.padding(10)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Shrink)
|
||||||
|
.style(style::Container::Frame)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
fn warning_container(phone: &Phone) -> Element<'static, Message, Theme, Renderer> {
|
fn warning_container(phone: &Phone) -> Element<'static, Message, Theme, Renderer> {
|
||||||
container(
|
container(
|
||||||
row![
|
row![
|
||||||
|
|
@ -691,4 +872,86 @@ impl Settings {
|
||||||
.on_blur(Message::ModalHide)
|
.on_blur(Message::ModalHide)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_adb_server_confirmation_modal(
|
||||||
|
content: Element<'_, Message, Theme, Renderer>,
|
||||||
|
) -> Element<'_, Message, Theme, Renderer> {
|
||||||
|
let title = container(
|
||||||
|
row![text("Stop the system ADB server?").size(24)].align_y(Alignment::Center),
|
||||||
|
)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.style(style::Container::Frame)
|
||||||
|
.padding([10, 0])
|
||||||
|
.center_x(Length::Shrink);
|
||||||
|
|
||||||
|
let explanation = text(
|
||||||
|
"Builtin ADB needs exclusive access to the USB device. The system ADB server may \
|
||||||
|
currently hold that access. Stop it and retry with Builtin ADB?",
|
||||||
|
)
|
||||||
|
.width(Length::Fill);
|
||||||
|
|
||||||
|
let actions = row![
|
||||||
|
button(text("Cancel")).on_press(Message::ModalHide),
|
||||||
|
Space::new().width(Length::Fill),
|
||||||
|
button_primary(text("Stop server and retry"))
|
||||||
|
.on_press(Message::ConfirmAdbBackendSwitch),
|
||||||
|
]
|
||||||
|
.spacing(10);
|
||||||
|
|
||||||
|
let modal = container(column![title, explanation, actions].spacing(20))
|
||||||
|
.width(520)
|
||||||
|
.padding(20)
|
||||||
|
.style(style::Container::Frame);
|
||||||
|
|
||||||
|
Modal::new(content, modal)
|
||||||
|
.on_blur(Message::ModalHide)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_adb_server_stopping_modal(
|
||||||
|
content: Element<'_, Message, Theme, Renderer>,
|
||||||
|
) -> Element<'_, Message, Theme, Renderer> {
|
||||||
|
let modal = container(
|
||||||
|
column![
|
||||||
|
text("Stopping the system ADB server").size(24),
|
||||||
|
text("Please wait before reconnecting with Builtin ADB."),
|
||||||
|
]
|
||||||
|
.spacing(20),
|
||||||
|
)
|
||||||
|
.width(520)
|
||||||
|
.padding(20)
|
||||||
|
.style(style::Container::Frame);
|
||||||
|
|
||||||
|
Modal::new(content, modal).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_adb_backend_error_modal<'a>(
|
||||||
|
&'a self,
|
||||||
|
content: Element<'a, Message, Theme, Renderer>,
|
||||||
|
) -> Element<'a, Message, Theme, Renderer> {
|
||||||
|
let message = self
|
||||||
|
.adb_backend_error
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or("Could not switch ADB backends.");
|
||||||
|
let actions = row![
|
||||||
|
Space::new().width(Length::Fill),
|
||||||
|
button(text("Close")).on_press(Message::ModalHide),
|
||||||
|
Space::new().width(Length::Fill),
|
||||||
|
];
|
||||||
|
let modal = container(
|
||||||
|
column![
|
||||||
|
text("ADB backend switch failed").size(24),
|
||||||
|
text(message),
|
||||||
|
actions,
|
||||||
|
]
|
||||||
|
.spacing(20),
|
||||||
|
)
|
||||||
|
.width(520)
|
||||||
|
.padding(20)
|
||||||
|
.style(style::Container::Frame);
|
||||||
|
|
||||||
|
Modal::new(content, modal)
|
||||||
|
.on_blur(Message::ModalHide)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,10 @@ pub fn nav_menu<'a>(
|
||||||
.gap(4);
|
.gap(4);
|
||||||
|
|
||||||
let device_list_text = match apps_view.loading_state {
|
let device_list_text = match apps_view.loading_state {
|
||||||
ListLoadingState::FindingPhones => text("Finding connected devices..."),
|
ListLoadingState::FindingPhones => apps_view.discovery_issue.as_ref().map_or_else(
|
||||||
|
|| text("Finding connected devices..."),
|
||||||
|
|issue| text(issue.to_string()),
|
||||||
|
),
|
||||||
_ => text("No devices/emulators found"),
|
_ => text("No devices/emulators found"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
6
flake.lock
generated
6
flake.lock
generated
|
|
@ -2,11 +2,11 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1776949667,
|
"lastModified": 1781607440,
|
||||||
"narHash": "sha256-GMSVw35Q+294GlrTUKlx087E31z7KurReQ1YHSKp5iw=",
|
"narHash": "sha256-rxO+uc/KFbSJp+pgyXRuAX6QlG9hJdnt0BXpEQRXY+U=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "01fbdeef22b76df85ea168fbfe1bfd9e63681b30",
|
"rev": "3e41b24abd260e8f71dbe2f5737d24122f972158",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue