use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Category {
Short,
Medium,
Long,
Completed,
}
impl Category {
pub fn as_str(&self) -> &'static str {
match self {
Category::Short => "Short",
Category::Medium => "Medium",
Category::Long => "Long",
Category::Completed => "Completed",
}
}
pub fn from_str(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"short" | "s" => Some(Category::Short),
"medium" | "m" => Some(Category::Medium),
"long" | "l" => Some(Category::Long),
"completed" | "c" | "done" => Some(Category::Completed),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ColorTag {
None,
Red,
Yellow,
Green,
Blue,
Magenta,
Cyan,
Gray,
}
impl ColorTag {
pub fn as_str(&self) -> &'static str {
match self {
ColorTag::None => "none",
ColorTag::Red => "red",
ColorTag::Yellow => "yellow",
ColorTag::Green => "green",
ColorTag::Blue => "blue",
ColorTag::Magenta => "magenta",
ColorTag::Cyan => "cyan",
ColorTag::Gray => "gray",
}
}
pub fn from_str(s: &str) -> Self {
match s.to_lowercase().as_str() {
"red" => ColorTag::Red,
"yellow" => ColorTag::Yellow,
"green" => ColorTag::Green,
"blue" => ColorTag::Blue,
"magenta" => ColorTag::Magenta,
"cyan" => ColorTag::Cyan,
"gray" => ColorTag::Gray,
_ => ColorTag::None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubTask {
pub id: u64,
pub title: String,
pub done: bool,
pub created_at: i64,
pub updated_at: i64,
pub color: ColorTag,
pub notes: Option<String>,
#[serde(default)]
pub subtasks: Vec<SubTask>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Todo {
pub id: u64,
pub title: String,
pub notes: Option<String>,
pub created_at: i64,
pub updated_at: i64,
pub color: ColorTag,
pub subtasks: Vec<SubTask>,
}
#[derive(Debug, Clone, Default)]
pub struct State {
pub next_id: u64,
pub short: Vec<Todo>,
pub medium: Vec<Todo>,
pub long: Vec<Todo>,
pub completed: Vec<Todo>,
}
impl State {
pub fn new() -> Self {
Self {
next_id: 1,
..Default::default()
}
}
pub fn get_category_mut(&mut self, cat: Category) -> &mut Vec<Todo> {
match cat {
Category::Short => &mut self.short,
Category::Medium => &mut self.medium,
Category::Long => &mut self.long,
Category::Completed => &mut self.completed,
}
}
pub fn get_category(&self, cat: Category) -> &Vec<Todo> {
match cat {
Category::Short => &self.short,
Category::Medium => &self.medium,
Category::Long => &self.long,
Category::Completed => &self.completed,
}
}
pub fn all_categories() -> [Category; 4] {
[Category::Short, Category::Medium, Category::Long, Category::Completed]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_category_from_str() {
assert_eq!(Category::from_str("short"), Some(Category::Short));
assert_eq!(Category::from_str("s"), Some(Category::Short));
assert_eq!(Category::from_str("MEDIUM"), Some(Category::Medium));
assert_eq!(Category::from_str("l"), Some(Category::Long));
assert_eq!(Category::from_str("done"), Some(Category::Completed));
assert_eq!(Category::from_str("invalid"), None);
}
#[test]
fn test_color_tag_from_str() {
assert_eq!(ColorTag::from_str("red"), ColorTag::Red);
assert_eq!(ColorTag::from_str("BLUE"), ColorTag::Blue);
assert_eq!(ColorTag::from_str("none"), ColorTag::None);
assert_eq!(ColorTag::from_str("invalid"), ColorTag::None);
}
}