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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Ui {
class InputField;
} // namespace Ui
namespace Main {
class Session;
} // namespace Main
namespace Data {
void ApplyPeerCloudDraft(
not_null<Main::Session*> session,
PeerId peerId,
MsgId topicRootId,
const MTPDdraftMessage &draft);
void ClearPeerCloudDraft(
not_null<Main::Session*> session,
PeerId peerId,
MsgId topicRootId,
TimeId date);
enum class PreviewState : char {
Allowed,
Cancelled,
EmptyOnEdit,
};
struct Draft {
Draft() = default;
Draft(
const TextWithTags &textWithTags,
MsgId msgId,
MsgId topicRootId,
const MessageCursor &cursor,
PreviewState previewState,
mtpRequestId saveRequestId = 0);
Draft(
not_null<const Ui::InputField*> field,
MsgId msgId,
MsgId topicRootId,
PreviewState previewState,
mtpRequestId saveRequestId = 0);
TimeId date = 0;
TextWithTags textWithTags;
MsgId msgId = 0; // replyToId for message draft, editMsgId for edit draft
MsgId topicRootId = 0;
MessageCursor cursor;
PreviewState previewState = PreviewState::Allowed;
mtpRequestId saveRequestId = 0;
};
class DraftKey {
public:
[[nodiscard]] static constexpr DraftKey None() {
return 0;
}
[[nodiscard]] static constexpr DraftKey Local(MsgId topicRootId) {
return (topicRootId < 0 || topicRootId >= ServerMaxMsgId)
? None()
: (topicRootId ? topicRootId.bare : kLocalDraftIndex);
}
[[nodiscard]] static constexpr DraftKey LocalEdit(MsgId topicRootId) {
return (topicRootId < 0 || topicRootId >= ServerMaxMsgId)
? None()
: ((topicRootId ? topicRootId.bare : kLocalDraftIndex)
+ kEditDraftShift);
}
[[nodiscard]] static constexpr DraftKey Cloud(MsgId topicRootId) {
return (topicRootId < 0 || topicRootId >= ServerMaxMsgId)
? None()
: topicRootId
? (kCloudDraftShift + topicRootId.bare)
: kCloudDraftIndex;
}
[[nodiscard]] static constexpr DraftKey Scheduled() {
return kScheduledDraftIndex;
}
[[nodiscard]] static constexpr DraftKey ScheduledEdit() {
return kScheduledDraftIndex + kEditDraftShift;
}
[[nodiscard]] static constexpr DraftKey FromSerialized(qint64 value) {
return value;
}
[[nodiscard]] constexpr qint64 serialize() const {
return _value;
}
[[nodiscard]] static constexpr DraftKey FromSerializedOld(int32 value) {
return !value
? None()
: (value == kLocalDraftIndex + kEditDraftShiftOld)
? LocalEdit(0)
: (value == kScheduledDraftIndex + kEditDraftShiftOld)
? ScheduledEdit()
: (value > 0 && value < 0x4000'0000)
? Local(MsgId(value))
: (value > kEditDraftShiftOld
&& value < kEditDraftShiftOld + 0x4000'000)
? LocalEdit(int64(value - kEditDraftShiftOld))
: None();
}
[[nodiscard]] constexpr bool isLocal() const {
return (_value == kLocalDraftIndex)
|| (_value > 0 && _value < ServerMaxMsgId.bare);
}
[[nodiscard]] constexpr bool isCloud() const {
return (_value == kCloudDraftIndex)
|| (_value > kCloudDraftShift
&& _value < kCloudDraftShift + ServerMaxMsgId.bare);
}
[[nodiscard]] constexpr MsgId topicRootId() const {
const auto max = ServerMaxMsgId.bare;
if (_value > kCloudDraftShift && _value < kCloudDraftShift + max) {
return (_value - kCloudDraftShift);
} else if (_value > kEditDraftShift && _value < kEditDraftShift + max) {
return (_value - kEditDraftShift);
} else if (_value > 0 && _value < max) {
return _value;
}
return 0;
}
friend inline constexpr auto operator<=>(DraftKey, DraftKey) = default;
inline explicit operator bool() const {
return _value != 0;
}
private:
constexpr DraftKey(int64 value) : _value(value) {
}
static constexpr auto kLocalDraftIndex = -1;
static constexpr auto kCloudDraftIndex = -2;
static constexpr auto kScheduledDraftIndex = -3;
static constexpr auto kEditDraftShift = ServerMaxMsgId.bare;
static constexpr auto kCloudDraftShift = 2 * ServerMaxMsgId.bare;
static constexpr auto kEditDraftShiftOld = 0x3FFF'FFFF;
int64 _value = 0;
};
using HistoryDrafts = base::flat_map<DraftKey, std::unique_ptr<Draft>>;
[[nodiscard]] inline bool DraftStringIsEmpty(const QString &text) {
for (const auto &ch : text) {
if (!ch.isSpace()) {
return false;
}
}
return true;
}
[[nodiscard]] inline bool DraftIsNull(const Draft *draft) {
return !draft
|| (!draft->msgId && DraftStringIsEmpty(draft->textWithTags.text));
}
[[nodiscard]] inline bool DraftsAreEqual(const Draft *a, const Draft *b) {
const auto aIsNull = DraftIsNull(a);
const auto bIsNull = DraftIsNull(b);
if (aIsNull) {
return bIsNull;
} else if (bIsNull) {
return false;
}
return (a->textWithTags == b->textWithTags)
&& (a->msgId == b->msgId)
&& (a->previewState == b->previewState);
}
} // namespace Data
|