use crossterm::event::{KeyCode, KeyEvent};
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UpdateButton {
Primary,
Skip,
Disable,
}
pub const UPDATE_BUTTONS: [UpdateButton; 3] = [
UpdateButton::Primary,
UpdateButton::Skip,
UpdateButton::Disable,
];
#[derive(Debug, Clone)]
pub enum UpdatePopupPhase {
Prompt { selected: usize },
Installing,
Done { message: String, ok: bool },
}
#[derive(Debug, Clone)]
pub struct UpdatePopup {
pub info: crate::update::UpdateInfo,
pub phase: UpdatePopupPhase,
}
impl App {
pub(crate) async fn handle_update_popup_key(&mut self, key: KeyEvent) {
let phase = match &self.view.update_popup {
Some(popup) => popup.phase.clone(),
None => return,
};
match phase {
UpdatePopupPhase::Prompt { selected } => match key.code {
KeyCode::Left | KeyCode::Char('h') => self.move_update_selection(-1),
KeyCode::Right | KeyCode::Char('l') | KeyCode::Tab => self.move_update_selection(1),
KeyCode::Enter => {
self.activate_update_choice(UPDATE_BUTTONS[selected]).await;
}
KeyCode::Esc => self.view.update_popup = None,
_ => {}
},
UpdatePopupPhase::Installing => {}
UpdatePopupPhase::Done { .. } => {
if matches!(key.code, KeyCode::Enter | KeyCode::Esc) {
self.view.update_popup = None;
}
}
}
}
fn move_update_selection(&mut self, delta: i32) {
if let Some(UpdatePopup {
phase: UpdatePopupPhase::Prompt { selected },
..
}) = &mut self.view.update_popup
{
let count = UPDATE_BUTTONS.len() as i32;
*selected = (*selected as i32 + delta).rem_euclid(count) as usize;
}
}
async fn activate_update_choice(&mut self, button: UpdateButton) {
let info = match &self.view.update_popup {
Some(popup) => popup.info.clone(),
None => return,
};
match button {
UpdateButton::Primary if info.can_self_update => {
if let Some(popup) = &mut self.view.update_popup {
popup.phase = UpdatePopupPhase::Installing;
}
let tx = self.event_tx.clone();
tokio::spawn(async move {
let result = crate::update::perform_update(&info)
.await
.map_err(|e| e.to_string());
let _ = tx.send(AppEvent::UpdateInstalled(result)).await;
});
}
UpdateButton::Primary => self.view.update_popup = None,
UpdateButton::Skip => {
self.config.update.skip_version = info.latest.clone();
self.persist_update_config();
self.view.update_popup = None;
}
UpdateButton::Disable => {
self.config.update.check_on_startup = false;
self.persist_update_config();
self.view.update_popup = None;
}
}
}
fn persist_update_config(&self) {
if let Err(e) = config::app_config::save_update_config(&self.config.update) {
tracing::warn!("Failed to save update config: {}", e);
}
}
}