feat: add an recap modal window (#565)

A modal window will now appear to give you a recap of the selected packages before applying the changes.

A complete overhaul of the way UAD handles package selection was required to implement this feature.
This commit is contained in:
w1nst0n
2023-03-18 18:15:31 +00:00
committed by GitHub
parent 28642075fd
commit 5fa6fea353
10 changed files with 920 additions and 258 deletions

295
Cargo.lock generated
View File

@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "ab_glyph"
version = "0.2.19"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5568a4aa5ba8adf5175c5c460b030e27d8893412976cc37bef0e4fbc16cfbba"
checksum = "fe21446ad43aa56417a767f3e2f3d7c4ca522904de1dd640529a76e9c5c3b33c"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser",
@@ -141,24 +141,24 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "bumpalo"
version = "3.11.1"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
[[package]]
name = "bytemuck"
version = "1.12.3"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f"
checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393"
dependencies = [
"bytemuck_derive",
]
[[package]]
name = "bytemuck_derive"
version = "1.3.0"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fe233b960f12f8007e3db2d136e3cb1c291bfd7396e384ee76025fc1a3932b4"
checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322"
dependencies = [
"proc-macro2",
"quote",
@@ -186,9 +186,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.78"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]]
name = "cfg-if"
@@ -470,9 +470,9 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]]
name = "cxx"
version = "1.0.86"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579"
checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -482,9 +482,9 @@ dependencies = [
[[package]]
name = "cxx-build"
version = "1.0.86"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70"
checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d"
dependencies = [
"cc",
"codespan-reporting",
@@ -497,15 +497,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
version = "1.0.86"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c"
checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a"
[[package]]
name = "cxxbridge-macro"
version = "1.0.86"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5"
checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2"
dependencies = [
"proc-macro2",
"quote",
@@ -615,9 +615,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.8.0"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "encase"
@@ -708,7 +708,7 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2"
dependencies = [
"toml",
"toml 0.5.11",
]
[[package]]
@@ -802,9 +802,9 @@ dependencies = [
[[package]]
name = "futures"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84"
dependencies = [
"futures-channel",
"futures-core",
@@ -817,9 +817,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5"
dependencies = [
"futures-core",
"futures-sink",
@@ -827,15 +827,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
[[package]]
name = "futures-executor"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e"
dependencies = [
"futures-core",
"futures-task",
@@ -845,15 +845,15 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531"
[[package]]
name = "futures-macro"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70"
dependencies = [
"proc-macro2",
"quote",
@@ -862,21 +862,21 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364"
[[package]]
name = "futures-task"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366"
[[package]]
name = "futures-util"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1"
dependencies = [
"futures-channel",
"futures-core",
@@ -1169,7 +1169,7 @@ dependencies = [
[[package]]
name = "iced"
version = "0.7.0"
source = "git+https://github.com/iced-rs/iced.git#18552f96df5d1fa72c3c87e96a5765f89c340e19"
source = "git+https://github.com/iced-rs/iced.git#98a717383acf71d7939d7cc90d350743487f0380"
dependencies = [
"iced_core",
"iced_futures",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]]
name = "iced_core"
version = "0.7.0"
source = "git+https://github.com/iced-rs/iced.git#18552f96df5d1fa72c3c87e96a5765f89c340e19"
source = "git+https://github.com/iced-rs/iced.git#98a717383acf71d7939d7cc90d350743487f0380"
dependencies = [
"bitflags",
"instant",
@@ -1195,7 +1195,7 @@ dependencies = [
[[package]]
name = "iced_futures"
version = "0.5.1"
source = "git+https://github.com/iced-rs/iced.git#18552f96df5d1fa72c3c87e96a5765f89c340e19"
source = "git+https://github.com/iced-rs/iced.git#98a717383acf71d7939d7cc90d350743487f0380"
dependencies = [
"futures",
"log",
@@ -1206,7 +1206,7 @@ dependencies = [
[[package]]
name = "iced_glow"
version = "0.6.0"
source = "git+https://github.com/iced-rs/iced.git#18552f96df5d1fa72c3c87e96a5765f89c340e19"
source = "git+https://github.com/iced-rs/iced.git#98a717383acf71d7939d7cc90d350743487f0380"
dependencies = [
"bytemuck",
"euclid",
@@ -1221,7 +1221,7 @@ dependencies = [
[[package]]
name = "iced_glutin"
version = "0.6.0"
source = "git+https://github.com/iced-rs/iced.git#18552f96df5d1fa72c3c87e96a5765f89c340e19"
source = "git+https://github.com/iced-rs/iced.git#98a717383acf71d7939d7cc90d350743487f0380"
dependencies = [
"glutin",
"iced_graphics",
@@ -1233,7 +1233,7 @@ dependencies = [
[[package]]
name = "iced_graphics"
version = "0.6.0"
source = "git+https://github.com/iced-rs/iced.git#18552f96df5d1fa72c3c87e96a5765f89c340e19"
source = "git+https://github.com/iced-rs/iced.git#98a717383acf71d7939d7cc90d350743487f0380"
dependencies = [
"bitflags",
"bytemuck",
@@ -1248,7 +1248,7 @@ dependencies = [
[[package]]
name = "iced_native"
version = "0.8.0"
source = "git+https://github.com/iced-rs/iced.git#18552f96df5d1fa72c3c87e96a5765f89c340e19"
source = "git+https://github.com/iced-rs/iced.git#98a717383acf71d7939d7cc90d350743487f0380"
dependencies = [
"iced_core",
"iced_futures",
@@ -1261,7 +1261,7 @@ dependencies = [
[[package]]
name = "iced_style"
version = "0.6.0"
source = "git+https://github.com/iced-rs/iced.git#18552f96df5d1fa72c3c87e96a5765f89c340e19"
source = "git+https://github.com/iced-rs/iced.git#98a717383acf71d7939d7cc90d350743487f0380"
dependencies = [
"iced_core",
"once_cell",
@@ -1271,7 +1271,7 @@ dependencies = [
[[package]]
name = "iced_wgpu"
version = "0.8.0"
source = "git+https://github.com/iced-rs/iced.git#18552f96df5d1fa72c3c87e96a5765f89c340e19"
source = "git+https://github.com/iced-rs/iced.git#98a717383acf71d7939d7cc90d350743487f0380"
dependencies = [
"bitflags",
"bytemuck",
@@ -1291,7 +1291,7 @@ dependencies = [
[[package]]
name = "iced_winit"
version = "0.7.0"
source = "git+https://github.com/iced-rs/iced.git#18552f96df5d1fa72c3c87e96a5765f89c340e19"
source = "git+https://github.com/iced-rs/iced.git#98a717383acf71d7939d7cc90d350743487f0380"
dependencies = [
"iced_futures",
"iced_graphics",
@@ -1356,9 +1356,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "js-sys"
version = "0.3.60"
version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
dependencies = [
"wasm-bindgen",
]
@@ -1637,14 +1637,23 @@ dependencies = [
[[package]]
name = "nom"
version = "7.1.2"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nom8"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
dependencies = [
"memchr",
]
[[package]]
name = "num-integer"
version = "0.1.45"
@@ -1676,18 +1685,18 @@ dependencies = [
[[package]]
name = "num_enum"
version = "0.5.7"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b"
dependencies = [
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.5.7"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -1760,9 +1769,9 @@ dependencies = [
[[package]]
name = "owned_ttf_parser"
version = "0.18.0"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a5f3c7ca08b6879e7965fb25e24d1f5eeb32ea73f9ad99b3854778a38c57e93"
checksum = "e25e9fb15717794fae58ab55c26e044103aad13186fbb625893f9a3bbcc24228"
dependencies = [
"ttf-parser",
]
@@ -1809,7 +1818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core 0.9.6",
"parking_lot_core 0.9.7",
]
[[package]]
@@ -1828,15 +1837,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.6"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys 0.42.0",
"windows-sys 0.45.0",
]
[[package]]
@@ -1925,20 +1934,19 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro-crate"
version = "1.2.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34"
dependencies = [
"once_cell",
"thiserror",
"toml",
"toml_edit 0.18.1",
]
[[package]]
name = "proc-macro2"
version = "1.0.49"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
dependencies = [
"unicode-ident",
]
@@ -2034,9 +2042,9 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.10.1"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
@@ -2215,6 +2223,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
dependencies = [
"serde",
]
[[package]]
name = "servo-fontconfig"
version = "0.5.1"
@@ -2397,9 +2414,9 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.1.3"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
@@ -2471,19 +2488,70 @@ dependencies = [
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "toml"
version = "0.5.10"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "toml"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "772c1426ab886e7362aedf4abc9c0d1348a979517efedfc25862944d10137af0"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime 0.6.1",
"toml_edit 0.19.1",
]
[[package]]
name = "toml_datetime"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5"
[[package]]
name = "toml_datetime"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b"
dependencies = [
"indexmap",
"nom8",
"toml_datetime 0.5.1",
]
[[package]]
name = "toml_edit"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90a238ee2e6ede22fb95350acc78e21dc40da00bb66c0334bde83de4ed89424e"
dependencies = [
"indexmap",
"nom8",
"serde",
"serde_spanned",
"toml_datetime 0.6.1",
]
[[package]]
name = "ttf-parser"
version = "0.18.1"
@@ -2510,6 +2578,7 @@ dependencies = [
"fern",
"flate2",
"iced",
"iced_native",
"log",
"regex",
"retry",
@@ -2517,15 +2586,15 @@ dependencies = [
"serde_json",
"static_init",
"tar",
"toml",
"toml 0.7.1",
"ureq",
]
[[package]]
name = "unicode-bidi"
version = "0.3.8"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58"
[[package]]
name = "unicode-ident"
@@ -2544,9 +2613,9 @@ dependencies = [
[[package]]
name = "unicode-segmentation"
version = "1.10.0"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-width"
@@ -2568,9 +2637,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "ureq"
version = "2.6.1"
version = "2.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "733b5ad78377302af52c0dbcb2623d78fe50e4b3bf215948ff29e9ee031d8566"
checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d"
dependencies = [
"base64",
"flate2",
@@ -2621,9 +2690,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.83"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -2631,9 +2700,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.83"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
dependencies = [
"bumpalo",
"log",
@@ -2646,9 +2715,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.33"
version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
dependencies = [
"cfg-if",
"js-sys",
@@ -2658,9 +2727,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.83"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -2668,9 +2737,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.83"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
dependencies = [
"proc-macro2",
"quote",
@@ -2681,9 +2750,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.83"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
[[package]]
name = "wasm-timer"
@@ -2785,9 +2854,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.60"
version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -3000,6 +3069,30 @@ dependencies = [
"windows_x86_64_msvc 0.42.1",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.1",
"windows_i686_gnu 0.42.1",
"windows_i686_msvc 0.42.1",
"windows_x86_64_gnu 0.42.1",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
@@ -3115,12 +3208,12 @@ dependencies = [
[[package]]
name = "x11-dl"
version = "2.20.1"
version = "2.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1536d6965a5d4e573c7ef73a2c15ebcd0b2de3347bdf526c34c297c00ac40f0"
checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
dependencies = [
"lazy_static",
"libc",
"once_cell",
"pkg-config",
]

View File

@@ -20,6 +20,7 @@ no-self-update = []
[dependencies]
iced = { git = "https://github.com/iced-rs/iced.git" }
iced_native = { git = "https://github.com/iced-rs/iced.git"}
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0"
static_init = "^1.0"

Binary file not shown.

View File

@@ -1,7 +1,6 @@
use crate::core::sync::{hashset_system_packages, list_all_system_packages, User};
use crate::core::theme::Theme;
use crate::core::uad_lists::{Package, PackageState, Removal, UadList};
use crate::gui::views::list::Selection;
use crate::gui::widgets::package_row::PackageRow;
use chrono::offset::Utc;
use chrono::DateTime;
@@ -52,33 +51,6 @@ pub fn fetch_packages(
user_package
}
pub fn update_selection_count(selection: &mut Selection, p_state: PackageState, add: bool) {
match p_state {
PackageState::Enabled => {
if add {
selection.enabled += 1
} else if selection.enabled > 0 {
selection.enabled -= 1
};
}
PackageState::Disabled => {
if add {
selection.disabled += 1
} else if selection.disabled > 0 {
selection.disabled -= 1
};
}
PackageState::Uninstalled => {
if add {
selection.uninstalled += 1
} else if selection.uninstalled > 0 {
selection.uninstalled -= 1
};
}
PackageState::All => {}
};
}
pub fn string_to_theme(theme: String) -> Theme {
match theme.as_str() {
"Dark" => Theme::Dark,

View File

@@ -107,7 +107,12 @@ impl Application for UadGui {
None => devices_list.first().map(|x| x.to_owned()),
};
self.devices_list = devices_list;
self.update(Message::SettingsAction(SettingsMessage::LoadDeviceSettings));
#[allow(unused_must_use)]
{
self.update(Message::SettingsAction(SettingsMessage::LoadDeviceSettings));
}
self.update(Message::AppsAction(AppsMessage::LoadUadList(true)))
}
Message::AppsPress => {
@@ -149,21 +154,46 @@ impl Application for UadGui {
)
.map(Message::AppsAction),
Message::SettingsAction(msg) => {
if let SettingsMessage::RestoringDevice(ref output) = msg {
self.nb_running_async_adb_commands -= 1;
self.view = View::List;
self.apps_view.update(
&mut self.settings_view,
&mut self.selected_device.clone().unwrap_or_default(),
&mut self.update_state.uad_list,
AppsMessage::RestoringDevice(output.clone()),
);
match msg {
SettingsMessage::RestoringDevice(ref output) => {
self.nb_running_async_adb_commands -= 1;
self.view = View::List;
if self.nb_running_async_adb_commands == 0 {
return self.update(Message::RefreshButtonPressed);
#[allow(unused_must_use)]
{
self.apps_view.update(
&mut self.settings_view,
&mut self.selected_device.clone().unwrap_or_default(),
&mut self.update_state.uad_list,
AppsMessage::RestoringDevice(output.clone()),
);
}
if self.nb_running_async_adb_commands == 0 {
return self.update(Message::RefreshButtonPressed);
}
}
SettingsMessage::MultiUserMode(toggled) => {
if toggled {
for user in self.apps_view.phone_packages.clone() {
for (i, _) in
user.iter().enumerate().filter(|&(_, pkg)| pkg.selected)
{
for u in self
.selected_device
.as_ref()
.unwrap()
.user_list
.iter()
.filter(|&u| !u.protected)
{
self.apps_view.phone_packages[u.index][i].selected = true;
}
}
}
}
}
_ => (),
}
self.settings_view
.update(
&self.selected_device.clone().unwrap_or_default(),
@@ -221,7 +251,11 @@ impl Application for UadGui {
);
info!("{:-^65}", "-");
self.apps_view.loading_state = ListLoadingState::FindingPhones("".to_string());
self.update(Message::SettingsAction(SettingsMessage::LoadDeviceSettings));
#[allow(unused_must_use)]
{
self.update(Message::SettingsAction(SettingsMessage::LoadDeviceSettings));
}
self.update(Message::AppsAction(AppsMessage::LoadPhonePackages((
self.apps_view.uad_lists.clone(),
UadListState::Done,

View File

@@ -28,6 +28,8 @@ pub enum Container {
Invisible,
Frame,
BorderedFrame,
Tooltip,
Background,
}
impl container::StyleSheet for Theme {
@@ -49,6 +51,20 @@ impl container::StyleSheet for Theme {
border_width: 1.0,
border_color: self.palette().normal.error,
},
Container::Tooltip => container::Appearance {
background: Some(Background::Color(self.palette().base.foreground)),
text_color: Some(self.palette().bright.surface),
border_radius: 8.0,
border_width: 1.0,
border_color: self.palette().normal.primary,
},
Container::Background => container::Appearance {
background: Some(Background::Color(self.palette().base.background)),
text_color: Some(self.palette().bright.surface),
border_radius: 5.0,
..container::Appearance::default()
},
}
}
}
@@ -152,7 +168,7 @@ impl button::StyleSheet for Theme {
match style {
Button::RestorePackage => disabled_appearance(p.normal.primary, Some(p.bright.primary)),
Button::UninstallPackage => disabled_appearance(p.bright.error, None),
Button::Primary => disabled_appearance(p.normal.primary, Some(p.bright.primary)),
Button::Primary => disabled_appearance(p.bright.primary, Some(p.bright.primary)),
_ => button::Appearance { ..active },
}
}
@@ -176,21 +192,21 @@ impl scrollable::StyleSheet for Theme {
fn active(&self, style: &Self::Style) -> scrollable::Scrollbar {
let from_appearance = |c: Color| scrollable::Scrollbar {
background: Some(Background::Color(c)),
background: Some(Background::Color(Color::TRANSPARENT)),
border_radius: 5.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
scroller: scrollable::Scroller {
color: self.palette().base.foreground,
color: c,
border_radius: 5.0,
border_width: 0.0,
border_width: 1.0,
border_color: Color::TRANSPARENT,
},
};
match style {
Scrollable::Description => from_appearance(self.palette().base.foreground),
Scrollable::Packages => from_appearance(self.palette().base.background),
Scrollable::Description => from_appearance(self.palette().normal.surface),
Scrollable::Packages => from_appearance(self.palette().base.foreground),
}
}
@@ -386,6 +402,7 @@ impl pick_list::StyleSheet for Theme {
pub enum Text {
#[default]
Default,
Ok,
Danger,
Commentary,
Color(Color),
@@ -403,6 +420,9 @@ impl text::StyleSheet for Theme {
fn appearance(&self, style: Self::Style) -> text::Appearance {
match style {
Text::Default => Default::default(),
Text::Ok => text::Appearance {
color: Some(self.palette().bright.secondary),
},
Text::Danger => text::Appearance {
color: Some(self.palette().bright.error),
},

View File

@@ -4,26 +4,21 @@ use crate::core::theme::Theme;
use crate::core::uad_lists::{
load_debloat_lists, Opposite, Package, PackageState, Removal, UadList, UadListState,
};
use crate::core::utils::{fetch_packages, update_selection_count};
use crate::core::utils::fetch_packages;
use crate::gui::style;
use crate::gui::widgets::navigation_menu::ICONS;
use std::collections::HashMap;
use std::env;
use crate::gui::views::settings::Settings;
use crate::gui::widgets::modal::Modal;
use crate::gui::widgets::package_row::{Message as RowMessage, PackageRow};
use iced::widget::{
button, column, container, pick_list, row, scrollable, text, text_input, Space,
button, column, container, horizontal_space, pick_list, radio, row, scrollable, text,
text_input, tooltip, vertical_rule, Space,
};
use iced::{alignment, Alignment, Command, Element, Length, Renderer};
#[derive(Debug, Default, Clone)]
pub struct Selection {
pub uninstalled: u16,
pub enabled: u16,
pub disabled: u16,
pub selected_packages: Vec<usize>, // phone_packages indexes (= what you've selected)
}
#[derive(Debug, Default, Clone)]
pub struct PackageInfo {
pub i_user: usize,
@@ -53,13 +48,14 @@ pub struct List {
pub uad_lists: HashMap<String, Package>,
pub phone_packages: Vec<Vec<PackageRow>>, // packages of all users of the phone
filtered_packages: Vec<usize>, // phone_packages indexes of the selected user (= what you see on screen)
pub selection: Selection,
selected_packages: Vec<(usize, usize)>, // Vec of (user_index, pkg_index)
selected_package_state: Option<PackageState>,
selected_removal: Option<Removal>,
selected_list: Option<UadList>,
selected_user: Option<User>,
pub input_value: String,
description: String,
selection_modal: bool,
current_package_index: usize,
}
@@ -79,6 +75,9 @@ pub enum Message {
List(usize, RowMessage),
ChangePackageState(Result<CommandType, ()>),
Nothing,
ModalHide,
ModalUserSelected(User),
ModalValidate,
}
impl List {
@@ -91,6 +90,25 @@ impl List {
) -> Command<Message> {
let i_user = self.selected_user.unwrap_or_default().index;
match message {
Message::ModalHide => {
self.selection_modal = false;
Command::none()
}
Message::ModalValidate => {
let mut commands = vec![];
self.selected_packages.sort();
self.selected_packages.dedup();
for selection in &self.selected_packages {
commands.append(&mut build_action_pkg_commands(
&self.phone_packages,
selected_device,
&settings.device,
*selection,
));
}
self.selection_modal = false;
Command::batch(commands)
}
Message::RestoringDevice(output) => {
if let Ok(res) = output {
if let CommandType::PackageManager(p) = res {
@@ -138,25 +156,14 @@ impl List {
Command::none()
}
Message::ToggleAllSelected(selected) => {
#[allow(unused_must_use)]
for i in self.filtered_packages.clone() {
self.phone_packages[i_user][i].selected = selected;
if !selected {
if self.selection.selected_packages.contains(&i) {
update_selection_count(
&mut self.selection,
self.phone_packages[i_user][i].state,
false,
);
self.selection.selected_packages.retain(|&s_i| s_i != i);
}
} else if !self.selection.selected_packages.contains(&i) {
self.selection.selected_packages.push(i);
update_selection_count(
&mut self.selection,
self.phone_packages[i_user][i].state,
true,
if self.phone_packages[i_user][i].selected != selected {
self.update(
settings,
selected_device,
list_update_state,
Message::List(i, RowMessage::ToggleSelection(selected)),
);
}
}
@@ -183,9 +190,12 @@ impl List {
Command::none()
}
Message::List(i_package, row_message) => {
self.phone_packages[i_user][i_package]
.update(row_message.clone())
.map(move |row_message| Message::List(i_package, row_message));
#[allow(unused_must_use)]
{
self.phone_packages[i_user][i_package]
.update(row_message.clone())
.map(move |row_message| Message::List(i_package, row_message));
}
let package = &mut self.phone_packages[i_user][i_package];
@@ -193,30 +203,35 @@ impl List {
RowMessage::ToggleSelection(toggle) => {
if package.removal == Removal::Unsafe && !settings.general.expert_mode {
package.selected = false;
return Command::none();
}
if settings.device.multi_user_mode {
for u in selected_device.user_list.iter().filter(|&u| !u.protected) {
self.phone_packages[u.index][i_package].selected = toggle;
if toggle {
self.selected_packages.push((u.index, i_package));
}
}
if !toggle {
self.selected_packages.retain(|&x| x.1 != i_package);
}
} else {
package.selected = toggle;
if package.selected {
self.selection.selected_packages.push(i_package);
if toggle {
self.selected_packages.push((i_user, i_package));
} else {
self.selection
.selected_packages
.retain(|&s_i| s_i != i_package);
self.selected_packages
.retain(|&x| x.1 != i_package || x.0 != i_user);
}
update_selection_count(
&mut self.selection,
package.state,
package.selected,
);
}
Command::none()
}
RowMessage::ActionPressed => Command::batch(build_action_pkg_commands(
&self.selected_user.unwrap(),
&self.phone_packages,
selected_device,
&settings.device,
i_package,
(i_user, i_package),
)),
RowMessage::PackagePressed => {
self.description = package.clone().description;
@@ -230,26 +245,11 @@ impl List {
}
}
Message::ApplyActionOnSelection => {
let mut commands = vec![];
for i in &self.selection.selected_packages {
commands.append(&mut build_action_pkg_commands(
&self.selected_user.unwrap(),
&self.phone_packages,
selected_device,
&settings.device,
*i,
));
}
Command::batch(commands)
self.selection_modal = true;
Command::none()
}
Message::UserSelected(user) => {
for p in &mut self.phone_packages[i_user] {
p.selected = false;
}
self.selected_user = Some(user);
for i_package in &self.selection.selected_packages {
self.phone_packages[user.index][*i_package].selected = true;
}
self.filtered_packages = (0..self.phone_packages[user.index].len()).collect();
Self::filter_package_lists(self);
Command::none()
@@ -258,15 +258,22 @@ impl List {
if let Ok(CommandType::PackageManager(p)) = res {
let package = &mut self.phone_packages[p.i_user][p.index];
package.state = package.state.opposite(settings.device.disable_mode);
update_selection_count(&mut self.selection, package.state, false);
self.selection
.selected_packages
.retain(|&s_i| s_i != p.index);
package.selected = false;
self.selected_packages
.retain(|&x| x.1 != p.index && x.0 != p.i_user);
Self::filter_package_lists(self);
}
Command::none()
}
Message::ModalUserSelected(user) => {
self.selected_user = Some(user);
self.update(
settings,
selected_device,
list_update_state,
Message::UserSelected(user),
)
}
Message::Nothing => Command::none(),
}
}
@@ -305,8 +312,6 @@ impl List {
)
.padding(5);
// let package_amount = text(format!("{} packages found", packages.len()));
let user_picklist = pick_list(
selected_device.user_list.clone(),
self.selected_user,
@@ -358,8 +363,6 @@ impl List {
.height(Length::FillPortion(6))
.style(style::Scrollable::Packages);
// let mut packages_v: Vec<&str> = self.packages.lines().collect();
let description_scroll =
scrollable(text(&self.description)).style(style::Scrollable::Description);
@@ -368,31 +371,21 @@ impl List {
.width(Length::Fill)
.style(style::Container::Frame);
let restore_action = match settings.device.disable_mode {
true => "Enable/Restore",
false => "Restore",
let review_selection = if !self.selected_packages.is_empty() {
button(text(format!(
"Review selection ({})",
self.selected_packages.len()
)))
.on_press(Message::ApplyActionOnSelection)
.padding(5)
.style(style::Button::Primary)
} else {
button(text(format!(
"Review selection ({})",
self.selected_packages.len()
)))
.padding(5)
};
let remove_action = match settings.device.disable_mode {
true => "Disable",
false => "Uninstall",
};
let apply_restore_selection = button(text(format!(
"{} selection ({})",
restore_action,
self.selection.uninstalled + self.selection.disabled
)))
.on_press(Message::ApplyActionOnSelection)
.padding(5)
.style(style::Button::Primary);
let apply_remove_selection = button(text(format!(
"{} selection ({})",
remove_action, self.selection.enabled
)))
.on_press(Message::ApplyActionOnSelection)
.padding(5)
.style(style::Button::Primary);
let select_all_btn = button("Select all")
.padding(5)
@@ -408,8 +401,7 @@ impl List {
select_all_btn,
unselect_all_btn,
Space::new(Length::Fill, Length::Shrink),
apply_restore_selection,
apply_remove_selection,
review_selection,
]
.width(Length::Fill)
.spacing(10)
@@ -450,11 +442,232 @@ impl List {
.spacing(10)
.align_items(Alignment::Center)
};
container(content).height(Length::Fill).padding(10).into()
if self.selection_modal {
Modal::new(
content.padding(10),
self.apply_selection_modal(
selected_device,
settings,
&self.phone_packages[self.selected_user.unwrap().index],
),
)
.on_blur(Message::ModalHide)
.into()
} else {
container(content).height(Length::Fill).padding(10).into()
}
}
}
}
fn apply_selection_modal(
&self,
device: &Phone,
settings: &Settings,
packages: &[PackageRow],
) -> Element<Message, Renderer<Theme>> {
let mut h_recap: HashMap<Removal, (u8, u8)> = HashMap::new();
for p in packages.iter().filter(|p| p.selected) {
if p.state != PackageState::Uninstalled {
h_recap.entry(p.removal).or_insert((0, 0)).0 += 1;
} else {
h_recap.entry(p.removal).or_insert((0, 0)).1 += 1;
}
}
let radio_btn_users = device.user_list.iter().filter(|&u| !u.protected).fold(
row![].spacing(10),
|row, user| {
row.push(
radio(
format!("{}", user.clone()),
*user,
self.selected_user,
Message::ModalUserSelected,
)
.size(23),
)
},
);
let title_ctn =
container(row![text("Review your selection").size(25)].align_items(Alignment::Center))
.width(Length::Fill)
.style(style::Container::Frame)
.padding([10, 0, 10, 0])
.center_y()
.center_x();
let users_ctn = container(radio_btn_users)
.padding(10)
.center_x()
.style(style::Container::Frame);
let explaination_ctn = container(
row![
text("The action for the selected user will be applied to all other users")
.style(style::Text::Danger),
tooltip(
text("\u{EA0C}")
.font(ICONS)
.width(Length::Units(17))
.horizontal_alignment(alignment::Horizontal::Center)
.style(style::Text::Commentary)
.size(17),
"Let's say you choose user 0. If a selected package on user 0\n\
is set to be uninstalled and if this same package is disabled on user 10,\n\
then the package on both users will be uninstalled.",
tooltip::Position::Top,
)
.gap(20)
.padding(10)
.size(17)
.style(style::Container::Tooltip)
]
.spacing(10),
)
.center_x()
.padding(10)
.style(style::Container::BorderedFrame);
let modal_btn_row = row![
button(text("Cancel")).on_press(Message::ModalHide),
horizontal_space(Length::Fill),
button(text("Apply")).on_press(Message::ModalValidate),
]
.padding([0, 15, 10, 10]);
let recap_view = Removal::ALL
.iter()
.filter(|&&r| r != Removal::All)
.fold(column![].spacing(6).width(Length::Fill), |col, r| {
col.push(recap(settings, &mut h_recap, *r))
});
let selected_pkgs_ctn = container(
container(
scrollable(
container(
if !self
.selected_packages
.iter()
.any(|s| s.0 == self.selected_user.unwrap().index)
{
column![text("No packages selected for this user")]
.align_items(Alignment::Center)
.width(Length::Fill)
} else {
self.selected_packages
.iter()
.filter(|s| s.0 == self.selected_user.unwrap().index)
.fold(
column![].spacing(6).width(Length::Fill),
|col, selection| {
col.push(
row![
row![text(
self.phone_packages[selection.0][selection.1]
.removal
)]
.width(Length::Units(100)),
row![text(
self.phone_packages[selection.0][selection.1]
.uad_list
)]
.width(Length::Units(60)),
row![text(
self.phone_packages[selection.0][selection.1]
.name
.clone()
),],
horizontal_space(Length::Fill),
row![match self.phone_packages[selection.0]
[selection.1]
.state
{
PackageState::Enabled =>
if settings.device.disable_mode {
text("Disable")
.style(style::Text::Danger)
} else {
text("Uninstall")
.style(style::Text::Danger)
},
PackageState::Disabled =>
text("Enable").style(style::Text::Ok),
PackageState::Uninstalled =>
text("Restore").style(style::Text::Ok),
_ => text("Impossible")
.style(style::Text::Danger),
},]
.width(Length::Units(60)),
]
.width(Length::Fill)
.spacing(20),
)
},
)
},
)
.padding(10)
.width(Length::Fill),
)
.style(style::Scrollable::Description),
)
.width(Length::Fill)
.style(style::Container::Frame),
)
.width(Length::Fill)
.max_height(150)
.padding([0, 10, 0, 10]);
container(
if device
.user_list
.iter()
.filter(|&u| !u.protected)
.collect::<Vec<&User>>()
.len()
> 1
&& settings.device.multi_user_mode
{
column![
title_ctn,
users_ctn,
row![explaination_ctn].padding([0, 10, 0, 10]),
container(recap_view).padding(10),
selected_pkgs_ctn,
modal_btn_row,
]
.spacing(10)
.align_items(Alignment::Center)
} else if !settings.device.multi_user_mode {
column![
title_ctn,
users_ctn,
container(recap_view).padding(10),
selected_pkgs_ctn,
modal_btn_row,
]
.spacing(10)
.align_items(Alignment::Center)
} else {
column![
title_ctn,
container(recap_view).padding(10),
selected_pkgs_ctn,
modal_btn_row,
]
.spacing(10)
.align_items(Alignment::Center)
},
)
.width(Length::Units(800))
.height(Length::Shrink)
.max_height(700)
.style(style::Container::Background)
.into()
}
fn filter_package_lists(&mut self) {
let list_filter: UadList = self.selected_list.unwrap();
let package_filter: PackageState = self.selected_package_state.unwrap();
@@ -545,30 +758,33 @@ fn waiting_view<'a>(
}
fn build_action_pkg_commands(
selected_user: &User,
packages: &[Vec<PackageRow>],
device: &Phone,
settings: &DeviceSettings,
p_index: usize,
selection: (usize, usize),
) -> Vec<Command<Message>> {
let pkg = &packages[selected_user.index][p_index];
let pkg = &packages[selection.0][selection.1];
let wanted_state = pkg.state.opposite(settings.disable_mode);
let mut commands = vec![];
for u in device.user_list.iter().filter(|&&u| {
!u.protected
&& (u != *selected_user || settings.multi_user_mode)
&& packages[u.index][p_index].state != wanted_state
!u.protected && (packages[u.index][selection.1].selected || settings.multi_user_mode)
}) {
let u_pkg = packages[u.index][p_index].clone();
let actions = apply_pkg_state_commands(u_pkg.into(), &wanted_state, u, device);
let u_pkg = packages[u.index][selection.1].clone();
let actions = if settings.multi_user_mode {
apply_pkg_state_commands(u_pkg.into(), &wanted_state, u, device)
} else {
let wanted_state = &u_pkg.state.opposite(settings.disable_mode);
apply_pkg_state_commands(u_pkg.into(), wanted_state, u, device)
};
for (j, action) in actions.into_iter().enumerate() {
let p_info = PackageInfo {
i_user: u.index,
index: p_index,
index: selection.1,
removal: pkg.removal.to_string(),
};
// Only the first command can change the package state
// In the end there is only one package state change
// even if we run multiple adb commands
commands.push(Command::perform(
perform_adb_commands(action, CommandType::PackageManager(p_info)),
if j == 0 {
@@ -581,3 +797,47 @@ fn build_action_pkg_commands(
}
commands
}
fn recap<'a>(
settings: &Settings,
recap: &mut HashMap<Removal, (u8, u8)>,
removal: Removal,
) -> Element<'a, Message, Renderer<Theme>> {
container(
row![
text(removal).size(25).width(Length::FillPortion(1)),
vertical_rule(5),
row![
if settings.device.disable_mode {
text("Disable").style(style::Text::Danger)
} else {
text("Uninstall").style(style::Text::Danger)
},
horizontal_space(Length::Fill),
text(recap.entry(removal).or_insert((0, 0)).0.to_string())
.style(style::Text::Danger)
]
.width(Length::FillPortion(1)),
vertical_rule(5),
row![
if settings.device.disable_mode {
text("Enable").style(style::Text::Ok)
} else {
text("Restore").style(style::Text::Ok)
},
horizontal_space(Length::Fill),
text(recap.entry(removal).or_insert((0, 0)).1.to_string()).style(style::Text::Ok)
]
.width(Length::FillPortion(1))
]
.spacing(20)
.padding([0, 10, 0, 0])
.width(Length::Fill)
.align_items(Alignment::Center),
)
.padding(10)
.width(Length::Fill)
.height(Length::Units(45))
.style(style::Container::Frame)
.into()
}

View File

@@ -252,7 +252,7 @@ impl Settings {
];
let multi_user_mode_checkbox = checkbox(
"Affect all the users of the phone (not only the selected user)",
"Affect all the users of the device (not only the selected user)",
self.device.multi_user_mode,
Message::MultiUserMode,
)

View File

@@ -1,2 +1,3 @@
pub mod modal;
pub mod navigation_menu;
pub mod package_row;

281
src/gui/widgets/modal.rs Normal file
View File

@@ -0,0 +1,281 @@
use iced_native::alignment::Alignment;
use iced_native::widget::{self, Tree};
use iced_native::{
event, layout, mouse, overlay, renderer, Clipboard, Color, Element, Event, Layout, Length,
Point, Rectangle, Shell, Size, Widget,
};
/// A widget that centers a modal element over some base element
pub struct Modal<'a, Message, Renderer> {
base: Element<'a, Message, Renderer>,
modal: Element<'a, Message, Renderer>,
on_blur: Option<Message>,
}
impl<'a, Message, Renderer> Modal<'a, Message, Renderer> {
/// Returns a new [`Modal`]
pub fn new(
base: impl Into<Element<'a, Message, Renderer>>,
modal: impl Into<Element<'a, Message, Renderer>>,
) -> Self {
Self {
base: base.into(),
modal: modal.into(),
on_blur: None,
}
}
/// Sets the message that will be produces when the background
/// of the [`Modal`] is pressed
pub fn on_blur(self, on_blur: Message) -> Self {
Self {
on_blur: Some(on_blur),
..self
}
}
}
impl<'a, Message, Renderer> Widget<Message, Renderer> for Modal<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
Message: Clone,
{
fn children(&self) -> Vec<Tree> {
vec![Tree::new(&self.base), Tree::new(&self.modal)]
}
fn diff(&self, tree: &mut Tree) {
tree.diff_children(&[&self.base, &self.modal]);
}
fn width(&self) -> Length {
self.base.as_widget().width()
}
fn height(&self) -> Length {
self.base.as_widget().height()
}
fn layout(&self, renderer: &Renderer, limits: &layout::Limits) -> layout::Node {
self.base.as_widget().layout(renderer, limits)
}
fn on_event(
&mut self,
state: &mut Tree,
event: Event,
layout: Layout<'_>,
cursor_position: Point,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
) -> event::Status {
self.base.as_widget_mut().on_event(
&mut state.children[0],
event,
layout,
cursor_position,
renderer,
clipboard,
shell,
)
}
fn draw(
&self,
state: &Tree,
renderer: &mut Renderer,
theme: &<Renderer as iced_native::Renderer>::Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
) {
self.base.as_widget().draw(
&state.children[0],
renderer,
theme,
style,
layout,
cursor_position,
viewport,
);
}
fn overlay<'b>(
&'b mut self,
state: &'b mut Tree,
layout: Layout<'_>,
_renderer: &Renderer,
) -> Option<overlay::Element<'b, Message, Renderer>> {
Some(overlay::Element::new(
layout.position(),
Box::new(Overlay {
content: &mut self.modal,
tree: &mut state.children[1],
size: layout.bounds().size(),
on_blur: self.on_blur.clone(),
}),
))
}
fn mouse_interaction(
&self,
state: &Tree,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.base.as_widget().mouse_interaction(
&state.children[0],
layout,
cursor_position,
viewport,
renderer,
)
}
fn operate(
&self,
state: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn widget::Operation<Message>,
) {
self.base
.as_widget()
.operate(&mut state.children[0], layout, renderer, operation);
}
}
struct Overlay<'a, 'b, Message, Renderer> {
content: &'b mut Element<'a, Message, Renderer>,
tree: &'b mut Tree,
size: Size,
on_blur: Option<Message>,
}
impl<'a, 'b, Message, Renderer> overlay::Overlay<Message, Renderer>
for Overlay<'a, 'b, Message, Renderer>
where
Renderer: iced_native::Renderer,
Message: Clone,
{
fn layout(&self, renderer: &Renderer, _bounds: Size, position: Point) -> layout::Node {
let limits = layout::Limits::new(Size::ZERO, self.size)
.width(Length::Fill)
.height(Length::Fill);
let mut child = self.content.as_widget().layout(renderer, &limits);
child.align(Alignment::Center, Alignment::Center, limits.max());
let mut node = layout::Node::with_children(self.size, vec![child]);
node.move_to(position);
node
}
fn on_event(
&mut self,
event: Event,
layout: Layout<'_>,
cursor_position: Point,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
) -> event::Status {
let content_bounds = layout.children().next().unwrap().bounds();
if let Some(message) = self.on_blur.as_ref() {
if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) = &event {
if !content_bounds.contains(cursor_position) {
shell.publish(message.clone());
return event::Status::Captured;
}
}
}
self.content.as_widget_mut().on_event(
self.tree,
event,
layout.children().next().unwrap(),
cursor_position,
renderer,
clipboard,
shell,
)
}
fn draw(
&self,
renderer: &mut Renderer,
theme: &Renderer::Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor_position: Point,
) {
renderer.fill_quad(
renderer::Quad {
bounds: layout.bounds(),
border_radius: renderer::BorderRadius::from(0.0),
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
Color {
a: 0.80,
..Color::BLACK
},
);
self.content.as_widget().draw(
self.tree,
renderer,
theme,
style,
layout.children().next().unwrap(),
cursor_position,
&layout.bounds(),
);
}
fn operate(
&mut self,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn widget::Operation<Message>,
) {
self.content.as_widget().operate(
self.tree,
layout.children().next().unwrap(),
renderer,
operation,
);
}
fn mouse_interaction(
&self,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.content.as_widget().mouse_interaction(
self.tree,
layout.children().next().unwrap(),
cursor_position,
viewport,
renderer,
)
}
}
impl<'a, Message, Renderer> From<Modal<'a, Message, Renderer>> for Element<'a, Message, Renderer>
where
Renderer: 'a + iced_native::Renderer,
Message: 'a + Clone,
{
fn from(modal: Modal<'a, Message, Renderer>) -> Self {
Element::new(modal)
}
}