rtd 0.3.3

Manage your todo in command line
Documentation
use time::OffsetDateTime;

use super::Priority;
use super::SmartDate;

pub const SMART_LISTS: [&str; 1] = ["today"];

#[derive(Debug)]
pub struct Task {
    pub id: u32,
    pub title: String,
    pub done: bool,
    pub today: String,
    pub list: String,
    pub priority: Priority,
    pub created_at: OffsetDateTime,
    pub completed_at: Option<OffsetDateTime>,
    pub due_date: Option<SmartDate>,
}

impl Task {
    pub fn new(
        title: String,
        list: String,
        priority: Priority,
        due_date: Option<SmartDate>,
    ) -> Task {
        Task {
            id: 0,
            title,
            done: false,
            today: "".to_string(),
            list,
            priority,
            created_at: OffsetDateTime::now_utc(),
            completed_at: None,
            due_date,
        }
    }

    #[allow(clippy::too_many_arguments)]
    pub fn create(
        id: u32,
        title: String,
        done: bool,
        list: String,
        priority: Priority,
        today: String,
        created_at: OffsetDateTime,
        completed_at: Option<OffsetDateTime>,
        due_date: Option<SmartDate>,
    ) -> Task {
        Task {
            id,
            title,
            done,
            today,
            list,
            priority,
            created_at,
            completed_at,
            due_date,
        }
    }

    pub fn mark_completed(self: &mut Self) {
        self.done = true;
        self.completed_at = Some(OffsetDateTime::now_utc());
    }

    pub fn mark_uncompleted(self: &mut Self) {
        self.done = false;
        self.completed_at = None;
    }

    pub fn is_in_list(&self, list: &str) -> bool {
        match list.to_lowercase().as_str() {
            "today" => self.is_marked_for_today() || self.is_due_today(),
            _ => self.list.to_lowercase().eq(list.to_lowercase().as_str()),
        }
    }

    pub fn mark_for_today(self: &mut Self) {
        self.today = Task::today();
    }

    pub fn remove_from_today(self: &mut Self) {
        self.today = String::new();
    }

    pub fn is_marked_for_today(&self) -> bool {
        self.today.eq(Task::today().as_str())
    }

    pub fn is_due_today (&self) -> bool {
        self.due_date.as_ref().map(|due_date| due_date.is_today()).unwrap_or(false)
    }

    fn today() -> String {
        OffsetDateTime::now_utc().format("%F")
    }

    pub fn is_overdue(&self) -> bool {
        !self.done
            && self.due_date.as_ref().map_or_else(
            || false,
            |due_date| OffsetDateTime::now_local().date().gt(&due_date),
        )
    }
}

#[cfg(test)]
pub mod test {
    use crate::model::{Priority, Task};

    #[test]
    fn test_mark_for_today() {
        let mut task = Task::new(
            "test-todo".to_string(),
            "inbox".to_string(),
            Priority::High,
            None,
        );

        task.mark_for_today();
        assert_eq!(task.is_marked_for_today(), true);

        task.remove_from_today();
        assert_eq!(task.is_marked_for_today(), false);
    }

    #[test]
    fn test_in_list() {
        let mut task = Task::new(
            "test-todo".to_string(),
            "inbox".to_string(),
            Priority::High,
            None,
        );

        task.mark_for_today();
        assert_eq!(task.is_in_list("Today"), true);
        assert_eq!(task.is_in_list("Inbox"), true);

        task.remove_from_today();
        assert_eq!(task.is_in_list("today"), false);
    }

    #[test]
    fn test_mark_completed() {
        let mut task = Task::new(
            "test-todo".to_string(),
            "inbox".to_string(),
            Priority::High,
            None,
        );

        assert!(task.completed_at.is_none());

        task.mark_completed();
        assert!(task.done);
        assert!(task.completed_at.is_some());

        task.mark_uncompleted();
        assert_eq!(task.done, false);
        assert_eq!(task.completed_at.is_some(), false);
    }
}