Add a self-update feature (#121)

- Add an update button in the About page which links to the Github Releases page
- Display if there is a new version available in the About page
- Display an error if the request to Github failed
- Download the new UAD version and update the software (the hard part)
- Display an update button instead of the `Apps` button if there is an update available
- Add a `no-self-update` cargo feature for this (we don't want auto-update if a package manager already handles this)

The request is done asynchronously, each time you launch UAD or press the About button
The message checking updates... is displayed in the meantime

Update process:
- Download the right release based on the current file name (temp_<release_name>)
- Extract the executable from the tarball for Linux and MacOS release
- Rename the current executable to a temp path and rename the new version as the original file name
- Spawn a new process to run the new (renamed) executable and kill the current one
- Remove the old executable

Acknowledgement:
@tarkah for the inspiration of the self-update code (https://github.com/ajour/ajour/pull/222)
This commit is contained in:
w1nst0n 2022-02-09 23:27:13 +00:00 committed by GitHub
commit 4659eb7b0f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 653 additions and 336 deletions

436
Cargo.lock generated
View file

@ -87,9 +87,9 @@ dependencies = [
[[package]]
name = "autocfg"
version = "1.0.1"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
@ -124,12 +124,6 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "bumpalo"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
[[package]]
name = "bumpalo"
version = "3.9.1"
@ -265,15 +259,6 @@ dependencies = [
"x11rb",
]
[[package]]
name = "cmake"
version = "0.1.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a"
dependencies = [
"cc",
]
[[package]]
name = "cocoa"
version = "0.24.0"
@ -283,7 +268,7 @@ dependencies = [
"bitflags",
"block",
"cocoa-foundation",
"core-foundation 0.9.2",
"core-foundation 0.9.3",
"core-graphics 0.22.3",
"foreign-types",
"libc",
@ -298,7 +283,7 @@ checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
dependencies = [
"bitflags",
"block",
"core-foundation 0.9.2",
"core-foundation 0.9.3",
"core-graphics-types",
"foreign-types",
"libc",
@ -344,9 +329,9 @@ dependencies = [
[[package]]
name = "core-foundation"
version = "0.9.2"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys 0.8.3",
"libc",
@ -383,7 +368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
dependencies = [
"bitflags",
"core-foundation 0.9.2",
"core-foundation 0.9.3",
"core-graphics-types",
"foreign-types",
"libc",
@ -396,19 +381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
dependencies = [
"bitflags",
"core-foundation 0.9.2",
"foreign-types",
"libc",
]
[[package]]
name = "core-text"
version = "19.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25"
dependencies = [
"core-foundation 0.9.2",
"core-graphics 0.22.3",
"core-foundation 0.9.3",
"foreign-types",
"libc",
]
@ -428,9 +401,9 @@ dependencies = [
[[package]]
name = "crc32fast"
version = "1.3.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if 1.0.0",
]
@ -458,9 +431,9 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.6"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762"
checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
@ -471,9 +444,9 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.6"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120"
checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
dependencies = [
"cfg-if 1.0.0",
"lazy_static",
@ -540,16 +513,6 @@ dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if 1.0.0",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys"
version = "0.3.6"
@ -561,17 +524,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "dispatch"
version = "0.2.0"
@ -587,40 +539,12 @@ dependencies = [
"libloading",
]
[[package]]
name = "dodrio"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7593dfc68e57dc1d058ada0f151ba07f4b05183c4da4c4df8ff651a81ef0fab"
dependencies = [
"bumpalo 2.6.0",
"cfg-if 0.1.10",
"fxhash",
"js-sys",
"longest-increasing-subsequence",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "downcast-rs"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "dwrote"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b"
dependencies = [
"lazy_static",
"libc",
"winapi",
"wio",
]
[[package]]
name = "either"
version = "1.6.1"
@ -646,16 +570,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "expat-sys"
version = "2.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa"
dependencies = [
"cmake",
"pkg-config",
]
[[package]]
name = "fern"
version = "0.6.0"
@ -666,6 +580,18 @@ dependencies = [
"log",
]
[[package]]
name = "filetime"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "flate2"
version = "1.0.22"
@ -678,43 +604,12 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "float-ord"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "font-kit"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c9a156ec38864999bc9c4156e5f3b50224d4a5578028a64e5a3875caa9ee28"
dependencies = [
"bitflags",
"byteorder",
"core-foundation 0.9.2",
"core-graphics 0.22.3",
"core-text",
"dirs-next",
"dwrote",
"float-ord",
"freetype",
"lazy_static",
"libc",
"log",
"pathfinder_geometry",
"pathfinder_simd",
"servo-fontconfig",
"walkdir",
"winapi",
]
[[package]]
name = "foreign-types"
version = "0.3.2"
@ -740,32 +635,11 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "freetype"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee38378a9e3db1cc693b4f88d166ae375338a0ff75cb8263e1c601d51f35dc6"
dependencies = [
"freetype-sys",
"libc",
]
[[package]]
name = "freetype-sys"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a"
dependencies = [
"cmake",
"libc",
"pkg-config",
]
[[package]]
name = "futures"
version = "0.3.19"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e"
dependencies = [
"futures-channel",
"futures-core",
@ -778,9 +652,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.19"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
dependencies = [
"futures-core",
"futures-sink",
@ -788,15 +662,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.19"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
[[package]]
name = "futures-executor"
version = "0.3.19"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
dependencies = [
"futures-core",
"futures-task",
@ -806,15 +680,15 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.19"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
[[package]]
name = "futures-macro"
version = "0.3.19"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c"
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
dependencies = [
"proc-macro2",
"quote",
@ -823,21 +697,21 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.19"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
[[package]]
name = "futures-task"
version = "0.3.19"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
[[package]]
name = "futures-util"
version = "0.3.19"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
dependencies = [
"futures-channel",
"futures-core",
@ -933,7 +807,7 @@ dependencies = [
"android_glue",
"cgl",
"cocoa",
"core-foundation 0.9.2",
"core-foundation 0.9.3",
"glutin_egl_sys",
"glutin_emscripten_sys",
"glutin_gles2_sys",
@ -1106,13 +980,12 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "iced"
version = "0.3.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
source = "git+https://github.com/hecrj/iced.git#313aff573433d9a4bc750285104c069fca0a566c"
dependencies = [
"iced_core",
"iced_futures",
"iced_glow",
"iced_glutin",
"iced_web",
"iced_wgpu",
"iced_winit",
"thiserror",
@ -1121,25 +994,27 @@ dependencies = [
[[package]]
name = "iced_core"
version = "0.4.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
source = "git+https://github.com/hecrj/iced.git#313aff573433d9a4bc750285104c069fca0a566c"
dependencies = [
"bitflags",
"wasm-timer",
]
[[package]]
name = "iced_futures"
version = "0.3.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
source = "git+https://github.com/hecrj/iced.git#313aff573433d9a4bc750285104c069fca0a566c"
dependencies = [
"futures",
"log",
"wasm-bindgen-futures",
"wasm-timer",
]
[[package]]
name = "iced_glow"
version = "0.2.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
source = "git+https://github.com/hecrj/iced.git#313aff573433d9a4bc750285104c069fca0a566c"
dependencies = [
"bytemuck",
"euclid",
@ -1154,7 +1029,7 @@ dependencies = [
[[package]]
name = "iced_glutin"
version = "0.2.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
source = "git+https://github.com/hecrj/iced.git#313aff573433d9a4bc750285104c069fca0a566c"
dependencies = [
"glutin",
"iced_graphics",
@ -1165,10 +1040,9 @@ dependencies = [
[[package]]
name = "iced_graphics"
version = "0.2.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
source = "git+https://github.com/hecrj/iced.git#313aff573433d9a4bc750285104c069fca0a566c"
dependencies = [
"bytemuck",
"font-kit",
"glam",
"iced_native",
"iced_style",
@ -1179,7 +1053,7 @@ dependencies = [
[[package]]
name = "iced_native"
version = "0.4.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
source = "git+https://github.com/hecrj/iced.git#313aff573433d9a4bc750285104c069fca0a566c"
dependencies = [
"iced_core",
"iced_futures",
@ -1192,32 +1066,15 @@ dependencies = [
[[package]]
name = "iced_style"
version = "0.3.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
source = "git+https://github.com/hecrj/iced.git#313aff573433d9a4bc750285104c069fca0a566c"
dependencies = [
"iced_core",
]
[[package]]
name = "iced_web"
version = "0.4.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
dependencies = [
"base64",
"dodrio",
"iced_core",
"iced_futures",
"iced_style",
"num-traits",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "iced_wgpu"
version = "0.4.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
source = "git+https://github.com/hecrj/iced.git#313aff573433d9a4bc750285104c069fca0a566c"
dependencies = [
"bitflags",
"bytemuck",
@ -1236,13 +1093,14 @@ dependencies = [
[[package]]
name = "iced_winit"
version = "0.3.0"
source = "git+https://github.com/hecrj/iced.git#c75ed37148b019358b0297171cf31b2577eeb9ae"
source = "git+https://github.com/hecrj/iced.git#313aff573433d9a4bc750285104c069fca0a566c"
dependencies = [
"iced_futures",
"iced_graphics",
"iced_native",
"log",
"thiserror",
"web-sys",
"winapi",
"window_clipboard",
"winit",
@ -1347,9 +1205,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.116"
version = "0.2.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "565dbd88872dbe4cc8a46e527f26483c1d1f7afa6b884a3bd6cd893d4f98da74"
checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c"
[[package]]
name = "libloading"
@ -1385,12 +1243,6 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "longest-increasing-subsequence"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86"
[[package]]
name = "malloc_buf"
version = "0.0.6"
@ -1744,40 +1596,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "pathfinder_geometry"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3"
dependencies = [
"log",
"pathfinder_simd",
]
[[package]]
name = "pathfinder_simd"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39fe46acc5503595e5949c17b818714d26fdf9b4920eacf3b2947f0199f4a6ff"
dependencies = [
"rustc_version",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "pin-project-lite"
version = "0.2.8"
@ -1968,6 +1792,15 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157"
[[package]]
name = "retry"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac95c60a949a63fd2822f4964939662d8f2c16c4fa0624fd954bc6e703b9a3f6"
dependencies = [
"rand",
]
[[package]]
name = "ring"
version = "0.16.20"
@ -1989,15 +1822,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc_version"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
dependencies = [
"semver",
]
[[package]]
name = "rustls"
version = "0.20.2"
@ -2016,15 +1840,6 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
@ -2047,24 +1862,6 @@ dependencies = [
"untrusted",
]
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
[[package]]
name = "serde"
version = "1.0.136"
@ -2096,27 +1893,6 @@ dependencies = [
"serde",
]
[[package]]
name = "servo-fontconfig"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c"
dependencies = [
"libc",
"servo-fontconfig-sys",
]
[[package]]
name = "servo-fontconfig-sys"
version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388"
dependencies = [
"expat-sys",
"freetype-sys",
"pkg-config",
]
[[package]]
name = "shared_library"
version = "0.1.9"
@ -2256,6 +2032,17 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tar"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
dependencies = [
"filetime",
"libc",
"xattr",
]
[[package]]
name = "termcolor"
version = "1.1.2"
@ -2338,27 +2125,24 @@ dependencies = [
[[package]]
name = "uad_gui"
version = "0.4.1"
version = "0.3.1"
dependencies = [
"chrono",
"dirs",
"fern",
"flate2",
"iced",
"log",
"regex",
"retry",
"serde",
"serde_json",
"static_init",
"tar",
"toml",
"ureq",
]
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unicode-bidi"
version = "0.3.7"
@ -2376,9 +2160,9 @@ dependencies = [
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]]
name = "unicode-width"
@ -2435,17 +2219,6 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
@ -2468,7 +2241,7 @@ version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca"
dependencies = [
"bumpalo 3.9.1",
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
@ -2518,6 +2291,21 @@ version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
[[package]]
name = "wasm-timer"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
dependencies = [
"futures",
"js-sys",
"parking_lot",
"pin-utils",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "wayland-client"
version = "0.29.4"
@ -2794,7 +2582,7 @@ source = "git+https://github.com/iced-rs/winit?rev=02a12380960cec2f351c09a33d6a7
dependencies = [
"bitflags",
"cocoa",
"core-foundation 0.9.2",
"core-foundation 0.9.3",
"core-graphics 0.22.3",
"core-video-sys",
"dispatch",
@ -2819,15 +2607,6 @@ dependencies = [
"x11-dl",
]
[[package]]
name = "wio"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
dependencies = [
"winapi",
]
[[package]]
name = "x11-dl"
version = "2.19.1"
@ -2851,6 +2630,15 @@ dependencies = [
"winapi-wsapoll",
]
[[package]]
name = "xattr"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c"
dependencies = [
"libc",
]
[[package]]
name = "xcursor"
version = "0.3.4"

View file

@ -12,9 +12,11 @@ categories = ["gui"]
edition = "2021"
[features]
default = ["wgpu"]
default = ["wgpu", "self-update"]
wgpu = [] # iced/wgpu is default
glow = ["iced/glow"] # OpenGL support
self-update = ["flate2", "tar", "retry"]
no-self-update = []
[dependencies]
iced = { git = "https://github.com/hecrj/iced.git" }
@ -28,6 +30,11 @@ regex = "^1.5"
toml = "^0"
dirs = "^4.0"
ureq = { version = "*", features = ["json"] }
retry = { version = "^1.0", optional = true }
[target.'cfg(not(target_os = "windows"))'.dependencies]
flate2 = { version = "^1", optional = true }
tar = { version = "^0", optional = true }
[profile.release]
opt-level = "s"

View file

@ -2,4 +2,5 @@ pub mod config;
pub mod sync;
pub mod theme;
pub mod uad_lists;
pub mod update;
pub mod utils;

297
src/core/update.rs Normal file
View file

@ -0,0 +1,297 @@
use serde::Deserialize;
#[cfg(feature = "self-update")]
use {
retry::{delay::Fibonacci, retry, OperationResult},
std::fs,
std::io,
std::io::copy,
std::path::Path,
std::path::PathBuf,
};
#[derive(Debug, Deserialize, Clone)]
pub struct Release {
pub tag_name: String,
pub assets: Vec<ReleaseAsset>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct ReleaseAsset {
pub name: String,
#[serde(rename = "browser_download_url")]
pub download_url: String,
}
#[derive(Default, Debug, Clone)]
pub struct SelfUpdateState {
pub latest_release: Option<Release>,
pub status: SelfUpdateStatus,
}
#[derive(Debug, PartialEq, Clone)]
pub enum SelfUpdateStatus {
Updating,
Checking,
Done,
Failed,
}
impl Default for SelfUpdateStatus {
fn default() -> Self {
SelfUpdateStatus::Checking
}
}
impl std::fmt::Display for SelfUpdateStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
SelfUpdateStatus::Checking => "Checking updates...",
SelfUpdateStatus::Updating => "Updating...",
SelfUpdateStatus::Failed => "Failed to check update!",
SelfUpdateStatus::Done => "Done",
};
write!(f, "{}", s)
}
}
/// Download a file from the internet
#[cfg(feature = "self-update")]
pub async fn download_file<T: ToString>(url: T, dest_file: PathBuf) -> Result<(), String> {
let url = url.to_string();
debug!("downloading file from {}", &url);
match ureq::get(&url).call() {
Ok(res) => {
let mut file = fs::File::create(&dest_file).unwrap();
if let Err(e) = copy(&mut res.into_reader(), &mut file) {
return Err(e.to_string());
}
}
Err(e) => return Err(e.to_string()),
}
Ok(())
}
/// Downloads the latest release file that matches `bin_name`, renames the current
/// executable to a temp path, renames the new version as the original file name,
/// then returns both the original file name (new version) and temp path (old version)
#[cfg(feature = "self-update")]
pub async fn download_update_to_temp_file(
bin_name: String,
release: Release,
) -> Result<(PathBuf, PathBuf), ()> {
let current_bin_path = std::env::current_exe().unwrap();
// Path to download the new version to
let download_path = current_bin_path
.parent()
.unwrap()
.join(&format!("tmp_{}", bin_name));
// Path to temporarily force rename current process to, se we can then
// rename `download_path` to `current_bin_path` and then launch new version
// cleanly as `current_bin_path`
let tmp_path = current_bin_path
.parent()
.unwrap()
.join(&format!("tmp2_{}", bin_name));
// MacOS and Linux release are gziped tarball
#[cfg(not(target_os = "windows"))]
{
let asset_name = format!("{}.tar.gz", bin_name);
let asset = release
.assets
.iter()
.find(|a| a.name == asset_name)
.cloned()
.unwrap();
let archive_path = current_bin_path.parent().unwrap().join(&asset_name);
if let Err(e) = download_file(asset.download_url, archive_path.clone()).await {
error!("Couldn't download UAD update: {}", e);
return Err(());
}
if extract_binary_from_tar(&archive_path, &download_path).is_err() {
error!("Couldn't extract UAD release tarball");
return Err(());
}
std::fs::remove_file(&archive_path).unwrap();
}
// For Windows we download the new binary directly
#[cfg(target_os = "windows")]
{
let asset = release
.assets
.iter()
.find(|a| a.name == bin_name)
.cloned()
.unwrap();
if let Err(e) = download_file(asset.download_url, download_path.clone()).await {
error!("Couldn't download UAD update: {}", e);
return Err(());
}
}
// Make the file executable
#[cfg(not(target_os = "windows"))]
{
use std::os::unix::fs::PermissionsExt;
let mut permissions = fs::metadata(&download_path).unwrap().permissions();
permissions.set_mode(0o755);
if let Err(e) = fs::set_permissions(&download_path, permissions) {
error!("[SelfUpdate] Couldn't set permission to temp file: {}", e);
return Err(());
}
}
if let Err(e) = rename(&current_bin_path, &tmp_path) {
error!("[SelfUpdate] Couldn't rename binary path: {}", e);
return Err(());
}
if let Err(e) = rename(&download_path, &current_bin_path) {
error!("[SelfUpdate] Couldn't rename binary path: {}", e);
return Err(());
}
Ok((current_bin_path, tmp_path))
}
#[cfg(not(feature = "self-update"))]
pub fn get_latest_release() -> Result<Option<Release>, ()> {
Ok(None)
}
// UAD only has pre-releases so we can't use
// https://api.github.com/repos/0x192/universal-android-debloater/releases/latest
// to only get the latest release
#[cfg(feature = "self-update")]
pub fn get_latest_release() -> Result<Option<Release>, ()> {
debug!("Checking for UAD update");
match ureq::get("https://api.github.com/repos/0x192/universal-android-debloater/releases")
.call()
{
Ok(res) => {
let release: Release =
serde_json::from_value(res.into_json::<serde_json::Value>().unwrap()[0].clone())
.unwrap();
if release.tag_name.as_str() > env!("CARGO_PKG_VERSION") {
Ok(Some(release))
} else {
Ok(None)
}
}
Err(_) => {
debug!("Failed to check UAD update");
Err(())
}
}
}
/// Extracts the binary from a `tar.gz` archive to temp_file path
#[cfg(feature = "self-update")]
#[cfg(not(target_os = "windows"))]
pub fn extract_binary_from_tar(archive_path: &Path, temp_file: &Path) -> Result<(), ()> {
use flate2::read::GzDecoder;
use std::fs::File;
use tar::Archive;
let mut archive = Archive::new(GzDecoder::new(File::open(&archive_path).unwrap()));
let mut temp_file = File::create(temp_file).unwrap();
for file in archive.entries().unwrap() {
let mut file = file.unwrap();
let path = file.path().unwrap();
if path.to_str().is_some() {
io::copy(&mut file, &mut temp_file).unwrap();
return Ok(());
}
}
Err(())
}
/// Hardcoded binary names for each compilation target
/// that gets published to the Github Release
#[cfg(feature = "self-update")]
pub const fn bin_name() -> &'static str {
#[cfg(target_os = "windows")]
{
"uad_gui.exe"
}
#[cfg(target_os = "macos")]
{
"uad_gui-macos"
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
{
"uad_gui-linux"
}
}
/// Rename a file or directory to a new name, retrying if the operation fails because of permissions
///
/// Will retry for ~30 seconds with longer and longer delays between each, to allow for virus scan
/// and other automated operations to complete.
#[cfg(feature = "self-update")]
pub fn rename<F, T>(from: F, to: T) -> Result<(), String>
where
F: AsRef<Path>,
T: AsRef<Path>,
{
// 21 Fibonacci steps starting at 1 ms is ~28 seconds total
// See https://github.com/rust-lang/rustup/pull/1873 where this was used by Rustup to work around
// virus scanning file locks
let from = from.as_ref();
let to = to.as_ref();
retry(Fibonacci::from_millis(1).take(21), || {
match fs::rename(from, to) {
Ok(_) => OperationResult::Ok(()),
Err(e) => match e.kind() {
io::ErrorKind::PermissionDenied => OperationResult::Retry(e),
_ => OperationResult::Err(e),
},
}
})
.map_err(|e| e.to_string())
}
/// Remove a file, retrying if the operation fails because of permissions
///
/// Will retry for ~30 seconds with longer and longer delays between each, to allow for virus scan
/// and other automated operations to complete.
#[cfg(feature = "self-update")]
pub fn remove_file<P>(path: P) -> Result<(), String>
where
P: AsRef<Path>,
{
// 21 Fibonacci steps starting at 1 ms is ~28 seconds total
// See https://github.com/rust-lang/rustup/pull/1873 where this was used by Rustup to work around
// virus scanning file locks
let path = path.as_ref();
retry(
Fibonacci::from_millis(1).take(21),
|| match fs::remove_file(path) {
Ok(_) => OperationResult::Ok(()),
Err(e) => match e.kind() {
io::ErrorKind::PermissionDenied => OperationResult::Retry(e),
_ => OperationResult::Err(e),
},
},
)
.map_err(|e| e.to_string())
}

View file

@ -5,6 +5,7 @@ pub mod widgets;
pub use crate::core::sync::{get_device_list, Phone};
use crate::core::uad_lists::load_debloat_lists;
pub use crate::core::uad_lists::Package;
use crate::core::update::{get_latest_release, SelfUpdateState, SelfUpdateStatus};
use crate::core::utils::icon;
use iced::{
button, pick_list, window::Settings as Window, Alignment, Application, Button, Column, Command,
@ -12,6 +13,7 @@ use iced::{
};
use std::collections::HashMap;
use std::env;
use std::path::PathBuf;
pub use views::about::{About as AboutView, Message as AboutMessage};
pub use views::list::{
List as AppsView, LoadingState as ListLoadingState, Message as AppsMessage, State as ListState,
@ -25,6 +27,9 @@ pub const ICONS: Font = Font::External {
bytes: include_bytes!("../../resources/assets/icons.ttf"),
};
#[cfg(feature = "self-update")]
use crate::core::update::{bin_name, download_update_to_temp_file, remove_file};
#[derive(Debug, Clone)]
pub enum View {
List,
@ -68,6 +73,7 @@ pub enum Message {
UadListsDownloaded(HashMap<String, Package>),
InitList,
InitDevice(Vec<Phone>),
_NewReleaseDownloaded(Result<(PathBuf, PathBuf), ()>),
}
impl Application for UadGui {
@ -81,6 +87,7 @@ impl Application for UadGui {
Command::batch([
Command::perform(Self::download_uad_list(), |_| Message::InitList),
Command::perform(get_device_list(), Message::InitDevice),
Command::perform(Self::send_self_update_message(), Message::SettingsAction),
]),
)
}
@ -153,7 +160,8 @@ impl Application for UadGui {
}
Message::AboutPressed => {
self.view = View::About;
Command::none()
self.settings_view.self_update_state = SelfUpdateState::default();
Command::perform(Self::send_self_update_message(), Message::SettingsAction)
}
Message::SettingsPressed => {
self.view = View::Settings;
@ -179,6 +187,36 @@ impl Application for UadGui {
AboutMessage::UpdateUadLists => {
Command::perform(Self::download_uad_list(), |_| Message::InitList)
}
AboutMessage::DoSelfUpdate => {
#[cfg(feature = "self-update")]
if self
.settings_view
.self_update_state
.latest_release
.is_some()
{
self.settings_view.self_update_state.status =
SelfUpdateStatus::Updating;
self.apps_view.state =
ListState::Loading(ListLoadingState::_UpdatingUad);
let bin_name = bin_name().to_owned();
let release = self
.settings_view
.self_update_state
.latest_release
.as_ref()
.unwrap()
.clone();
Command::perform(
download_update_to_temp_file(bin_name, release),
Message::_NewReleaseDownloaded,
)
} else {
Command::none()
}
#[cfg(not(feature = "self-update"))]
Command::none()
}
_ => Command::none(),
}
}
@ -190,21 +228,93 @@ impl Application for UadGui {
Message::AppsAction,
)
}
Message::_NewReleaseDownloaded(_res) => {
debug!("UAD update has been download!");
#[cfg(feature = "self-update")]
match _res {
Ok((relaunch_path, cleanup_path)) => {
// Remove first arg, which is path to binary. We don't use this first
// arg as binary path because it's not reliable, per the docs.
let mut args = std::env::args();
args.next();
let mut args: Vec<_> = args.collect();
// Remove the `--self-update-temp` arg from args if it exists,
// since we need to pass it cleanly. Otherwise new process will
// fail during arg parsing.
if let Some(idx) = args.iter().position(|a| a == "--self-update-temp") {
args.remove(idx);
// Remove path passed after this arg
args.remove(idx);
}
match std::process::Command::new(&relaunch_path)
.args(args)
.arg("--self-update-temp")
.arg(&cleanup_path)
.spawn()
{
Ok(_) => {
if let Err(e) = remove_file(cleanup_path) {
error!("Could not remove temp update file: {}", e);
}
std::process::exit(0)
}
Err(error) => {
if let Err(e) = remove_file(cleanup_path) {
error!("Could not remove temp update file: {}", e);
}
error!("Failed to update UAD: {}", error)
}
}
}
Err(()) => error!("Failed to update UAD!"),
}
Command::none()
}
}
}
fn view(&mut self) -> Element<Message> {
let apps_btn = Button::new(&mut self.apps_btn, Text::new("Apps"))
.on_press(Message::AppsPress)
.padding(5)
.style(style::PrimaryButton(self.settings_view.theme.palette));
let apps_refresh_btn = Button::new(&mut self.apps_refresh_btn, refresh_icon())
.on_press(Message::RefreshButtonPressed)
.padding(5)
.style(style::RefreshButton(self.settings_view.theme.palette));
let uad_version = Text::new(env!("CARGO_PKG_VERSION"));
let uad_version_text = if let Some(r) = &self.settings_view.self_update_state.latest_release
{
if self.settings_view.self_update_state.status == SelfUpdateStatus::Updating {
Text::new("Updating please wait...")
.color(self.settings_view.theme.palette.normal.surface)
} else {
Text::new(format!(
"New UAD version available {} -> {}",
env!("CARGO_PKG_VERSION"),
r.tag_name
))
.color(self.settings_view.theme.palette.normal.surface)
}
} else {
Text::new(env!("CARGO_PKG_VERSION"))
};
let apps_btn = if self
.settings_view
.self_update_state
.latest_release
.is_some()
{
Button::new(&mut self.apps_btn, Text::new("Update"))
.on_press(Message::AboutAction(AboutMessage::DoSelfUpdate))
.padding(5)
.style(style::SelfUpdateButton(self.settings_view.theme.palette))
} else {
Button::new(&mut self.apps_btn, Text::new("Apps"))
.on_press(Message::AppsPress)
.padding(5)
.style(style::PrimaryButton(self.settings_view.theme.palette))
};
let about_btn = Button::new(&mut self.about_btn, Text::new("About"))
.on_press(Message::AboutPressed)
@ -232,7 +342,7 @@ impl Application for UadGui {
.push(apps_refresh_btn)
.push(device_picklist)
.push(Space::new(Length::Fill, Length::Shrink))
.push(uad_version)
.push(uad_version_text)
.push(apps_btn)
.push(about_btn)
.push(settings_btn),
@ -243,7 +353,7 @@ impl Application for UadGui {
.push(apps_refresh_btn)
.push(Text::new("no devices/emulators found"))
.push(Space::new(Length::Fill, Length::Shrink))
.push(uad_version)
.push(uad_version_text)
.push(apps_btn)
.push(about_btn)
.push(settings_btn),
@ -308,6 +418,10 @@ impl UadGui {
pub async fn download_uad_list() -> Message {
Message::InitList
}
pub async fn send_self_update_message() -> SettingsMessage {
SettingsMessage::GetLatestRelease(get_latest_release())
}
}
fn refresh_icon() -> Text {

View file

@ -77,6 +77,33 @@ impl button::StyleSheet for UnavailableButton {
}
}
pub struct SelfUpdateButton(pub ColorPalette);
impl button::StyleSheet for SelfUpdateButton {
fn active(&self) -> button::Style {
button::Style {
border_color: Color {
a: 0.5,
..self.0.bright.secondary
},
border_width: 1.0,
border_radius: 2.0,
text_color: self.0.bright.secondary,
..button::Style::default()
}
}
fn hovered(&self) -> button::Style {
button::Style {
background: Some(Background::Color(Color {
a: 0.25,
..self.0.normal.surface
})),
text_color: self.0.bright.secondary,
..self.active()
}
}
}
pub struct RefreshButton(pub ColorPalette);
impl button::StyleSheet for RefreshButton {
fn active(&self) -> button::Style {

View file

@ -5,6 +5,9 @@ use crate::CACHE_DIR;
use iced::{button, Alignment, Button, Column, Container, Element, Length, Row, Space, Text};
use std::path::PathBuf;
#[cfg(feature = "self-update")]
use crate::core::update::SelfUpdateStatus;
#[derive(Default, Debug, Clone)]
pub struct About {
website_btn: button::State,
@ -12,12 +15,14 @@ pub struct About {
wiki_btn: button::State,
log_btn: button::State,
lists_btn: button::State,
_self_update_btn: button::State,
}
#[derive(Debug, Clone)]
pub enum Message {
UrlPressed(PathBuf),
UpdateUadLists,
DoSelfUpdate,
}
impl About {
@ -29,6 +34,9 @@ impl About {
Message::UpdateUadLists => {
// Action is taken by UadGui update()
}
Message::DoSelfUpdate => {
// Action is taken by UadGui update()
}
}
}
pub fn view(&mut self, settings: &Settings) -> Element<Message> {
@ -43,7 +51,8 @@ impl About {
.style(style::NavigationContainer(settings.theme.palette));
let date = last_modified_date(CACHE_DIR.join("uad_lists.json"));
let uad_list_text = Text::new(format!("Documentation: v{}", date.format("%Y%m%d")));
let uad_list_text = Text::new(format!("Documentation: v{}", date.format("%Y%m%d")))
.width(Length::Units(250));
let last_update_text = Text::new(format!("(last was {})", format_diff_time_from_now(date)))
.color(settings.theme.palette.normal.surface);
let uad_lists_btn = Button::new(&mut self.lists_btn, Text::new("Update"))
@ -51,14 +60,69 @@ impl About {
.padding(5)
.style(style::PrimaryButton(settings.theme.palette));
#[cfg(feature = "self-update")]
let self_update_btn = Button::new(&mut self._self_update_btn, Text::new("Update"))
.on_press(Message::DoSelfUpdate)
.padding(5)
.style(style::PrimaryButton(settings.theme.palette));
#[cfg(feature = "self-update")]
let uad_version_text = Text::new(format!("UAD version: v{}", env!("CARGO_PKG_VERSION")))
.width(Length::Units(250));
#[cfg(feature = "self-update")]
let self_update_text = match &settings.self_update_state.latest_release {
Some(r) => {
if settings.self_update_state.status == SelfUpdateStatus::Updating {
settings.self_update_state.status.to_string()
} else {
format!("(v{} available)", r.tag_name)
}
}
None => {
if settings.self_update_state.status == SelfUpdateStatus::Done {
"(No update available)".to_string()
} else {
settings.self_update_state.status.to_string()
}
}
};
#[cfg(feature = "self-update")]
let last_self_update_text =
Text::new(self_update_text).color(settings.theme.palette.normal.surface);
#[cfg(feature = "self-update")]
let self_update_row = Row::new()
.align_items(Alignment::Center)
.spacing(10)
.width(iced::Length::Units(550))
.push(uad_version_text)
.push(self_update_btn)
.push(last_self_update_text);
let uad_list_row = Row::new()
.align_items(Alignment::Center)
.spacing(10)
.width(iced::Length::Units(550))
.push(uad_list_text)
.push(uad_lists_btn)
.push(last_update_text);
let update_container = Container::new(uad_list_row)
#[cfg(feature = "self-update")]
let update_column = Column::new()
.align_items(Alignment::Center)
.spacing(10)
.push(uad_list_row)
.push(self_update_row);
#[cfg(not(feature = "self-update"))]
let update_column = Column::new()
.align_items(Alignment::Center)
.spacing(10)
.push(uad_list_row);
let update_container = Container::new(update_column)
.width(Length::Fill)
.center_x()
.padding(10)

View file

@ -34,6 +34,7 @@ pub enum Action {
pub enum LoadingState {
DownloadingList,
LoadingPackages,
_UpdatingUad,
}
#[derive(Debug, Clone, PartialEq)]
@ -351,6 +352,10 @@ impl List {
let text = "Pulling packages from the phone. Please wait...";
waiting_view(settings, text, None)
}
State::Loading(LoadingState::_UpdatingUad) => {
let text = "Updating UAD. Please wait...";
waiting_view(settings, text, None)
}
State::Ready => {
let search_packages = TextInput::new(
&mut self.search_input,

View file

@ -1,6 +1,7 @@
use crate::core::config::Config;
use crate::core::sync::{get_android_sdk, Phone as CorePhone};
use crate::core::theme::Theme;
use crate::core::update::{Release, SelfUpdateState, SelfUpdateStatus};
use crate::core::utils::{open_url, string_to_theme};
use crate::gui::style;
use crate::IN_FILE_CONFIGURATION;
@ -16,6 +17,7 @@ pub struct Settings {
pub theme: Theme,
theme_picklist: pick_list::State<Theme>,
unavailable_btn: button::State,
pub self_update_state: SelfUpdateState,
}
#[derive(Debug, Clone)]
@ -42,6 +44,7 @@ impl Default for Settings {
theme: string_to_theme(IN_FILE_CONFIGURATION.theme.clone()),
theme_picklist: pick_list::State::default(),
unavailable_btn: button::State::default(),
self_update_state: SelfUpdateState::default(),
}
}
}
@ -53,11 +56,21 @@ pub enum Message {
MultiUserMode(bool),
ApplyTheme(Theme),
UrlPressed(PathBuf),
GetLatestRelease(Result<Option<Release>, ()>),
}
impl Settings {
pub fn update(&mut self, phone: &CorePhone, msg: Message) {
match msg {
Message::GetLatestRelease(release) => {
match release {
Ok(r) => {
self.self_update_state.status = SelfUpdateStatus::Done;
self.self_update_state.latest_release = r
}
Err(_) => self.self_update_state.status = SelfUpdateStatus::Failed,
};
}
Message::ExpertMode(toggled) => {
info!(
"Expert mode {}",
@ -158,6 +171,7 @@ impl Settings {
)))
.height(Length::Units(22))
.style(style::UnavailableButton(self.theme.palette));
// Disabling package without root isn't really possible before Android Oreo (8.0)
// see https://github.com/0x192/universal-android-debloater/wiki/ADB-reference
let disable_mode_checkbox = Checkbox::new(