Allocate 64 bits for message ids.

This commit is contained in:
John Preston 2021-09-30 10:04:55 +04:00
parent 6adf791b3b
commit 1e660fc2a2
29 changed files with 337 additions and 162 deletions

View file

@ -415,6 +415,7 @@ PRIVATE
data/data_media_types.h
data/data_messages.cpp
data/data_messages.h
data/data_msg_id.h
data/data_notify_settings.cpp
data/data_notify_settings.h
data/data_peer.cpp

View file

@ -662,8 +662,8 @@ QString ApiWrap::exportDirectMessageLink(
const auto fallback = [&] {
auto linkChannel = channel;
auto linkItemId = item->id;
auto linkCommentId = 0;
auto linkThreadId = 0;
auto linkCommentId = MsgId();
auto linkThreadId = MsgId();
if (inRepliesContext) {
if (const auto rootId = item->replyToTop()) {
const auto root = item->history()->owner().message(
@ -693,11 +693,11 @@ QString ApiWrap::exportDirectMessageLink(
: "c/" + QString::number(peerToChannel(linkChannel->id).bare);
const auto query = base
+ '/'
+ QString::number(linkItemId)
+ QString::number(linkItemId.bare)
+ (linkCommentId
? "?comment=" + QString::number(linkCommentId)
? "?comment=" + QString::number(linkCommentId.bare)
: linkThreadId
? "?thread=" + QString::number(linkThreadId)
? "?thread=" + QString::number(linkThreadId.bare)
: "");
if (linkChannel->hasUsername()
&& !linkChannel->isMegagroup()

View file

@ -288,7 +288,6 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
bool out) {
Expects(history->peer->isUser());
static auto id = ServerMaxMsgId + (ServerMaxMsgId / 3);
const auto flags = MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId
| (out ? MessageFlag::Outgoing : MessageFlag(0));
@ -296,7 +295,7 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
const auto viaBotId = UserId();
const auto groupedId = uint64();
const auto item = history->makeMessage(
++id,
history->owner().nextNonHistoryEntryId(),
flags,
replyTo,
viaBotId,

View file

@ -1113,7 +1113,7 @@ QString AppendShareGameScoreUrl(
auto channelAccessHash = uint64(channel ? channel->access : 0);
shareHashDataInts[0] = session->userId().bare;
shareHashDataInts[1] = fullId.channel.bare;
shareHashDataInts[2] = fullId.msg;
shareHashDataInts[2] = uint64(fullId.msg.bare);
shareHashDataInts[3] = channelAccessHash;
// Count SHA1() of data.
@ -1200,7 +1200,6 @@ void ShareGameScoreByHash(
//}
if (((hashDataInts[1] >> 40) != 0)
|| ((hashDataInts[2] >> 32) != 0)
|| (!hashDataInts[1] && channelAccessHash)) {
// If there is no channel id, there should be no channel access_hash.
Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
@ -1208,7 +1207,7 @@ void ShareGameScoreByHash(
}
auto channelId = ChannelId(hashDataInts[1]);
auto msgId = MsgId(hashDataInts[2]);
auto msgId = MsgId(int64(hashDataInts[2]));
if (const auto item = session->data().message(channelId, msgId)) {
FastShareMessage(item);
} else {

View file

@ -141,7 +141,7 @@ private:
};
BoxController::Row::Row(not_null<HistoryItem*> item)
: PeerListRow(item->history()->peer, item->id)
: PeerListRow(item->history()->peer, item->id.bare)
, _items(1, item)
, _date(ItemDateTime(item).date())
, _type(ComputeType(item))

View file

@ -16,7 +16,7 @@ struct SendCommandRequest {
not_null<PeerData*> peer;
QString command;
FullMsgId context;
int replyTo = 0;
MsgId replyTo = 0;
};
[[nodiscard]] QString WrapCommandInChat(

View file

@ -19,6 +19,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Data {
DraftKey DraftKey::FromSerializedOld(int32 value) {
return !value
? DraftKey::None()
: (value == kLocalDraftIndex + kEditDraftShiftOld)
? DraftKey::LocalEdit()
: (value == kScheduledDraftIndex + kEditDraftShiftOld)
? DraftKey::ScheduledEdit()
: (value > 0 && value < 0x4000'0000)
? DraftKey::Replies(int64(value))
: (value > kEditDraftShiftOld
&& value < kEditDraftShiftOld + 0x4000'000)
? DraftKey::RepliesEdit(int64(value - kEditDraftShiftOld))
: DraftKey::None();
}
Draft::Draft(
const TextWithTags &textWithTags,
MsgId msgId,

View file

@ -75,19 +75,21 @@ public:
return kScheduledDraftIndex + kEditDraftShift;
}
[[nodiscard]] static DraftKey Replies(MsgId rootId) {
return rootId;
return rootId.bare;
}
[[nodiscard]] static DraftKey RepliesEdit(MsgId rootId) {
return rootId + kEditDraftShift;
return rootId.bare + kEditDraftShift;
}
[[nodiscard]] static DraftKey FromSerialized(int32 value) {
[[nodiscard]] static DraftKey FromSerialized(qint64 value) {
return value;
}
[[nodiscard]] int32 serialize() const {
[[nodiscard]] qint64 serialize() const {
return _value;
}
[[nodiscard]] static DraftKey FromSerializedOld(int32 value);
inline bool operator<(const DraftKey &other) const {
return _value < other._value;
}
@ -111,15 +113,16 @@ public:
}
private:
DraftKey(int value) : _value(value) {
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;
static constexpr auto kEditDraftShift = ServerMaxMsgId.bare;
static constexpr auto kEditDraftShiftOld = 0x3FFF'FFFF;
int _value = 0;
int64 _value = 0;
};

View file

@ -72,13 +72,13 @@ void Histories::readInbox(not_null<History*> history) {
if (history->lastServerMessageKnown()) {
const auto last = history->lastServerMessage();
DEBUG_LOG(("Reading: last known, reading till %1."
).arg(last ? last->id : 0));
).arg(last ? last->id.bare : 0));
readInboxTill(history, last ? last->id : 0);
return;
} else if (history->loadedAtBottom()) {
if (const auto lastId = history->maxMsgId()) {
DEBUG_LOG(("Reading: loaded at bottom, maxMsgId %1."
).arg(lastId));
).arg(lastId.bare));
readInboxTill(history, lastId);
return;
} else if (history->loadedAtTop()) {
@ -93,7 +93,7 @@ void Histories::readInbox(not_null<History*> history) {
const auto last = history->lastServerMessage();
DEBUG_LOG(("Reading: got entry, reading till %1."
).arg(last ? last->id : 0));
).arg(last ? last->id.bare : 0));
readInboxTill(history, last ? last->id : 0);
});
}
@ -147,7 +147,7 @@ void Histories::readInboxTill(
Expects(IsServerMsgId(tillId) || (!tillId && !force));
DEBUG_LOG(("Reading: readInboxTill %1, force %2."
).arg(tillId
).arg(tillId.bare
).arg(Logs::b(force)));
const auto syncGuard = gsl::finally([&] {
@ -156,8 +156,8 @@ void Histories::readInboxTill(
if (history->unreadCount() > 0) {
if (const auto last = history->lastServerMessage()) {
DEBUG_LOG(("Reading: checking last %1 and %2."
).arg(last->id
).arg(tillId));
).arg(last->id.bare
).arg(tillId.bare));
if (last->id == tillId) {
DEBUG_LOG(("Reading: locally marked as read."));
history->setUnreadCount(0);
@ -180,11 +180,11 @@ void Histories::readInboxTill(
const auto maybeState = lookup(history);
if (maybeState && maybeState->sentReadTill >= tillId) {
DEBUG_LOG(("Reading: readInboxTill finish 3 with %1."
).arg(maybeState->sentReadTill));
).arg(maybeState->sentReadTill.bare));
return;
} else if (maybeState && maybeState->willReadTill >= tillId) {
DEBUG_LOG(("Reading: readInboxTill finish 4 with %1 and force %2."
).arg(maybeState->sentReadTill
).arg(maybeState->sentReadTill.bare
).arg(Logs::b(force)));
if (force) {
sendPendingReadInbox(history);
@ -200,7 +200,7 @@ void Histories::readInboxTill(
&& history->unreadCountKnown()
&& *stillUnread == history->unreadCount()) {
DEBUG_LOG(("Reading: count didn't change so just update till %1"
).arg(tillId));
).arg(tillId.bare));
history->setInboxReadTill(tillId);
return;
}
@ -208,7 +208,7 @@ void Histories::readInboxTill(
state.willReadTill = tillId;
if (force || !stillUnread || !*stillUnread) {
DEBUG_LOG(("Reading: will read till %1 with still unread %2"
).arg(tillId
).arg(tillId.bare
).arg(stillUnread.value_or(-666)));
state.willReadWhen = 0;
sendReadRequests();
@ -216,17 +216,18 @@ void Histories::readInboxTill(
return;
}
} else if (!state.willReadWhen) {
DEBUG_LOG(("Reading: will read till %1 with postponed").arg(tillId));
DEBUG_LOG(("Reading: will read till %1 with postponed"
).arg(tillId.bare));
state.willReadWhen = crl::now() + kReadRequestTimeout;
if (!_readRequestsTimer.isActive()) {
_readRequestsTimer.callOnce(kReadRequestTimeout);
}
} else {
DEBUG_LOG(("Reading: will read till %1 postponed already"
).arg(tillId));
).arg(tillId.bare));
}
DEBUG_LOG(("Reading: marking now with till %1 and still %2"
).arg(tillId
).arg(tillId.bare
).arg(*stillUnread));
history->setInboxReadTill(tillId);
history->setUnreadCount(*stillUnread);
@ -440,7 +441,7 @@ void Histories::requestFakeChatListMessage(
void Histories::sendPendingReadInbox(not_null<History*> history) {
if (const auto state = lookup(history)) {
DEBUG_LOG(("Reading: send pending now with till %1 and when %2"
).arg(state->willReadTill
).arg(state->willReadTill.bare
).arg(state->willReadWhen));
if (state->willReadTill && state->willReadWhen) {
state->willReadWhen = 0;
@ -462,7 +463,7 @@ void Histories::sendReadRequests() {
continue;
} else if (state.willReadWhen <= now) {
DEBUG_LOG(("Reading: sending with till %1."
).arg(state.willReadTill));
).arg(state.willReadTill.bare));
sendReadRequest(history, state);
} else if (!next || *next > state.willReadWhen) {
DEBUG_LOG(("Reading: scheduling for later send."));
@ -483,10 +484,10 @@ void Histories::sendReadRequest(not_null<History*> history, State &state) {
state.willReadWhen = 0;
state.sentReadDone = false;
DEBUG_LOG(("Reading: sending request now with till %1."
).arg(tillId));
).arg(tillId.bare));
sendRequest(history, RequestType::ReadInbox, [=](Fn<void()> finish) {
DEBUG_LOG(("Reading: sending request invoked with till %1."
).arg(tillId));
).arg(tillId.bare));
const auto finished = [=] {
const auto state = lookup(history);
Assert(state != nullptr);

View file

@ -0,0 +1,187 @@
/*
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
#include "data/data_peer_id.h"
struct MsgId {
constexpr MsgId() noexcept = default;
constexpr MsgId(int64 value) noexcept : bare(value) {
}
[[nodiscard]] constexpr explicit operator bool() const noexcept {
return (bare != 0);
}
[[nodiscard]] constexpr bool operator!() const noexcept {
return !bare;
}
[[nodiscard]] constexpr MsgId operator-() const noexcept {
return -bare;
}
constexpr MsgId operator++() noexcept {
return ++bare;
}
constexpr MsgId operator++(int) noexcept {
return bare++;
}
constexpr MsgId operator--() noexcept {
return --bare;
}
constexpr MsgId operator--(int) noexcept {
return bare--;
}
int64 bare = 0;
};
Q_DECLARE_METATYPE(MsgId);
[[nodiscard]] inline constexpr MsgId operator+(MsgId a, MsgId b) noexcept {
return MsgId(a.bare + b.bare);
}
[[nodiscard]] inline constexpr MsgId operator-(MsgId a, MsgId b) noexcept {
return MsgId(a.bare - b.bare);
}
[[nodiscard]] inline constexpr bool operator==(MsgId a, MsgId b) noexcept {
return (a.bare == b.bare);
}
[[nodiscard]] inline constexpr bool operator!=(MsgId a, MsgId b) noexcept {
return (a.bare != b.bare);
}
[[nodiscard]] inline constexpr bool operator<(MsgId a, MsgId b) noexcept {
return (a.bare < b.bare);
}
[[nodiscard]] inline constexpr bool operator>(MsgId a, MsgId b) noexcept {
return (a.bare > b.bare);
}
[[nodiscard]] inline constexpr bool operator<=(MsgId a, MsgId b) noexcept {
return (a.bare <= b.bare);
}
[[nodiscard]] inline constexpr bool operator>=(MsgId a, MsgId b) noexcept {
return (a.bare >= b.bare);
}
constexpr auto StartClientMsgId = MsgId(-0x7FFFFFFF);
constexpr auto EndClientMsgId = MsgId(-0x40000000);
constexpr auto ShowAtTheEndMsgId = MsgId(-0x40000000);
constexpr auto SwitchAtTopMsgId = MsgId(-0x3FFFFFFF);
constexpr auto ShowAtProfileMsgId = MsgId(-0x3FFFFFFE);
constexpr auto ShowAndStartBotMsgId = MsgId(-0x3FFFFFFD);
constexpr auto ShowAtGameShareMsgId = MsgId(-0x3FFFFFFC);
constexpr auto ShowForChooseMessagesMsgId = MsgId(-0x3FFFFFFB);
constexpr auto ServerMaxMsgId = MsgId(1LL << 56);
constexpr auto ShowAtUnreadMsgId = MsgId(0);
[[nodiscard]] constexpr inline bool IsClientMsgId(MsgId id) noexcept {
return (id >= StartClientMsgId && id < EndClientMsgId);
}
[[nodiscard]] constexpr inline bool IsServerMsgId(MsgId id) noexcept {
return (id > 0 && id < ServerMaxMsgId);
}
struct MsgRange {
constexpr MsgRange() noexcept = default;
constexpr MsgRange(MsgId from, MsgId till) noexcept
: from(from)
, till(till) {
}
MsgId from = 0;
MsgId till = 0;
};
[[nodiscard]] inline constexpr bool operator==(
MsgRange a,
MsgRange b) noexcept {
return (a.from == b.from) && (a.till == b.till);
}
[[nodiscard]] inline constexpr bool operator!=(
MsgRange a,
MsgRange b) noexcept {
return !(a == b);
}
struct FullMsgId {
constexpr FullMsgId() noexcept = default;
constexpr FullMsgId(ChannelId channel, MsgId msg) noexcept
: channel(channel), msg(msg) {
}
constexpr explicit operator bool() const noexcept {
return msg != 0;
}
constexpr bool operator!() const noexcept {
return msg == 0;
}
ChannelId channel = NoChannel;
MsgId msg = 0;
};
[[nodiscard]] inline constexpr bool operator<(
const FullMsgId &a,
const FullMsgId &b) noexcept {
if (a.channel < b.channel) {
return true;
} else if (a.channel > b.channel) {
return false;
}
return a.msg < b.msg;
}
[[nodiscard]] inline constexpr bool operator>(
const FullMsgId &a,
const FullMsgId &b) noexcept {
return b < a;
}
[[nodiscard]] inline constexpr bool operator<=(
const FullMsgId &a,
const FullMsgId &b) noexcept {
return !(b < a);
}
[[nodiscard]] inline constexpr bool operator>=(
const FullMsgId &a,
const FullMsgId &b) noexcept {
return !(a < b);
}
[[nodiscard]] inline constexpr bool operator==(
const FullMsgId &a,
const FullMsgId &b) noexcept {
return (a.channel == b.channel) && (a.msg == b.msg);
}
[[nodiscard]] inline constexpr bool operator!=(
const FullMsgId &a,
const FullMsgId &b) noexcept {
return !(a == b);
}
Q_DECLARE_METATYPE(FullMsgId);
namespace std {
template <>
struct hash<MsgId> : private hash<int64> {
size_t operator()(MsgId value) const noexcept {
return hash<int64>::operator()(value.bare);
}
};
} // namespace std

View file

@ -546,7 +546,7 @@ uint64 ScheduledMessages::countListHash(const List &list) const {
}) | ranges::views::reverse;
for (const auto &item : serverside) {
const auto j = list.idByItem.find(item.get());
HashUpdate(hash, j->second);
HashUpdate(hash, j->second.bare);
if (const auto edited = item->Get<HistoryMessageEdited>()) {
HashUpdate(hash, edited->date);
} else {

View file

@ -1838,8 +1838,8 @@ void Session::processMessages(
continue;
}
}
const auto id = IdFromMessage(message);
indices.emplace((uint64(uint32(id)) << 32) | uint64(i), i);
const auto id = IdFromMessage(message); // Only 32 bit values here.
indices.emplace((uint64(uint32(id.bare)) << 32) | uint64(i), i);
}
for (const auto &[position, index] : indices) {
addNewMessage(

View file

@ -366,7 +366,7 @@ std::optional<int> SharedMediaWithLastSlice::indexOf(Value value) const {
: QString("-"));
if (const auto msgId = std::get_if<FullMsgId>(&value)) {
info.push_back("value:" + QString::number(msgId->channel.bare));
info.push_back(QString::number(msgId->msg));
info.push_back(QString::number(msgId->msg.bare));
const auto index = _slice.indexOf(*std::get_if<FullMsgId>(&value));
info.push_back("index:" + (index
? QString::number(*index)

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/value_ordering.h"
#include "ui/text/text.h" // For QFIXED_MAX
#include "data/data_peer_id.h"
#include "data/data_msg_id.h"
class HistoryItem;
using HistoryItemsList = std::vector<not_null<HistoryItem*>>;
@ -100,80 +101,6 @@ class Folder;
using FolderId = int32;
using FilterId = int32;
using MsgId = int32;
constexpr auto StartClientMsgId = MsgId(-0x7FFFFFFF);
constexpr auto EndClientMsgId = MsgId(-0x40000000);
constexpr auto ShowAtTheEndMsgId = MsgId(-0x40000000);
constexpr auto SwitchAtTopMsgId = MsgId(-0x3FFFFFFF);
constexpr auto ShowAtProfileMsgId = MsgId(-0x3FFFFFFE);
constexpr auto ShowAndStartBotMsgId = MsgId(-0x3FFFFFFD);
constexpr auto ShowAtGameShareMsgId = MsgId(-0x3FFFFFFC);
constexpr auto ShowForChooseMessagesMsgId = MsgId(-0x3FFFFFFB);
constexpr auto ServerMaxMsgId = MsgId(0x3FFFFFFF);
constexpr auto ShowAtUnreadMsgId = MsgId(0);
constexpr inline bool IsClientMsgId(MsgId id) {
return (id >= StartClientMsgId && id < EndClientMsgId);
}
constexpr inline bool IsServerMsgId(MsgId id) {
return (id > 0 && id < ServerMaxMsgId);
}
struct MsgRange {
MsgRange() = default;
MsgRange(MsgId from, MsgId till) : from(from), till(till) {
}
MsgId from = 0;
MsgId till = 0;
};
inline bool operator==(const MsgRange &a, const MsgRange &b) {
return (a.from == b.from) && (a.till == b.till);
}
inline bool operator!=(const MsgRange &a, const MsgRange &b) {
return !(a == b);
}
struct FullMsgId {
constexpr FullMsgId() = default;
constexpr FullMsgId(ChannelId channel, MsgId msg)
: channel(channel), msg(msg) {
}
explicit operator bool() const {
return msg != 0;
}
inline constexpr bool operator<(const FullMsgId &other) const {
if (channel < other.channel) {
return true;
} else if (channel > other.channel) {
return false;
}
return msg < other.msg;
}
inline constexpr bool operator>(const FullMsgId &other) const {
return other < *this;
}
inline constexpr bool operator<=(const FullMsgId &other) const {
return !(other < *this);
}
inline constexpr bool operator>=(const FullMsgId &other) const {
return !(*this < other);
}
inline constexpr bool operator==(const FullMsgId &other) const {
return (channel == other.channel) && (msg == other.msg);
}
inline constexpr bool operator!=(const FullMsgId &other) const {
return !(*this == other);
}
ChannelId channel = NoChannel;
MsgId msg = 0;
};
Q_DECLARE_METATYPE(FullMsgId);
using MessageIdsList = std::vector<FullMsgId>;
@ -182,6 +109,10 @@ MTPDmessage::Flags FlagsFromMessage(const MTPmessage &message);
MsgId IdFromMessage(const MTPmessage &message);
TimeId DateFromMessage(const MTPmessage &message);
[[nodiscard]] inline MTPint MTP_int(MsgId id) noexcept {
return MTP_int(id.bare);
}
class DocumentData;
class PhotoData;
struct WebPageData;

View file

@ -1173,7 +1173,7 @@ HistoryItem *History::latestSendingMessage() const {
});
const auto i = ranges::max_element(sending, ranges::less(), [](
not_null<HistoryItem*> item) {
return uint64(item->date()) << 32 | uint32(item->id);
return std::pair(item->date(), item->id.bare);
});
return (i == sending.end()) ? nullptr : i->get();
}
@ -1466,7 +1466,7 @@ bool History::readInboxTillNeedsRequest(MsgId tillId) {
}
DEBUG_LOG(("Reading: readInboxTillNeedsRequest is_server %1, before %2."
).arg(Logs::b(IsServerMsgId(tillId))
).arg(_inboxReadBefore.value_or(-666)));
).arg(_inboxReadBefore.value_or(-666).bare));
return IsServerMsgId(tillId) && (_inboxReadBefore.value_or(1) <= tillId);
}
@ -1492,9 +1492,9 @@ std::optional<int> History::countStillUnreadLocal(MsgId readTillId) const {
if (_inboxReadBefore) {
const auto before = *_inboxReadBefore;
DEBUG_LOG(("Reading: check before %1 with min %2 and max %3."
).arg(before
).arg(minMsgId()
).arg(maxMsgId()));
).arg(before.bare
).arg(minMsgId().bare
).arg(maxMsgId().bare));
if (minMsgId() <= before && maxMsgId() >= readTillId) {
auto result = 0;
for (const auto &block : blocks) {
@ -1520,7 +1520,7 @@ std::optional<int> History::countStillUnreadLocal(MsgId readTillId) const {
}
const auto minimalServerId = minMsgId();
DEBUG_LOG(("Reading: check at end loaded from %1 loaded %2 - %3").arg(
QString::number(minimalServerId),
QString::number(minimalServerId.bare),
Logs::b(loadedAtBottom()),
Logs::b(loadedAtTop())));
if (!loadedAtBottom()

View file

@ -477,7 +477,7 @@ HistoryMessage::HistoryMessage(
}
config.replyTo = data.vreply_to_msg_id().v;
config.replyToTop = data.vreply_to_top_id().value_or(
config.replyTo);
data.vreply_to_msg_id().v);
});
}
config.viaBotId = data.vvia_bot_id().value_or_empty();
@ -527,7 +527,7 @@ HistoryMessage::HistoryMessage(
if (!peer || peer == history->peer->id) {
config.replyTo = data.vreply_to_msg_id().v;
config.replyToTop = data.vreply_to_top_id().value_or(
config.replyTo);
data.vreply_to_msg_id().v);
}
});
}
@ -820,7 +820,7 @@ void HistoryMessage::setRepliesInboxReadTill(
MsgId readTillId,
std::optional<int> unreadCount) {
if (const auto views = Get<HistoryMessageViews>()) {
const auto newReadTillId = std::max(readTillId, 1);
const auto newReadTillId = std::max(readTillId.bare, int64(1));
const auto ignore = (newReadTillId < views->repliesInboxReadTillId);
if (ignore) {
return;
@ -870,7 +870,7 @@ MsgId HistoryMessage::repliesOutboxReadTill() const {
void HistoryMessage::setRepliesOutboxReadTill(MsgId readTillId) {
if (const auto views = Get<HistoryMessageViews>()) {
const auto newReadTillId = std::max(readTillId, 1);
const auto newReadTillId = std::max(readTillId.bare, int64(1));
if (newReadTillId > views->repliesOutboxReadTillId) {
views->repliesOutboxReadTillId = newReadTillId;
if (!repliesAreComments()) {
@ -1747,10 +1747,15 @@ void HistoryMessage::setReplies(const MTPMessageReplies &data) {
const auto channelId = ChannelId(
data.vchannel_id().value_or_empty());
const auto readTillId = data.vread_max_id()
? std::max(
{ views->repliesInboxReadTillId, data.vread_max_id()->v, 1 })
? std::max({
views->repliesInboxReadTillId.bare,
int64(data.vread_max_id()->v),
int64(1),
})
: views->repliesInboxReadTillId;
const auto maxId = data.vmax_id().value_or(views->repliesMaxId);
const auto maxId = data.vmax_id()
? data.vmax_id()->v
: views->repliesMaxId;
const auto countsChanged = (views->replies.count != count)
|| (views->repliesInboxReadTillId != readTillId)
|| (views->repliesMaxId != maxId);

View file

@ -1172,7 +1172,7 @@ void HistoryWidget::checkNextHighlight() {
return msgId;
}
}
return 0;
return MsgId();
}();
if (!nextHighlight) {
return;
@ -2844,7 +2844,7 @@ void HistoryWidget::firstLoadMessages() {
}
auto from = _history;
auto offsetId = 0;
auto offsetId = MsgId();
auto offset = 0;
auto loadCount = kMessagesPerPage;
if (_showAtMsgId == ShowAtUnreadMsgId) {
@ -3018,7 +3018,7 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) {
_delayedShowAtMsgId = showAtMsgId;
auto from = _history;
auto offsetId = 0;
auto offsetId = MsgId();
auto offset = 0;
auto loadCount = kMessagesPerPage;
if (_delayedShowAtMsgId == ShowAtUnreadMsgId) {

View file

@ -60,7 +60,7 @@ namespace {
PinnedMemento::PinnedMemento(
not_null<History*> history,
MsgId highlightId)
UniversalMsgId highlightId)
: _history(history)
, _highlightId(highlightId) {
_list.setAroundPosition({

View file

@ -166,7 +166,7 @@ private:
class PinnedMemento : public Window::SectionMemento {
public:
using UniversalMsgId = int32;
using UniversalMsgId = MsgId;
explicit PinnedMemento(
not_null<History*> history,

View file

@ -153,7 +153,7 @@ void PinnedTracker::clear() {
_current = PinnedId();
}
void PinnedTracker::trackAround(MsgId messageId) {
void PinnedTracker::trackAround(UniversalMsgId messageId) {
if (_aroundId == messageId) {
return;
}

View file

@ -19,7 +19,7 @@ namespace HistoryView {
class PinnedTracker final {
public:
using UniversalMsgId = int32;
using UniversalMsgId = MsgId;
explicit PinnedTracker(not_null<History*> history);
~PinnedTracker();

View file

@ -49,7 +49,7 @@ QString DocumentTimestampLinkBase(
FullMsgId context) {
return QString(
"doc%1_%2_%3"
).arg(document->id).arg(context.channel.bare).arg(context.msg);
).arg(document->id).arg(context.channel.bare).arg(context.msg.bare);
}
TextWithEntities AddTimestampLinks(

View file

@ -986,7 +986,7 @@ SparseIdsMergedSlice::Key ListWidget::sliceKey(
}
if (universalId < 0) {
// Convert back to plain id for non-migrated histories.
universalId += ServerMaxMsgId;
universalId = universalId + ServerMaxMsgId;
}
return Key(_peer->id, 0, universalId);
}

View file

@ -46,7 +46,7 @@ class AbstractController;
namespace Media {
using BaseLayout = Overview::Layout::ItemBase;
using UniversalMsgId = int32;
using UniversalMsgId = MsgId;
class ListWidget final
: public Ui::RpWidget

View file

@ -64,13 +64,14 @@ QByteArray SessionSettings::serialize() const {
for (const auto &[id, time] : _mediaLastPlaybackPosition) {
stream << quint64(id) << qint64(time);
}
stream << qint32(_hiddenPinnedMessages.size());
for (const auto &[key, value] : _hiddenPinnedMessages) {
stream << SerializePeerId(key) << qint32(value);
}
stream << qint32(0);
stream << qint32(_dialogsFiltersEnabled ? 1 : 0);
stream << qint32(_supportAllSilent ? 1 : 0);
stream << qint32(_photoEditorHintShowsCount);
stream << qint32(_hiddenPinnedMessages.size());
for (const auto &[key, value] : _hiddenPinnedMessages) {
stream << SerializePeerId(key) << qint64(value.bare);
}
}
return result;
}
@ -310,6 +311,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
auto count = qint32(0);
stream >> count;
if (stream.status() == QDataStream::Ok) {
// Legacy.
for (auto i = 0; i != count; ++i) {
auto key = quint64();
auto value = qint32();
@ -332,6 +334,23 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> photoEditorHintShowsCount;
}
if (!stream.atEnd()) {
auto count = qint32(0);
stream >> count;
if (stream.status() == QDataStream::Ok) {
for (auto i = 0; i != count; ++i) {
auto key = quint64();
auto value = qint64();
stream >> key >> value;
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for SessionSettings::addFromSerialized()"));
return;
}
hiddenPinnedMessages.emplace(DeserializePeerId(key), value);
}
}
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for SessionSettings::addFromSerialized()"));

View file

@ -133,12 +133,10 @@ AdminLog::OwnedItem GenerateForwardedItem(
Expects(history->peer->isUser());
using Flag = MTPDmessage::Flag;
// #TODO common global incrementable id for fake items, like clientMsgId.
static auto id = ServerMaxMsgId + (ServerMaxMsgId / 6);
const auto flags = Flag::f_from_id | Flag::f_fwd_from;
const auto item = MTP_message(
MTP_flags(flags),
MTP_int(++id),
MTP_int(history->owner().nextNonHistoryEntryId()),
peerToMTP(history->peer->id),
peerToMTP(history->peer->id),
MTP_messageFwdHeader(

View file

@ -1074,14 +1074,14 @@ bool ReadSetting(
} break;
case dbiHiddenPinnedMessagesOld: {
auto v = QMap<uint64, MsgId>();
auto v = QMap<uint64, int32>();
stream >> v;
if (!CheckStreamStatus(stream)) return false;
for (auto i = v.begin(), e = v.end(); i != e; ++i) {
context.sessionSettings().setHiddenPinnedMessageId(
DeserializePeerId(i.key()),
i.value());
MsgId(i.value()));
}
context.legacyRead = true;
} break;

View file

@ -54,8 +54,10 @@ constexpr auto kSinglePeerTypeChat = qint32(8 + 2);
constexpr auto kSinglePeerTypeChannel = qint32(8 + 3);
constexpr auto kSinglePeerTypeSelf = qint32(4);
constexpr auto kSinglePeerTypeEmpty = qint32(0);
constexpr auto kMultiDraftTag = quint64(0xFFFFFFFFFFFFFF01ULL);
constexpr auto kMultiDraftCursorsTag = quint64(0xFFFFFFFFFFFFFF02ULL);
constexpr auto kMultiDraftTagOld = quint64(0xFFFF'FFFF'FFFF'FF01ULL);
constexpr auto kMultiDraftCursorsTagOld = quint64(0xFFFF'FFFF'FFFF'FF02ULL);
constexpr auto kMultiDraftTag = quint64(0xFFFF'FFFF'FFFF'FF03ULL);
constexpr auto kMultiDraftCursorsTag = quint64(0xFFFF'FFFF'FFFF'FF04ULL);
enum { // Local Storage Keys
lskUserMap = 0x00,
@ -1068,10 +1070,10 @@ void Account::writeDrafts(not_null<History*> history) {
const TextWithTags &text,
Data::PreviewState,
auto&&) { // cursor
size += sizeof(qint32) // key
size += sizeof(qint64) // key
+ Serialize::stringSize(text.text)
+ sizeof(quint32) + TextUtilities::SerializeTagsSize(text.tags)
+ 2 * sizeof(qint32); // msgId, previewState
+ sizeof(qint64) + TextUtilities::SerializeTagsSize(text.tags)
+ sizeof(qint64) + sizeof(qint32); // msgId, previewState
};
EnumerateDrafts(
map,
@ -1096,7 +1098,7 @@ void Account::writeDrafts(not_null<History*> history) {
<< key.serialize()
<< text.text
<< TextUtilities::SerializeTags(text.tags)
<< qint32(msgId)
<< qint64(msgId.bare)
<< qint32(previewState);
};
EnumerateDrafts(
@ -1143,7 +1145,7 @@ void Account::writeDraftCursors(not_null<History*> history) {
auto size = int(sizeof(quint64) * 2
+ sizeof(quint32)
+ sizeof(qint32) * 4 * count);
+ (sizeof(qint64) + sizeof(qint32) * 3) * count);
EncryptedDescriptor data(size);
data.stream
@ -1196,7 +1198,9 @@ void Account::readDraftCursors(PeerId peerId, Data::HistoryDrafts &map) {
}
quint64 tag = 0;
draft.stream >> tag;
if (tag != kMultiDraftTag && tag != kMultiDraftCursorsTag) {
if (tag != kMultiDraftCursorsTag
&& tag != kMultiDraftCursorsTagOld
&& tag != kMultiDraftTagOld) {
readDraftCursorsLegacy(peerId, draft, tag, map);
return;
}
@ -1209,13 +1213,19 @@ void Account::readDraftCursors(PeerId peerId, Data::HistoryDrafts &map) {
return;
}
const auto keysWritten = (tag == kMultiDraftCursorsTag);
const auto keysOld = (tag == kMultiDraftCursorsTagOld);
for (auto i = 0; i != count; ++i) {
qint32 keyValue = 0;
qint64 keyValue = 0;
qint32 keyValueOld = 0;
if (keysWritten) {
draft.stream >> keyValue;
} else if (keysOld) {
draft.stream >> keyValueOld;
}
const auto key = keysWritten
? Data::DraftKey::FromSerialized(keyValue)
: keysOld
? Data::DraftKey::FromSerializedOld(keyValueOld)
: Data::DraftKey::Local();
qint32 position = 0, anchor = 0, scroll = QFIXED_MAX;
draft.stream >> position >> anchor >> scroll;
@ -1287,7 +1297,7 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
quint64 tag = 0;
draft.stream >> tag;
if (tag != kMultiDraftTag) {
if (tag != kMultiDraftTag && tag != kMultiDraftTagOld) {
readDraftsWithCursorsLegacy(history, draft, tag);
return;
}
@ -1302,12 +1312,18 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
return;
}
auto map = Data::HistoryDrafts();
const auto keysOld = (tag == kMultiDraftTagOld);
for (auto i = 0; i != count; ++i) {
TextWithTags data;
QByteArray tagsSerialized;
qint32 keyValue = 0, messageId = 0, uncheckedPreviewState = 0;
qint64 keyValue = 0;
qint32 keyValueOld = 0, messageId = 0, uncheckedPreviewState = 0;
if (keysOld) {
draft.stream >> keyValueOld;
} else {
draft.stream >> keyValue;
}
draft.stream
>> keyValue
>> data.text
>> tagsSerialized
>> messageId
@ -1321,7 +1337,9 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
case Data::PreviewState::EmptyOnEdit:
previewState = Data::PreviewState(uncheckedPreviewState);
}
const auto key = Data::DraftKey::FromSerialized(keyValue);
const auto key = keysOld
? Data::DraftKey::FromSerializedOld(keyValueOld)
: Data::DraftKey::FromSerialized(keyValue);
if (key && key != Data::DraftKey::Cloud()) {
map.emplace(key, std::make_unique<Data::Draft>(
data,

View file

@ -274,7 +274,6 @@ AdminLog::OwnedItem GenerateCommentItem(
if (data.comment.isEmpty()) {
return nullptr;
}
const auto id = ServerMaxMsgId + (ServerMaxMsgId / 2);
const auto flags = MessageFlag::HasFromId
| MessageFlag::Outgoing
| MessageFlag::FakeHistoryItem;
@ -282,7 +281,7 @@ AdminLog::OwnedItem GenerateCommentItem(
const auto viaBotId = UserId();
const auto groupedId = uint64();
const auto item = history->makeMessage(
id,
history->owner().nextNonHistoryEntryId(),
flags,
replyTo,
viaBotId,
@ -305,7 +304,7 @@ AdminLog::OwnedItem GenerateContactItem(
const auto postAuthor = QString();
const auto groupedId = uint64();
const auto item = history->makeMessage(
(ServerMaxMsgId + (ServerMaxMsgId / 2) + 1),
history->owner().nextNonHistoryEntryId(),
(MessageFlag::HasFromId
| MessageFlag::Outgoing
| MessageFlag::FakeHistoryItem),