1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
// Copyright 2023 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::{ops::Deref, sync::Arc};
use as_variant::as_variant;
use super::{EventTimelineItem, VirtualTimelineItem};
/// Opaque unique identifier for a timeline item.
///
/// It is transferred whenever a timeline item is updated. This can be used as a
/// stable identifier for UI purposes, as well as operations on the event
/// represented by the item.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TimelineUniqueId(pub String);
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum TimelineItemKind {
/// An event or aggregation of multiple events.
Event(EventTimelineItem),
/// An item that doesn't correspond to an event, for example the user's
/// own read marker.
Virtual(VirtualTimelineItem),
}
/// A single entry in timeline.
#[derive(Clone, Debug)]
pub struct TimelineItem {
pub(crate) kind: TimelineItemKind,
pub(crate) internal_id: TimelineUniqueId,
}
impl TimelineItem {
/// Create a new `TimelineItem` with the given kind and internal id.
pub(crate) fn new(
kind: impl Into<TimelineItemKind>,
internal_id: TimelineUniqueId,
) -> Arc<Self> {
Arc::new(TimelineItem { kind: kind.into(), internal_id })
}
/// Create a clone of the current `TimelineItem` with the given kind.
pub(crate) fn with_kind(&self, kind: impl Into<TimelineItemKind>) -> Arc<Self> {
Arc::new(Self { kind: kind.into(), internal_id: self.internal_id.clone() })
}
/// Get the [`TimelineItemKind`] of this item.
pub fn kind(&self) -> &TimelineItemKind {
&self.kind
}
/// Get the inner `EventTimelineItem`, if this is a
/// [`TimelineItemKind::Event`].
pub fn as_event(&self) -> Option<&EventTimelineItem> {
as_variant!(&self.kind, TimelineItemKind::Event)
}
/// Get the inner `VirtualTimelineItem`, if this is a
/// [`TimelineItemKind::Virtual`].
pub fn as_virtual(&self) -> Option<&VirtualTimelineItem> {
as_variant!(&self.kind, TimelineItemKind::Virtual)
}
/// Get a unique ID for this timeline item.
///
/// It identifies the item on a best-effort basis. For instance, edits
/// to an [`EventTimelineItem`] will not change the ID of the
/// enclosing `TimelineItem`. For some virtual items like day
/// dividers, identity isn't easy to define though and you might
/// see a new ID getting generated for a day divider that you
/// perceive to be "the same" as a previous one.
pub fn unique_id(&self) -> &TimelineUniqueId {
&self.internal_id
}
pub(crate) fn read_marker() -> Arc<TimelineItem> {
Arc::new(Self {
kind: TimelineItemKind::Virtual(VirtualTimelineItem::ReadMarker),
internal_id: TimelineUniqueId("__read_marker".to_owned()),
})
}
pub(crate) fn is_local_echo(&self) -> bool {
matches!(&self.kind, TimelineItemKind::Event(ev) if ev.is_local_echo())
}
pub(crate) fn is_remote_event(&self) -> bool {
matches!(&self.kind, TimelineItemKind::Event(ev) if ev.is_remote_event())
}
pub(crate) fn is_event(&self) -> bool {
matches!(&self.kind, TimelineItemKind::Event(_))
}
/// Check whether this item is a day divider.
#[must_use]
pub fn is_day_divider(&self) -> bool {
matches!(self.kind, TimelineItemKind::Virtual(VirtualTimelineItem::DayDivider(_)))
}
pub(crate) fn is_read_marker(&self) -> bool {
matches!(self.kind, TimelineItemKind::Virtual(VirtualTimelineItem::ReadMarker))
}
}
impl Deref for TimelineItem {
type Target = TimelineItemKind;
fn deref(&self) -> &Self::Target {
&self.kind
}
}
impl From<EventTimelineItem> for TimelineItemKind {
fn from(item: EventTimelineItem) -> Self {
Self::Event(item)
}
}
impl From<VirtualTimelineItem> for TimelineItemKind {
fn from(item: VirtualTimelineItem) -> Self {
Self::Virtual(item)
}
}