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
29 /// uploaded to the server
30 Departed = 0x03, ///< The event has left the client
31 ReachedServer = 0x04, ///< The server has received the event
32 SendingFailed = 0x05, ///< The server could not receive the event
33 Redacted = 0x08, ///< The event has been redacted
34 Replaced = 0x10, ///< The event has been replaced
35 Hidden = 0x100, ///< The event should not be shown in the timeline
36 };
37 Q_ENUM_NS(Code)
38} // namespace EventStatus
39
40class QUOTIENT_API EventItemBase {
41public:
42 using value_type = RoomEvent;
43
44 explicit EventItemBase(RoomEventPtr&& e) : evt(std::move(e))
45 {
46 Q_ASSERT(evt);
47 }
48
49 const RoomEvent* event() const { return std::to_address(evt); }
50 const RoomEvent* get() const { return event(); }
51 template <EventClass<RoomEvent> EventT>
52 const EventT* viewAs() const
53 {
54 return eventCast<const EventT>(evt);
55 }
56 const RoomEventPtr& operator->() const { return evt; }
57 const RoomEvent& operator*() const { return *evt; }
58
59 // Used for event redaction
60 RoomEventPtr replaceEvent(RoomEventPtr&& other)
61 {
62 return std::exchange(evt, std::move(other));
63 }
64
65 /// Store arbitrary data with the event item
66 void setUserData(std::any userData) { data = std::move(userData); }
67 /// Obtain custom data previously stored with the event item
68 const std::any& userdata() const { return data; }
69 std::any& userData() { return data; }
70
71protected:
72 template <EventClass<RoomEvent> EventT>
73 EventT* getAs()
74 {
75 return eventCast<EventT>(evt);
76 }
77
78private:
79 RoomEventPtr evt;
80 std::any data;
81};
82
83class QUOTIENT_API TimelineItem : public EventItemBase {
84public:
85 // For compatibility with Qt containers, even though we use
86 // a std:: container now for the room timeline
87 using index_t = int;
88
89 TimelineItem(RoomEventPtr&& e, index_t number)
90 : EventItemBase(std::move(e)), idx(number)
91 {}
92
93 index_t index() const { return idx; }
94
95private:
96 index_t idx;
97};
98
99class QUOTIENT_API PendingEventItem : public EventItemBase {
100public:
101 using future_type = QFuture<std::reference_wrapper<const RoomEvent>>;
102
103 explicit PendingEventItem(RoomEventPtr&& e) : EventItemBase(std::move(e))
104 {
105 _promise.setProgressRange(0, 5);
106 }
107
108 EventStatus::Code deliveryStatus() const { return _status; }
109 QDateTime lastUpdated() const { return _lastUpdated; }
110 QString annotation() const { return _annotation; }
111
112 void setDeparted() { setStatus(EventStatus::Departed); }
113 void setFileUploaded(const FileSourceInfo &uploadedFileData);
114 void setReachedServer(const QString& eventId)
115 {
116 setStatus(EventStatus::ReachedServer);
117 (*this)->addId(eventId);
118 }
119 void setMerged(const RoomEvent& intoEvent)
120 {
121 _promise.addResult(intoEvent);
122 _promise.finish();
123 }
124 void setSendingFailed(QString errorText)
125 {
126 setStatus(EventStatus::SendingFailed);
127 _annotation = std::move(errorText);
128 }
129 void resetStatus() { setStatus(EventStatus::Submitted); }
130
131 //! \brief Get a future for the moment when the item gets merged in the timeline
132 //!
133 //! The future will get finished just before this pending item is merged into its remote
134 //! counterpart that comes with /sync. The pending item will always be in ReachedServer state.
135 //! The future result has type implicitly convertible to `const RoomEvent&`.
136 future_type whenMerged() const { return _promise.future(); }
137
138private:
139 // Unlike TimelineItems, it's reasonable to assume PendingEventItems are not many; so we can
140 // add extra fields without breaking the memory bill
141 EventStatus::Code _status = EventStatus::Submitted;
142 QDateTime _lastUpdated = QDateTime::currentDateTimeUtc();
143 QString _annotation;
144 QPromise<std::reference_wrapper<const RoomEvent>> _promise;
145
146 void setStatus(EventStatus::Code status)
147 {
148 _status = status;
149 _lastUpdated = QDateTime::currentDateTimeUtc();
150 _annotation.clear();
151 _promise.start();
152 _promise.setProgressValue(_status);
153 }
154};
155
156inline QDebug& operator<<(QDebug& d, const TimelineItem& ti)
157{
158 QDebugStateSaver dss(d);
159 d.nospace() << "(" << ti.index() << "|" << ti->id() << ")";
160 return d;
161}
162} // namespace Quotient
#define QUOTIENT_API