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