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 std::cmp::min;
|
||||
use tui_textarea::TextArea;
|
||||
use int_enum::IntEnum;
|
||||
|
||||
use crate::db;
|
||||
|
||||
@ -24,12 +25,15 @@ pub struct Task {
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub const EDIT_WINDOW_FOCUS_STATES: i8 = 4;
|
||||
|
||||
#[repr(i8)]
|
||||
#[derive(Debug, IntEnum, Copy, Clone)]
|
||||
pub enum TaskEditFocus {
|
||||
Title,
|
||||
Description,
|
||||
ConfirmBtn,
|
||||
CancelBtn,
|
||||
Title = 0,
|
||||
Description = 1,
|
||||
ConfirmBtn = 2,
|
||||
CancelBtn = 3,
|
||||
}
|
||||
|
||||
pub struct TaskState<'a> {
|
||||
@ -276,8 +280,9 @@ impl<'a> State<'a> {
|
||||
if let Some(selected_task) = self.get_selected_task_mut() {
|
||||
selected_task.title = title;
|
||||
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(())
|
||||
}
|
||||
|
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::{Event, KeyCode};
|
||||
use int_enum::IntEnum;
|
||||
use anyhow::Error;
|
||||
|
||||
pub fn handle_task_edit(state: &mut State<'_>, key: event::KeyEvent) -> Result<(), anyhow::Error> {
|
||||
if let Some(mut task) = state.task_edit_state.take() {
|
||||
let mut clear_task = false;
|
||||
match task.focus {
|
||||
// TODO: Handle wrapping around the enum rather than doing it manually
|
||||
TaskEditFocus::Title => match key.code {
|
||||
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);
|
||||
}
|
||||
pub fn cycle_focus(task: &mut TaskState<'_>, forward: bool) -> Result<(), Error>{
|
||||
let cycle;
|
||||
if forward {
|
||||
cycle = (task.focus.int_value() + 1) % EDIT_WINDOW_FOCUS_STATES;
|
||||
} else {
|
||||
cycle = (task.focus.int_value() - 1) % EDIT_WINDOW_FOCUS_STATES;
|
||||
}
|
||||
task.focus = TaskEditFocus::from_int(cycle)?;
|
||||
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 {
|
||||
KeyCode::Char('q') => state.quit = true,
|
||||
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
|
||||
///
|
||||
/// 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 state.task_edit_state.is_some() {
|
||||
handle_task_edit(state, key)?;
|
||||
|
Loading…
x
Reference in New Issue
Block a user