Skip to main content

wire_desktop_core/
timeline.rs

1//! A chronological view of the Wire event records.
2//!
3//! Only [`WireRecordKind::Event`] records with a parseable `time` participate.
4//! Entries carry the cleartext metadata and the payload state, so an encrypted
5//! message still appears on the timeline (with its body marked unrecoverable)
6//! rather than vanishing.
7
8use crate::record::{PayloadState, WireRecord, WireRecordKind, WireStore};
9
10/// One entry in the reconstructed Wire timeline.
11#[non_exhaustive]
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct TimelineEntry {
14    /// The event time as stored (ISO-8601 string).
15    pub time: String,
16    /// The conversation the event belongs to.
17    pub conversation: Option<String>,
18    /// The sender/author.
19    pub sender: Option<String>,
20    /// The Wire event type.
21    pub message_type: Option<String>,
22    /// Whether the body is cleartext, encrypted, or undecodable.
23    pub payload: PayloadState,
24    /// `true` if this event is a recovered deletion tombstone.
25    pub deleted: bool,
26}
27
28/// Build the chronological timeline of event records from an interpreted store.
29///
30/// Events are ordered by their stored `time` (ISO-8601 strings sort
31/// lexicographically in chronological order); an event with no `time` is omitted.
32#[must_use]
33pub fn timeline(store: &WireStore) -> Vec<TimelineEntry> {
34    let mut entries: Vec<TimelineEntry> = store
35        .records
36        .iter()
37        .filter(|r| r.kind == WireRecordKind::Event)
38        .filter_map(entry_for)
39        .collect();
40    entries.sort_by(|a, b| a.time.cmp(&b.time));
41    entries
42}
43
44/// Build a timeline entry for an event record, or `None` when it has no `time`.
45fn entry_for(r: &WireRecord) -> Option<TimelineEntry> {
46    let time = r.time.clone()?;
47    Some(TimelineEntry {
48        time,
49        conversation: r.conversation.clone(),
50        sender: r.sender.clone(),
51        message_type: r.message_type.clone(),
52        payload: r.payload.clone(),
53        deleted: r.deleted,
54    })
55}