Skip to content

Commit

Permalink
Add confirmation prompt for closing (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
ifd3f committed May 7, 2024
1 parent 784d778 commit edd8b15
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 12 deletions.
33 changes: 31 additions & 2 deletions src/ui/fancy_ui/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,29 +113,54 @@ struct ComputedLayout {
progress: Rect,
graph: Rect,
args_display: Rect,
quit_modal: Rect,
}

impl From<Rect> for ComputedLayout {
fn from(value: Rect) -> Self {
fn from(area: Rect) -> Self {
let root = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(1),
Constraint::Min(10),
Constraint::Length(10),
])
.split(value);
.split(area);

let info_pane = root[2];

let quit_modal = centered_rect(area, 40, 4);

Self {
graph: root[1],
progress: root[0],
args_display: info_pane,
quit_modal,
}
}
}

/// Given an outer rect and desired inner rect dimensions, returns the inner rect.
fn centered_rect(r: Rect, w: u16, h: u16) -> Rect {
let popup_layout = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Fill(1),
Constraint::Length(h),
Constraint::Fill(1),
])
.split(r);

Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Fill(1),
Constraint::Length(w),
Constraint::Fill(1),
])
.split(popup_layout[1])[1]
}

pub fn draw(
state: &mut State,
terminal: &mut Terminal<impl ratatui::backend::Backend>,
Expand Down Expand Up @@ -184,6 +209,10 @@ pub fn draw(
} else {
f.render_widget(info_table, layout.args_display);
}

if let Some(qm) = state.quit_modal {
f.render_widget(qm, layout.quit_modal)
}
})?;
Ok(())
}
35 changes: 29 additions & 6 deletions src/ui/fancy_ui/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
writer_process::ipc::StatusMessage,
};

use super::widgets::SpeedChartState;
use super::widgets::{QuitModal, QuitModalResult, SpeedChartState};

#[derive(Debug, PartialEq, Clone)]
pub enum UIEvent {
Expand All @@ -23,6 +23,7 @@ pub struct State {
pub target_filename: String,
pub child: WriterState,
pub graph_state: SpeedChartState,
pub quit_modal: Option<QuitModal>,
}

impl State {
Expand All @@ -32,6 +33,7 @@ impl State {
target_filename: params.target.devnode.to_string_lossy().to_string(),
child: WriterState::initial(now, !params.compression.is_identity(), input_file_bytes),
graph_state: SpeedChartState::default(),
quit_modal: None,
}
}

Expand All @@ -51,13 +53,34 @@ impl State {
fn on_term_event(self, ev: Event) -> anyhow::Result<Self> {
match ev {
Event::Key(KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
kind: KeyEventKind::Press,
code,
modifiers,
..
}) => {
info!("Got CTRL-C, quitting");
Err(Quit)?
}) => self.handle_key_down((code, modifiers)),
_ => Ok(self),
}
}

fn handle_key_down(mut self, (kc, km): (KeyCode, KeyModifiers)) -> anyhow::Result<Self> {
if let Some(qm) = &self.quit_modal {
return match qm.handle_key_down(kc) {
Some(QuitModalResult::Quit) => Err(Quit.into()),
Some(QuitModalResult::Stay) => Ok(Self {
quit_modal: None,
..self
}),
None => Ok(self),
};
}

match (kc, km) {
(KeyCode::Char('c'), KeyModifiers::CONTROL)
| (KeyCode::Esc, _)
| (KeyCode::Char('q'), _) => {
info!("Got request to quit, spawning prompt");
self.quit_modal = Some(QuitModal::new());
Ok(self)
}
_ => Ok(self),
}
Expand Down
68 changes: 64 additions & 4 deletions src/ui/fancy_ui/widgets.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use std::time::Instant;

use bytesize::ByteSize;
use crossterm::event::KeyCode;
use ratatui::{
layout::{Alignment, Constraint, Rect},
style::{Color, Style},
style::{Color, Style, Stylize},
symbols,
text::Span,
widgets::{
Axis, Block, Borders, Cell, Chart, Dataset, Gauge, GraphType, Row, StatefulWidget, Table,
Widget,
Axis, Block, BorderType, Borders, Cell, Chart, Clear, Dataset, Gauge, GraphType, Paragraph,
Row, StatefulWidget, Table, Widget,
},
};

Expand Down Expand Up @@ -160,7 +161,11 @@ impl WriterProgressBar {
} => WriterProgressBar::from_simple(
write_hist.bytes_encountered(),
*total_write_bytes,
if error.is_some() { "Error!" } else { "Done!" },
if error.is_some() {
"Error!"
} else {
"Done! Press q to quit."
},
if error.is_some() {
Style::default().fg(Color::White).bg(Color::Red)
} else {
Expand Down Expand Up @@ -267,3 +272,58 @@ impl Widget for WritingInfoTable<'_> {
Widget::render(self.make_info_table(), area, buf)
}
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct QuitModal {
_private: (),
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum QuitModalResult {
/// Quit the program.
Quit,

/// Stay in the program.
Stay,
}

impl QuitModal {
pub fn new() -> Self {
Self { _private: () }
}

/// Handle a key down event. If this would conclude the modal, returns the result.
/// Otherwise, if an indecisive keystroke was detected and we are to stay inside the
/// modal, returns None.
pub fn handle_key_down(self, kc: KeyCode) -> Option<QuitModalResult> {
use KeyCode::*;
use QuitModalResult::*;
match kc {
Esc => Some(Stay),
Char('q') | Char('Q') => Some(Quit),
_ => None,
}
}
}

impl Widget for QuitModal {
fn render(self, area: Rect, buf: &mut ratatui::prelude::Buffer)
where
Self: Sized,
{
let prompt =
Paragraph::new("Are you sure you want to quit?\nPress q again to quit, ESC to stay")
.alignment(Alignment::Center)
.style(Style::new().yellow())
.block(
Block::new()
.bg(Color::Red)
.border_style(Style::new().white())
.border_type(BorderType::Plain)
.borders(Borders::ALL),
);

Clear.render(area, buf);
prompt.render(area, buf);
}
}

0 comments on commit edd8b15

Please sign in to comment.