Change columns up. Refactor input and state change code.
This commit is contained in:
		
							parent
							
								
									77f9c95cf1
								
							
						
					
					
						commit
						c38fa823c9
					
				
							
								
								
									
										19
									
								
								src/input.rs
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/input.rs
									
									
									
									
									
								
							@ -1,28 +1,19 @@
 | 
				
			|||||||
use std::cmp::min;
 | 
					 | 
				
			||||||
use crossterm::event;
 | 
					use crossterm::event;
 | 
				
			||||||
use crossterm::event::{Event, KeyCode};
 | 
					use crossterm::event::{Event, KeyCode};
 | 
				
			||||||
use int_enum::IntEnum;
 | 
					use crate::types::{AppState};
 | 
				
			||||||
use crate::types::{AppState, TaskStatus};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn handle_input(state: &mut AppState) -> Result<(), std::io::Error> {
 | 
					pub fn handle_input(state: &mut AppState) -> Result<(), std::io::Error> {
 | 
				
			||||||
    if let Event::Key(key) = event::read()? {
 | 
					    if let Event::Key(key) = event::read()? {
 | 
				
			||||||
        match key.code {
 | 
					        match key.code {
 | 
				
			||||||
            KeyCode::Char('q') => state.quit = true,
 | 
					            KeyCode::Char('q') => state.quit = true,
 | 
				
			||||||
            KeyCode::Char('h') |
 | 
					            KeyCode::Char('h') |
 | 
				
			||||||
            KeyCode::Left      => state.selected_column = state.selected_column.saturating_sub(1),
 | 
					            KeyCode::Left      => state.select_previous_column(),
 | 
				
			||||||
            KeyCode::Char('j') |
 | 
					            KeyCode::Char('j') |
 | 
				
			||||||
            KeyCode::Down => {
 | 
					            KeyCode::Down      => state.select_next_task(),
 | 
				
			||||||
                let column: TaskStatus = TaskStatus::from_int(state.selected_column).unwrap();
 | 
					 | 
				
			||||||
                let tasks = state.current_project.tasks_per_column.get(&column).unwrap();
 | 
					 | 
				
			||||||
                if tasks.len() > 0 {
 | 
					 | 
				
			||||||
                    let mins = min(state.selected_task[state.selected_column] + 1, tasks.len() - 1);
 | 
					 | 
				
			||||||
                    state.selected_task[state.selected_column] = mins;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            KeyCode::Char('k') |
 | 
					            KeyCode::Char('k') |
 | 
				
			||||||
            KeyCode::Up        => state.selected_task[state.selected_column] = state.selected_task[state.selected_column].saturating_sub(1),
 | 
					            KeyCode::Up        => state.select_previous_task(),
 | 
				
			||||||
            KeyCode::Char('l') |
 | 
					            KeyCode::Char('l') |
 | 
				
			||||||
            KeyCode::Right     => state.selected_column = min(state.selected_column + 1, 4),
 | 
					            KeyCode::Right     => state.select_next_column(),
 | 
				
			||||||
            _ => {}
 | 
					            _ => {}
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										83
									
								
								src/types.rs
									
									
									
									
									
								
							
							
						
						
									
										83
									
								
								src/types.rs
									
									
									
									
									
								
							@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					use std::cmp::min;
 | 
				
			||||||
use indexmap::IndexMap;
 | 
					use indexmap::IndexMap;
 | 
				
			||||||
use int_enum::IntEnum;
 | 
					use int_enum::IntEnum;
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
@ -5,13 +6,13 @@ use serde::{Deserialize, Serialize};
 | 
				
			|||||||
#[repr(usize)]
 | 
					#[repr(usize)]
 | 
				
			||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, IntEnum)]
 | 
					#[derive(Deserialize, Serialize, Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, IntEnum)]
 | 
				
			||||||
pub enum TaskStatus {
 | 
					pub enum TaskStatus {
 | 
				
			||||||
    Done = 0,
 | 
					    Todo = 0,
 | 
				
			||||||
    Todo = 1,
 | 
					    InProgress = 1,
 | 
				
			||||||
    InProgress = 2,
 | 
					    Done = 2,
 | 
				
			||||||
    Testing = 3,
 | 
					    Ideas = 3,
 | 
				
			||||||
    Backlog = 4,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// #[derive(Deserialize, Serialize, Debug, Clone, Copy)]
 | 
				
			||||||
#[derive(Deserialize, Serialize, Debug)]
 | 
					#[derive(Deserialize, Serialize, Debug)]
 | 
				
			||||||
pub struct Task {
 | 
					pub struct Task {
 | 
				
			||||||
    pub title: String,
 | 
					    pub title: String,
 | 
				
			||||||
@ -27,6 +28,7 @@ impl Default for Task {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Type used mainly for serialization at this time
 | 
				
			||||||
#[derive(Deserialize, Serialize, Debug)]
 | 
					#[derive(Deserialize, Serialize, Debug)]
 | 
				
			||||||
pub struct Project {
 | 
					pub struct Project {
 | 
				
			||||||
    pub name: String,
 | 
					    pub name: String,
 | 
				
			||||||
@ -41,15 +43,30 @@ impl Project {
 | 
				
			|||||||
                [(TaskStatus::Done, vec![]),
 | 
					                [(TaskStatus::Done, vec![]),
 | 
				
			||||||
                    (TaskStatus::Todo, vec![]),
 | 
					                    (TaskStatus::Todo, vec![]),
 | 
				
			||||||
                    (TaskStatus::InProgress, vec![]),
 | 
					                    (TaskStatus::InProgress, vec![]),
 | 
				
			||||||
                    (TaskStatus::Testing, vec![]),
 | 
					                    (TaskStatus::Ideas, vec![])],
 | 
				
			||||||
                    (TaskStatus::Backlog, vec![])],
 | 
					 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn add_task(&mut self, status: TaskStatus, task: Task) {
 | 
					    pub fn load() -> Self {
 | 
				
			||||||
 | 
					        let json = std::fs::read_to_string("kanban-tui.json")
 | 
				
			||||||
 | 
					            .expect("Could not read json file");
 | 
				
			||||||
 | 
					        serde_json::from_str(&json)
 | 
				
			||||||
 | 
					            .expect("There is something wrong with the json schema, it doesn't match Project struct")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn add_task(&mut self, status: TaskStatus, task: Task) {
 | 
				
			||||||
        self.tasks_per_column.entry(status).or_default().push(task);
 | 
					        self.tasks_per_column.entry(status).or_default().push(task);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Comment out cause this is dangerous
 | 
				
			||||||
 | 
					    pub fn save() {
 | 
				
			||||||
 | 
					        // let mut project = Project::new("Kanban Tui");
 | 
				
			||||||
 | 
					        // project.add_task(Task::default());
 | 
				
			||||||
 | 
					        // project.add_task(Task::default());
 | 
				
			||||||
 | 
					        // let json = serde_json::to_string_pretty(&project).unwrap();
 | 
				
			||||||
 | 
					        // std::fs::write("./project.json", json).unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for Project {
 | 
					impl Default for Project {
 | 
				
			||||||
@ -61,27 +78,10 @@ impl Default for Project {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Project {
 | 
					 | 
				
			||||||
    pub fn load() -> Self {
 | 
					 | 
				
			||||||
        let json = std::fs::read_to_string("kanban-tui.json")
 | 
					 | 
				
			||||||
            .expect("Could not read json file");
 | 
					 | 
				
			||||||
        serde_json::from_str(&json)
 | 
					 | 
				
			||||||
            .expect("There is something wrong with the json schema, it doesn't match Project struct")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /// Comment out cause this is dangerous
 | 
					 | 
				
			||||||
    pub fn save() {
 | 
					 | 
				
			||||||
        // let mut project = Project::new("Kanban Tui");
 | 
					 | 
				
			||||||
        // project.add_task(Task::default());
 | 
					 | 
				
			||||||
        // project.add_task(Task::default());
 | 
					 | 
				
			||||||
        // let json = serde_json::to_string_pretty(&project).unwrap();
 | 
					 | 
				
			||||||
        // std::fs::write("./project.json", json).unwrap();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub struct AppState {
 | 
					pub struct AppState {
 | 
				
			||||||
    pub selected_column: usize,
 | 
					    pub selected_column: usize,
 | 
				
			||||||
    pub selected_task: [usize; 5],
 | 
					    pub selected_task: [usize; 4],
 | 
				
			||||||
    pub current_project: Project,
 | 
					    pub project: Project,
 | 
				
			||||||
    pub quit: bool,
 | 
					    pub quit: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -89,10 +89,35 @@ impl AppState {
 | 
				
			|||||||
    pub fn new(project: Project) -> Self {
 | 
					    pub fn new(project: Project) -> Self {
 | 
				
			||||||
        AppState {
 | 
					        AppState {
 | 
				
			||||||
            selected_column: 0,
 | 
					            selected_column: 0,
 | 
				
			||||||
            selected_task: [0, 0, 0, 0, 0],
 | 
					            selected_task: [0, 0, 0, 0],
 | 
				
			||||||
            quit: false,
 | 
					            quit: false,
 | 
				
			||||||
            current_project: project,
 | 
					            project: project,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn get_tasks_in_active_column(&self) -> &Vec<Task> {
 | 
				
			||||||
 | 
					        let column: TaskStatus = TaskStatus::from_int(self.selected_column).unwrap().clone();
 | 
				
			||||||
 | 
					        self.project.tasks_per_column.get(&column).unwrap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn select_previous_task(&mut self) {
 | 
				
			||||||
 | 
					        self.selected_task[self.selected_column] = self.selected_task[self.selected_column].saturating_sub(1)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn select_next_task(&mut self) {
 | 
				
			||||||
 | 
					        let tasks = self.get_tasks_in_active_column();
 | 
				
			||||||
 | 
					        if tasks.len() > 0 {
 | 
				
			||||||
 | 
					            let mins = min(self.selected_task[self.selected_column] + 1, tasks.len() - 1);
 | 
				
			||||||
 | 
					            self.selected_task[self.selected_column] = mins;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn select_previous_column(&mut self) {
 | 
				
			||||||
 | 
					        self.selected_column = self.selected_column.saturating_sub(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn select_next_column(&mut self) {
 | 
				
			||||||
 | 
					        self.selected_column = min(self.selected_column + 1, self.project.tasks_per_column.len() - 1)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -11,12 +11,12 @@ fn draw_tasks<B: Backend>(f: &mut Frame<B>, area: &Rect, state: &AppState) {
 | 
				
			|||||||
    let columns = Layout::default()
 | 
					    let columns = Layout::default()
 | 
				
			||||||
        .direction(Direction::Horizontal)
 | 
					        .direction(Direction::Horizontal)
 | 
				
			||||||
        .constraints(
 | 
					        .constraints(
 | 
				
			||||||
            vec![Constraint::Percentage(20);
 | 
					            vec![Constraint::Percentage(100 / state.project.tasks_per_column.len() as u16);
 | 
				
			||||||
                 state.current_project.tasks_per_column.len()].as_ref()
 | 
					                 state.project.tasks_per_column.len()].as_ref()
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .split(*area);
 | 
					        .split(*area);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i, (status, tasks)) in state.current_project.tasks_per_column.iter().enumerate() {
 | 
					    for (i, (status, tasks)) in state.project.tasks_per_column.iter().enumerate() {
 | 
				
			||||||
        let items: Vec<ListItem> = tasks.iter().enumerate().map(|(j, task)| {
 | 
					        let items: Vec<ListItem> = tasks.iter().enumerate().map(|(j, task)| {
 | 
				
			||||||
            let mut style = Style::default();
 | 
					            let mut style = Style::default();
 | 
				
			||||||
            if i == state.selected_column && j == state.selected_task[state.selected_column] {
 | 
					            if i == state.selected_column && j == state.selected_task[state.selected_column] {
 | 
				
			||||||
@ -48,7 +48,7 @@ fn draw_task_info<B: Backend>(f: &mut Frame<B>, area: &Rect, state: &AppState) {
 | 
				
			|||||||
        .title("TASK INFO")
 | 
					        .title("TASK INFO")
 | 
				
			||||||
        .borders(Borders::ALL);
 | 
					        .borders(Borders::ALL);
 | 
				
			||||||
    let column: TaskStatus = TaskStatus::from_int(state.selected_column).unwrap();
 | 
					    let column: TaskStatus = TaskStatus::from_int(state.selected_column).unwrap();
 | 
				
			||||||
    let tasks = state.current_project.tasks_per_column.get(&column).unwrap();
 | 
					    let tasks = state.project.tasks_per_column.get(&column).unwrap();
 | 
				
			||||||
    if tasks.len() > 0 {
 | 
					    if tasks.len() > 0 {
 | 
				
			||||||
        let task: &Task = &tasks[state.selected_task[state.selected_column]];
 | 
					        let task: &Task = &tasks[state.selected_task[state.selected_column]];
 | 
				
			||||||
        let p = Paragraph::new(task.description.as_str()).block(block).wrap(Wrap { trim: true });
 | 
					        let p = Paragraph::new(task.description.as_str()).block(block).wrap(Wrap { trim: true });
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user