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