Added task shifting up and down and left and right.
Francesco added some stuff as well.
This commit is contained in:
		
							parent
							
								
									c38fa823c9
								
							
						
					
					
						commit
						ae99fa193c
					
				
							
								
								
									
										8
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -2,6 +2,12 @@
 | 
			
		||||
# It is not intended for manual editing.
 | 
			
		||||
version = 3
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "anyhow"
 | 
			
		||||
version = "1.0.66"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "autocfg"
 | 
			
		||||
version = "1.1.0"
 | 
			
		||||
@ -99,11 +105,13 @@ checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
 | 
			
		||||
name = "kanban-tui"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "crossterm",
 | 
			
		||||
 "indexmap",
 | 
			
		||||
 "int-enum",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
 "tui",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -11,4 +11,8 @@ crossterm = "0.25"
 | 
			
		||||
serde = { version = "1.0.148" , features = [ "derive" ] }
 | 
			
		||||
serde_json = "1.0.89"
 | 
			
		||||
indexmap = { version = "1.9.2" , features = [ "serde" ] }
 | 
			
		||||
int-enum = "0.5.0"
 | 
			
		||||
int-enum = "0.5.0"
 | 
			
		||||
 | 
			
		||||
#error handling
 | 
			
		||||
thiserror = "1"
 | 
			
		||||
anyhow = "1"
 | 
			
		||||
							
								
								
									
										198
									
								
								src/app.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								src/app.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,198 @@
 | 
			
		||||
use std::cmp::min;
 | 
			
		||||
use indexmap::IndexMap;
 | 
			
		||||
use int_enum::IntEnum;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests;
 | 
			
		||||
 | 
			
		||||
#[repr(usize)]
 | 
			
		||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, IntEnum)]
 | 
			
		||||
pub enum TaskStatus {
 | 
			
		||||
    Todo = 0,
 | 
			
		||||
    InProgress = 1,
 | 
			
		||||
    Done = 2,
 | 
			
		||||
    Ideas = 3,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// #[derive(Deserialize, Serialize, Debug, Clone, Copy)]
 | 
			
		||||
#[derive(Deserialize, Serialize, Debug)]
 | 
			
		||||
pub struct Task {
 | 
			
		||||
    pub title: String,
 | 
			
