Better loading state management

- Dedicated state for the UadList (Downloading, Done, Failed)
- Some bugfixes introduced by previous commits (not in 0.4 release)
This commit is contained in:
w1nst0n 2022-04-03 01:11:30 +02:00
commit 18cefe3e80
No known key found for this signature in database
GPG key ID: 34D27465928A0A1D
5 changed files with 132 additions and 63 deletions

View file

@ -1,6 +1,6 @@
use crate::core::utils::{format_diff_time_from_now, last_modified_date};
use crate::CACHE_DIR;
/*use chrono::DateTime;
use chrono::Utc;*/
use retry::{delay::Fixed, retry, OperationResult};
use serde::Deserialize;
use serde_json;
use std::collections::HashMap;
@ -31,6 +31,31 @@ pub enum UadList {
Unlisted,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UadListState {
Downloading,
Done,
Failed,
}
impl Default for UadListState {
fn default() -> Self {
UadListState::Downloading
}
}
impl std::fmt::Display for UadListState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let date = last_modified_date(CACHE_DIR.join("uad_lists.json"));
let s = match self {
UadListState::Downloading => "Checking updates...".to_string(),
UadListState::Done => format!("Done (last was {})", format_diff_time_from_now(date)),
UadListState::Failed => "Failed to check update!".to_string(),
};
write!(f, "{}", s)
}
}
impl Default for UadList {
fn default() -> UadList {
UadList::All
@ -172,26 +197,32 @@ impl std::fmt::Display for Removal {
}
}
pub async fn load_debloat_lists(remote: bool) -> HashMap<String, Package> {
pub async fn load_debloat_lists(remote: bool) -> (Result<HashMap<String, Package>, ()>, bool) {
let cached_uad_lists: PathBuf = CACHE_DIR.join("uad_lists.json");
let mut error = false;
let list: Vec<Package> = if remote {
let req = ureq::get(
"https://raw.githubusercontent.com/0x192/universal-android-debloater/\
match retry(Fixed::from_millis(500).take(120), || {
match ureq::get(
"https://raw.githubusercontent.com/0x192/universal-android-debloater/\
main/resources/assets/uad_lists.json",
)
.call();
match req {
Ok(data) => {
let text = data.into_string().unwrap();
fs::write(cached_uad_lists, &text).expect("Unable to write file");
serde_json::from_str(&text).expect("Unable to parse")
}
Err(e) => {
warn!("Could not load remote debloat list: {}", e);
get_local_lists()
)
.call()
{
Ok(data) => {
let text = data.into_string().unwrap();
fs::write(cached_uad_lists.clone(), &text).expect("Unable to write file");
let list = serde_json::from_str(&text).expect("Unable to parse");
OperationResult::Ok(list)
}
Err(e) => {
warn!("Could not load remote debloat list: {}", e);
error = true;
OperationResult::Retry(Vec::<Package>::new())
}
}
}) {
Ok(list) => list,
Err(_) => vec![],
}
} else {
warn!("Could not load remote debloat list");
@ -204,7 +235,11 @@ pub async fn load_debloat_lists(remote: bool) -> HashMap<String, Package> {
let name = p.id.clone();
package_lists.insert(name, p);
}
package_lists
if error {
(Err(()), remote)
} else {
(Ok(package_lists), remote)
}
}
fn get_local_lists() -> Vec<Package> {

View file

@ -3,8 +3,8 @@ pub mod views;
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::uad_lists::{load_debloat_lists, UadListState};
use crate::core::update::{get_latest_release, SelfUpdateState, SelfUpdateStatus};
use crate::core::utils::{icon, perform_commands};
use iced::pure::widget::Text;
@ -70,7 +70,7 @@ pub enum Message {
SettingsAction(SettingsMessage),
RefreshButtonPressed,
RebootButtonPressed,
UadListsDownloaded(HashMap<String, Package>),
UadListsDownloaded((Result<HashMap<String, Package>, ()>, bool)),
InitList,
InitDevice(Vec<Phone>),
_NewReleaseDownloaded(Result<(PathBuf, PathBuf), ()>),
@ -99,25 +99,41 @@ impl Application for UadGui {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::InitList => {
debug!("Trying to download remote UAD list");
warn!("Trying to download remote UAD list");
self.apps_view.state = ListState::Loading(ListLoadingState::DownloadingList);
Command::perform(load_debloat_lists(true), Message::UadListsDownloaded)
}
Message::UadListsDownloaded(uad_lists) => {
self.apps_view.uad_lists = uad_lists;
if self.ready {
Command::perform(
Self::load_phone_packages(self.selected_device.clone().unwrap_or_default()),
Message::AppsAction,
)
} else {
self.ready = true;
self.apps_view.state = ListState::Loading(ListLoadingState::FindingPhones);
Message::UadListsDownloaded((uad_lists, _)) => match uad_lists {
Ok(list) => {
if !list.is_empty() {
self.apps_view.uad_lists = list;
}
self.settings_view.list_update_state = UadListState::Done;
if self.ready {
Command::perform(
Self::load_phone_packages(
self.selected_device.clone().unwrap_or_default(),
),
Message::AppsAction,
)
} else {
self.ready = true;
self.apps_view.state = ListState::Loading(ListLoadingState::FindingPhones);
Command::none()
}
}
Err(_) => {
self.settings_view.list_update_state = UadListState::Failed;
if let ListState::Ready = self.apps_view.state {
} else {
self.apps_view.state =
ListState::Loading(ListLoadingState::DownloadingList);
}
Command::none()
}
}
},
Message::InitDevice(device_list) => {
self.apps_view.state = ListState::Loading(ListLoadingState::LoadingPackages);
self.device_list = device_list;
self.settings_view.phone = SettingsPhone::default();
@ -141,7 +157,7 @@ impl Application for UadGui {
} else {
self.selected_device = None;
}
if self.ready {
if self.settings_view.list_update_state != UadListState::Downloading || self.ready {
Command::perform(
Self::load_phone_packages(self.selected_device.clone().unwrap_or_default()),
Message::AppsAction,
@ -160,14 +176,12 @@ impl Application for UadGui {
Message::RebootButtonPressed => {
self.apps_view.state = ListState::Loading(ListLoadingState::FindingPhones);
self.selected_device = None;
self.device_list = vec![];
self.ready = false;
Command::batch([
Command::perform(
perform_commands("reboot".to_string(), 0, "ADB".to_string()),
|_| Message::Nothing,
),
Command::perform(get_device_list(), Message::InitDevice),
])
Command::perform(
perform_commands("reboot".to_string(), 0, "ADB".to_string()),
|_| Message::Nothing,
)
}
Message::AppsPress => {
self.view = View::List;
@ -185,7 +199,7 @@ impl Application for UadGui {
Message::AppsAction(msg) => self
.apps_view
.update(
&self.settings_view.phone,
&mut self.settings_view,
&mut self.selected_device.clone().unwrap_or_default(),
msg,
)
@ -200,6 +214,7 @@ impl Application for UadGui {
match msg {
AboutMessage::UpdateUadLists => {
self.settings_view.list_update_state = UadListState::Downloading;
Command::perform(Self::download_uad_list(), |_| Message::InitList)
}
AboutMessage::DoSelfUpdate => {
@ -288,7 +303,7 @@ impl Application for UadGui {
}
Command::none()
}
Message::Nothing => Command::none(),
Message::Nothing => Command::perform(get_device_list(), Message::InitDevice),
}
}

View file

@ -1,4 +1,4 @@
use crate::core::utils::{format_diff_time_from_now, last_modified_date, open_url};
use crate::core::utils::{last_modified_date, open_url};
use crate::gui::style;
use crate::gui::views::settings::Settings;
use crate::CACHE_DIR;
@ -47,7 +47,7 @@ impl About {
let date = last_modified_date(CACHE_DIR.join("uad_lists.json"));
let uad_list_text =
text(format!("Documentation: v{}", date.format("%Y%m%d"))).width(Length::Units(250));
let last_update_text = text(format!("(last was {})", format_diff_time_from_now(date)))
let last_update_text = text(settings.list_update_state.to_string())
.color(settings.theme.palette.normal.surface);
let uad_lists_btn = button("Update")
.on_press(Message::UpdateUadLists)

View file

@ -1,6 +1,6 @@
use crate::core::sync::{action_handler, Phone, User};
use crate::core::uad_lists::{
load_debloat_lists, Opposite, Package, PackageState, Removal, UadList,
load_debloat_lists, Opposite, Package, PackageState, Removal, UadList, UadListState,
};
use crate::core::utils::{
export_selection, fetch_packages, import_selection, perform_commands, update_selection_count,
@ -9,7 +9,7 @@ use crate::gui::style;
use std::collections::HashMap;
use std::env;
use crate::gui::views::settings::{Phone as SettingsPhone, Settings};
use crate::gui::views::settings::Settings;
use crate::gui::widgets::package_row::{Message as RowMessage, PackageRow};
use iced::pure::{
button, column, container, pick_list, row, scrollable, text, text_input, Element,
@ -70,7 +70,7 @@ pub enum Message {
SearchInputChanged(String),
ToggleAllSelected(bool),
InitUadList(bool),
ListsIsInitialized(HashMap<String, Package>),
ListsIsInitialized((Result<HashMap<String, Package>, ()>, bool)),
LoadPackages,
ListSelected(UadList),
UserSelected(User),
@ -88,7 +88,7 @@ pub enum Message {
impl List {
pub fn update(
&mut self,
settings: &SettingsPhone,
settings: &mut Settings,
phone: &mut Phone,
message: Message,
) -> Command<Message> {
@ -96,18 +96,30 @@ impl List {
match message {
Message::Nothing => Command::none(),
Message::InitUadList(remote) => {
self.state = State::Loading(LoadingState::LoadingPackages);
self.state = State::Loading(LoadingState::FindingPhones);
if remote {
Command::perform(load_debloat_lists(true), Message::ListsIsInitialized)
} else {
Command::perform(load_debloat_lists(false), Message::ListsIsInitialized)
}
}
Message::ListsIsInitialized(uad_lists) => {
self.uad_lists = uad_lists;
env::set_var("ANDROID_SERIAL", phone.adb_id.clone());
Command::perform(Self::do_load_packages(), |_| Message::LoadPackages)
}
Message::ListsIsInitialized((uad_lists, remote)) => match uad_lists {
Ok(list) => {
if !remote {
settings.list_update_state = UadListState::Failed;
} else {
settings.list_update_state = UadListState::Done;
}
self.uad_lists = list;
if !phone.adb_id.is_empty() {
env::set_var("ANDROID_SERIAL", phone.adb_id.clone());
Command::perform(Self::do_load_packages(), |_| Message::LoadPackages)
} else {
Command::none()
}
}
Err(_) => Command::none(),
},
Message::LoadPackages => {
self.state = State::Loading(LoadingState::LoadingPackages);
self.selected_package_state = Some(PackageState::Enabled);
@ -186,7 +198,7 @@ impl List {
match row_message {
RowMessage::ToggleSelection(toggle) => {
if package.removal == Removal::Unsafe && !settings.expert_mode {
if package.removal == Removal::Unsafe && !settings.phone.expert_mode {
package.selected = false;
} else {
package.selected = toggle;
@ -208,8 +220,12 @@ impl List {
}
RowMessage::ActionPressed => {
let mut commands = vec![];
let actions =
action_handler(&self.selected_user.unwrap(), package, phone, settings);
let actions = action_handler(
&self.selected_user.unwrap(),
package,
phone,
&settings.phone,
);
for (i, action) in actions.into_iter().enumerate() {
// Only the first command can change the package state
@ -262,7 +278,7 @@ impl List {
&self.selected_user.unwrap(),
&self.phone_packages[*i_user][i],
phone,
settings,
&settings.phone,
);
for (j, action) in actions.into_iter().enumerate() {
// Only the first command can change the package state
@ -317,14 +333,14 @@ impl List {
let package = &mut self.phone_packages[*i_user][i];
update_selection_count(&mut self.selection, package.state, false);
if !settings.multi_user_mode {
package.state = package.state.opposite(settings.disable_mode);
if !settings.phone.multi_user_mode {
package.state = package.state.opposite(settings.phone.disable_mode);
package.selected = false;
} else {
for u in &phone.user_list {
self.phone_packages[u.index][i].state = self.phone_packages[u.index][i]
.state
.opposite(settings.disable_mode);
.opposite(settings.phone.disable_mode);
self.phone_packages[u.index][i].selected = false;
}
}

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::uad_lists::UadListState;
use crate::core::update::{Release, SelfUpdateState, SelfUpdateStatus};
use crate::core::utils::{open_url, string_to_theme};
use crate::gui::style;
@ -16,6 +17,7 @@ pub struct Settings {
pub phone: Phone,
pub theme: Theme,
pub self_update_state: SelfUpdateState,
pub list_update_state: UadListState,
}
#[derive(Debug, Clone)]
@ -41,6 +43,7 @@ impl Default for Settings {
phone: Phone::default(),
theme: string_to_theme(IN_FILE_CONFIGURATION.theme.clone()),
self_update_state: SelfUpdateState::default(),
list_update_state: UadListState::default(),
}
}
}