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 add_response(
88 &mut self,
89 sender: OwnedUserId,
90 timestamp: MilliSecondsSinceUnixEpoch,
91 answers: Vec<String>,
92 ) {
93 self.response_data.push(ResponseData { sender, timestamp, answers });
94 }
95
96 pub(crate) fn remove_response(
99 &mut self,
100 sender: &UserId,
101 timestamp: MilliSecondsSinceUnixEpoch,
102 ) {
103 if let Some(idx) = self
104 .response_data
105 .iter()
106 .position(|resp| resp.sender == sender && resp.timestamp == timestamp)
107 {
108 self.response_data.remove(idx);
109 }
110 }
111
112 pub(crate) fn end(&mut self, timestamp: MilliSecondsSinceUnixEpoch) -> bool {
116 if self.end_event_timestamp.is_none() {
117 self.end_event_timestamp = Some(timestamp);
118 true
119 } else {
120 false
121 }
122 }
123
124 pub fn fallback_text(&self) -> Option<String> {
125 self.fallback_text.clone()
126 }
127
128 pub fn results(&self) -> PollResult {
129 let results = compile_unstable_poll_results(
130 &self.poll_start,
131 self.response_data.iter().map(|response_data| PollResponseData {
132 sender: &response_data.sender,
133 origin_server_ts: response_data.timestamp,
134 selections: &response_data.answers,
135 }),
136 self.end_event_timestamp,
137 );
138
139 PollResult {
140 question: self.poll_start.question.text.clone(),
141 kind: self.poll_start.kind.clone(),
142 max_selections: self.poll_start.max_selections.into(),
143 answers: self
144 .poll_start
145 .answers
146 .iter()
147 .map(|i| PollResultAnswer { id: i.id.clone(), text: i.text.clone() })
148 .collect(),
149 votes: results
150 .iter()
151 .map(|i| ((*i.0).to_owned(), i.1.iter().map(|i| i.to_string()).collect()))
152 .collect(),
153 end_time: self.end_event_timestamp,
154 has_been_edited: self.has_been_edited,
155 }
156 }
157
158 pub fn is_edit(&self) -> bool {
160 self.has_been_edited
161 }
162}
163
164impl From<PollState> for NewUnstablePollStartEventContent {
165 fn from(value: PollState) -> Self {
166 let content = UnstablePollStartContentBlock::new(
167 value.poll_start.question.text.clone(),
168 value.poll_start.answers.clone(),
169 );
170 if let Some(text) = value.fallback_text() {
171 NewUnstablePollStartEventContent::plain_text(text, content)
172 } else {
173 NewUnstablePollStartEventContent::new(content)
174 }
175 }
176}
177
178#[derive(Debug)]
179pub struct PollResult {
180 pub question: String,
181 pub kind: PollKind,
182 pub max_selections: u64,
183 pub answers: Vec<PollResultAnswer>,
184 pub votes: HashMap<String, Vec<String>>,
185 pub end_time: Option<MilliSecondsSinceUnixEpoch>,
186 pub has_been_edited: bool,
187}
188
189#[derive(Debug)]
190pub struct PollResultAnswer {
191 pub id: String,
192 pub text: String,
193}