Refactor task edit by wrapping focus with int-enum, remove some .clone()'s
This commit is contained in:
parent
41778accdc
commit
a479b72a29
19
src/app.rs
19
src/app.rs
@ -3,6 +3,7 @@ use rusqlite::Connection;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use tui_textarea::TextArea;
|
use tui_textarea::TextArea;
|
||||||
|
use int_enum::IntEnum;
|
||||||
|
|
||||||
use crate::db;
|
use crate::db;
|
||||||
|
|
||||||
@ -24,12 +25,15 @@ pub struct Task {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
pub const EDIT_WINDOW_FOCUS_STATES: i8 = 4;
|
||||||
|
|
||||||
|
#[repr(i8)]
|
||||||
|
#[derive(Debug, IntEnum, Copy, Clone)]
|
||||||
pub enum TaskEditFocus {
|
pub enum TaskEditFocus {
|
||||||
Title,
|
Title = 0,
|
||||||
Description,
|
Description = 1,
|
||||||
ConfirmBtn,
|
ConfirmBtn = 2,
|
||||||
CancelBtn,
|
CancelBtn = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TaskState<'a> {
|
pub struct TaskState<'a> {
|
||||||
@ -276,8 +280,9 @@ impl<'a> State<'a> {
|
|||||||
if let Some(selected_task) = self.get_selected_task_mut() {
|
if let Some(selected_task) = self.get_selected_task_mut() {
|
||||||
selected_task.title = title;
|
selected_task.title = title;
|
||||||
selected_task.description = description;
|
selected_task.description = description;
|
||||||
let cloned = selected_task.clone();
|
}
|
||||||
self.db_conn.update_task_text(&cloned)?;
|
if let Some(task) = self.get_selected_task() {
|
||||||
|
self.db_conn.update_task_text(task)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
104
src/input.rs
104
src/input.rs
@ -1,57 +1,65 @@
|
|||||||
use crate::app::{State, TaskEditFocus, TaskState};
|
use crate::app::{State, TaskEditFocus, TaskState, EDIT_WINDOW_FOCUS_STATES};
|
||||||
use crossterm::event;
|
use crossterm::event;
|
||||||
use crossterm::event::{Event, KeyCode};
|
use crossterm::event::{Event, KeyCode};
|
||||||
|
use int_enum::IntEnum;
|
||||||
|
use anyhow::Error;
|
||||||
|
|
||||||
pub fn handle_task_edit(state: &mut State<'_>, key: event::KeyEvent) -> Result<(), anyhow::Error> {
|
pub fn cycle_focus(task: &mut TaskState<'_>, forward: bool) -> Result<(), Error>{
|
||||||
if let Some(mut task) = state.task_edit_state.take() {
|
let cycle;
|
||||||
let mut clear_task = false;
|
if forward {
|
||||||
match task.focus {
|
cycle = (task.focus.int_value() + 1) % EDIT_WINDOW_FOCUS_STATES;
|
||||||
// TODO: Handle wrapping around the enum rather than doing it manually
|
} else {
|
||||||
TaskEditFocus::Title => match key.code {
|
cycle = (task.focus.int_value() - 1) % EDIT_WINDOW_FOCUS_STATES;
|
||||||
KeyCode::Tab => task.focus = TaskEditFocus::Description,
|
|
||||||
KeyCode::BackTab => task.focus = TaskEditFocus::CancelBtn,
|
|
||||||
KeyCode::Enter => (),
|
|
||||||
_ => {
|
|
||||||
task.title.input(key);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TaskEditFocus::Description => match key.code {
|
|
||||||
KeyCode::Tab => task.focus = TaskEditFocus::ConfirmBtn,
|
|
||||||
KeyCode::BackTab => task.focus = TaskEditFocus::Title,
|
|
||||||
_ => {
|
|
||||||
task.description.input(key);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TaskEditFocus::ConfirmBtn => match key.code {
|
|
||||||
KeyCode::Tab => task.focus = TaskEditFocus::CancelBtn,
|
|
||||||
KeyCode::BackTab => task.focus = TaskEditFocus::Description,
|
|
||||||
KeyCode::Enter => {
|
|
||||||
let title = task.title.clone().into_lines().join("\n");
|
|
||||||
let description = task.description.clone().into_lines().join("\n");
|
|
||||||
if task.is_edit {
|
|
||||||
state.edit_task(title, description)?;
|
|
||||||
} else {
|
|
||||||
state.add_new_task(title, description)?;
|
|
||||||
}
|
|
||||||
clear_task = true;
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
TaskEditFocus::CancelBtn => match key.code {
|
|
||||||
KeyCode::Tab => task.focus = TaskEditFocus::Title,
|
|
||||||
KeyCode::BackTab => task.focus = TaskEditFocus::ConfirmBtn,
|
|
||||||
KeyCode::Enter => clear_task = true,
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if !clear_task {
|
|
||||||
state.task_edit_state = Some(task);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
task.focus = TaskEditFocus::from_int(cycle)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_main(state: &mut State<'_>, key: event::KeyEvent) -> Result<(), anyhow::Error> {
|
pub fn handle_task_edit(state: &mut State<'_>, key: event::KeyEvent) -> Result<(), Error> {
|
||||||
|
// .take() the option so we can avoid borrow checker issues when
|
||||||
|
// we try to edit the task since that mutably borrows State, then
|
||||||
|
// assign later to task_edit_state
|
||||||
|
let updated_task = if let Some(mut task) = state.task_edit_state.take() {
|
||||||
|
match (key.code, task.focus) {
|
||||||
|
(KeyCode::Tab, _) => {
|
||||||
|
cycle_focus(&mut task, true)?;
|
||||||
|
Some(task)
|
||||||
|
},
|
||||||
|
(KeyCode::BackTab, _) => {
|
||||||
|
cycle_focus(&mut task, false)?;
|
||||||
|
Some(task)
|
||||||
|
},
|
||||||
|
(KeyCode::Enter, TaskEditFocus::ConfirmBtn) => {
|
||||||
|
let title = task.title.clone().into_lines().join("\n");
|
||||||
|
let description = task.description.clone().into_lines().join("\n");
|
||||||
|
if task.is_edit {
|
||||||
|
state.edit_task(title, description)?;
|
||||||
|
} else {
|
||||||
|
state.add_new_task(title, description)?;
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
(KeyCode::Enter, TaskEditFocus::CancelBtn) => None,
|
||||||
|
// Ignore enter on the title bar to effectively make it single line
|
||||||
|
(KeyCode::Enter, TaskEditFocus::Title) => Some(task),
|
||||||
|
(_, TaskEditFocus::Title) => {
|
||||||
|
task.title.input(key);
|
||||||
|
Some(task)
|
||||||
|
},
|
||||||
|
(_, TaskEditFocus::Description) => {
|
||||||
|
task.description.input(key);
|
||||||
|
Some(task)
|
||||||
|
}
|
||||||
|
_ => Some(task)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
state.task_edit_state = updated_task;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_main(state: &mut State<'_>, key: event::KeyEvent) -> Result<(), Error> {
|
||||||
match key.code {
|
match key.code {
|
||||||
KeyCode::Char('q') => state.quit = true,
|
KeyCode::Char('q') => state.quit = true,
|
||||||
KeyCode::Char('h') | KeyCode::Left => state.select_previous_column()?,
|
KeyCode::Char('h') | KeyCode::Left => state.select_previous_column()?,
|
||||||
@ -75,7 +83,7 @@ pub fn handle_main(state: &mut State<'_>, key: event::KeyEvent) -> Result<(), an
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Crossterm `event::read()` might return an error
|
/// Crossterm `event::read()` might return an error
|
||||||
pub fn handle(state: &mut State<'_>) -> Result<(), anyhow::Error> {
|
pub fn handle(state: &mut State<'_>) -> Result<(), Error> {
|
||||||
if let Event::Key(key) = event::read()? {
|
if let Event::Key(key) = event::read()? {
|
||||||
if state.task_edit_state.is_some() {
|
if state.task_edit_state.is_some() {
|
||||||
handle_task_edit(state, key)?;
|
handle_task_edit(state, key)?;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user