use serde::{Deserialize, Serialize};
use uuid::Uuid;
use chrono::{DateTime, Utc};
use ical::property::Property;
use url::Url;
use crate::item::SyncStatus;
use crate::utils::random_url;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum CompletionStatus {
Completed(Option<DateTime<Utc>>),
Uncompleted,
}
impl CompletionStatus {
pub fn is_completed(&self) -> bool {
match self {
CompletionStatus::Completed(_) => true,
_ => false,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Task {
url: Url,
uid: String,
sync_status: SyncStatus,
creation_date: Option<DateTime<Utc>>,
last_modified: DateTime<Utc>,
completion_status: CompletionStatus,
name: String,
ical_prod_id: String,
extra_parameters: Vec<Property>,
}
impl Task {
pub fn new(name: String, completed: bool, parent_calendar_url: &Url) -> Self {
let new_url = random_url(parent_calendar_url);
let new_sync_status = SyncStatus::NotSynced;
let new_uid = Uuid::new_v4().to_hyphenated().to_string();
let new_creation_date = Some(Utc::now());
let new_last_modified = Utc::now();
let new_completion_status = if completed {
CompletionStatus::Completed(Some(Utc::now()))
} else { CompletionStatus::Uncompleted };
let ical_prod_id = crate::ical::default_prod_id();
let extra_parameters = Vec::new();
Self::new_with_parameters(name, new_uid, new_url, new_completion_status, new_sync_status, new_creation_date, new_last_modified, ical_prod_id, extra_parameters)
}
pub fn new_with_parameters(name: String, uid: String, new_url: Url,
completion_status: CompletionStatus,
sync_status: SyncStatus, creation_date: Option<DateTime<Utc>>, last_modified: DateTime<Utc>,
ical_prod_id: String, extra_parameters: Vec<Property>,
) -> Self
{
Self {
url: new_url,
uid,
name,
completion_status,
sync_status,
creation_date,
last_modified,
ical_prod_id,
extra_parameters,
}
}
pub fn url(&self) -> &Url { &self.url }
pub fn uid(&self) -> &str { &self.uid }
pub fn name(&self) -> &str { &self.name }
pub fn completed(&self) -> bool { self.completion_status.is_completed() }
pub fn ical_prod_id(&self) -> &str { &self.ical_prod_id }
pub fn sync_status(&self) -> &SyncStatus { &self.sync_status }
pub fn last_modified(&self) -> &DateTime<Utc> { &self.last_modified }
pub fn creation_date(&self) -> Option<&DateTime<Utc>> { self.creation_date.as_ref() }
pub fn completion_status(&self) -> &CompletionStatus { &self.completion_status }
pub fn extra_parameters(&self) -> &[Property] { &self.extra_parameters }
#[cfg(any(test, feature = "integration_tests"))]
pub fn has_same_observable_content_as(&self, other: &Task) -> bool {
self.url == other.url
&& self.uid == other.uid
&& self.name == other.name
&& std::mem::discriminant(&self.sync_status) == std::mem::discriminant(&other.sync_status)
&& std::mem::discriminant(&self.completion_status) == std::mem::discriminant(&other.completion_status)
}
pub fn set_sync_status(&mut self, new_status: SyncStatus) {
self.sync_status = new_status;
}
fn update_sync_status(&mut self) {
match &self.sync_status {
SyncStatus::NotSynced => return,
SyncStatus::LocallyModified(_) => return,
SyncStatus::Synced(prev_vt) => {
self.sync_status = SyncStatus::LocallyModified(prev_vt.clone());
}
SyncStatus::LocallyDeleted(_) => {
log::warn!("Trying to update an item that has previously been deleted. These changes will probably be ignored at next sync.");
return;
},
}
}
fn update_last_modified(&mut self) {
self.last_modified = Utc::now();
}
pub fn set_name(&mut self, new_name: String) {
self.update_sync_status();
self.update_last_modified();
self.name = new_name;
}
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
pub fn mock_remote_calendar_set_name(&mut self, new_name: String) {
self.sync_status = SyncStatus::random_synced();
self.update_last_modified();
self.name = new_name;
}
pub fn set_completion_status(&mut self, new_completion_status: CompletionStatus) {
self.update_sync_status();
self.update_last_modified();
self.completion_status = new_completion_status;
}
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
pub fn mock_remote_calendar_set_completion_status(&mut self, new_completion_status: CompletionStatus) {
self.sync_status = SyncStatus::random_synced();
self.completion_status = new_completion_status;
}
}