mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-08-31 14:38:15 +00:00
Show saved messages sublists in profile.
This commit is contained in:
@@ -343,12 +343,6 @@ int Folder::storiesUnreadCount() const {
|
||||
return _storiesUnreadCount;
|
||||
}
|
||||
|
||||
void Folder::requestChatListMessage() {
|
||||
if (!chatListMessageKnown()) {
|
||||
owner().histories().requestDialogEntry(this);
|
||||
}
|
||||
}
|
||||
|
||||
TimeId Folder::adjustedChatListTimeId() const {
|
||||
return chatListTimeId();
|
||||
}
|
||||
|
@@ -49,9 +49,9 @@ public:
|
||||
Dialogs::BadgesState chatListBadgesState() const override;
|
||||
HistoryItem *chatListMessage() const override;
|
||||
bool chatListMessageKnown() const override;
|
||||
void requestChatListMessage() override;
|
||||
const QString &chatListName() const override;
|
||||
const QString &chatListNameSortKey() const override;
|
||||
int chatListNameVersion() const override;
|
||||
const base::flat_set<QString> &chatListNameWords() const override;
|
||||
const base::flat_set<QChar> &chatListFirstLetters() const override;
|
||||
|
||||
@@ -82,8 +82,6 @@ public:
|
||||
private:
|
||||
void indexNameParts();
|
||||
|
||||
int chatListNameVersion() const override;
|
||||
|
||||
void reorderLastHistories();
|
||||
|
||||
void paintUserpic(
|
||||
|
@@ -98,6 +98,7 @@ public:
|
||||
|
||||
void setRealRootId(MsgId realId);
|
||||
void readTillEnd();
|
||||
void requestChatListMessage();
|
||||
|
||||
void applyTopic(const MTPDforumTopic &data);
|
||||
|
||||
@@ -109,9 +110,9 @@ public:
|
||||
Dialogs::BadgesState chatListBadgesState() const override;
|
||||
HistoryItem *chatListMessage() const override;
|
||||
bool chatListMessageKnown() const override;
|
||||
void requestChatListMessage() override;
|
||||
const QString &chatListName() const override;
|
||||
const QString &chatListNameSortKey() const override;
|
||||
int chatListNameVersion() const override;
|
||||
const base::flat_set<QString> &chatListNameWords() const override;
|
||||
const base::flat_set<QChar> &chatListFirstLetters() const override;
|
||||
|
||||
@@ -187,8 +188,6 @@ private:
|
||||
void allowChatListMessageResolve();
|
||||
void resolveChatListMessageGroup();
|
||||
|
||||
int chatListNameVersion() const override;
|
||||
|
||||
void subscribeToUnreadChanges();
|
||||
[[nodiscard]] Dialogs::UnreadState unreadStateFor(
|
||||
int count,
|
||||
|
@@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_saved_messages.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_histories.h"
|
||||
@@ -1029,6 +1030,10 @@ bool PeerData::sharedMediaInfo() const {
|
||||
return isSelf() || isRepliesChat();
|
||||
}
|
||||
|
||||
bool PeerData::savedSublistsInfo() const {
|
||||
return isSelf() && owner().savedMessages().supported();
|
||||
}
|
||||
|
||||
bool PeerData::hasStoriesHidden() const {
|
||||
if (const auto user = asUser()) {
|
||||
return user->hasStoriesHidden();
|
||||
|
@@ -203,6 +203,7 @@ public:
|
||||
[[nodiscard]] bool isGigagroup() const;
|
||||
[[nodiscard]] bool isRepliesChat() const;
|
||||
[[nodiscard]] bool sharedMediaInfo() const;
|
||||
[[nodiscard]] bool savedSublistsInfo() const;
|
||||
[[nodiscard]] bool hasStoriesHidden() const;
|
||||
void setStoriesHidden(bool hidden);
|
||||
|
||||
|
@@ -141,6 +141,18 @@ int PremiumLimits::topicsPinnedCurrent() const {
|
||||
return appConfigLimit("topics_pinned_limit", 5);
|
||||
}
|
||||
|
||||
int PremiumLimits::savedSublistsPinnedDefault() const {
|
||||
return appConfigLimit("saved_dialogs_pinned_limit_default", 5);
|
||||
}
|
||||
int PremiumLimits::savedSublistsPinnedPremium() const {
|
||||
return appConfigLimit("saved_dialogs_pinned_limit_premium", 100);
|
||||
}
|
||||
int PremiumLimits::savedSublistsPinnedCurrent() const {
|
||||
return isPremium()
|
||||
? savedSublistsPinnedPremium()
|
||||
: savedSublistsPinnedDefault();
|
||||
}
|
||||
|
||||
int PremiumLimits::channelsPublicDefault() const {
|
||||
return appConfigLimit("channels_public_limit_default", 10);
|
||||
}
|
||||
|
@@ -59,6 +59,10 @@ public:
|
||||
|
||||
[[nodiscard]] int topicsPinnedCurrent() const;
|
||||
|
||||
[[nodiscard]] int savedSublistsPinnedDefault() const;
|
||||
[[nodiscard]] int savedSublistsPinnedPremium() const;
|
||||
[[nodiscard]] int savedSublistsPinnedCurrent() const;
|
||||
|
||||
[[nodiscard]] int channelsPublicDefault() const;
|
||||
[[nodiscard]] int channelsPublicPremium() const;
|
||||
[[nodiscard]] int channelsPublicCurrent() const;
|
||||
|
181
Telegram/SourceFiles/data/data_saved_messages.cpp
Normal file
181
Telegram/SourceFiles/data/data_saved_messages.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
#include "data/data_saved_messages.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_saved_sublist.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
constexpr auto kPerPage = 50;
|
||||
constexpr auto kFirstPerPage = 10;
|
||||
|
||||
} // namespace
|
||||
|
||||
SavedMessages::SavedMessages(not_null<Session*> owner)
|
||||
: _owner(owner)
|
||||
, _chatsList(
|
||||
&owner->session(),
|
||||
FilterId(),
|
||||
owner->maxPinnedChatsLimitValue(this)) {
|
||||
}
|
||||
|
||||
SavedMessages::~SavedMessages() = default;
|
||||
|
||||
bool SavedMessages::supported() const {
|
||||
return !_unsupported;
|
||||
}
|
||||
|
||||
Session &SavedMessages::owner() const {
|
||||
return *_owner;
|
||||
}
|
||||
|
||||
Main::Session &SavedMessages::session() const {
|
||||
return _owner->session();
|
||||
}
|
||||
|
||||
not_null<Dialogs::MainList*> SavedMessages::chatsList() {
|
||||
return &_chatsList;
|
||||
}
|
||||
|
||||
not_null<SavedSublist*> SavedMessages::sublist(not_null<PeerData*> peer) {
|
||||
const auto i = _sublists.find(peer);
|
||||
if (i != end(_sublists)) {
|
||||
return i->second.get();
|
||||
}
|
||||
return _sublists.emplace(
|
||||
peer,
|
||||
std::make_unique<SavedSublist>(peer)).first->second.get();
|
||||
}
|
||||
|
||||
void SavedMessages::loadMore() {
|
||||
if (_loadMoreRequestId || _chatsList.loaded()) {
|
||||
return;
|
||||
}
|
||||
_loadMoreRequestId = _owner->session().api().request(
|
||||
MTPmessages_GetSavedDialogs(
|
||||
MTP_flags(0),
|
||||
MTP_int(_offsetDate),
|
||||
MTP_int(_offsetId),
|
||||
_offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(),
|
||||
MTP_int(kPerPage),
|
||||
MTP_long(0)) // hash
|
||||
).done([=](const MTPmessages_SavedDialogs &result) {
|
||||
auto list = (const QVector<MTPSavedDialog>*)nullptr;
|
||||
result.match([](const MTPDmessages_savedDialogsNotModified &) {
|
||||
LOG(("API Error: messages.savedDialogsNotModified."));
|
||||
}, [&](const auto &data) {
|
||||
_owner->processUsers(data.vusers());
|
||||
_owner->processChats(data.vchats());
|
||||
_owner->processMessages(
|
||||
data.vmessages(),
|
||||
NewMessageType::Existing);
|
||||
list = &data.vdialogs().v;
|
||||
});
|
||||
_loadMoreRequestId = 0;
|
||||
if (!list) {
|
||||
_chatsList.setLoaded();
|
||||
return;
|
||||
}
|
||||
auto lastValid = false;
|
||||
const auto selfId = _owner->session().userPeerId();
|
||||
for (const auto &dialog : *list) {
|
||||
const auto &data = dialog.data();
|
||||
const auto peer = _owner->peer(peerFromMTP(data.vpeer()));
|
||||
const auto topId = MsgId(data.vtop_message().v);
|
||||
if (const auto item = _owner->message(selfId, topId)) {
|
||||
_offsetPeer = peer;
|
||||
_offsetDate = item->date();
|
||||
_offsetId = topId;
|
||||
lastValid = true;
|
||||
sublist(peer)->applyMaybeLast(item);
|
||||
} else {
|
||||
lastValid = false;
|
||||
}
|
||||
}
|
||||
if (!lastValid) {
|
||||
LOG(("API Error: Unknown message in the end of a slice."));
|
||||
_chatsList.setLoaded();
|
||||
} else if (result.type() == mtpc_messages_savedDialogs) {
|
||||
_chatsList.setLoaded();
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
|
||||
_unsupported = true;
|
||||
}
|
||||
_chatsList.setLoaded();
|
||||
_loadMoreRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
void SavedMessages::loadMore(not_null<SavedSublist*> sublist) {
|
||||
if (_loadMoreRequests.contains(sublist) || sublist->isFullLoaded()) {
|
||||
return;
|
||||
}
|
||||
const auto &list = sublist->messages();
|
||||
const auto offsetId = list.empty() ? MsgId(0) : list.back()->id;
|
||||
const auto offsetDate = list.empty() ? MsgId(0) : list.back()->date();
|
||||
const auto limit = offsetId ? kPerPage : kFirstPerPage;
|
||||
const auto requestId = _owner->session().api().request(
|
||||
MTPmessages_GetSavedHistory(
|
||||
sublist->peer()->input,
|
||||
MTP_int(offsetId),
|
||||
MTP_int(offsetDate),
|
||||
MTP_int(0), // add_offset
|
||||
MTP_int(limit),
|
||||
MTP_int(0), // max_id
|
||||
MTP_int(0), // min_id
|
||||
MTP_long(0)) // hash
|
||||
).done([=](const MTPmessages_Messages &result) {
|
||||
auto list = (const QVector<MTPMessage>*)nullptr;
|
||||
result.match([](const MTPDmessages_channelMessages &) {
|
||||
LOG(("API Error: messages.channelMessages in sublist."));
|
||||
}, [](const MTPDmessages_messagesNotModified &) {
|
||||
LOG(("API Error: messages.messagesNotModified in sublist."));
|
||||
}, [&](const auto &data) {
|
||||
owner().processUsers(data.vusers());
|
||||
owner().processChats(data.vchats());
|
||||
list = &data.vmessages().v;
|
||||
});
|
||||
|
||||
_loadMoreRequests.remove(sublist);
|
||||
if (!list) {
|
||||
sublist->setFullLoaded();
|
||||
return;
|
||||
}
|
||||
auto items = std::vector<not_null<HistoryItem*>>();
|
||||
items.reserve(list->size());
|
||||
for (const auto &message : *list) {
|
||||
const auto item = owner().addNewMessage(
|
||||
message,
|
||||
{},
|
||||
NewMessageType::Existing);
|
||||
if (item) {
|
||||
items.push_back(item);
|
||||
}
|
||||
}
|
||||
sublist->append(std::move(items));
|
||||
if (result.type() == mtpc_messages_messages) {
|
||||
sublist->setFullLoaded();
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
|
||||
_unsupported = true;
|
||||
}
|
||||
sublist->setFullLoaded();
|
||||
_loadMoreRequests.remove(sublist);
|
||||
}).send();
|
||||
}
|
||||
|
||||
} // namespace Data
|
56
Telegram/SourceFiles/data/data_saved_messages.h
Normal file
56
Telegram/SourceFiles/data/data_saved_messages.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
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 "dialogs/dialogs_main_list.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Data {
|
||||
|
||||
class Session;
|
||||
class SavedSublist;
|
||||
|
||||
class SavedMessages final {
|
||||
public:
|
||||
explicit SavedMessages(not_null<Session*> owner);
|
||||
~SavedMessages();
|
||||
|
||||
[[nodiscard]] bool supported() const;
|
||||
|
||||
[[nodiscard]] Session &owner() const;
|
||||
[[nodiscard]] Main::Session &session() const;
|
||||
|
||||
[[nodiscard]] not_null<Dialogs::MainList*> chatsList();
|
||||
[[nodiscard]] not_null<SavedSublist*> sublist(not_null<PeerData*> peer);
|
||||
|
||||
void loadMore();
|
||||
void loadMore(not_null<SavedSublist*> sublist);
|
||||
|
||||
private:
|
||||
const not_null<Session*> _owner;
|
||||
|
||||
Dialogs::MainList _chatsList;
|
||||
base::flat_map<
|
||||
not_null<PeerData*>,
|
||||
std::unique_ptr<SavedSublist>> _sublists;
|
||||
|
||||
base::flat_map<not_null<SavedSublist*>, mtpRequestId> _loadMoreRequests;
|
||||
mtpRequestId _loadMoreRequestId = 0;
|
||||
|
||||
TimeId _offsetDate = 0;
|
||||
MsgId _offsetId = 0;
|
||||
PeerData *_offsetPeer = nullptr;
|
||||
|
||||
bool _unsupported = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
212
Telegram/SourceFiles/data/data_saved_sublist.cpp
Normal file
212
Telegram/SourceFiles/data/data_saved_sublist.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
#include "data/data_saved_sublist.h"
|
||||
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_saved_messages.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/view/history_view_item_preview.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
|
||||
namespace Data {
|
||||
|
||||
SavedSublist::SavedSublist(not_null<PeerData*> peer)
|
||||
: Entry(&peer->owner(), Dialogs::Entry::Type::SavedSublist)
|
||||
, _history(peer->owner().history(peer)) {
|
||||
}
|
||||
|
||||
SavedSublist::~SavedSublist() = default;
|
||||
|
||||
not_null<History*> SavedSublist::history() const {
|
||||
return _history;
|
||||
}
|
||||
|
||||
not_null<PeerData*> SavedSublist::peer() const {
|
||||
return _history->peer;
|
||||
}
|
||||
|
||||
bool SavedSublist::isHiddenAuthor() const {
|
||||
return peer()->isSavedHiddenAuthor();
|
||||
}
|
||||
|
||||
bool SavedSublist::isFullLoaded() const {
|
||||
return (_flags & Flag::FullLoaded) != 0;
|
||||
}
|
||||
|
||||
auto SavedSublist::messages() const
|
||||
-> const std::vector<not_null<HistoryItem*>> & {
|
||||
return _items;
|
||||
}
|
||||
|
||||
void SavedSublist::applyMaybeLast(not_null<HistoryItem*> item) {
|
||||
const auto before = [](
|
||||
not_null<HistoryItem*> a,
|
||||
not_null<HistoryItem*> b) {
|
||||
return IsServerMsgId(a->id)
|
||||
? (IsServerMsgId(b->id) ? (a->id < b->id) : true)
|
||||
: (IsServerMsgId(b->id) ? false : (a->id < b->id));
|
||||
};
|
||||
|
||||
if (_items.empty()) {
|
||||
_items.push_back(item);
|
||||
} else if (_items.front() == item) {
|
||||
return;
|
||||
} else if (_items.size() == 1 && before(_items.front(), item)) {
|
||||
_items[0] = item;
|
||||
} else if (before(_items.back(), item)) {
|
||||
for (auto i = begin(_items); i != end(_items); ++i) {
|
||||
if (item == *i) {
|
||||
break;
|
||||
} else if (before(*i, item)) {
|
||||
_items.insert(i, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_items.front() == item) {
|
||||
setChatListTimeId(item->date());
|
||||
resolveChatListMessageGroup();
|
||||
}
|
||||
}
|
||||
|
||||
void SavedSublist::removeOne(not_null<HistoryItem*> item) {
|
||||
if (_items.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto last = (_items.front() == item);
|
||||
_items.erase(ranges::remove(_items, item), end(_items));
|
||||
if (last) {
|
||||
if (_items.empty()) {
|
||||
if (isFullLoaded()) {
|
||||
updateChatListExistence();
|
||||
} else {
|
||||
updateChatListEntry();
|
||||
crl::on_main(this, [=] {
|
||||
owner().savedMessages().loadMore(this);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setChatListTimeId(_items.front()->date());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SavedSublist::append(std::vector<not_null<HistoryItem*>> &&items) {
|
||||
if (items.empty()) {
|
||||
setFullLoaded();
|
||||
} else if (!_items.empty()) {
|
||||
_items.insert(end(_items), begin(items), end(items));
|
||||
} else {
|
||||
_items = std::move(items);
|
||||
setChatListTimeId(_items.front()->date());
|
||||
}
|
||||
}
|
||||
|
||||
void SavedSublist::setFullLoaded(bool loaded) {
|
||||
if (loaded != isFullLoaded()) {
|
||||
if (loaded) {
|
||||
_flags |= Flag::FullLoaded;
|
||||
if (_items.empty()) {
|
||||
updateChatListExistence();
|
||||
}
|
||||
} else {
|
||||
_flags &= ~Flag::FullLoaded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SavedSublist::fixedOnTopIndex() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SavedSublist::shouldBeInChatList() const {
|
||||
return isPinnedDialog(FilterId()) || !_items.empty();
|
||||
}
|
||||
|
||||
Dialogs::UnreadState SavedSublist::chatListUnreadState() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
Dialogs::BadgesState SavedSublist::chatListBadgesState() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
HistoryItem *SavedSublist::chatListMessage() const {
|
||||
return _items.empty() ? nullptr : _items.front().get();
|
||||
}
|
||||
|
||||
bool SavedSublist::chatListMessageKnown() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString &SavedSublist::chatListName() const {
|
||||
return _history->chatListName();
|
||||
}
|
||||
|
||||
const base::flat_set<QString> &SavedSublist::chatListNameWords() const {
|
||||
return _history->chatListNameWords();
|
||||
}
|
||||
|
||||
const base::flat_set<QChar> &SavedSublist::chatListFirstLetters() const {
|
||||
return _history->chatListFirstLetters();
|
||||
}
|
||||
|
||||
const QString &SavedSublist::chatListNameSortKey() const {
|
||||
return _history->chatListNameSortKey();
|
||||
}
|
||||
|
||||
int SavedSublist::chatListNameVersion() const {
|
||||
return _history->chatListNameVersion();
|
||||
}
|
||||
|
||||
void SavedSublist::paintUserpic(
|
||||
Painter &p,
|
||||
Ui::PeerUserpicView &view,
|
||||
const Dialogs::Ui::PaintContext &context) const {
|
||||
_history->paintUserpic(p, view, context);
|
||||
}
|
||||
|
||||
void SavedSublist::chatListPreloadData() {
|
||||
peer()->loadUserpic();
|
||||
allowChatListMessageResolve();
|
||||
}
|
||||
|
||||
void SavedSublist::allowChatListMessageResolve() {
|
||||
if (_flags & Flag::ResolveChatListMessage) {
|
||||
return;
|
||||
}
|
||||
_flags |= Flag::ResolveChatListMessage;
|
||||
resolveChatListMessageGroup();
|
||||
}
|
||||
|
||||
bool SavedSublist::hasOrphanMediaGroupPart() const {
|
||||
if (isFullLoaded() || _items.size() != 1) {
|
||||
return false;
|
||||
}
|
||||
return (_items.front()->groupId() != MessageGroupId());
|
||||
}
|
||||
|
||||
void SavedSublist::resolveChatListMessageGroup() {
|
||||
const auto item = chatListMessage();
|
||||
if (!(_flags & Flag::ResolveChatListMessage)
|
||||
|| !item
|
||||
|| !hasOrphanMediaGroupPart()) {
|
||||
return;
|
||||
}
|
||||
// If we set a single album part, request the full album.
|
||||
const auto withImages = !item->toPreview({
|
||||
.hideSender = true,
|
||||
.hideCaption = true }).images.empty();
|
||||
if (withImages) {
|
||||
owner().histories().requestGroupAround(item);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Data
|
79
Telegram/SourceFiles/data/data_saved_sublist.h
Normal file
79
Telegram/SourceFiles/data/data_saved_sublist.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
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 "dialogs/ui/dialogs_message_view.h"
|
||||
#include "dialogs/dialogs_entry.h"
|
||||
|
||||
class PeerData;
|
||||
class History;
|
||||
|
||||
namespace Data {
|
||||
|
||||
class Session;
|
||||
|
||||
class SavedSublist final : public Dialogs::Entry {
|
||||
public:
|
||||
explicit SavedSublist(not_null<PeerData*> peer);
|
||||
~SavedSublist();
|
||||
|
||||
[[nodiscard]] not_null<History*> history() const;
|
||||
[[nodiscard]] not_null<PeerData*> peer() const;
|
||||
[[nodiscard]] bool isHiddenAuthor() const;
|
||||
[[nodiscard]] bool isFullLoaded() const;
|
||||
|
||||
[[nodiscard]] auto messages() const
|
||||
-> const std::vector<not_null<HistoryItem*>> &;
|
||||
void applyMaybeLast(not_null<HistoryItem*> item);
|
||||
void removeOne(not_null<HistoryItem*> item);
|
||||
void append(std::vector<not_null<HistoryItem*>> &&items);
|
||||
void setFullLoaded(bool loaded = true);
|
||||
|
||||
[[nodiscard]] Dialogs::Ui::MessageView &lastItemDialogsView() {
|
||||
return _lastItemDialogsView;
|
||||
}
|
||||
|
||||
int fixedOnTopIndex() const override;
|
||||
bool shouldBeInChatList() const override;
|
||||
Dialogs::UnreadState chatListUnreadState() const override;
|
||||
Dialogs::BadgesState chatListBadgesState() const override;
|
||||
HistoryItem *chatListMessage() const override;
|
||||
bool chatListMessageKnown() const override;
|
||||
const QString &chatListName() const override;
|
||||
const QString &chatListNameSortKey() const override;
|
||||
int chatListNameVersion() const override;
|
||||
const base::flat_set<QString> &chatListNameWords() const override;
|
||||
const base::flat_set<QChar> &chatListFirstLetters() const override;
|
||||
|
||||
void chatListPreloadData() override;
|
||||
void paintUserpic(
|
||||
Painter &p,
|
||||
Ui::PeerUserpicView &view,
|
||||
const Dialogs::Ui::PaintContext &context) const override;
|
||||
|
||||
private:
|
||||
enum class Flag : uchar {
|
||||
ResolveChatListMessage = (1 << 0),
|
||||
FullLoaded = (1 << 1),
|
||||
};
|
||||
friend inline constexpr bool is_flag_type(Flag) { return true; }
|
||||
using Flags = base::flags<Flag>;
|
||||
|
||||
bool hasOrphanMediaGroupPart() const;
|
||||
void allowChatListMessageResolve();
|
||||
void resolveChatListMessageGroup();
|
||||
|
||||
const not_null<History*> _history;
|
||||
|
||||
std::vector<not_null<HistoryItem*>> _items;
|
||||
Dialogs::Ui::MessageView _lastItemDialogsView;
|
||||
Flags _flags;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
@@ -60,6 +60,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_emoji_statuses.h"
|
||||
#include "data/data_forum_icons.h"
|
||||
#include "data/data_cloud_themes.h"
|
||||
#include "data/data_saved_messages.h"
|
||||
#include "data/data_saved_sublist.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_streaming.h"
|
||||
#include "data/data_media_rotation.h"
|
||||
@@ -261,7 +263,8 @@ Session::Session(not_null<Main::Session*> session)
|
||||
, _forumIcons(std::make_unique<ForumIcons>(this))
|
||||
, _notifySettings(std::make_unique<NotifySettings>(this))
|
||||
, _customEmojiManager(std::make_unique<CustomEmojiManager>(this))
|
||||
, _stories(std::make_unique<Stories>(this)) {
|
||||
, _stories(std::make_unique<Stories>(this))
|
||||
, _savedMessages(std::make_unique<SavedMessages>(this)) {
|
||||
_cache->open(_session->local().cacheKey());
|
||||
_bigFileCache->open(_session->local().cacheBigFileKey());
|
||||
|
||||
@@ -1712,6 +1715,11 @@ void Session::requestItemRepaint(not_null<const HistoryItem*> item) {
|
||||
topic->updateChatListEntry();
|
||||
}
|
||||
}
|
||||
if (const auto sublist = item->savedSublist()) {
|
||||
if (sublist->lastItemDialogsView().dependsOn(item)) {
|
||||
sublist->updateChatListEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<not_null<const HistoryItem*>> Session::itemRepaintRequest() const {
|
||||
@@ -2137,6 +2145,11 @@ int Session::pinnedChatsLimit(not_null<Data::Forum*> forum) const {
|
||||
return limits.topicsPinnedCurrent();
|
||||
}
|
||||
|
||||
int Session::pinnedChatsLimit(not_null<Data::SavedMessages*> saved) const {
|
||||
const auto limits = Data::PremiumLimits(_session);
|
||||
return limits.savedSublistsPinnedCurrent();
|
||||
}
|
||||
|
||||
rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
||||
Data::Folder *folder) const {
|
||||
// Premium limit from appconfig.
|
||||
@@ -2177,6 +2190,20 @@ rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
||||
});
|
||||
}
|
||||
|
||||
rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
||||
not_null<SavedMessages*> saved) const {
|
||||
// Premium limit from appconfig.
|
||||
// We always use premium limit in the MainList limit producer,
|
||||
// because it slices the list to that limit. We don't want to slice
|
||||
// premium-ly added chats from the pinned list because of sync issues.
|
||||
return rpl::single(rpl::empty_value()) | rpl::then(
|
||||
_session->account().appConfig().refreshed()
|
||||
) | rpl::map([=] {
|
||||
const auto limits = Data::PremiumLimits(_session);
|
||||
return limits.savedSublistsPinnedPremium();
|
||||
});
|
||||
}
|
||||
|
||||
const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
|
||||
Data::Folder *folder) const {
|
||||
return chatsList(folder)->pinned()->order();
|
||||
@@ -2192,6 +2219,11 @@ const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
|
||||
return forum->topicsList()->pinned()->order();
|
||||
}
|
||||
|
||||
const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
|
||||
not_null<Data::SavedMessages*> saved) const {
|
||||
return saved->chatsList()->pinned()->order();
|
||||
}
|
||||
|
||||
void Session::clearPinnedChats(Data::Folder *folder) {
|
||||
chatsList(folder)->pinned()->clear();
|
||||
}
|
||||
@@ -4198,6 +4230,8 @@ not_null<Dialogs::MainList*> Session::chatsListFor(
|
||||
const auto topic = entry->asTopic();
|
||||
return topic
|
||||
? topic->forum()->topicsList()
|
||||
: entry->asSublist()
|
||||
? _savedMessages->chatsList()
|
||||
: chatsList(entry->folder());
|
||||
}
|
||||
|
||||
|
@@ -61,6 +61,7 @@ class GroupCall;
|
||||
class NotifySettings;
|
||||
class CustomEmojiManager;
|
||||
class Stories;
|
||||
class SavedMessages;
|
||||
|
||||
struct RepliesReadTillUpdate {
|
||||
FullMsgId id;
|
||||
@@ -137,6 +138,9 @@ public:
|
||||
[[nodiscard]] Stories &stories() const {
|
||||
return *_stories;
|
||||
}
|
||||
[[nodiscard]] SavedMessages &savedMessages() const {
|
||||
return *_savedMessages;
|
||||
}
|
||||
|
||||
[[nodiscard]] MsgId nextNonHistoryEntryId() {
|
||||
return ++_nonHistoryEntryId;
|
||||
@@ -352,18 +356,24 @@ public:
|
||||
[[nodiscard]] int pinnedChatsLimit(Folder *folder) const;
|
||||
[[nodiscard]] int pinnedChatsLimit(FilterId filterId) const;
|
||||
[[nodiscard]] int pinnedChatsLimit(not_null<Forum*> forum) const;
|
||||
[[nodiscard]] int pinnedChatsLimit(
|
||||
not_null<SavedMessages*> saved) const;
|
||||
[[nodiscard]] rpl::producer<int> maxPinnedChatsLimitValue(
|
||||
Folder *folder) const;
|
||||
[[nodiscard]] rpl::producer<int> maxPinnedChatsLimitValue(
|
||||
FilterId filterId) const;
|
||||
[[nodiscard]] rpl::producer<int> maxPinnedChatsLimitValue(
|
||||
not_null<Forum*> forum) const;
|
||||
[[nodiscard]] rpl::producer<int> maxPinnedChatsLimitValue(
|
||||
not_null<SavedMessages*> saved) const;
|
||||
[[nodiscard]] const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
||||
Folder *folder) const;
|
||||
[[nodiscard]] const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
||||
not_null<Forum*> forum) const;
|
||||
[[nodiscard]] const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
||||
FilterId filterId) const;
|
||||
[[nodiscard]] const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
||||
not_null<Data::SavedMessages*> saved) const;
|
||||
void setChatPinned(Dialogs::Key key, FilterId filterId, bool pinned);
|
||||
void setPinnedFromEntryList(Dialogs::Key key, bool pinned);
|
||||
void clearPinnedChats(Folder *folder);
|
||||
@@ -1041,6 +1051,7 @@ private:
|
||||
const std::unique_ptr<NotifySettings> _notifySettings;
|
||||
const std::unique_ptr<CustomEmojiManager> _customEmojiManager;
|
||||
const std::unique_ptr<Stories> _stories;
|
||||
const std::unique_ptr<SavedMessages> _savedMessages;
|
||||
|
||||
MsgId _nonHistoryEntryId = ServerMaxMsgId.bare + ScheduledMsgIdsRange;
|
||||
|
||||
|
Reference in New Issue
Block a user