		||||
    pub description: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for Task {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Task {
 | 
			
		||||
            title: String::new(),
 | 
			
		||||
            description: String::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Type used mainly for serialization at this time
 | 
			
		||||
#[derive(Deserialize, Serialize, Debug)]
 | 
			
		||||
pub struct Project {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub tasks_per_column: IndexMap<TaskStatus, Vec<Task>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, thiserror::Error)]
 | 
			
		||||
pub enum KanbanError {
 | 
			
		||||
    #[error("There is something wrong with the json schema, it doesn't match Project struct")]
 | 
			
		||||
    BadJson,
 | 
			
		||||
    #[error("Some form of IO error occured: {0}")]
 | 
			
		||||
    Io(#[from] std::io::Error),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Project {
 | 
			
		||||
    pub fn new(name: &str) -> Self {
 | 
			
		||||
        Project {
 | 
			
		||||
            name: name.to_owned(),
 | 
			
		||||
            tasks_per_column: IndexMap::from(
 | 
			
		||||
                [(TaskStatus::Done, vec![]),
 | 
			
		||||
                    (TaskStatus::Todo, vec![]),
 | 
			
		||||
                    (TaskStatus::InProgress, vec![]),
 | 
			
		||||
                    (TaskStatus::Ideas, vec![])],
 | 
			
		||||
            ),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn load_from_json(json: &str) -> Result<Self, KanbanError> {
 | 
			
		||||
        serde_json::from_str(json).map_err(|_| KanbanError::BadJson)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn load() -> Result<Self, KanbanError> {
 | 
			
		||||
        let json = std::fs::read_to_string("kanban-tui.json")?;
 | 
			
		||||
        Self::load_from_json(&json)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn add_task(&mut self, status: TaskStatus, task: 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 {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Project {
 | 
			
		||||
            name: String::new(),
 | 
			
		||||
            tasks_per_column: IndexMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct AppState {
 | 
			
		||||
    pub selected_column: usize,
 | 
			
		||||
    pub selected_task: [usize; 4],
 | 
			
		||||
    pub project: Project,
 | 
			
		||||
    pub quit: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AppState {
 | 
			
		||||
    pub fn new(project: Project) -> Self {
 | 
			
		||||
        AppState {
 | 
			
		||||
            selected_column: 0,
 | 
			
		||||
            selected_task: [0, 0, 0, 0],
 | 
			
		||||
            quit: false,
 | 
			
		||||
            project,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn selected_task_idx(&self) -> usize {
 | 
			
		||||
        self.selected_task[self.selected_column]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn selected_task_idx_mut(&mut self) -> &mut usize {
 | 
			
		||||
        &mut self.selected_task[self.selected_column]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_tasks_in_active_column(&self) -> &[Task] {
 | 
			
		||||
        let column: TaskStatus = TaskStatus::from_int(self.selected_column).unwrap().clone();
 | 
			
		||||
        self.project.tasks_per_column.get(&column).unwrap()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_tasks_in_active_column_mut(&mut self) -> &mut Vec<Task> {
 | 
			
		||||
        let column: TaskStatus = TaskStatus::from_int(self.selected_column).unwrap().clone();
 | 
			
		||||
        self.project.tasks_per_column.get_mut(&column).unwrap()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_selected_task(&self) -> Option<&Task> {
 | 
			
		||||
        let tasks = self.get_tasks_in_active_column();
 | 
			
		||||
        tasks.get(self.selected_task_idx())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn select_previous_task(&mut self) {
 | 
			
		||||
        *self.selected_task_idx_mut() = self.selected_task_idx().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_idx() + 1, tasks.len() - 1);
 | 
			
		||||
            *self.selected_task_idx_mut() = 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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn move_task_previous_column(&mut self) {
 | 
			
		||||
        let tasks = self.get_tasks_in_active_column();
 | 
			
		||||
        let task_idx = self.selected_task_idx();
 | 
			
		||||
        if self.selected_column > 0 && tasks.len() > 0 && task_idx.clone() < tasks.len() {
 | 
			
		||||
            let task = self.get_tasks_in_active_column_mut().remove(task_idx);
 | 
			
		||||
            *self.selected_task_idx_mut() = self.selected_task_idx().saturating_sub(1);
 | 
			
		||||
            self.select_previous_column();
 | 
			
		||||
            let target_tasks = self.get_tasks_in_active_column_mut();
 | 
			
		||||
            target_tasks.push(task);
 | 
			
		||||
            *self.selected_task_idx_mut() = target_tasks.len() - 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn move_task_next_column(&mut self) {
 | 
			
		||||
        let tasks = self.get_tasks_in_active_column();
 | 
			
		||||
        let task_idx = self.selected_task_idx();
 | 
			
		||||
        if self.selected_column < self.project.tasks_per_column.len() && tasks.len() > 0 && task_idx < tasks.len() {
 | 
			
		||||
            let task = self.get_tasks_in_active_column_mut().remove(task_idx);
 | 
			
		||||
            *self.selected_task_idx_mut() = self.selected_task_idx().saturating_sub(1);
 | 
			
		||||
            self.select_next_column();
 | 
			
		||||
            let target_tasks = self.get_tasks_in_active_column_mut();
 | 
			
		||||
            target_tasks.push(task);
 | 
			
		||||
            *self.selected_task_idx_mut() = target_tasks.len() - 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn move_task_up(&mut self) {
 | 
			
		||||
        let task_idx = self.selected_task_idx();
 | 
			
		||||
        if task_idx > 0 {
 | 
			
		||||
            let tasks = self.get_tasks_in_active_column_mut();
 | 
			
		||||
            tasks.swap(task_idx, task_idx - 1);
 | 
			
		||||
            *self.selected_task_idx_mut() = task_idx - 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn move_task_down(&mut self) {
 | 
			
		||||
        let task_idx = self.selected_task_idx();
 | 
			
		||||
        let tasks = self.get_tasks_in_active_column_mut();
 | 
			
		||||
        if task_idx < tasks.len() - 1 {
 | 
			
		||||
            tasks.swap(task_idx, task_idx + 1);
 | 
			
		||||
            *self.selected_task_idx_mut() = task_idx + 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								src/app/tests.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/app/tests.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
use super::*;
 | 
			
		||||
							
								
								
									
										10
									
								
								src/input.rs
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/input.rs
									
									
									
									
									
								
							@ -1,6 +1,6 @@
 | 
			
		||||
use crossterm::event;
 | 
			
		||||
use crossterm::event::{Event, KeyCode};
 | 
			
		||||
use crate::types::{AppState};
 | 
			
		||||
use crate::app::{AppState};
 | 
			
		||||
 | 
			
		||||
pub fn handle_input(state: &mut AppState) -> Result<(), std::io::Error> {
 | 
			
		||||
    if let Event::Key(key) = event::read()? {
 | 
			
		||||
@ -14,6 +14,14 @@ pub fn handle_input(state: &mut AppState) -> Result<(), std::io::Error> {
 | 
			
		||||
            KeyCode::Up        => state.select_previous_task(),
 | 
			
		||||
            KeyCode::Char('l') |
 | 
			
		||||
            KeyCode::Right     => state.select_next_column(),
 | 
			
		||||
            KeyCode::Char('<') |
 | 
			
		||||
            KeyCode::Char('H') => state.move_task_previous_column(),
 | 
			
		||||
            KeyCode::Char('>') |
 | 
			
		||||
            KeyCode::Char('L') => state.move_task_next_column(),
 | 
			
		||||
            KeyCode::Char('=') |
 | 
			
		||||
            KeyCode::Char('J') => state.move_task_down(),
 | 
			
		||||
            KeyCode::Char('-') |
 | 
			
		||||
            KeyCode::Char('K') => state.move_task_up(),
 | 
			
		||||
            _ => {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
mod app;
 | 
			
		||||
mod ui;
 | 
			
		||||
mod input;
 | 
			
		||||
 | 
			
		||||
pub use app::*;
 | 
			
		||||
pub use ui::draw;
 | 
			
		||||
pub use input::handle_input;
 | 
			
		||||
							
								
								
									
										18
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/main.rs
									
									
									
									
									
								
							@ -1,29 +1,23 @@
 | 
			
		||||
#![allow(dead_code)]
 | 
			
		||||
mod ui;
 | 
			
		||||
mod types;
 | 
			
		||||
mod input;
 | 
			
		||||
use kanban_tui::{AppState, Project};
 | 
			
		||||
 | 
			
		||||
use std::{io};
 | 
			
		||||
use crossterm::{event::*, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}};
 | 
			
		||||
use tui::backend::CrosstermBackend;
 | 
			
		||||
use tui::Terminal;
 | 
			
		||||
use crate::input::handle_input;
 | 
			
		||||
use crate::types::*;
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), io::Error> {
 | 
			
		||||
    // setup terminal
 | 
			
		||||
fn main() -> anyhow::Result<()> {
 | 
			
		||||
    enable_raw_mode()?;
 | 
			
		||||
    let mut stdout = io::stdout();
 | 
			
		||||
    crossterm::execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
 | 
			
		||||
    let backend = CrosstermBackend::new(stdout);
 | 
			
		||||
    let mut terminal = Terminal::new(backend)?;
 | 
			
		||||
 | 
			
		||||
    let mut state = AppState::new(Project::load());
 | 
			
		||||
    let mut state = AppState::new(Project::load()?);
 | 
			
		||||
 | 
			
		||||
    loop {
 | 
			
		||||
        terminal.draw(|f| ui::draw(f, &mut state))?;
 | 
			
		||||
        handle_input(&mut state)?;
 | 
			
		||||
        if state.quit { break }
 | 
			
		||||
    while !state.quit {
 | 
			
		||||
        terminal.draw(|f| kanban_tui::draw(f, &mut state))?;
 | 
			
		||||
        kanban_tui::handle_input(&mut state)?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // restore terminal
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										123
									
								
								src/types.rs
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								src/types.rs
									
									
									
									
									
								
							@ -1,123 +0,0 @@
 | 
			
		||||
use std::cmp::min;
 | 
			
		||||
use indexmap::IndexMap;
 | 
			
		||||
use int_enum::IntEnum;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
#[repr(usize)]
 | 
			
		||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, IntEnum)]
 | 
			
		||||
pub enum TaskStatus {
 | 
			
		||||
    Todo = 0,
 | 
			
		||||
    InProgress = 1,
 | 
			
		||||
    Done = 2,
 | 
			
		||||
    Ideas = 3,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// #[derive(Deserialize, Serialize, Debug, Clone, Copy)]
 | 
			
		||||
#[derive(Deserialize, Serialize, Debug)]
 | 
			
		||||
pub struct Task {
 | 
			
		||||
    pub title: String,
 | 
			
		||||
    pub description: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for Task {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Task {
 | 
			
		||||
            title: String::new(),
 | 
			
		||||
            description: String::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Type used mainly for serialization at this time
 | 
			
		||||
#[derive(Deserialize, Serialize, Debug)]
 | 
			
		||||
pub struct Project {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub tasks_per_column: IndexMap<TaskStatus, Vec<Task>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Project {
 | 
			
		||||
    fn new(name: &str) -> Self {
 | 
			
		||||
        Project {
 | 
			
		||||
            name: name.to_owned(),
 | 
			
		||||
            tasks_per_column: IndexMap::from(
 | 
			
		||||
                [(TaskStatus::Done, vec![]),
 | 
			
		||||
                    (TaskStatus::Todo, vec![]),
 | 
			
		||||
                    (TaskStatus::InProgress, vec![]),
 | 
			
		||||
                    (TaskStatus::Ideas, vec![])],
 | 
			
		||||
            ),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// 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 {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Project {
 | 
			
		||||
            name: String::new(),
 | 
			
		||||
            tasks_per_column: IndexMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct AppState {
 | 
			
		||||
    pub selected_column: usize,
 | 
			
		||||
    pub selected_task: [usize; 4],
 | 
			
		||||
    pub project: Project,
 | 
			
		||||
    pub quit: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AppState {
 | 
			
		||||
    pub fn new(project: Project) -> Self {
 | 
			
		||||
        AppState {
 | 
			
		||||
            selected_column: 0,
 | 
			
		||||
            selected_task: [0, 0, 0, 0],
 | 
			
		||||
            quit: false,
 | 
			
		||||
            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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,7 @@ use tui::{Frame};
 | 
			
		||||
use tui::style::{Color, Modifier, Style};
 | 
			
		||||
use tui::text::{Span, Spans};
 | 
			
		||||
use tui::widgets::*;
 | 
			
		||||
use crate::types::*;
 | 
			
		||||
use int_enum::IntEnum;
 | 
			
		||||
use crate::app::*;
 | 
			
		||||
 | 
			
		||||
fn draw_tasks<B: Backend>(f: &mut Frame<B>, area: &Rect, state: &AppState) {
 | 
			
		||||
    let columns = Layout::default()
 | 
			
		||||
@ -47,10 +46,7 @@ fn draw_task_info<B: Backend>(f: &mut Frame<B>, area: &Rect, state: &AppState) {
 | 
			
		||||
    let block = Block::default()
 | 
			
		||||
        .title("TASK INFO")
 | 
			
		||||
        .borders(Borders::ALL);
 | 
			
		||||
    let column: TaskStatus = TaskStatus::from_int(state.selected_column).unwrap();
 | 
			
		||||
    let tasks = state.project.tasks_per_column.get(&column).unwrap();
 | 
			
		||||
    if tasks.len() > 0 {
 | 
			
		||||
        let task: &Task = &tasks[state.selected_task[state.selected_column]];
 | 
			
		||||
    if let Some(task) = state.get_selected_task() {
 | 
			
		||||
        let p = Paragraph::new(task.description.as_str()).block(block).wrap(Wrap { trim: true });
 | 
			
		||||
        f.render_widget(p, *area);
 | 
			
		||||
    } else {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user