libQuotient
A Qt library for building matrix clients
Loading...
Searching...
No Matches
eventitem.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net>
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#pragma once
5
6#include "events/roomevent.h"
7#include "events/filesourceinfo.h"
8
9#include <QtCore/QPromise>
10#include <QtCore/QFuture>
11
12#include <any>
13#include <utility>
14
15namespace Quotient {
16
17namespace EventStatus {
18 Q_NAMESPACE_EXPORT(QUOTIENT_API)
19
20 /** Special marks an event can assume
21 *
22 * This is used to hint at a special status of some events in UI.
23 * All values except Redacted and Hidden are mutually exclusive.
24 */
25 enum Code : uint16_t {
26 Normal = 0x0, //!< No special designation
27 Submitted = 0x01, //!< The event has just been submitted for sending
28 FileUploaded = 0x02, //!< The file attached to the event has been uploaded to the server
29 Departed = 0x03, //!< The event has left the client
30 ReachedServer = 0x04, //!< The server has received the event
31 SendingFailed = 0x05, //!< The server could not receive the event
32 Redacted = 0x08, //!< The event has been redacted
33 Replaced = 0x10, //!< The event has been replaced
34 Hidden = 0x100, //!< The event should not be shown in the timeline
35 };
36 Q_ENUM_NS(Code)
37} // namespace EventStatus
38
39class QUOTIENT_API EventItemBase {
40public:
41 using value_type = RoomEvent;
42
43 explicit EventItemBase(RoomEventPtr&& e) : evt(std::move(e))
44 {
45 Q_ASSERT(evt);
46 }
47
48 const RoomEvent* event() const { return std::to_address(evt); }
49 const RoomEvent* get() const { return event(); }
50 template <EventClass<RoomEvent> EventT>
51 const EventT* viewAs() const
52 {
53 return eventCast<const EventT>(evt);
54 }
55 const RoomEventPtr& operator->() const { return evt; }
56 const RoomEvent& operator*() const { return *evt; }
57
58 // Used for event redaction
59 RoomEventPtr replaceEvent(RoomEventPtr&& other)
60 {
61 return std::exchange(evt, std::move(other));
62 }
63
64 /// Store arbitrary data with the event item
65 void setUserData(std::any userData) { data = std::move(userData); }
66 /// Obtain custom data previously stored with the event item
67 const std::any& userdata() const { return data; }
68 std::any& userData() { return data; }
69
70protected:
71 template <EventClass<RoomEvent> EventT>
72 EventT* getAs()
73 {
74 return eventCast<EventT>(evt);
75 }
76
77private:
78 RoomEventPtr evt;
79 std::any data;
80};
81
82class QUOTIENT_API TimelineItem : public EventItemBase {
83public:
84 // For compatibility with Qt containers, even though we use
85 // a std:: container now for the room timeline
86 using index_t = int;
87
88 TimelineItem(RoomEventPtr&& e, index_t number)
89 : EventItemBase(std::move(e)), idx(number)
90 {}
91
92 index_t index() const { return idx; }
93
94private:
95 index_t idx;
96};
97
98class QUOTIENT_API PendingEventItem : public EventItemBase {
99public:
100 using future_type = QFuture<std::reference_wrapper<const RoomEvent>>;
101
102 explicit PendingEventItem(RoomEventPtr&& e) : EventItemBase(std::move(e))
103 {
104 _promise.setProgressRange(0, 5);
105 }
106
107 EventStatus::Code deliveryStatus() const { return _status; }
108 QDateTime lastUpdated() const { return _lastUpdated; }
109 QString annotation() const { return _annotation; }
110
111 void setDeparted() { setStatus(EventStatus::Departed); }
112 void setFileUploaded(const FileSourceInfo &uploadedFileData);
113 void setReachedServer(const QString& eventId)
114 {
115 setStatus(EventStatus::ReachedServer);
116 (*this)->addId(eventId);
117 }
118 void setMerged(const RoomEvent& intoEvent)
119 {
120 _promise.addResult(intoEvent);
121 _promise.finish();
122 }
123 void setSendingFailed(QString errorText)
124 {
125 setStatus(EventStatus::SendingFailed);
126 _annotation = std::move(errorText);
127 }
128 void resetStatus() { setStatus(EventStatus::Submitted); }
129
130 //! \brief Get a future for the moment when the item gets merged in the timeline
131 //!
132 //! The future will get finished just before this pending item is merged into its remote
133 //! counterpart that comes with /sync. The pending item will always be in ReachedServer state.
134 //! The future result has type implicitly convertible to `const RoomEvent&`.
135 future_type whenMerged() const { return _promise.future(); }
136
137private:
138 // Unlike TimelineItems, it's reasonable to assume PendingEventItems are not many; so we can
139 // add extra fields without breaking the memory bill
140 EventStatus::Code _status = EventStatus::Submitted;
141 QDateTime _lastUpdated = QDateTime::currentDateTimeUtc();
142 QString _annotation;
143 QPromise<std::reference_wrapper<const RoomEvent>> _promise;
144
145 void setStatus(EventStatus::Code status)
146 {
147 _status = status;
148 _lastUpdated = QDateTime::currentDateTimeUtc();
149 _annotation.clear();
150 _promise.start();
151 _promise.setProgressValue(_status);
152 }
153};
154
155inline QDebug& operator<<(QDebug& d, const TimelineItem& ti)
156{
157 QDebugStateSaver dss(d);
158 d.nospace() << "(" << ti.index() << "|" << ti->id() << ")";
159 return d;
160}
161} // namespace Quotient
#define QUOTIENT_API