use std::{collections::HashMap, time::Duration};
use crate::{
errors::ActivitySpecBuildError,
nf,
types::{
ActivitySpec, ActivityType, StatusDisplayType,
payloads::{AssetsPayload, ButtonPayload},
},
};
pub struct Activity;
impl Activity {
#[must_use]
#[allow(clippy::new_ret_no_self)]
pub fn new() -> ActivityBuilder {
ActivityBuilder::default()
}
#[must_use]
pub fn empty_spec() -> ActivitySpec {
ActivitySpec::default()
}
}
#[derive(Default)]
pub struct ActivityBuilder {
name: Option<String>,
activity_type: Option<ActivityType>,
status_display_type: Option<StatusDisplayType>,
instance: Option<bool>,
details: Option<String>,
details_url: Option<String>,
state: Option<String>,
state_url: Option<String>,
duration: Option<Duration>,
large_image: Option<String>,
large_text: Option<String>,
large_url: Option<String>,
small_image: Option<String>,
small_text: Option<String>,
small_url: Option<String>,
buttons: Option<HashMap<String, String>>,
}
impl ActivityBuilder {
nf!(name, "Name of the activity.", name);
nf!(details, "Top text for your activity.", text);
nf!(details_url, "URL for the top text of your activity.", url);
nf!(
state,
"Bottom text (top if field `details` is missing) for your activity.",
text
);
nf!(state_url, "URL for the state of your activity.", url);
nf!(
large_image,
"Large image for your activity (e.g. game icon)",
key
);
nf!(
large_text,
"Text for the large image of your activity.",
text
);
nf!(large_url, "URL for the large image of your activity.", url);
nf!(
small_image,
"Small image for your activity (e.g. game icon)",
key
);
nf!(
small_text,
"Text for the small image of your activity.",
text
);
nf!(small_url, "URL for the small image of your activity.", url);
#[must_use]
pub fn activity_type(mut self, r#type: ActivityType) -> Self {
self.activity_type = Some(r#type);
self
}
#[must_use]
pub fn set_as_instance(mut self) -> Self {
self.instance = Some(true);
self
}
#[must_use]
pub fn status_display_type(mut self, r#type: StatusDisplayType) -> Self {
self.status_display_type = Some(r#type);
self
}
#[must_use]
pub fn duration(mut self, duration: Duration) -> Self {
self.duration = Some(duration);
self
}
pub fn add_button(mut self, label: impl Into<String>, url: impl Into<String>) -> Self {
if let Some(btns) = &mut self.buttons {
btns.insert(label.into(), url.into());
} else {
let mut btns: HashMap<String, String> = HashMap::new();
btns.insert(label.into(), url.into());
self.buttons = Some(btns);
};
self
}
pub fn build(self) -> Result<ActivitySpec, ActivitySpecBuildError> {
if (self.large_image.is_none() && (self.large_text.is_some() || self.large_url.is_some()))
|| (self.small_image.is_none()
&& (self.small_text.is_some() || self.small_url.is_some()))
{
return Err(ActivitySpecBuildError::ImageAssetsTooEarly);
}
if self.details.is_none() && self.details_url.is_some() {
return Err(ActivitySpecBuildError::ElementURLProvidedEarly("details"));
} else if self.state.is_none() && self.state_url.is_some() {
return Err(ActivitySpecBuildError::ElementURLProvidedEarly("state"));
}
if let Some(s) = self.status_display_type {
match s {
StatusDisplayType::Details if self.details.is_none() => {
return Err(ActivitySpecBuildError::StatusDisplayElementMissing(
"details",
));
}
StatusDisplayType::State if self.state.is_none() => {
return Err(ActivitySpecBuildError::StatusDisplayElementMissing("state"));
}
_ => {}
}
}
Ok(ActivitySpec {
name: self.name,
r#type: self.activity_type,
status_display_type: self.status_display_type,
details: self.details,
details_url: self.details_url,
state: self.state,
state_url: self.state_url,
instance: self.instance,
assets: Some(AssetsPayload {
large_image: self.large_image,
large_url: self.large_url,
large_text: self.large_text,
small_image: self.small_image,
small_text: self.small_text,
small_url: self.small_url,
}),
buttons: self.buttons.map(|btns| {
btns.into_iter()
.map(|f| ButtonPayload {
label: f.0,
url: f.1,
})
.collect()
}),
duration: self.duration,
})
}
}