1use crate::{
4 endpoints,
5 error::{InvalidUrl, Result},
6};
7use snafu::ResultExt;
8use std::collections::HashMap;
9use url::Url;
10
11#[derive(Clone, Debug)]
12struct Widget(u64, HashMap<&'static str, String>, bool);
13
14impl Widget {
15 fn build(self) -> Result<String> {
16 let widget_uri = if self.2 {
17 endpoints::png_widget(self.0)
18 } else {
19 endpoints::widget(self.0)
20 };
21
22 let params = self.1.into_iter().map(|(k, v)| (k, v)).collect::<Vec<_>>();
23
24 let url = Url::parse_with_params(&widget_uri, params)
25 .with_context(|| InvalidUrl { uri: widget_uri })?;
26
27 Ok(url.into_string())
28 }
29
30 fn insert(&mut self, k: &'static str, v: impl Into<String>) -> &mut Self {
31 self._insert(k, v.into())
32 }
33
34 fn _insert(&mut self, k: &'static str, v: String) -> &mut Self {
35 self.1.insert(k, v);
36
37 self
38 }
39}
40
41#[derive(Clone, Debug)]
43pub struct LargeWidget(Widget);
44
45impl LargeWidget {
46 pub fn new(bot_id: u64) -> Self {
48 Self(Widget(bot_id, HashMap::new(), false))
49 }
50
51 pub fn build(self) -> Result<String> {
59 self.0.build()
60 }
61
62 pub fn top_color(&mut self, value: impl Into<String>) -> &mut Self {
64 self.0.insert("topcolor", value);
65
66 self
67 }
68
69 pub fn middle_color(&mut self, value: impl Into<String>) -> &mut Self {
71 self.0.insert("middlecolor", value);
72
73 self
74 }
75
76 pub fn username_color(&mut self, value: impl Into<String>) -> &mut Self {
78 self.0.insert("usernamecolor", value);
79
80 self
81 }
82
83 pub fn certified_color(&mut self, value: impl Into<String>) -> &mut Self {
85 self.0.insert("certifiedcolor", value);
86
87 self
88 }
89
90 pub fn data_color(&mut self, value: impl Into<String>) -> &mut Self {
92 self.0.insert("datacolor", value);
93
94 self
95 }
96
97 pub fn label_color(&mut self, value: impl Into<String>) -> &mut Self {
99 self.0.insert("labelcolor", value);
100
101 self
102 }
103
104 pub fn png(&mut self, value: bool) -> &mut Self {
106 (self.0).2 = value;
107
108 self
109 }
110}
111
112#[derive(Clone, Debug)]
114pub struct SmallWidget(Widget);
115
116impl SmallWidget {
117 pub fn new(bot_id: u64) -> Self {
119 Self(Widget(bot_id, HashMap::new(), false))
120 }
121
122 pub fn build(self) -> Result<String> {
130 self.0.build()
131 }
132
133 pub fn avatar_background(&mut self, value: impl Into<String>) -> &mut Self {
135 self.0.insert("avatarbg", value);
136
137 self
138 }
139
140 pub fn left_color(&mut self, value: impl Into<String>) -> &mut Self {
142 self.0.insert("leftcolor", value);
143
144 self
145 }
146
147 pub fn left_text_color(&mut self, value: impl Into<String>) -> &mut Self {
149 self.0.insert("lefttextcolor", value);
150
151 self
152 }
153
154 pub fn right_color(&mut self, value: impl Into<String>) -> &mut Self {
156 self.0.insert("rightcolor", value);
157
158 self
159 }
160
161 pub fn right_text_color(&mut self, value: impl Into<String>) -> &mut Self {
163 self.0.insert("righttextcolor", value);
164
165 self
166 }
167
168 pub fn png(&mut self, value: bool) -> &mut Self {
170 (self.0).2 = value;
171
172 self
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::{LargeWidget, SmallWidget};
179 use crate::Result;
180
181 #[test]
184 fn test_small_widget() -> Result<()> {
185 let mut widget = SmallWidget::new(1);
186 widget
187 .avatar_background("00FF00")
188 .left_color("FF0000")
189 .left_text_color("FFFFFF")
190 .right_color("0F0F0F")
191 .right_text_color("F0F0F0")
192 .png(true);
193
194 let url = widget.build()?;
195 assert!(url.contains("avatarbg=00FF00"));
196 assert!(url.contains("lefttextcolor=FFFFFF"));
197 assert!(url.contains("leftcolor=FF0000"));
198 assert!(url.contains("rightcolor=0F0F0F"));
199 assert!(url.contains("righttextcolor=F0F0F0"));
200 assert!(url.starts_with("https://top.gg/api/widget/1.png?"));
201
202 Ok(())
203 }
204
205 #[test]
206 fn test_large_widget() -> Result<()> {
207 let mut widget = LargeWidget::new(1);
208 widget
209 .certified_color("FF0000")
210 .data_color("00FF00")
211 .label_color("0000FF")
212 .middle_color("FFF000")
213 .top_color("000FFF")
214 .username_color("AAAAAA");
215
216 let url = widget.build()?;
217 assert!(url.contains("certifiedcolor=FF0000"));
218 assert!(url.contains("datacolor=00FF00"));
219 assert!(url.contains("labelcolor=0000FF"));
220 assert!(url.contains("middlecolor=FFF000"));
221 assert!(url.contains("topcolor=000FFF"));
222 assert!(url.contains("usernamecolor=AAAAAA"));
223 assert!(url.starts_with("https://top.gg/api/widget/1.svg?"));
224
225 Ok(())
226 }
227}