tdesktop/Telegram/SourceFiles/data/data_changes.h

395 lines
11 KiB
C++

/*
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 "base/flags.h"
class History;
class PeerData;
class HistoryItem;
namespace Dialogs {
class Entry;
} // namespace Dialogs
namespace Main {
class Session;
} // namespace Main
namespace Data::details {
template <typename Flag>
inline constexpr int CountBit(Flag Last = Flag::LastUsedBit) {
auto i = 0;
while ((1ULL << i) != static_cast<uint64>(Last)) {
++i;
Assert(i != 64);
}
return i;
}
} // namespace Data::details
namespace Data {
class ForumTopic;
class Story;
struct NameUpdate {
NameUpdate(
not_null<PeerData*> peer,
base::flat_set<QChar> oldFirstLetters)
: peer(peer)
, oldFirstLetters(std::move(oldFirstLetters)) {
}
not_null<PeerData*> peer;
base::flat_set<QChar> oldFirstLetters;
};
struct PeerUpdate {
enum class Flag : uint64 {
None = 0,
// Common flags
Name = (1ULL << 0),
Username = (1ULL << 1),
Photo = (1ULL << 2),
About = (1ULL << 3),
Notifications = (1ULL << 4),
Migration = (1ULL << 5),
UnavailableReason = (1ULL << 6),
ChatThemeEmoji = (1ULL << 7),
ChatWallPaper = (1ULL << 8),
IsBlocked = (1ULL << 9),
MessagesTTL = (1ULL << 10),
FullInfo = (1ULL << 11),
Usernames = (1ULL << 12),
TranslationDisabled = (1ULL << 13),
// For users
CanShareContact = (1ULL << 14),
IsContact = (1ULL << 15),
PhoneNumber = (1ULL << 16),
OnlineStatus = (1ULL << 17),
BotCommands = (1ULL << 18),
BotCanBeInvited = (1ULL << 19),
BotStartToken = (1ULL << 20),
CommonChats = (1ULL << 21),
HasCalls = (1ULL << 22),
SupportInfo = (1ULL << 23),
IsBot = (1ULL << 24),
EmojiStatus = (1ULL << 25),
StoriesState = (1ULL << 26),
// For chats and channels
InviteLinks = (1ULL << 27),
Members = (1ULL << 28),
Admins = (1ULL << 29),
BannedUsers = (1ULL << 30),
Rights = (1ULL << 31),
PendingRequests = (1ULL << 32),
Reactions = (1ULL << 33),
// For channels
ChannelAmIn = (1ULL << 34),
StickersSet = (1ULL << 35),
ChannelLinkedChat = (1ULL << 36),
ChannelLocation = (1ULL << 37),
Slowmode = (1ULL << 38),
GroupCall = (1ULL << 39),
// For iteration
LastUsedBit = (1ULL << 39),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }
not_null<PeerData*> peer;
Flags flags = 0;
};
struct HistoryUpdate {
enum class Flag : uint32 {
None = 0,
IsPinned = (1U << 0),
UnreadView = (1U << 1),
TopPromoted = (1U << 2),
Folder = (1U << 3),
UnreadMentions = (1U << 4),
UnreadReactions = (1U << 5),
ClientSideMessages = (1U << 6),
ChatOccupied = (1U << 7),
MessageSent = (1U << 8),
ScheduledSent = (1U << 9),
OutboxRead = (1U << 10),
BotKeyboard = (1U << 11),
CloudDraft = (1U << 12),
TranslateFrom = (1U << 13),
TranslatedTo = (1U << 14),
LastUsedBit = (1U << 14),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }
not_null<History*> history;
Flags flags = 0;
};
struct TopicUpdate {
enum class Flag : uint32 {
None = 0,
UnreadView = (1U << 1),
UnreadMentions = (1U << 2),
UnreadReactions = (1U << 3),
Notifications = (1U << 4),
Title = (1U << 5),
IconId = (1U << 6),
ColorId = (1U << 7),
CloudDraft = (1U << 8),
Closed = (1U << 9),
Creator = (1U << 10),
Destroyed = (1U << 11),
LastUsedBit = (1U << 11),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }
not_null<ForumTopic*> topic;
Flags flags = 0;
};
struct MessageUpdate {
enum class Flag : uint32 {
None = 0,
Edited = (1U << 0),
Destroyed = (1U << 1),
DialogRowRepaint = (1U << 2),
DialogRowRefresh = (1U << 3),
NewAdded = (1U << 4),
ReplyMarkup = (1U << 5),
BotCallbackSent = (1U << 6),
NewMaybeAdded = (1U << 7),
ReplyToTopAdded = (1U << 8),
NewUnreadReaction = (1U << 9),
LastUsedBit = (1U << 9),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }
not_null<HistoryItem*> item;
Flags flags = 0;
};
struct EntryUpdate {
enum class Flag : uint32 {
None = 0,
Repaint = (1U << 0),
HasPinnedMessages = (1U << 1),
ForwardDraft = (1U << 2),
LocalDraftSet = (1U << 3),
Height = (1U << 4),
Destroyed = (1U << 5),
LastUsedBit = (1U << 5),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }
not_null<Dialogs::Entry*> entry;
Flags flags = 0;
};
struct StoryUpdate {
enum class Flag : uint32 {
None = 0,
Edited = (1U << 0),
Destroyed = (1U << 1),
NewAdded = (1U << 2),
ViewsAdded = (1U << 3),
MarkRead = (1U << 4),
Reaction = (1U << 5),
LastUsedBit = (1U << 5),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }
not_null<Story*> story;
Flags flags = 0;
};
class Changes final {
public:
explicit Changes(not_null<Main::Session*> session);
[[nodiscard]] Main::Session &session() const;
void nameUpdated(
not_null<PeerData*> peer,
base::flat_set<QChar> oldFirstLetters);
[[nodiscard]] rpl::producer<NameUpdate> realtimeNameUpdates() const;
[[nodiscard]] rpl::producer<NameUpdate> realtimeNameUpdates(
not_null<PeerData*> peer) const;
void peerUpdated(not_null<PeerData*> peer, PeerUpdate::Flags flags);
[[nodiscard]] rpl::producer<PeerUpdate> peerUpdates(
PeerUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<PeerUpdate> peerUpdates(
not_null<PeerData*> peer,
PeerUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<PeerUpdate> peerFlagsValue(
not_null<PeerData*> peer,
PeerUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<PeerUpdate> realtimePeerUpdates(
PeerUpdate::Flag flag) const;
void historyUpdated(
not_null<History*> history,
HistoryUpdate::Flags flags);
[[nodiscard]] rpl::producer<HistoryUpdate> historyUpdates(
HistoryUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<HistoryUpdate> historyUpdates(
not_null<History*> history,
HistoryUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<HistoryUpdate> historyFlagsValue(
not_null<History*> history,
HistoryUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<HistoryUpdate> realtimeHistoryUpdates(
HistoryUpdate::Flag flag) const;
void topicUpdated(
not_null<ForumTopic*> topic,
TopicUpdate::Flags flags);
[[nodiscard]] rpl::producer<TopicUpdate> topicUpdates(
TopicUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<TopicUpdate> topicUpdates(
not_null<ForumTopic*> topic,
TopicUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<TopicUpdate> topicFlagsValue(
not_null<ForumTopic*> topic,
TopicUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<TopicUpdate> realtimeTopicUpdates(
TopicUpdate::Flag flag) const;
void topicRemoved(not_null<ForumTopic*> topic);
void messageUpdated(
not_null<HistoryItem*> item,
MessageUpdate::Flags flags);
[[nodiscard]] rpl::producer<MessageUpdate> messageUpdates(
MessageUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<MessageUpdate> messageUpdates(
not_null<HistoryItem*> item,
MessageUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<MessageUpdate> messageFlagsValue(
not_null<HistoryItem*> item,
MessageUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<MessageUpdate> realtimeMessageUpdates(
MessageUpdate::Flag flag) const;
void entryUpdated(
not_null<Dialogs::Entry*> entry,
EntryUpdate::Flags flags);
[[nodiscard]] rpl::producer<EntryUpdate> entryUpdates(
EntryUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<EntryUpdate> entryUpdates(
not_null<Dialogs::Entry*> entry,
EntryUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<EntryUpdate> entryFlagsValue(
not_null<Dialogs::Entry*> entry,
EntryUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<EntryUpdate> realtimeEntryUpdates(
EntryUpdate::Flag flag) const;
void entryRemoved(not_null<Dialogs::Entry*> entry);
void storyUpdated(
not_null<Story*> story,
StoryUpdate::Flags flags);
[[nodiscard]] rpl::producer<StoryUpdate> storyUpdates(
StoryUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<StoryUpdate> storyUpdates(
not_null<Story*> story,
StoryUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<StoryUpdate> storyFlagsValue(
not_null<Story*> story,
StoryUpdate::Flags flags) const;
[[nodiscard]] rpl::producer<StoryUpdate> realtimeStoryUpdates(
StoryUpdate::Flag flag) const;
void sendNotifications();
private:
template <typename DataType, typename UpdateType>
class Manager final {
public:
using Flag = typename UpdateType::Flag;
using Flags = typename UpdateType::Flags;
void updated(
not_null<DataType*> data,
Flags flags,
bool dropScheduled = false);
[[nodiscard]] rpl::producer<UpdateType> updates(Flags flags) const;
[[nodiscard]] rpl::producer<UpdateType> updates(
not_null<DataType*> data,
Flags flags) const;
[[nodiscard]] rpl::producer<UpdateType> flagsValue(
not_null<DataType*> data,
Flags flags) const;
[[nodiscard]] rpl::producer<UpdateType> realtimeUpdates(
Flag flag) const;
void drop(not_null<DataType*> data);
void sendNotifications();
private:
static constexpr auto kCount = details::CountBit<Flag>() + 1;
void sendRealtimeNotifications(
not_null<DataType*> data,
Flags flags);
std::array<rpl::event_stream<UpdateType>, kCount> _realtimeStreams;
base::flat_map<not_null<DataType*>, Flags> _updates;
rpl::event_stream<UpdateType> _stream;
};
void scheduleNotifications();
const not_null<Main::Session*> _session;
rpl::event_stream<NameUpdate> _nameStream;
Manager<PeerData, PeerUpdate> _peerChanges;
Manager<History, HistoryUpdate> _historyChanges;
Manager<ForumTopic, TopicUpdate> _topicChanges;
Manager<HistoryItem, MessageUpdate> _messageChanges;
Manager<Dialogs::Entry, EntryUpdate> _entryChanges;
Manager<Story, StoryUpdate> _storyChanges;
bool _notify = false;
};
} // namespace Data