📅 Initial task dates
This commit is contained in:
parent
9595df093e
commit
19e5011f27
38
Cargo.lock
generated
38
Cargo.lock
generated
@ -2,6 +2,20 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "agenda"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"clap",
|
||||||
|
"colored",
|
||||||
|
"dirs",
|
||||||
|
"fuzzydate",
|
||||||
|
"prettytable-rs",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android_system_properties"
|
name = "android_system_properties"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@ -265,6 +279,17 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuzzydate"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10cc638ce39f54e307c2648a5cf89fb549a0b66bc59f9de933b51b1dfe53c813"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"lazy_static",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
@ -587,19 +612,6 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tasks"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"chrono",
|
|
||||||
"clap",
|
|
||||||
"colored",
|
|
||||||
"dirs",
|
|
||||||
"prettytable-rs",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "term"
|
name = "term"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -14,3 +14,4 @@ chrono = { version = "0.4.23", features = ["serde"] }
|
|||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
colored = "2.0.0"
|
colored = "2.0.0"
|
||||||
prettytable-rs = "0.10.0"
|
prettytable-rs = "0.10.0"
|
||||||
|
fuzzydate = "0.2.1"
|
||||||
|
106
src/cli.rs
106
src/cli.rs
@ -1,19 +1,21 @@
|
|||||||
|
use chrono::NaiveDateTime;
|
||||||
use crate::args::{TasksArgs, Commands};
|
use crate::args::{TasksArgs, Commands};
|
||||||
use crate::args::{CreateTask, DeleteTask, ShowTask, StartTask, StopTask, CompleteTask};
|
use crate::args::{CreateTask, DeleteTask, ShowTask, StartTask, StopTask, CompleteTask};
|
||||||
use crate::tasks::{Tasks, Task, Status};
|
use crate::tasks::{Tasks, Task, Status};
|
||||||
use prettytable::{Table, Row, row, format};
|
use prettytable::{Table, Row, row, format};
|
||||||
use colored::*;
|
use colored::*;
|
||||||
|
use fuzzydate;
|
||||||
|
|
||||||
fn success(msg: String) {
|
pub fn success(msg: String) {
|
||||||
println!("{} {}", "success:".green().bold(), msg);
|
println!("{} {}", "success:".green().bold(), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn warning(msg: &str) {
|
pub fn warning(msg: &str) {
|
||||||
println!("{} {}", "warning:".yellow().bold(), msg);
|
println!("{} {}", "warning:".yellow().bold(), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn error(msg: String) {
|
pub fn error(msg: String) {
|
||||||
println!("{} {}", "error:".red().bold(), msg);
|
println!("{} {}", "error:".red().bold(), msg);
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
@ -29,6 +31,14 @@ fn get_task(tasks: &mut Tasks, id: usize) -> Task {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_date(date_string: Option<String>) -> Option<NaiveDateTime> {
|
||||||
|
if date_string.is_some() {
|
||||||
|
Some(fuzzydate::parse(date_string.unwrap()).unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn calc_row(task: &Task, id: usize) -> Row {
|
fn calc_row(task: &Task, id: usize) -> Row {
|
||||||
if task.status == Status::Complete {
|
if task.status == Status::Complete {
|
||||||
// Generate greyed out rows for complete tasks
|
// Generate greyed out rows for complete tasks
|
||||||
@ -36,30 +46,73 @@ fn calc_row(task: &Task, id: usize) -> Row {
|
|||||||
task.status.as_string().bright_black().italic(),
|
task.status.as_string().bright_black().italic(),
|
||||||
task.title.clone().bright_black().italic()])
|
task.title.clone().bright_black().italic()])
|
||||||
} else {
|
} else {
|
||||||
|
let when = if task.when.is_some() {
|
||||||
|
format!("{}", task.when.unwrap().format("%Y-%m-%d")).bright_black()
|
||||||
|
} else {
|
||||||
|
String::from("N/A").bright_black()
|
||||||
|
};
|
||||||
|
|
||||||
// Generate normal colored rows for uncompleted tasks
|
// Generate normal colored rows for uncompleted tasks
|
||||||
Row::from([id.to_string().cyan(), task.status.as_string(), task.title.clone().white()])
|
Row::from([id.to_string().cyan(), task.status.as_string(), when, task.title.clone().white()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> &mut Tasks {
|
pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> &mut Tasks {
|
||||||
match arguments.command {
|
match arguments.command {
|
||||||
Commands::Add(CreateTask { title, .. }) => {
|
Commands::Add(CreateTask { title, notes, tags, when, deadline, reminder, ..}) => {
|
||||||
let task = Task::new(title);
|
let when = parse_date(when);
|
||||||
|
let deadline = parse_date(deadline);
|
||||||
|
let reminder = parse_date(reminder);
|
||||||
|
let tags: Option<Vec<String>> = if tags.is_some() {
|
||||||
|
Some(tags.unwrap().split(",").map(str::to_string).collect())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let task = Task::new(title, notes, tags, when, deadline, reminder);
|
||||||
tasks.add(task.clone());
|
tasks.add(task.clone());
|
||||||
|
|
||||||
let id = tasks.len() - 1;
|
let id = tasks.len() - 1;
|
||||||
success(task_msg("created", &task, id));
|
success(task_msg("created", &task, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::Del(DeleteTask { id }) => {
|
Commands::Del(DeleteTask { id }) => {
|
||||||
let mut binding = tasks.clone();
|
let task = get_task(tasks, id);
|
||||||
let task = match binding.get_task(id) {
|
|
||||||
Ok(task) => task,
|
|
||||||
Err(error) => panic!("error: {}", error),
|
|
||||||
};
|
|
||||||
|
|
||||||
tasks.del(id);
|
tasks.del(id);
|
||||||
success(task_msg("deleted", task, id));
|
success(task_msg("deleted", &task, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Commands::Done(CompleteTask { id }) => {
|
||||||
|
let task = get_task(&mut tasks.clone(), id);
|
||||||
|
|
||||||
|
tasks.set_status(id, Status::Complete);
|
||||||
|
success(task_msg("completed", &task, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
Commands::Start(StartTask { id }) => {
|
||||||
|
let task = get_task(&mut tasks.clone(), id);
|
||||||
|
|
||||||
|
tasks.set_status(id, Status::Active);
|
||||||
|
success(task_msg("started", &task, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
Commands::Stop(StopTask { id }) => {
|
||||||
|
let task = get_task(&mut tasks.clone(), id);
|
||||||
|
|
||||||
|
if task.when.is_none() {
|
||||||
|
tasks.set_status(id, Status::Inbox);
|
||||||
|
} else {
|
||||||
|
tasks.set_status(id, Status::Pending);
|
||||||
|
};
|
||||||
|
success(task_msg("stopped", &task, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
Commands::Clear => {
|
||||||
|
tasks.clear();
|
||||||
|
success(String::from("cleared all tasks"));
|
||||||
|
}
|
||||||
|
|
||||||
Commands::Show(ShowTask { id }) => {
|
Commands::Show(ShowTask { id }) => {
|
||||||
if id.is_none() {
|
if id.is_none() {
|
||||||
if tasks.tasks.is_none() {
|
if tasks.tasks.is_none() {
|
||||||
@ -67,7 +120,7 @@ pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> &mut Tasks {
|
|||||||
} else {
|
} else {
|
||||||
// Create the table for printing
|
// Create the table for printing
|
||||||
let mut table = Table::new();
|
let mut table = Table::new();
|
||||||
table.set_titles(row!["ID".magenta().bold(), "Status".magenta().bold(), "Title".magenta().bold()]);
|
table.set_titles(row!["ID".magenta().bold(), "Status".magenta().bold(), "When".magenta().bold(), "Title".magenta().bold()]);
|
||||||
table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
|
table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
|
||||||
|
|
||||||
// Iterate through each task
|
// Iterate through each task
|
||||||
@ -86,38 +139,13 @@ pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> &mut Tasks {
|
|||||||
|
|
||||||
// Generate and print the table
|
// Generate and print the table
|
||||||
let mut table = Table::new();
|
let mut table = Table::new();
|
||||||
table.set_titles(row!["ID".magenta().bold(), "Status".magenta().bold(), "Title".magenta().bold()]);
|
table.set_titles(row!["ID".magenta().bold(), "Status".magenta().bold(), "When".magenta().bold(), "Title".magenta().bold()]);
|
||||||
table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
|
table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
|
||||||
table.add_row(calc_row(&task, id));
|
table.add_row(calc_row(&task, id));
|
||||||
println!("{}", table)
|
println!("{}", table)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Commands::Done(CompleteTask { id }) => {
|
|
||||||
let task = get_task(&mut tasks.clone(), id);
|
|
||||||
|
|
||||||
tasks.set_status(id, Status::Complete);
|
|
||||||
success(task_msg("completed", &task, id));
|
|
||||||
}
|
|
||||||
Commands::Start(StartTask { id }) => {
|
|
||||||
let task = get_task(&mut tasks.clone(), id);
|
|
||||||
|
|
||||||
tasks.set_status(id, Status::Active);
|
|
||||||
success(task_msg("started", &task, id));
|
|
||||||
}
|
|
||||||
Commands::Stop(StopTask { id }) => {
|
|
||||||
let task = get_task(&mut tasks.clone(), id);
|
|
||||||
|
|
||||||
if task.when.is_none() {
|
|
||||||
tasks.set_status(id, Status::Inbox);
|
|
||||||
} else {
|
|
||||||
tasks.set_status(id, Status::Pending);
|
|
||||||
};
|
|
||||||
success(task_msg("stopped", &task, id));
|
|
||||||
}
|
|
||||||
Commands::Clear => {
|
|
||||||
tasks.clear();
|
|
||||||
success(String::from("cleared all tasks"));
|
|
||||||
}
|
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
};
|
};
|
||||||
tasks
|
tasks
|
||||||
|
@ -14,7 +14,7 @@ fn main() {
|
|||||||
|
|
||||||
// If the tasks file doesn't exist, create it first
|
// If the tasks file doesn't exist, create it first
|
||||||
if !Path::new(&tasks_file_path).exists() {
|
if !Path::new(&tasks_file_path).exists() {
|
||||||
println!("warning: file '~/.local/share/tasks' does not exist. creating..");
|
cli::warning("file '~/.local/share/tasks' does not exist. creating..");
|
||||||
let tasks = Tasks::new(&tasks_file_path);
|
let tasks = Tasks::new(&tasks_file_path);
|
||||||
data::save_tasks(&tasks_file_path, &tasks).unwrap();
|
data::save_tasks(&tasks_file_path, &tasks).unwrap();
|
||||||
};
|
};
|
||||||
|
37
src/tasks.rs
37
src/tasks.rs
@ -1,13 +1,8 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{NaiveDateTime, Utc};
|
||||||
use colored::*;
|
use colored::*;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct Tag {
|
|
||||||
title: String, // The required title of the tag
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
Inbox,
|
Inbox,
|
||||||
@ -20,7 +15,7 @@ impl Status {
|
|||||||
pub fn as_string(&self) -> ColoredString {
|
pub fn as_string(&self) -> ColoredString {
|
||||||
match self {
|
match self {
|
||||||
Status::Inbox => "📮 Inbox".blue(),
|
Status::Inbox => "📮 Inbox".blue(),
|
||||||
Status::Pending => "🗓️ Pending".yellow(),
|
Status::Pending => "📅 Pending".yellow(),
|
||||||
Status::Active => "✍️ Active".red(),
|
Status::Active => "✍️ Active".red(),
|
||||||
Status::Complete => "📗 Complete".green(),
|
Status::Complete => "📗 Complete".green(),
|
||||||
}
|
}
|
||||||
@ -32,11 +27,11 @@ pub struct Task {
|
|||||||
pub title: String, // The required title of the task
|
pub title: String, // The required title of the task
|
||||||
pub status: Status, // Current status of the task
|
pub status: Status, // Current status of the task
|
||||||
pub notes: Option<String>, // Any notes to explain the task
|
pub notes: Option<String>, // Any notes to explain the task
|
||||||
pub tags: Option<Vec<Tag>>, // Tasks can be tagged for organisation
|
pub tags: Option<Vec<String>>, // Tasks can be tagged for organisation
|
||||||
pub subtasks: Option<Vec<Task>>, // Tasks can be hierarchically split into subtasks
|
pub subtasks: Option<Vec<Task>>, // Tasks can be hierarchically split into subtasks
|
||||||
pub when: Option<DateTime<Utc>>, // The date you want to do the task
|
pub when: Option<NaiveDateTime>, // The date you want to do the task
|
||||||
pub deadline: Option<DateTime<Utc>>, // The latest date the task should be done
|
pub deadline: Option<NaiveDateTime>, // The latest date the task should be done
|
||||||
pub reminder: Option<DateTime<Utc>>, // The datetime a reminder will alert you
|
pub reminder: Option<NaiveDateTime>, // The datetime a reminder will alert you
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
@ -46,16 +41,22 @@ pub struct Tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
pub fn new(title: String) -> Self {
|
pub fn new(title: String, notes: Option<String>, tags: Option<Vec<String>>, when: Option<NaiveDateTime>, deadline: Option<NaiveDateTime>, reminder: Option<NaiveDateTime>) -> Self {
|
||||||
|
let status = if when.is_some() {
|
||||||
|
Status::Pending
|
||||||
|
} else {
|
||||||
|
Status::Inbox
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
title,
|
title,
|
||||||
status: Status::Inbox,
|
status,
|
||||||
notes: None,
|
notes,
|
||||||
tags: None,
|
tags,
|
||||||
subtasks: None,
|
subtasks: None,
|
||||||
when: None,
|
when,
|
||||||
deadline: None,
|
deadline,
|
||||||
reminder: None,
|
reminder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user