matrix_sdk_ui/timeline/event_item/content/
polls.rs1use 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(content: NewUnstablePollStartEventContent) -> Self {
54 Self {
55 start_event_content: content,
56 response_data: vec![],
57 end_event_timestamp: None,
58 has_been_edited: false,
59 }
60 }
61
62 pub(crate) fn edit(
65 &self,
66 replacement: NewUnstablePollStartEventContentWithoutRelation,
67 ) -> Option<Self> {
68 if self.end_event_timestamp.is_none() {
69 let mut clone = self.clone();
70 clone.start_event_content.poll_start = replacement.poll_start;
71 clone.start_event_content.text = replacement.text;
72 clone.has_been_edited = true;
73 Some(clone)
74 } else {
75 None
76 }
77 }
78
79 pub(crate) fn add_response(
81 &mut self,
82 sender: OwnedUserId,
83 timestamp: MilliSecondsSinceUnixEpoch,
84 answers: Vec<String>,
85 ) {
86 self.response_data.push(ResponseData { sender, timestamp, answers });
87 }
88
89 pub(crate) fn remove_response(
92 &mut self,
93 sender: &UserId,
94 timestamp: MilliSecondsSinceUnixEpoch,
95 ) {
96 if let Some(idx) = self
97 .response_data
98 .iter()
99 .position(|resp| resp.sender == sender && resp.timestamp == timestamp)
100 {
101 self.response_data.remove(idx);
102 }
103 }
104
105 pub(crate) fn end(&mut self, timestamp: MilliSecondsSinceUnixEpoch) -> bool {
109 if self.end_event_timestamp.is_none() {
110 self.end_event_timestamp = Some(timestamp);
111 true
112 } else {
113 false
114 }
115 }
116
117 pub fn fallback_text(&self) -> Option<String> {
118 self.start_event_content.text.clone()
119 }
120
121 pub fn results(&self) -> PollResult {
122 let results = compile_unstable_poll_results(
123 &self.start_event_content.poll_start,
124 self.response_data.iter().map(|response_data| PollResponseData {
125 sender: &response_data.sender,
126 origin_server_ts: response_data.timestamp,
127 selections: &response_data.answers,
128 }),
129 self.end_event_timestamp,
130 );
131
132 PollResult {
133 question: self.start_event_content.poll_start.question.text.clone(),
134 kind: self.start_event_content.poll_start.kind.clone(),
135 max_selections: self.start_event_content.poll_start.max_selections.into(),
136 answers: self
137 .start_event_content
138 .poll_start
139 .answers
140 .iter()
141 .map(|i| PollResultAnswer { id: i.id.clone(), text: i.text.clone() })
142 .collect(),
143 votes: results
144 .iter()
145 .map(|i| ((*i.0).to_owned(), i.1.iter().map(|i| i.to_string()).collect()))
146 .collect(),
147 end_time: self.end_event_timestamp,
148 has_been_edited: self.has_been_edited,
149 }
150 }
151
152 pub fn is_edit(&self) -> bool {
154 self.has_been_edited
155 }
156}
157
158impl From<PollState> for NewUnstablePollStartEventContent {
159 fn from(value: PollState) -> Self {
160 let content = UnstablePollStartContentBlock::new(
161 value.start_event_content.poll_start.question.text.clone(),
162 value.start_event_content.poll_start.answers.clone(),
163 );
164 if let Some(text) = value.fallback_text() {
165 NewUnstablePollStartEventContent::plain_text(text, content)
166 } else {
167 NewUnstablePollStartEventContent::new(content)
168 }
169 }
170}
171
172#[derive(Debug)]
173pub struct PollResult {
174 pub question: String,
175 pub kind: PollKind,
176 pub max_selections: u64,
177 pub answers: Vec<PollResultAnswer>,
178 pub votes: HashMap<String, Vec<String>>,
179 pub end_time: Option<MilliSecondsSinceUnixEpoch>,
180 pub has_been_edited: bool,
181}
182
183#[derive(Debug)]
184pub struct PollResultAnswer {
185 pub id: String,
186 pub text: String,
187}