-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(gtk): Separate state and event handling into their own modules
- Loading branch information
Showing
8 changed files
with
1,005 additions
and
853 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
mod recovery; | ||
mod release; | ||
mod scan; | ||
|
||
use crate::{errors::UnderlyingError, events::*, reboot}; | ||
|
||
use self::scan::scan; | ||
|
||
use num_traits::cast::FromPrimitive; | ||
use pop_upgrade::{ | ||
client::{Client, ReleaseInfo, Status}, | ||
daemon::DaemonStatus, | ||
release::RefreshOp, | ||
}; | ||
|
||
use std::sync::mpsc::{self, SyncSender}; | ||
|
||
/// Events sent to this widget's background thread. | ||
#[derive(Debug)] | ||
pub enum BackgroundEvent { | ||
DownloadUpgrade(ReleaseInfo), | ||
Finalize, | ||
GetStatus(DaemonStatus), | ||
IsActive(SyncSender<bool>), | ||
DismissNotification(bool), | ||
RefreshOS, | ||
RepoModify(Vec<Box<str>>, Vec<bool>), | ||
Reset, | ||
Scan, | ||
Shutdown, | ||
} | ||
|
||
pub fn run( | ||
receiver: mpsc::Receiver<BackgroundEvent>, | ||
send: impl Fn(UiEvent) + Send + Sync + 'static, | ||
) { | ||
let send: &dyn Fn(UiEvent) = &send; | ||
if let Ok(ref client) = Client::new() { | ||
while let Ok(event) = receiver.recv() { | ||
trace!("received BackgroundEvent: {:?}", event); | ||
match event { | ||
BackgroundEvent::DismissNotification(dismiss) => { | ||
let event = match client.dismiss_notification(dismiss) { | ||
Ok(dismissed) => UiEvent::Dismissed(dismissed), | ||
Err(why) => { | ||
UiEvent::Error(UiError::Dismiss(dismiss, UnderlyingError::Client(why))) | ||
} | ||
}; | ||
|
||
send(event) | ||
} | ||
|
||
BackgroundEvent::DownloadUpgrade(info) => { | ||
self::release::download(client, send, info); | ||
} | ||
|
||
BackgroundEvent::Finalize => match client.release_upgrade_finalize() { | ||
Ok(()) => reboot(), | ||
Err(why) => send(UiEvent::Error(UiError::Finalize(why))), | ||
}, | ||
|
||
BackgroundEvent::GetStatus(from) => { | ||
get_status(client, send, from); | ||
} | ||
|
||
BackgroundEvent::IsActive(tx) => { | ||
let _ = tx.send(client.status().is_ok()); | ||
} | ||
|
||
BackgroundEvent::RefreshOS => { | ||
refresh_os(client, send); | ||
} | ||
|
||
BackgroundEvent::RepoModify(failures, answers) => { | ||
repo_modify(client, send, failures, answers); | ||
} | ||
|
||
BackgroundEvent::Reset => { | ||
send(match client.reset() { | ||
Ok(()) => UiEvent::CancelledUpgrade, | ||
Err(why) => UiEvent::Error(UiError::Cancel(why)), | ||
}); | ||
} | ||
|
||
BackgroundEvent::Scan => scan(client, send), | ||
|
||
BackgroundEvent::Shutdown => { | ||
send(UiEvent::Shutdown); | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
fn get_status(client: &Client, send: &dyn Fn(UiEvent), from: DaemonStatus) { | ||
match from { | ||
DaemonStatus::RecoveryUpgrade => { | ||
let event = match client.recovery_upgrade_release_status() { | ||
Ok(status) => { | ||
if status.status == 0 { | ||
UiEvent::Completed(CompletedEvent::Recovery) | ||
} else { | ||
UiEvent::Error(UiError::Recovery(status.why.into())) | ||
} | ||
} | ||
Err(why) => UiEvent::Error(UiError::Recovery(why.into())), | ||
}; | ||
|
||
send(event); | ||
} | ||
DaemonStatus::ReleaseUpgrade => { | ||
let event = match client.release_upgrade_status() { | ||
Ok(status) => { | ||
if status.status == 0 { | ||
UiEvent::Completed(CompletedEvent::Download) | ||
} else { | ||
UiEvent::Error(UiError::Upgrade(status.why.into())) | ||
} | ||
} | ||
Err(why) => UiEvent::Error(UiError::Upgrade(why.into())), | ||
}; | ||
|
||
send(event); | ||
} | ||
_ => (), | ||
} | ||
} | ||
|
||
fn refresh_os(client: &Client, send: &dyn Fn(UiEvent)) { | ||
send(UiEvent::Initiated(InitiatedEvent::Refresh)); | ||
|
||
if let Err(why) = client.refresh_os(RefreshOp::Enable) { | ||
send(UiEvent::Error(UiError::Refresh(why.into()))); | ||
return; | ||
} | ||
|
||
send(UiEvent::Completed(CompletedEvent::Refresh)); | ||
} | ||
|
||
fn repo_modify( | ||
client: &Client, | ||
send: &dyn Fn(UiEvent), | ||
failures: Vec<Box<str>>, | ||
answers: Vec<bool>, | ||
) { | ||
let input = failures.into_iter().zip(answers.into_iter()); | ||
if let Err(why) = client.repo_modify(input) { | ||
send(UiEvent::Error(UiError::Repos(why.into()))); | ||
return; | ||
} | ||
|
||
send(UiEvent::UpgradeClicked); | ||
} | ||
|
||
fn status_changed(send: &dyn Fn(UiEvent), new_status: Status, expected: DaemonStatus) { | ||
let status = DaemonStatus::from_u8(new_status.status).expect("unknown daemon status value"); | ||
send(UiEvent::StatusChanged(expected, status, new_status.why)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
use crate::{ | ||
errors::UiError, | ||
events::{CompletedEvent, InitiatedEvent, ProgressEvent, UiEvent}, | ||
}; | ||
|
||
use super::status_changed; | ||
|
||
use pop_upgrade::{ | ||
client::{self, Client, Signal}, | ||
daemon::DaemonStatus, | ||
recovery::ReleaseFlags, | ||
}; | ||
|
||
pub fn upgrade(client: &Client, send: &dyn Fn(UiEvent), version: &str) -> bool { | ||
send(UiEvent::Initiated(InitiatedEvent::Recovery)); | ||
|
||
let arch = "nvidia"; | ||
let flags = ReleaseFlags::empty(); | ||
|
||
if let Err(why) = client.recovery_upgrade_release(version, arch, flags) { | ||
send(UiEvent::Error(UiError::Recovery(why.into()))); | ||
return false; | ||
} | ||
|
||
let error = &mut None; | ||
|
||
let _ = client.event_listen( | ||
DaemonStatus::RecoveryUpgrade, | ||
Client::recovery_upgrade_release_status, | ||
|status| status_changed(send, status, DaemonStatus::RecoveryUpgrade), | ||
|_client, signal| { | ||
match signal { | ||
Signal::RecoveryDownloadProgress(progress) => { | ||
send(UiEvent::Progress(ProgressEvent::Recovery( | ||
progress.progress, | ||
progress.total, | ||
))); | ||
} | ||
Signal::RecoveryResult(status) => { | ||
if status.status != 0 { | ||
*error = Some(status.why); | ||
} | ||
|
||
return Ok(client::Continue(false)); | ||
} | ||
_ => (), | ||
} | ||
|
||
Ok(client::Continue(true)) | ||
}, | ||
); | ||
|
||
if let Some(why) = error.take() { | ||
send(UiEvent::Error(UiError::Recovery(why.into()))); | ||
return false; | ||
} | ||
|
||
send(UiEvent::Completed(CompletedEvent::Recovery)); | ||
true | ||
} |
Oops, something went wrong.