filthy_rich/types/
builder.rs1use std::{collections::HashMap, time::Duration};
2
3use crate::{
4 errors::ActivitySpecBuildError,
5 nf,
6 types::{
7 ActivitySpec, ActivityType, StatusDisplayType,
8 payloads::{AssetsPayload, ButtonPayload},
9 },
10};
11
12pub struct Activity;
15
16impl Activity {
17 #[must_use]
19 #[allow(clippy::new_ret_no_self)]
20 pub fn new() -> ActivityBuilder {
21 ActivityBuilder::default()
22 }
23
24 #[must_use]
32 pub fn empty_spec() -> ActivitySpec {
33 ActivitySpec::default()
34 }
35}
36
37#[derive(Default)]
40pub struct ActivityBuilder {
41 name: Option<String>,
42 activity_type: Option<ActivityType>,
43 status_display_type: Option<StatusDisplayType>,
44 instance: Option<bool>,
45 details: Option<String>,
46 details_url: Option<String>,
47 state: Option<String>,
48 state_url: Option<String>,
49 duration: Option<Duration>,
50 large_image: Option<String>,
51 large_text: Option<String>,
52 large_url: Option<String>,
53 small_image: Option<String>,
54 small_text: Option<String>,
55 small_url: Option<String>,
56 buttons: Option<HashMap<String, String>>,
57}
58
59impl ActivityBuilder {
60 nf!(name, "Name of the activity.", name);
61 nf!(details, "Top text for your activity.", text);
62 nf!(details_url, "URL for the top text of your activity.", url);
63 nf!(
64 state,
65 "Bottom text (top if field `details` is missing) for your activity.",
66 text
67 );
68 nf!(state_url, "URL for the state of your activity.", url);
69 nf!(
70 large_image,
71 "Large image for your activity (e.g. game icon)",
72 key
73 );
74 nf!(
75 large_text,
76 "Text for the large image of your activity.",
77 text
78 );
79 nf!(large_url, "URL for the large image of your activity.", url);
80 nf!(
81 small_image,
82 "Small image for your activity (e.g. game icon)",
83 key
84 );
85 nf!(
86 small_text,
87 "Text for the small image of your activity.",
88 text
89 );
90 nf!(small_url, "URL for the small image of your activity.", url);
91
92 #[must_use]
94 pub fn activity_type(mut self, r#type: ActivityType) -> Self {
95 self.activity_type = Some(r#type);
96 self
97 }
98
99 #[must_use]
101 pub fn set_as_instance(mut self) -> Self {
102 self.instance = Some(true);
103 self
104 }
105
106 #[must_use]
108 pub fn status_display_type(mut self, r#type: StatusDisplayType) -> Self {
109 self.status_display_type = Some(r#type);
110 self
111 }
112
113 #[must_use]
115 pub fn duration(mut self, duration: Duration) -> Self {
116 self.duration = Some(duration);
117 self
118 }
119
120 pub fn add_button(mut self, label: impl Into<String>, url: impl Into<String>) -> Self {
125 if let Some(btns) = &mut self.buttons {
126 btns.insert(label.into(), url.into());
127 } else {
128 let mut btns: HashMap<String, String> = HashMap::new();
129 btns.insert(label.into(), url.into());
130 self.buttons = Some(btns);
131 };
132
133 self
134 }
135
136 pub fn build(self) -> Result<ActivitySpec, ActivitySpecBuildError> {
138 if (self.large_image.is_none() && (self.large_text.is_some() || self.large_url.is_some()))
139 || (self.small_image.is_none()
140 && (self.small_text.is_some() || self.small_url.is_some()))
141 {
142 return Err(ActivitySpecBuildError::ImageAssetsTooEarly);
143 }
144
145 if self.details.is_none() && self.details_url.is_some() {
146 return Err(ActivitySpecBuildError::ElementURLProvidedEarly("details"));
147 } else if self.state.is_none() && self.state_url.is_some() {
148 return Err(ActivitySpecBuildError::ElementURLProvidedEarly("state"));
149 }
150
151 if let Some(s) = self.status_display_type {
152 match s {
153 StatusDisplayType::Details if self.details.is_none() => {
154 return Err(ActivitySpecBuildError::StatusDisplayElementMissing(
155 "details",
156 ));
157 }
158 StatusDisplayType::State if self.state.is_none() => {
159 return Err(ActivitySpecBuildError::StatusDisplayElementMissing("state"));
160 }
161 _ => {}
162 }
163 }
164
165 Ok(ActivitySpec {
166 name: self.name,
167 r#type: self.activity_type,
168 status_display_type: self.status_display_type,
169 details: self.details,
170 details_url: self.details_url,
171 state: self.state,
172 state_url: self.state_url,
173 instance: self.instance,
174 assets: Some(AssetsPayload {
175 large_image: self.large_image,
176 large_url: self.large_url,
177 large_text: self.large_text,
178 small_image: self.small_image,
179 small_text: self.small_text,
180 small_url: self.small_url,
181 }),
182 buttons: self.buttons.map(|btns| {
183 btns.into_iter()
184 .map(|f| ButtonPayload {
185 label: f.0,
186 url: f.1,
187 })
188 .collect()
189 }),
190 duration: self.duration,
191 })
192 }
193}