use derive_builder::Builder;
use derive_getters::Getters;
use matrix_sdk_base::ruma::events::{macros::EventContent, room::message::TextMessageEventContent};
use serde::{Deserialize, Serialize};
use tracing::trace;
use crate::{models::TextMessageContent, util::deserialize_some, Result};
use super::{Display, Icon, Update, UtcDateTime};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum EventLocation {
Physical {
#[serde(default, skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
description: Option<TextMessageEventContent>,
#[serde(default, skip_serializing_if = "Option::is_none")]
icon: Option<Icon>,
#[serde(default, skip_serializing_if = "Option::is_none")]
coordinates: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
uri: Option<String>,
},
Virtual {
uri: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
description: Option<TextMessageEventContent>,
#[serde(default, skip_serializing_if = "Option::is_none")]
icon: Option<Icon>,
},
}
pub struct EventLocationInfo {
pub inner: EventLocation,
}
impl EventLocationInfo {
pub fn new(location: &EventLocation) -> Self {
match location {
EventLocation::Physical {
name,
description,
icon,
coordinates,
uri,
} => EventLocationInfo {
inner: EventLocation::Physical {
name: name.clone(),
description: description.clone(),
icon: icon.clone(),
coordinates: coordinates.clone(),
uri: uri.clone(),
},
},
EventLocation::Virtual {
uri,
name,
description,
icon,
} => EventLocationInfo {
inner: EventLocation::Virtual {
uri: uri.clone(),
name: name.clone(),
description: description.clone(),
icon: icon.clone(),
},
},
}
}
pub fn location_type(&self) -> String {
match &self.inner {
EventLocation::Physical { .. } => "Physical".to_string(),
EventLocation::Virtual { .. } => "Virtual".to_string(),
}
}
pub fn name(&self) -> Option<String> {
match &self.inner {
EventLocation::Physical { name, .. } => name.clone(),
EventLocation::Virtual { name, .. } => name.clone(),
}
}
pub fn description(&self) -> Option<TextMessageContent> {
match &self.inner {
EventLocation::Physical { description, .. } => {
description.clone().map(TextMessageContent::from)
}
EventLocation::Virtual { description, .. } => {
description.clone().map(TextMessageContent::from)
}
}
}
pub fn icon(&self) -> Option<Icon> {
match &self.inner {
EventLocation::Physical { icon, .. } => icon.clone(),
EventLocation::Virtual { icon, .. } => icon.clone(),
}
}
pub fn coordinates(&self) -> Option<String> {
match &self.inner {
EventLocation::Physical { coordinates, .. } => coordinates.clone(),
_ => None,
}
}
pub fn uri(&self) -> Option<String> {
match &self.inner {
EventLocation::Physical { uri, .. } => uri.clone(),
EventLocation::Virtual { uri, .. } => Some(uri.clone()),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, EventContent, Builder, Getters)]
#[ruma_event(type = "global.acter.dev.calendar_event", kind = MessageLike)]
#[builder(name = "CalendarEventBuilder", derive(Debug))]
pub struct CalendarEventEventContent {
pub title: String,
#[builder(setter(into), default)]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<TextMessageEventContent>,
#[builder(setter(into), default)]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub display: Option<Display>,
#[builder(setter(into))]
pub utc_start: UtcDateTime,
#[builder(setter(into))]
pub utc_end: UtcDateTime,
#[builder(default)]
#[serde(default)]
pub show_without_time: bool,
#[builder(default)]
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub locations: Vec<EventLocation>,
#[builder(setter(into), default)]
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub keywords: Vec<String>,
#[builder(setter(into), default)]
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub categories: Vec<String>,
}
impl CalendarEventBuilder {
pub fn into_event_loc(&mut self, loc_info: &EventLocationInfo) -> Self {
let event_loc = loc_info.inner.clone();
self.locations
.as_mut()
.expect("we have growable list")
.push(event_loc);
self.clone()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, EventContent, Builder)]
#[ruma_event(type = "global.acter.dev.calendar_event.update", kind = MessageLike)]
#[builder(name = "CalendarEventUpdateBuilder", derive(Debug))]
pub struct CalendarEventUpdateEventContent {
#[builder(setter(into))]
#[serde(rename = "m.relates_to")]
pub calendar_event: Update,
#[builder(default)]
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_some"
)]
pub title: Option<String>,
#[builder(default)]
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_some"
)]
pub description: Option<Option<TextMessageEventContent>>,
#[builder(default)]
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_some"
)]
pub utc_start: Option<UtcDateTime>,
#[builder(default)]
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_some"
)]
pub utc_end: Option<UtcDateTime>,
#[builder(default)]
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_some"
)]
pub show_without_time: Option<bool>,
#[builder(default)]
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_some"
)]
pub locations: Option<Vec<EventLocation>>,
#[builder(default)]
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_some"
)]
pub keywords: Option<Vec<String>>,
#[builder(default)]
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_some"
)]
pub categories: Option<Vec<String>>,
#[builder(setter(into), default)]
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_some"
)]
pub display: Option<Option<Display>>,
}
impl CalendarEventUpdateEventContent {
pub fn apply(&self, calendar_event: &mut CalendarEventEventContent) -> Result<bool> {
let mut updated = false;
if let Some(title) = &self.title {
calendar_event.title.clone_from(title);
updated = true;
}
if let Some(description) = &self.description {
calendar_event.description.clone_from(description);
updated = true;
}
if let Some(utc_start) = &self.utc_start {
calendar_event.utc_start = *utc_start;
updated = true;
}
if let Some(utc_end) = &self.utc_end {
calendar_event.utc_end = *utc_end;
updated = true;
}
if let Some(locations) = &self.locations {
calendar_event.locations.clone_from(locations);
updated = true;
}
if let Some(show_without_time) = &self.show_without_time {
calendar_event.show_without_time = *show_without_time;
updated = true;
}
if let Some(display) = &self.display {
calendar_event.display.clone_from(display);
updated = true;
}
if let Some(keywords) = &self.keywords {
calendar_event.keywords.clone_from(keywords);
updated = true;
}
if let Some(categories) = &self.categories {
calendar_event.categories.clone_from(categories);
updated = true;
}
trace!(update = ?self, ?updated, ?calendar_event, "CalendarEvent updated");
Ok(updated)
}
}