matrix_sdk_ui/timeline/event_item/content/
polls.rs1use std::collections::HashMap;
18
19use ruma::{
20 MilliSecondsSinceUnixEpoch, OwnedUserId, UserId,
21 events::poll::{
22 PollResponseData, compile_unstable_poll_results,
23 start::PollKind,
24 unstable_start::{
25 NewUnstablePollStartEventContent, NewUnstablePollStartEventContentWithoutRelation,
26 UnstablePollStartContentBlock,
27 },
28 },
29};
30
31#[derive(Clone, Debug)]
37pub struct PollState {
38 pub(in crate::timeline) fallback_text: Option<String>,
41 pub(in crate::timeline) poll_start: UnstablePollStartContentBlock,
43 pub(in crate::timeline) response_data: Vec<ResponseData>,
44 pub(in crate::timeline) end_event_timestamp: Option<MilliSecondsSinceUnixEpoch>,
45 pub(in crate::timeline) has_been_edited: bool,
46}
47
48#[derive(Clone, Debug)]
49pub(in crate::timeline) struct ResponseData {
50 pub sender: OwnedUserId,
51 pub timestamp: MilliSecondsSinceUnixEpoch,
52 pub answers: Vec<String>,
53}
54
55impl PollState {
56 pub(crate) fn new(
57 poll_start: UnstablePollStartContentBlock,
58 fallback_text: Option<String>,
59 ) -> Self {
60 Self {
61 fallback_text,
62 poll_start,
63 response_data: vec![],
64 end_event_timestamp: None,
65 has_been_edited: false,
66 }
67 }
68
69 pub(crate) fn edit(
72 &self,
73 replacement: NewUnstablePollStartEventContentWithoutRelation,
74 ) -> Option<Self> {
75 if self.end_event_timestamp.is_none() {
76 let mut clone = self.clone();
77 clone.poll_start = replacement.poll_start;
78 clone.fallback_text = replacement.text;
79 clone.has_been_edited = true;
80 Some(clone)
81 } else {
82 None
83 }
84 }
85
86 pub(crate) fn unedit(&self, unedited: &Self) -> Self {
92 let mut clone = self.clone();
93 clone.poll_start = unedited.poll_start.clone();
94 clone.fallback_text = unedited.fallback_text.clone();
95 clone.has_been_edited = unedited.has_been_edited;
96 clone
97 }
98
99 pub(crate) fn add_response(
101 &mut self,
102 sender: OwnedUserId,
103 timestamp: MilliSecondsSinceUnixEpoch,
104 answers: Vec<String>,
105 ) {
106 self.response_data.push(ResponseData { sender, timestamp, answers });
107 }
108
109 pub(crate) fn remove_response(
112 &mut self,
113 sender: &UserId,
114 timestamp: MilliSecondsSinceUnixEpoch,
115 ) {
116 if let Some(idx) = self
117 .response_data
118 .iter()
119 .position(|resp| resp.sender == sender && resp.timestamp == timestamp)
120 {
121 self.response_data.remove(idx);
122 }
123 }
124
125 pub(crate) fn end(&mut self, timestamp: MilliSecondsSinceUnixEpoch) -> bool {
129 if self.end_event_timestamp.is_none() {
130 self.end_event_timestamp = Some(timestamp);
131 true
132 } else {
133 false
134 }
135 }
136
137 pub fn fallback_text(&self) -> Option<String> {
140 self.fallback_text.clone()
141 }
142
143 pub fn results(&self) -> PollResult {
145 let results = compile_unstable_poll_results(
146 &self.poll_start,
147 self.response_data.iter().map(|response_data| PollResponseData {
148 sender: &response_data.sender,
149 origin_server_ts: response_data.timestamp,
150 selections: &response_data.answers,
151 }),
152 self.end_event_timestamp,
153 );
154
155 PollResult {
156 question: self.poll_start.question.text.clone(),
157 kind: self.poll_start.kind.clone(),
158 max_selections: self.poll_start.max_selections.into(),
159 answers: self
160 .poll_start
161 .answers
162 .iter()
163 .map(|i| PollResultAnswer { id: i.id.clone(), text: i.text.clone() })
164 .collect(),
165 votes: results
166 .into_iter()
167 .map(|(id, users)| {
168 (id.to_owned(), users.into_iter().map(ToOwned::to_owned).collect())
169 })
170 .collect(),
171 end_time: self.end_event_timestamp,
172 has_been_edited: self.has_been_edited,
173 }
174 }
175
176 pub fn is_edit(&self) -> bool {
178 self.has_been_edited
179 }
180}
181
182impl From<PollState> for NewUnstablePollStartEventContent {
183 fn from(value: PollState) -> Self {
184 let content = UnstablePollStartContentBlock::new(
185 value.poll_start.question.text.clone(),
186 value.poll_start.answers.clone(),
187 );
188 if let Some(text) = value.fallback_text() {
189 NewUnstablePollStartEventContent::plain_text(text, content)
190 } else {
191 NewUnstablePollStartEventContent::new(content)
192 }
193 }
194}
195
196#[derive(Debug)]
198pub struct PollResult {
199 pub question: String,
201 pub kind: PollKind,
203 pub max_selections: u64,
205 pub answers: Vec<PollResultAnswer>,
207 pub votes: HashMap<String, Vec<OwnedUserId>>,
212 pub end_time: Option<MilliSecondsSinceUnixEpoch>,
216 pub has_been_edited: bool,
218}
219
220#[derive(Debug)]
222pub struct PollResultAnswer {
223 pub id: String,
227 pub text: String,
231}