matrix_sdk_ffi/timeline/
configuration.rs

1use std::sync::Arc;
2
3use matrix_sdk_ui::timeline::{
4    event_type_filter::TimelineEventTypeFilter as InnerTimelineEventTypeFilter,
5    TimelineReadReceiptTracking,
6};
7use ruma::{
8    events::{AnySyncTimelineEvent, TimelineEventType},
9    EventId,
10};
11
12use super::FocusEventError;
13use crate::{
14    error::ClientError,
15    event::{MessageLikeEventType, RoomMessageEventMessageType, StateEventType},
16};
17
18#[derive(uniffi::Object)]
19pub struct TimelineEventTypeFilter {
20    inner: InnerTimelineEventTypeFilter,
21}
22
23#[matrix_sdk_ffi_macros::export]
24impl TimelineEventTypeFilter {
25    #[uniffi::constructor]
26    pub fn include(event_types: Vec<FilterTimelineEventType>) -> Arc<Self> {
27        let event_types: Vec<TimelineEventType> =
28            event_types.iter().map(|t| t.clone().into()).collect();
29        Arc::new(Self { inner: InnerTimelineEventTypeFilter::Include(event_types) })
30    }
31
32    #[uniffi::constructor]
33    pub fn exclude(event_types: Vec<FilterTimelineEventType>) -> Arc<Self> {
34        let event_types: Vec<TimelineEventType> =
35            event_types.iter().map(|t| t.clone().into()).collect();
36        Arc::new(Self { inner: InnerTimelineEventTypeFilter::Exclude(event_types) })
37    }
38}
39
40impl TimelineEventTypeFilter {
41    /// Filters an [`event`] to decide whether it should be part of the timeline
42    /// based on [`AnySyncTimelineEvent::event_type()`].
43    pub(crate) fn filter(&self, event: &AnySyncTimelineEvent) -> bool {
44        self.inner.filter(event)
45    }
46}
47
48#[derive(uniffi::Enum, Clone)]
49pub enum FilterTimelineEventType {
50    MessageLike { event_type: MessageLikeEventType },
51    State { event_type: StateEventType },
52}
53
54impl From<FilterTimelineEventType> for TimelineEventType {
55    fn from(value: FilterTimelineEventType) -> TimelineEventType {
56        match value {
57            FilterTimelineEventType::MessageLike { event_type } => {
58                ruma::events::MessageLikeEventType::from(event_type).into()
59            }
60            FilterTimelineEventType::State { event_type } => {
61                ruma::events::StateEventType::from(event_type).into()
62            }
63        }
64    }
65}
66
67#[derive(uniffi::Enum)]
68pub enum TimelineFocus {
69    Live {
70        /// Whether to hide in-thread replies from the live timeline.
71        hide_threaded_events: bool,
72    },
73    Event {
74        /// The initial event to focus on. This is usually the target of a
75        /// permalink.
76        event_id: String,
77        /// The number of context events to load around the focused event.
78        num_context_events: u16,
79        /// Whether to hide in-thread replies from the live timeline.
80        hide_threaded_events: bool,
81    },
82    Thread {
83        /// The thread root event ID to focus on.
84        root_event_id: String,
85    },
86    PinnedEvents {
87        max_events_to_load: u16,
88        max_concurrent_requests: u16,
89    },
90}
91
92impl TryFrom<TimelineFocus> for matrix_sdk_ui::timeline::TimelineFocus {
93    type Error = ClientError;
94
95    fn try_from(
96        value: TimelineFocus,
97    ) -> Result<matrix_sdk_ui::timeline::TimelineFocus, Self::Error> {
98        match value {
99            TimelineFocus::Live { hide_threaded_events } => Ok(Self::Live { hide_threaded_events }),
100            TimelineFocus::Event { event_id, num_context_events, hide_threaded_events } => {
101                let parsed_event_id =
102                    EventId::parse(&event_id).map_err(|err| FocusEventError::InvalidEventId {
103                        event_id: event_id.clone(),
104                        err: err.to_string(),
105                    })?;
106
107                Ok(Self::Event {
108                    target: parsed_event_id,
109                    num_context_events,
110                    hide_threaded_events,
111                })
112            }
113            TimelineFocus::Thread { root_event_id } => {
114                let parsed_root_event_id = EventId::parse(&root_event_id).map_err(|err| {
115                    FocusEventError::InvalidEventId {
116                        event_id: root_event_id.clone(),
117                        err: err.to_string(),
118                    }
119                })?;
120
121                Ok(Self::Thread { root_event_id: parsed_root_event_id })
122            }
123            TimelineFocus::PinnedEvents { max_events_to_load, max_concurrent_requests } => {
124                Ok(Self::PinnedEvents { max_events_to_load, max_concurrent_requests })
125            }
126        }
127    }
128}
129
130/// Changes how date dividers get inserted, either in between each day or in
131/// between each month
132#[derive(uniffi::Enum)]
133pub enum DateDividerMode {
134    Daily,
135    Monthly,
136}
137
138impl From<DateDividerMode> for matrix_sdk_ui::timeline::DateDividerMode {
139    fn from(value: DateDividerMode) -> Self {
140        match value {
141            DateDividerMode::Daily => Self::Daily,
142            DateDividerMode::Monthly => Self::Monthly,
143        }
144    }
145}
146
147#[derive(uniffi::Enum)]
148pub enum TimelineFilter {
149    /// Show all the events in the timeline, independent of their type.
150    All,
151    /// Show only `m.room.messages` of the given room message types.
152    OnlyMessage {
153        /// A list of [`RoomMessageEventMessageType`] that will be allowed to
154        /// appear in the timeline.
155        types: Vec<RoomMessageEventMessageType>,
156    },
157    /// Show only events which match this filter.
158    EventTypeFilter { filter: Arc<TimelineEventTypeFilter> },
159}
160
161/// Various options used to configure the timeline's behavior.
162#[derive(uniffi::Record)]
163pub struct TimelineConfiguration {
164    /// What should the timeline focus on?
165    pub focus: TimelineFocus,
166
167    /// How should we filter out events from the timeline?
168    pub filter: TimelineFilter,
169
170    /// An optional String that will be prepended to
171    /// all the timeline item's internal IDs, making it possible to
172    /// distinguish different timeline instances from each other.
173    pub internal_id_prefix: Option<String>,
174
175    /// How often to insert date dividers
176    pub date_divider_mode: DateDividerMode,
177
178    /// Should the read receipts and read markers be tracked for the timeline
179    /// items in this instance and on which event types?
180    ///
181    /// As this has a non negligible performance impact, make sure to enable it
182    /// only when you need it.
183    pub track_read_receipts: TimelineReadReceiptTracking,
184
185    /// Whether this timeline instance should report UTDs through the client's
186    /// delegate.
187    pub report_utds: bool,
188}