summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormo8it <mo8it@proton.me>2024-04-07 19:05:29 +0200
committermo8it <mo8it@proton.me>2024-04-07 19:05:29 +0200
commit0a674a158da0d519f03a88bfabf31d98c0e064c6 (patch)
treeccc842e345d1992a972a1bc5245bc24f930d2bf1
parent3bd26c7a24a97f9b4b87c453fbdbb06fe9971920 (diff)
Separate UiState
-rw-r--r--src/list.rs144
-rw-r--r--src/list/state.rs145
2 files changed, 150 insertions, 139 deletions
diff --git a/src/list.rs b/src/list.rs
index c59b8d8..4d26702 100644
--- a/src/list.rs
+++ b/src/list.rs
@@ -4,148 +4,14 @@ use crossterm::{
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
ExecutableCommand,
};
-use ratatui::{
- backend::CrosstermBackend,
- layout::{Constraint, Rect},
- style::{Style, Stylize},
- text::Span,
- widgets::{Block, Borders, HighlightSpacing, Row, Table, TableState},
- Frame, Terminal,
-};
+use ratatui::{backend::CrosstermBackend, Terminal};
use std::io;
-use crate::{exercise::Exercise, state_file::StateFile};
-
-struct UiState<'a> {
- pub table: Table<'a>,
- selected: usize,
- table_state: TableState,
- last_ind: usize,
-}
-
-impl<'a> UiState<'a> {
- pub fn rows<'s, 'i>(
- state_file: &'s StateFile,
- exercises: &'a [Exercise],
- ) -> impl Iterator<Item = Row<'a>> + 'i
- where
- 's: 'i,
- 'a: 'i,
- {
- exercises
- .iter()
- .zip(state_file.progress())
- .enumerate()
- .map(|(ind, (exercise, done))| {
- let next = if ind == state_file.next_exercise_ind() {
- ">>>>".bold().red()
- } else {
- Span::default()
- };
-
- let exercise_state = if *done {
- "DONE".green()
- } else {
- "PENDING".yellow()
- };
-
- Row::new([
- next,
- exercise_state,
- Span::raw(&exercise.name),
- Span::raw(exercise.path.to_string_lossy()),
- ])
- })
- }
-
- pub fn new(state_file: &StateFile, exercises: &'a [Exercise]) -> Self {
- let header = Row::new(["Next", "State", "Name", "Path"]);
-
- let max_name_len = exercises
- .iter()
- .map(|exercise| exercise.name.len())
- .max()
- .unwrap_or(4) as u16;
-
- let widths = [
- Constraint::Length(4),
- Constraint::Length(7),
- Constraint::Length(max_name_len),
- Constraint::Fill(1),
- ];
-
- let rows = Self::rows(state_file, exercises);
+mod state;
- let table = Table::new(rows, widths)
- .header(header)
- .column_spacing(2)
- .highlight_spacing(HighlightSpacing::Always)
- .highlight_style(Style::new().bg(ratatui::style::Color::Rgb(50, 50, 50)))
- .highlight_symbol("🦀")
- .block(Block::default().borders(Borders::BOTTOM));
-
- let selected = 0;
- let table_state = TableState::default().with_selected(Some(selected));
- let last_ind = exercises.len() - 1;
-
- Self {
- table,
- selected,
- table_state,
- last_ind,
- }
- }
-
- fn select(&mut self, ind: usize) {
- self.selected = ind;
- self.table_state.select(Some(ind));
- }
-
- pub fn select_next(&mut self) {
- self.select(self.selected.saturating_add(1).min(self.last_ind));
- }
-
- pub fn select_previous(&mut self) {
- self.select(self.selected.saturating_sub(1));
- }
-
- #[inline]
- pub fn select_first(&mut self) {
- self.select(0);
- }
-
- #[inline]
- pub fn select_last(&mut self) {
- self.select(self.last_ind);
- }
-
- pub fn draw(&mut self, frame: &mut Frame) {
- let area = frame.size();
-
- frame.render_stateful_widget(
- &self.table,
- Rect {
- x: 0,
- y: 0,
- width: area.width,
- height: area.height - 1,
- },
- &mut self.table_state,
- );
+use crate::{exercise::Exercise, state_file::StateFile};
- let help_footer =
- "↓/j ↑/k home/g end/G │ Filter <d>one/<p>ending │ <r>eset │ <c>ontinue at │ <q>uit";
- frame.render_widget(
- Span::raw(help_footer),
- Rect {
- x: 0,
- y: area.height - 1,
- width: area.width,
- height: 1,
- },
- );
- }
-}
+use self::state::UiState;
pub fn list(state_file: &mut StateFile, exercises: &[Exercise]) -> Result<()> {
let mut stdout = io::stdout().lock();
@@ -183,7 +49,7 @@ pub fn list(state_file: &mut StateFile, exercises: &[Exercise]) -> Result<()> {
KeyCode::Home | KeyCode::Char('g') => ui_state.select_first(),
KeyCode::End | KeyCode::Char('G') => ui_state.select_last(),
KeyCode::Char('c') => {
- state_file.set_next_exercise_ind(ui_state.selected)?;
+ state_file.set_next_exercise_ind(ui_state.selected())?;
ui_state.table = ui_state.table.rows(UiState::rows(state_file, exercises));
}
_ => (),
diff --git a/src/list/state.rs b/src/list/state.rs
new file mode 100644
index 0000000..3d2f0a6
--- /dev/null
+++ b/src/list/state.rs
@@ -0,0 +1,145 @@
+use ratatui::{
+ layout::{Constraint, Rect},
+ style::{Style, Stylize},
+ text::Span,
+ widgets::{Block, Borders, HighlightSpacing, Row, Table, TableState},
+ Frame,
+};
+
+use crate::{exercise::Exercise, state_file::StateFile};
+
+pub struct UiState<'a> {
+ pub table: Table<'a>,
+ selected: usize,
+ table_state: TableState,
+ last_ind: usize,
+}
+
+impl<'a> UiState<'a> {
+ pub fn rows<'s, 'i>(
+ state_file: &'s StateFile,
+ exercises: &'a [Exercise],
+ ) -> impl Iterator<Item = Row<'a>> + 'i
+ where
+ 's: 'i,
+ 'a: 'i,
+ {
+ exercises
+ .iter()
+ .zip(state_file.progress())
+ .enumerate()
+ .map(|(ind, (exercise, done))| {
+ let next = if ind == state_file.next_exercise_ind() {
+ ">>>>".bold().red()
+ } else {
+ Span::default()
+ };
+
+ let exercise_state = if *done {
+ "DONE".green()
+ } else {
+ "PENDING".yellow()
+ };
+
+ Row::new([
+ next,
+ exercise_state,
+ Span::raw(&exercise.name),
+ Span::raw(exercise.path.to_string_lossy()),
+ ])
+ })
+ }
+
+ pub fn new(state_file: &StateFile, exercises: &'a [Exercise]) -> Self {
+ let header = Row::new(["Next", "State", "Name", "Path"]);
+
+ let max_name_len = exercises
+ .iter()
+ .map(|exercise| exercise.name.len())
+ .max()
+ .unwrap_or(4) as u16;
+
+ let widths = [
+ Constraint::Length(4),
+ Constraint::Length(7),
+ Constraint::Length(max_name_len),
+ Constraint::Fill(1),
+ ];
+
+ let rows = Self::rows(state_file, exercises);
+
+ let table = Table::new(rows, widths)
+ .header(header)
+ .column_spacing(2)
+ .highlight_spacing(HighlightSpacing::Always)
+ .highlight_style(Style::new().bg(ratatui::style::Color::Rgb(50, 50, 50)))
+ .highlight_symbol("🦀")
+ .block(Block::default().borders(Borders::BOTTOM));
+
+ let selected = 0;
+ let table_state = TableState::default().with_selected(Some(selected));
+ let last_ind = exercises.len() - 1;
+
+ Self {
+ table,
+ selected,
+ table_state,
+ last_ind,
+ }
+ }
+
+ #[inline]
+ pub fn selected(&self) -> usize {
+ self.selected
+ }
+
+ fn select(&mut self, ind: usize) {
+ self.selected = ind;
+ self.table_state.select(Some(ind));
+ }
+
+ pub fn select_next(&mut self) {
+ self.select(self.selected.saturating_add(1).min(self.last_ind));
+ }
+
+ pub fn select_previous(&mut self) {
+ self.select(self.selected.saturating_sub(1));
+ }
+
+ #[inline]
+ pub fn select_first(&mut self) {
+ self.select(0);
+ }
+
+ #[inline]
+ pub fn select_last(&mut self) {
+ self.select(self.last_ind);
+ }
+
+ pub fn draw(&mut self, frame: &mut Frame) {
+ let area = frame.size();
+
+ frame.render_stateful_widget(
+ &self.table,
+ Rect {
+ x: 0,
+ y: 0,
+ width: area.width,
+ height: area.height - 1,
+ },
+ &mut self.table_state,
+ );
+
+ let help_footer =
+ "↓/j ↑/k home/g end/G │ Filter <d>one/<p>ending │ <r>eset │ <c>ontinue at │ <q>uit";
+ frame.render_widget(
+ Span::raw(help_footer),
+ Rect {
+ x: 0,
+ y: area.height - 1,
+ width: area.width,
+ height: 1,
+ },
+ );
+ }
+}