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