Added support for calendar colors
This commit is contained in:
parent
2b339a7aff
commit
17716575d8
11 changed files with 198 additions and 27 deletions
10
src/cache.rs
10
src/cache.rs
|
@ -9,6 +9,7 @@ use std::ffi::OsStr;
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use async_trait::async_trait;
|
||||
use csscolorparser::Color;
|
||||
|
||||
use crate::traits::CalDavSource;
|
||||
use crate::traits::BaseCalendar;
|
||||
|
@ -208,12 +209,12 @@ impl CalDavSource<CachedCalendar> for Cache {
|
|||
self.get_calendar_sync(id)
|
||||
}
|
||||
|
||||
async fn create_calendar(&mut self, id: CalendarId, name: String, supported_components: SupportedComponents) -> Result<Arc<Mutex<CachedCalendar>>, Box<dyn Error>> {
|
||||
async fn create_calendar(&mut self, id: CalendarId, name: String, supported_components: SupportedComponents, color: Option<Color>) -> Result<Arc<Mutex<CachedCalendar>>, Box<dyn Error>> {
|
||||
log::debug!("Inserting local calendar {}", id);
|
||||
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||
self.mock_behaviour.as_ref().map_or(Ok(()), |b| b.lock().unwrap().can_create_calendar())?;
|
||||
|
||||
let new_calendar = CachedCalendar::new(name, id.clone(), supported_components);
|
||||
let new_calendar = CachedCalendar::new(name, id.clone(), supported_components, color);
|
||||
let arc = Arc::new(Mutex::new(new_calendar));
|
||||
|
||||
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||
|
@ -244,12 +245,14 @@ mod tests {
|
|||
Url::parse("https://caldav.com/shopping").unwrap(),
|
||||
"My shopping list".to_string(),
|
||||
SupportedComponents::TODO,
|
||||
Some(csscolorparser::parse("lime").unwrap()),
|
||||
).await.unwrap();
|
||||
|
||||
let bucket_list = cache.create_calendar(
|
||||
Url::parse("https://caldav.com/bucket-list").unwrap(),
|
||||
"My bucket list".to_string(),
|
||||
SupportedComponents::TODO,
|
||||
Some(csscolorparser::parse("#ff8000").unwrap()),
|
||||
).await.unwrap();
|
||||
|
||||
{
|
||||
|
@ -288,11 +291,12 @@ mod tests {
|
|||
let cache_path = PathBuf::from(String::from("test_cache/sanity_tests"));
|
||||
let mut cache = populate_cache(&cache_path).await;
|
||||
|
||||
// We should not be able to add twice the same calendar
|
||||
// We should not be able to add a second calendar with the same id
|
||||
let second_addition_same_calendar = cache.create_calendar(
|
||||
Url::parse("https://caldav.com/shopping").unwrap(),
|
||||
"My shopping list".to_string(),
|
||||
SupportedComponents::TODO,
|
||||
None,
|
||||
).await;
|
||||
assert!(second_addition_same_calendar.is_err());
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::error::Error;
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use async_trait::async_trait;
|
||||
use csscolorparser::Color;
|
||||
|
||||
use crate::item::SyncStatus;
|
||||
use crate::traits::{BaseCalendar, CompleteCalendar};
|
||||
|
@ -24,6 +25,7 @@ pub struct CachedCalendar {
|
|||
name: String,
|
||||
id: CalendarId,
|
||||
supported_components: SupportedComponents,
|
||||
color: Option<Color>,
|
||||
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||
#[serde(skip)]
|
||||
mock_behaviour: Option<Arc<Mutex<MockBehaviour>>>,
|
||||
|
@ -85,7 +87,9 @@ impl CachedCalendar {
|
|||
pub async fn has_same_observable_content_as(&self, other: &CachedCalendar) -> Result<bool, Box<dyn Error>> {
|
||||
if self.name != other.name
|
||||
|| self.id != other.id
|
||||
|| self.supported_components != other.supported_components {
|
||||
|| self.supported_components != other.supported_components
|
||||
|| self.color != other.color
|
||||
{
|
||||
log::debug!("Calendar properties mismatch");
|
||||
return Ok(false);
|
||||
}
|
||||
|
@ -156,6 +160,10 @@ impl BaseCalendar for CachedCalendar {
|
|||
self.supported_components
|
||||
}
|
||||
|
||||
fn color(&self) -> Option<&Color> {
|
||||
self.color.as_ref()
|
||||
}
|
||||
|
||||
async fn add_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
||||
if self.items.contains_key(item.id()) {
|
||||
return Err(format!("Item {:?} cannot be added, it exists already", item.id()).into());
|
||||
|
@ -181,9 +189,9 @@ impl BaseCalendar for CachedCalendar {
|
|||
|
||||
#[async_trait]
|
||||
impl CompleteCalendar for CachedCalendar {
|
||||
fn new(name: String, id: CalendarId, supported_components: SupportedComponents) -> Self {
|
||||
fn new(name: String, id: CalendarId, supported_components: SupportedComponents, color: Option<Color>) -> Self {
|
||||
Self {
|
||||
name, id, supported_components,
|
||||
name, id, supported_components, color,
|
||||
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||
mock_behaviour: None,
|
||||
items: HashMap::new(),
|
||||
|
@ -253,8 +261,8 @@ use crate::{item::VersionTag,
|
|||
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||
#[async_trait]
|
||||
impl DavCalendar for CachedCalendar {
|
||||
fn new(name: String, resource: Resource, supported_components: SupportedComponents) -> Self {
|
||||
crate::traits::CompleteCalendar::new(name, resource.url().clone(), supported_components)
|
||||
fn new(name: String, resource: Resource, supported_components: SupportedComponents, color: Option<Color>) -> Self {
|
||||
crate::traits::CompleteCalendar::new(name, resource.url().clone(), supported_components, color)
|
||||
}
|
||||
|
||||
async fn get_item_version_tags(&self) -> Result<HashMap<ItemId, VersionTag>, Box<dyn Error>> {
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::sync::Mutex;
|
|||
|
||||
use async_trait::async_trait;
|
||||
use reqwest::{header::CONTENT_TYPE, header::CONTENT_LENGTH};
|
||||
use csscolorparser::Color;
|
||||
|
||||
use crate::traits::BaseCalendar;
|
||||
use crate::traits::DavCalendar;
|
||||
|
@ -37,6 +38,7 @@ pub struct RemoteCalendar {
|
|||
name: String,
|
||||
resource: Resource,
|
||||
supported_components: SupportedComponents,
|
||||
color: Option<Color>,
|
||||
|
||||
cached_version_tags: Mutex<Option<HashMap<ItemId, VersionTag>>>,
|
||||
}
|
||||
|
@ -48,6 +50,9 @@ impl BaseCalendar for RemoteCalendar {
|
|||
fn supported_components(&self) -> crate::calendar::SupportedComponents {
|
||||
self.supported_components
|
||||
}
|
||||
fn color(&self) -> Option<&Color> {
|
||||
self.color.as_ref()
|
||||
}
|
||||
|
||||
async fn add_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
||||
let ical_text = crate::ical::build_from(&item)?;
|
||||
|
@ -114,9 +119,9 @@ impl BaseCalendar for RemoteCalendar {
|
|||
|
||||
#[async_trait]
|
||||
impl DavCalendar for RemoteCalendar {
|
||||
fn new(name: String, resource: Resource, supported_components: SupportedComponents) -> Self {
|
||||
fn new(name: String, resource: Resource, supported_components: SupportedComponents, color: Option<Color>) -> Self {
|
||||
Self {
|
||||
name, resource, supported_components,
|
||||
name, resource, supported_components, color,
|
||||
cached_version_tags: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use reqwest::{Method, StatusCode};
|
|||
use reqwest::header::CONTENT_TYPE;
|
||||
use minidom::Element;
|
||||
use url::Url;
|
||||
use csscolorparser::Color;
|
||||
|
||||
use crate::resource::Resource;
|
||||
use crate::utils::{find_elem, find_elems};
|
||||
|
@ -42,6 +43,7 @@ static CAL_BODY: &str = r#"
|
|||
<d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav" >
|
||||
<d:prop>
|
||||
<d:displayname />
|
||||
<E:calendar-color xmlns:E="http://apple.com/ns/ical/"/>
|
||||
<d:resourcetype />
|
||||
<c:supported-calendar-component-set />
|
||||
</d:prop>
|
||||
|
@ -205,7 +207,14 @@ impl Client {
|
|||
},
|
||||
Ok(sc) => sc,
|
||||
};
|
||||
let this_calendar = RemoteCalendar::new(display_name, this_calendar_url, supported_components);
|
||||
|
||||
let this_calendar_color = find_elem(&rep, "calendar-color")
|
||||
.and_then(|col| {
|
||||
col.texts().next()
|
||||
.and_then(|t| csscolorparser::parse(t).ok())
|
||||
});
|
||||
|
||||
let this_calendar = RemoteCalendar::new(display_name, this_calendar_url, supported_components, this_calendar_color);
|
||||
log::info!("Found calendar {}", this_calendar.name());
|
||||
calendars.insert(this_calendar.id().clone(), Arc::new(Mutex::new(this_calendar)));
|
||||
}
|
||||
|
@ -243,7 +252,7 @@ impl CalDavSource<RemoteCalendar> for Client {
|
|||
.map(|cal| cal.clone())
|
||||
}
|
||||
|
||||
async fn create_calendar(&mut self, id: CalendarId, name: String, supported_components: SupportedComponents) -> Result<Arc<Mutex<RemoteCalendar>>, Box<dyn Error>> {
|
||||
async fn create_calendar(&mut self, id: CalendarId, name: String, supported_components: SupportedComponents, color: Option<Color>) -> Result<Arc<Mutex<RemoteCalendar>>, Box<dyn Error>> {
|
||||
self.populate_calendars().await?;
|
||||
|
||||
match self.cached_replies.lock().unwrap().calendars.as_ref() {
|
||||
|
|
|
@ -390,10 +390,12 @@ where
|
|||
let src = needle.lock().unwrap();
|
||||
let name = src.name().to_string();
|
||||
let supported_comps = src.supported_components();
|
||||
let color = src.color();
|
||||
if let Err(err) = haystack.create_calendar(
|
||||
cal_id.clone(),
|
||||
name,
|
||||
supported_comps,
|
||||
color.cloned(),
|
||||
).await{
|
||||
return Err(err);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::collections::{HashMap, HashSet};
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use csscolorparser::Color;
|
||||
|
||||
use crate::item::SyncStatus;
|
||||
use crate::item::Item;
|
||||
|
@ -21,7 +22,7 @@ pub trait CalDavSource<T: BaseCalendar> {
|
|||
/// Returns the calendar matching the ID
|
||||
async fn get_calendar(&self, id: &CalendarId) -> Option<Arc<Mutex<T>>>;
|
||||
/// Create a calendar if it did not exist, and return it
|
||||
async fn create_calendar(&mut self, id: CalendarId, name: String, supported_components: SupportedComponents)
|
||||
async fn create_calendar(&mut self, id: CalendarId, name: String, supported_components: SupportedComponents, color: Option<Color>)
|
||||
-> Result<Arc<Mutex<T>>, Box<dyn Error>>;
|
||||
|
||||
// Removing a calendar is not supported yet
|
||||
|
@ -39,6 +40,9 @@ pub trait BaseCalendar {
|
|||
/// Returns the supported kinds of components for this calendar
|
||||
fn supported_components(&self) -> crate::calendar::SupportedComponents;
|
||||
|
||||
/// Returns the user-defined color of this calendar
|
||||
fn color(&self) -> Option<&Color>;
|
||||
|
||||
/// Add an item into this calendar, and return its new sync status.
|
||||
/// For local calendars, the sync status is not modified.
|
||||
/// For remote calendars, the sync status is updated by the server
|
||||
|
@ -64,7 +68,7 @@ pub trait BaseCalendar {
|
|||
#[async_trait]
|
||||
pub trait DavCalendar : BaseCalendar {
|
||||
/// Create a new calendar
|
||||
fn new(name: String, resource: Resource, supported_components: SupportedComponents) -> Self;
|
||||
fn new(name: String, resource: Resource, supported_components: SupportedComponents, color: Option<Color>) -> Self;
|
||||
|
||||
/// Get the IDs and the version tags of every item in this calendar
|
||||
async fn get_item_version_tags(&self) -> Result<HashMap<ItemId, VersionTag>, Box<dyn Error>>;
|
||||
|
@ -94,7 +98,7 @@ pub trait DavCalendar : BaseCalendar {
|
|||
#[async_trait]
|
||||
pub trait CompleteCalendar : BaseCalendar {
|
||||
/// Create a new calendar
|
||||
fn new(name: String, id: CalendarId, supported_components: SupportedComponents) -> Self;
|
||||
fn new(name: String, id: CalendarId, supported_components: SupportedComponents, color: Option<Color>) -> Self;
|
||||
|
||||
/// Get the IDs of all current items in this calendar
|
||||
async fn get_item_ids(&self) -> Result<HashSet<ItemId>, Box<dyn Error>>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue