use std::{
convert::TryFrom,
fmt::{self, Display, Formatter},
};
use chrono_elapsed::*;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use super::DueDateTime;
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Task {
pub id: usize,
pub project_id: usize,
pub content: String,
pub description: Option<String>,
pub completed: State,
pub label_ids: Option<Vec<usize>>,
pub parent_id: Option<usize>,
pub order: usize,
pub priority: Priority,
#[serde(rename = "due")]
pub due_datetime_obj: Option<DueDateTime>,
pub url: String,
}
impl Display for Task {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{completed} {content} {due_in} [{id}]",
completed = self.completed,
content = self.content,
due_in = "", id = self.id
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum Priority {
Low = 1,
Medium = 2,
High = 3,
Urgent = 4,
}
impl Default for Priority {
fn default() -> Self {
Self::Low
}
}
impl From<Priority> for u8 {
fn from(prio: Priority) -> Self {
match prio {
Priority::Low => 1,
Priority::Medium => 2,
Priority::High => 3,
Priority::Urgent => 4,
}
}
}
impl TryFrom<u8> for Priority {
type Error = &'static str;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::Low),
2 => Ok(Self::Medium),
3 => Ok(Self::High),
4 => Ok(Self::Urgent),
_ => Err("`task::Priority` can only be represented by numbers 1-4 (low to urgent)"),
}
}
}
impl From<Priority> for String {
fn from(prio: Priority) -> Self {
match prio {
Priority::Low => Self::from("low"),
Priority::Medium => Self::from("medium"),
Priority::High => Self::from("high"),
Priority::Urgent => Self::from("urgent"),
}
}
}
impl TryFrom<&str> for Priority {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value.trim() {
"low" => Ok(Self::Low),
"medium" => Ok(Self::Medium),
"high" => Ok(Self::High),
"urgent" => Ok(Self::Urgent),
_ => Err("`task::Priority` valid strings are: 'low', 'medium', 'high' and 'urgent'"),
}
}
}
impl Display for Priority {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Priority::Low => write!(f, "{}", String::from(Priority::Low)),
Priority::Medium => write!(f, "{}", String::from(Priority::Medium)),
Priority::High => write!(f, "{}", String::from(Priority::High)),
Priority::Urgent => write!(f, "{}", String::from(Priority::Urgent)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum State {
Incomplete = 0, Complete = 1, }
impl State {
pub fn as_char(&self) -> char {
char::from(*self)
}
pub fn as_bool(&self) -> bool {
bool::from(*self)
}
}
impl Default for State {
fn default() -> Self {
Self::Incomplete
}
}
impl From<State> for bool {
fn from(state: State) -> Self {
match state {
State::Complete => true,
State::Incomplete => false,
}
}
}
impl From<bool> for State {
fn from(b: bool) -> Self {
match b {
true => Self::Complete,
false => Self::Incomplete,
}
}
}
impl From<State> for char {
fn from(state: State) -> Self {
match state {
State::Complete => '✔',
State::Incomplete => '☐',
}
}
}
impl TryFrom<char> for State {
type Error = &'static str;
fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'✔' => Ok(Self::Complete),
'☐' => Ok(Self::Incomplete),
_ => Err("invalid char for `task::State`"),
}
}
}
impl Display for State {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Complete => write!(f, "{}", char::from(Self::Complete)),
Self::Incomplete => write!(f, "{}", char::from(Self::Incomplete)),
}
}
}