mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Implement pinned topics reordering.
This commit is contained in:
parent
c7741cb62a
commit
8a288476b8
17 changed files with 221 additions and 105 deletions
|
@ -17,9 +17,7 @@ namespace Api {
|
||||||
void SaveNewFilterPinned(
|
void SaveNewFilterPinned(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
FilterId filterId) {
|
FilterId filterId) {
|
||||||
const auto &order = session->data().pinnedChatsOrder(
|
const auto &order = session->data().pinnedChatsOrder(filterId);
|
||||||
nullptr,
|
|
||||||
filterId);
|
|
||||||
auto &filters = session->data().chatsFilters();
|
auto &filters = session->data().chatsFilters();
|
||||||
const auto &filter = filters.applyUpdatedPinned(filterId, order);
|
const auto &filter = filters.applyUpdatedPinned(filterId, order);
|
||||||
session->api().request(MTPmessages_UpdateDialogFilter(
|
session->api().request(MTPmessages_UpdateDialogFilter(
|
||||||
|
|
|
@ -2308,6 +2308,29 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
|
|
||||||
case mtpc_updateChannelPinnedTopics: {
|
case mtpc_updateChannelPinnedTopics: {
|
||||||
const auto &d = update.c_updateChannelPinnedTopics();
|
const auto &d = update.c_updateChannelPinnedTopics();
|
||||||
|
const auto peerId = peerFromChannel(d.vchannel_id());
|
||||||
|
if (const auto peer = session().data().peerLoaded(peerId)) {
|
||||||
|
if (const auto forum = peer->forum()) {
|
||||||
|
const auto done = [&] {
|
||||||
|
const auto list = d.vorder();
|
||||||
|
if (!list) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto &order = list->v;
|
||||||
|
const auto notLoaded = [&](const MTPint &topicId) {
|
||||||
|
return !forum->topicFor(topicId.v);
|
||||||
|
};
|
||||||
|
if (!ranges::none_of(order, notLoaded)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
session().data().applyPinnedTopics(forum, order);
|
||||||
|
return true;
|
||||||
|
}();
|
||||||
|
if (!done) {
|
||||||
|
forum->reloadTopics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
// Pinned message.
|
// Pinned message.
|
||||||
|
|
|
@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_web_page.h"
|
#include "data/data_web_page.h"
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
#include "data/data_forum_topic.h"
|
#include "data/data_forum_topic.h"
|
||||||
|
#include "data/data_forum.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "data/data_sparse_ids.h"
|
#include "data/data_sparse_ids.h"
|
||||||
#include "data/data_search_controller.h"
|
#include "data/data_search_controller.h"
|
||||||
|
@ -384,9 +385,7 @@ void ApiWrap::checkChatInvite(
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::savePinnedOrder(Data::Folder *folder) {
|
void ApiWrap::savePinnedOrder(Data::Folder *folder) {
|
||||||
const auto &order = _session->data().pinnedChatsOrder(
|
const auto &order = _session->data().pinnedChatsOrder(folder);
|
||||||
folder,
|
|
||||||
FilterId());
|
|
||||||
const auto input = [](const Dialogs::Key &key) {
|
const auto input = [](const Dialogs::Key &key) {
|
||||||
if (const auto history = key.history()) {
|
if (const auto history = key.history()) {
|
||||||
return MTP_inputDialogPeer(history->peer->input);
|
return MTP_inputDialogPeer(history->peer->input);
|
||||||
|
@ -408,6 +407,29 @@ void ApiWrap::savePinnedOrder(Data::Folder *folder) {
|
||||||
)).send();
|
)).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApiWrap::savePinnedOrder(not_null<Data::Forum*> forum) {
|
||||||
|
const auto &order = _session->data().pinnedChatsOrder(forum);
|
||||||
|
const auto input = [](const Dialogs::Key &key) {
|
||||||
|
if (const auto topic = key.topic()) {
|
||||||
|
return MTP_int(topic->rootId().bare);
|
||||||
|
}
|
||||||
|
Unexpected("Key type in pinnedDialogsOrder().");
|
||||||
|
};
|
||||||
|
auto topics = QVector<MTPint>();
|
||||||
|
topics.reserve(order.size());
|
||||||
|
ranges::transform(
|
||||||
|
order,
|
||||||
|
ranges::back_inserter(topics),
|
||||||
|
input);
|
||||||
|
request(MTPchannels_ReorderPinnedForumTopics(
|
||||||
|
MTP_flags(MTPchannels_ReorderPinnedForumTopics::Flag::f_force),
|
||||||
|
forum->channel()->inputChannel,
|
||||||
|
MTP_vector(topics)
|
||||||
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
applyUpdates(result);
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
void ApiWrap::toggleHistoryArchived(
|
void ApiWrap::toggleHistoryArchived(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
bool archived,
|
bool archived,
|
||||||
|
|
|
@ -32,6 +32,7 @@ class WallPaper;
|
||||||
struct ResolvedForwardDraft;
|
struct ResolvedForwardDraft;
|
||||||
enum class DefaultNotify;
|
enum class DefaultNotify;
|
||||||
enum class StickersType : uchar;
|
enum class StickersType : uchar;
|
||||||
|
class Forum;
|
||||||
class ForumTopic;
|
class ForumTopic;
|
||||||
class Thread;
|
class Thread;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
@ -149,6 +150,7 @@ public:
|
||||||
void saveCurrentDraftToCloud();
|
void saveCurrentDraftToCloud();
|
||||||
|
|
||||||
void savePinnedOrder(Data::Folder *folder);
|
void savePinnedOrder(Data::Folder *folder);
|
||||||
|
void savePinnedOrder(not_null<Data::Forum*> forum);
|
||||||
void toggleHistoryArchived(
|
void toggleHistoryArchived(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
bool archived,
|
bool archived,
|
||||||
|
|
|
@ -127,7 +127,7 @@ ChooseFilterValidator::LimitData ChooseFilterValidator::limitReached(
|
||||||
|
|
||||||
const auto list = _history->owner().chatsFilters().list();
|
const auto list = _history->owner().chatsFilters().list();
|
||||||
const auto i = ranges::find(list, filterId, &Data::ChatFilter::id);
|
const auto i = ranges::find(list, filterId, &Data::ChatFilter::id);
|
||||||
const auto limit = _history->owner().pinnedChatsLimit(nullptr, filterId);
|
const auto limit = _history->owner().pinnedChatsLimit(filterId);
|
||||||
return {
|
return {
|
||||||
.reached = (i != end(list))
|
.reached = (i != end(list))
|
||||||
&& !ranges::contains(i->always(), _history)
|
&& !ranges::contains(i->always(), _history)
|
||||||
|
|
|
@ -236,12 +236,12 @@ not_null<Dialogs::MainList*> ChatFilters::chatsList(FilterId filterId) {
|
||||||
auto limit = rpl::single(rpl::empty_value()) | rpl::then(
|
auto limit = rpl::single(rpl::empty_value()) | rpl::then(
|
||||||
_owner->session().account().appConfig().refreshed()
|
_owner->session().account().appConfig().refreshed()
|
||||||
) | rpl::map([=] {
|
) | rpl::map([=] {
|
||||||
return _owner->pinnedChatsLimit(nullptr, filterId);
|
return _owner->pinnedChatsLimit(filterId);
|
||||||
});
|
});
|
||||||
pointer = std::make_unique<Dialogs::MainList>(
|
pointer = std::make_unique<Dialogs::MainList>(
|
||||||
&_owner->session(),
|
&_owner->session(),
|
||||||
filterId,
|
filterId,
|
||||||
_owner->maxPinnedChatsLimitValue(nullptr, filterId));
|
_owner->maxPinnedChatsLimitValue(filterId));
|
||||||
}
|
}
|
||||||
return pointer.get();
|
return pointer.get();
|
||||||
}
|
}
|
||||||
|
@ -476,7 +476,7 @@ const ChatFilter &ChatFilters::applyUpdatedPinned(
|
||||||
const auto i = ranges::find(_list, id, &ChatFilter::id);
|
const auto i = ranges::find(_list, id, &ChatFilter::id);
|
||||||
Assert(i != end(_list));
|
Assert(i != end(_list));
|
||||||
|
|
||||||
const auto limit = _owner->pinnedChatsLimit(nullptr, id);
|
const auto limit = _owner->pinnedChatsLimit(id);
|
||||||
auto always = i->always();
|
auto always = i->always();
|
||||||
auto pinned = std::vector<not_null<History*>>();
|
auto pinned = std::vector<not_null<History*>>();
|
||||||
pinned.reserve(dialogs.size());
|
pinned.reserve(dialogs.size());
|
||||||
|
|
|
@ -41,7 +41,7 @@ Folder::Folder(not_null<Data::Session*> owner, FolderId id)
|
||||||
, _chatsList(
|
, _chatsList(
|
||||||
&owner->session(),
|
&owner->session(),
|
||||||
FilterId(),
|
FilterId(),
|
||||||
owner->maxPinnedChatsLimitValue(this, FilterId()))
|
owner->maxPinnedChatsLimitValue(this))
|
||||||
, _name(tr::lng_archived_name(tr::now)) {
|
, _name(tr::lng_archived_name(tr::now)) {
|
||||||
indexNameParts();
|
indexNameParts();
|
||||||
|
|
||||||
|
|
|
@ -37,14 +37,13 @@ constexpr auto kTopicsFirstLoad = 20;
|
||||||
constexpr auto kLoadedTopicsMinCount = 20;
|
constexpr auto kLoadedTopicsMinCount = 20;
|
||||||
constexpr auto kTopicsPerPage = 500;
|
constexpr auto kTopicsPerPage = 500;
|
||||||
constexpr auto kStalePerRequest = 100;
|
constexpr auto kStalePerRequest = 100;
|
||||||
constexpr auto kPinnedLimit = 5;
|
|
||||||
// constexpr auto kGeneralColorId = 0xA9A9A9;
|
// constexpr auto kGeneralColorId = 0xA9A9A9;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Forum::Forum(not_null<History*> history)
|
Forum::Forum(not_null<History*> history)
|
||||||
: _history(history)
|
: _history(history)
|
||||||
, _topicsList(&session(), FilterId(0), rpl::single(kPinnedLimit)) {
|
, _topicsList(&session(), {}, owner().maxPinnedChatsLimitValue(this)) {
|
||||||
Expects(_history->peer->isChannel());
|
Expects(_history->peer->isChannel());
|
||||||
|
|
||||||
if (_history->inChatList()) {
|
if (_history->inChatList()) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace {
|
||||||
|
|
||||||
using UpdateFlag = TopicUpdate::Flag;
|
using UpdateFlag = TopicUpdate::Flag;
|
||||||
|
|
||||||
constexpr auto kUserpicLoopsCount = 2;
|
constexpr auto kUserpicLoopsCount = 1;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -315,12 +315,7 @@ void ForumTopic::applyTopic(const MTPDforumTopic &data) {
|
||||||
if (min) {
|
if (min) {
|
||||||
int a = 0;
|
int a = 0;
|
||||||
} else {
|
} else {
|
||||||
if (data.is_pinned()) {
|
owner().setPinnedFromEntryList(this, data.is_pinned());
|
||||||
owner().setChatPinned(this, 0, true);
|
|
||||||
} else {
|
|
||||||
_list->pinned()->setPinned(this, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
owner().notifySettings().apply(this, data.vnotify_settings());
|
owner().notifySettings().apply(this, data.vnotify_settings());
|
||||||
|
|
||||||
if (const auto draft = data.vdraft()) {
|
if (const auto draft = data.vdraft()) {
|
||||||
|
|
|
@ -85,6 +85,8 @@ namespace {
|
||||||
|
|
||||||
using ViewElement = HistoryView::Element;
|
using ViewElement = HistoryView::Element;
|
||||||
|
|
||||||
|
constexpr auto kTopicsPinLimit = 5;
|
||||||
|
|
||||||
// s: box 100x100
|
// s: box 100x100
|
||||||
// m: box 320x320
|
// m: box 320x320
|
||||||
// x: box 800x800
|
// x: box 800x800
|
||||||
|
@ -241,7 +243,7 @@ Session::Session(not_null<Main::Session*> session)
|
||||||
, _chatsList(
|
, _chatsList(
|
||||||
session,
|
session,
|
||||||
FilterId(),
|
FilterId(),
|
||||||
maxPinnedChatsLimitValue(nullptr, FilterId()))
|
maxPinnedChatsLimitValue(nullptr))
|
||||||
, _contactsList(Dialogs::SortMode::Name)
|
, _contactsList(Dialogs::SortMode::Name)
|
||||||
, _contactsNoChatsList(Dialogs::SortMode::Name)
|
, _contactsNoChatsList(Dialogs::SortMode::Name)
|
||||||
, _ttlCheckTimer([=] { checkTTLs(); })
|
, _ttlCheckTimer([=] { checkTTLs(); })
|
||||||
|
@ -1925,10 +1927,10 @@ void Session::setChatPinned(
|
||||||
notifyPinnedDialogsOrderUpdated();
|
notifyPinnedDialogsOrderUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::setPinnedFromDialog(const Dialogs::Key &key, bool pinned) {
|
void Session::setPinnedFromEntryList(const Dialogs::Key &key, bool pinned) {
|
||||||
Expects(key.entry()->folderKnown());
|
Expects(key.entry()->folderKnown());
|
||||||
|
|
||||||
const auto list = chatsList(key.entry()->folder())->pinned();
|
const auto list = chatsListFor(key.entry())->pinned();
|
||||||
if (pinned) {
|
if (pinned) {
|
||||||
list->addPinned(key);
|
list->addPinned(key);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1957,6 +1959,13 @@ void Session::applyPinnedChats(
|
||||||
notifyPinnedDialogsOrderUpdated();
|
notifyPinnedDialogsOrderUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::applyPinnedTopics(
|
||||||
|
not_null<Data::Forum*> forum,
|
||||||
|
const QVector<MTPint> &list) {
|
||||||
|
forum->topicsList()->pinned()->applyList(forum, list);
|
||||||
|
notifyPinnedDialogsOrderUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
void Session::applyDialogs(
|
void Session::applyDialogs(
|
||||||
Data::Folder *requestFolder,
|
Data::Folder *requestFolder,
|
||||||
const QVector<MTPMessage> &messages,
|
const QVector<MTPMessage> &messages,
|
||||||
|
@ -1983,7 +1992,7 @@ void Session::applyDialog(
|
||||||
|
|
||||||
const auto history = this->history(peerId);
|
const auto history = this->history(peerId);
|
||||||
history->applyDialog(requestFolder, data);
|
history->applyDialog(requestFolder, data);
|
||||||
setPinnedFromDialog(history, data.is_pinned());
|
setPinnedFromEntryList(history, data.is_pinned());
|
||||||
|
|
||||||
if (const auto from = history->peer->migrateFrom()) {
|
if (const auto from = history->peer->migrateFrom()) {
|
||||||
if (const auto historyFrom = historyLoaded(from)) {
|
if (const auto historyFrom = historyLoaded(from)) {
|
||||||
|
@ -2004,37 +2013,63 @@ void Session::applyDialog(
|
||||||
}
|
}
|
||||||
const auto folder = processFolder(data.vfolder());
|
const auto folder = processFolder(data.vfolder());
|
||||||
folder->applyDialog(data);
|
folder->applyDialog(data);
|
||||||
setPinnedFromDialog(folder, data.is_pinned());
|
setPinnedFromEntryList(folder, data.is_pinned());
|
||||||
}
|
}
|
||||||
|
|
||||||
int Session::pinnedCanPin(
|
bool Session::pinnedCanPin(not_null<Data::Thread*> thread) const {
|
||||||
Data::Folder *folder,
|
if (const auto topic = thread->asTopic()) {
|
||||||
|
const auto forum = topic->forum();
|
||||||
|
return pinnedChatsOrder(forum).size() < pinnedChatsLimit(forum);
|
||||||
|
}
|
||||||
|
const auto folder = thread->folder();
|
||||||
|
return pinnedChatsOrder(folder).size() < pinnedChatsLimit(folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::pinnedCanPin(
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
not_null<History*> history) const {
|
not_null<History*> history) const {
|
||||||
if (!filterId) {
|
Expects(filterId != 0);
|
||||||
const auto limit = pinnedChatsLimit(folder, filterId);
|
|
||||||
return pinnedChatsOrder(folder, FilterId()).size() < limit;
|
|
||||||
}
|
|
||||||
const auto &list = chatsFilters().list();
|
const auto &list = chatsFilters().list();
|
||||||
const auto i = ranges::find(list, filterId, &Data::ChatFilter::id);
|
const auto i = ranges::find(list, filterId, &Data::ChatFilter::id);
|
||||||
return (i == end(list))
|
return (i == end(list))
|
||||||
|| (i->always().contains(history))
|
|| (i->always().contains(history))
|
||||||
|| (i->always().size() < pinnedChatsLimit(folder, filterId));
|
|| (i->always().size() < pinnedChatsLimit(filterId));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Session::pinnedChatsLimit(
|
int Session::pinnedChatsLimit(Data::Folder *folder) const {
|
||||||
Data::Folder *folder,
|
|
||||||
FilterId filterId) const {
|
|
||||||
const auto limits = Data::PremiumLimits(_session);
|
const auto limits = Data::PremiumLimits(_session);
|
||||||
return filterId
|
return folder
|
||||||
? limits.dialogFiltersChatsCurrent()
|
|
||||||
: folder
|
|
||||||
? limits.dialogsFolderPinnedCurrent()
|
? limits.dialogsFolderPinnedCurrent()
|
||||||
: limits.dialogsPinnedCurrent();
|
: limits.dialogsPinnedCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Session::pinnedChatsLimit(FilterId filterId) const {
|
||||||
|
const auto limits = Data::PremiumLimits(_session);
|
||||||
|
return limits.dialogFiltersChatsCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Session::pinnedChatsLimit(not_null<Data::Forum*> forum) const {
|
||||||
|
return kTopicsPinLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
||||||
|
Data::Folder *folder) 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 folder
|
||||||
|
? limits.dialogsFolderPinnedPremium()
|
||||||
|
: limits.dialogsPinnedPremium();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
||||||
Data::Folder *folder,
|
|
||||||
FilterId filterId) const {
|
FilterId filterId) const {
|
||||||
// Premium limit from appconfig.
|
// Premium limit from appconfig.
|
||||||
// We always use premium limit in the MainList limit producer,
|
// We always use premium limit in the MainList limit producer,
|
||||||
|
@ -2044,21 +2079,28 @@ rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
||||||
_session->account().appConfig().refreshed()
|
_session->account().appConfig().refreshed()
|
||||||
) | rpl::map([=] {
|
) | rpl::map([=] {
|
||||||
const auto limits = Data::PremiumLimits(_session);
|
const auto limits = Data::PremiumLimits(_session);
|
||||||
return filterId
|
return limits.dialogFiltersChatsPremium();
|
||||||
? limits.dialogFiltersChatsPremium()
|
|
||||||
: folder
|
|
||||||
? limits.dialogsFolderPinnedPremium()
|
|
||||||
: limits.dialogsPinnedPremium();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
||||||
|
not_null<Data::Forum*> forum) const {
|
||||||
|
return rpl::single(pinnedChatsLimit(forum));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
|
||||||
|
Data::Folder *folder) const {
|
||||||
|
return chatsList(folder)->pinned()->order();
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
|
const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
|
||||||
Data::Folder *folder,
|
|
||||||
FilterId filterId) const {
|
FilterId filterId) const {
|
||||||
const auto list = filterId
|
return chatsFilters().chatsList(filterId)->pinned()->order();
|
||||||
? chatsFilters().chatsList(filterId)
|
}
|
||||||
: chatsList(folder);
|
|
||||||
return list->pinned()->order();
|
const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
|
||||||
|
not_null<Data::Forum*> forum) const {
|
||||||
|
return forum->topicsList()->pinned()->order();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::clearPinnedChats(Data::Folder *folder) {
|
void Session::clearPinnedChats(Data::Folder *folder) {
|
||||||
|
@ -2072,7 +2114,10 @@ void Session::reorderTwoPinnedChats(
|
||||||
Expects(key1.entry()->folderKnown() && key2.entry()->folderKnown());
|
Expects(key1.entry()->folderKnown() && key2.entry()->folderKnown());
|
||||||
Expects(filterId || (key1.entry()->folder() == key2.entry()->folder()));
|
Expects(filterId || (key1.entry()->folder() == key2.entry()->folder()));
|
||||||
|
|
||||||
const auto list = filterId
|
const auto topic = key1.topic();
|
||||||
|
const auto list = topic
|
||||||
|
? topic->forum()->topicsList()
|
||||||
|
: filterId
|
||||||
? chatsFilters().chatsList(filterId)
|
? chatsFilters().chatsList(filterId)
|
||||||
: chatsList(key1.entry()->folder());
|
: chatsList(key1.entry()->folder());
|
||||||
list->pinned()->reorder(key1, key2);
|
list->pinned()->reorder(key1, key2);
|
||||||
|
|
|
@ -230,16 +230,16 @@ public:
|
||||||
[[nodiscard]] rpl::variable<bool> &contactsLoaded() {
|
[[nodiscard]] rpl::variable<bool> &contactsLoaded() {
|
||||||
return _contactsLoaded;
|
return _contactsLoaded;
|
||||||
}
|
}
|
||||||
[[nodiscard]] rpl::producer<Data::Folder*> chatsListChanges() const {
|
[[nodiscard]] rpl::producer<Folder*> chatsListChanges() const {
|
||||||
return _chatsListChanged.events();
|
return _chatsListChanged.events();
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool chatsListLoaded(Data::Folder *folder = nullptr);
|
[[nodiscard]] bool chatsListLoaded(Folder *folder = nullptr);
|
||||||
[[nodiscard]] rpl::producer<Data::Folder*> chatsListLoadedEvents() const {
|
[[nodiscard]] rpl::producer<Folder*> chatsListLoadedEvents() const {
|
||||||
return _chatsListLoadedEvents.events();
|
return _chatsListLoadedEvents.events();
|
||||||
}
|
}
|
||||||
void chatsListChanged(FolderId folderId);
|
void chatsListChanged(FolderId folderId);
|
||||||
void chatsListChanged(Data::Folder *folder);
|
void chatsListChanged(Folder *folder);
|
||||||
void chatsListDone(Data::Folder *folder);
|
void chatsListDone(Folder *folder);
|
||||||
|
|
||||||
void userIsBotChanged(not_null<UserData*> user);
|
void userIsBotChanged(not_null<UserData*> user);
|
||||||
[[nodiscard]] rpl::producer<not_null<UserData*>> userIsBotChanges() const;
|
[[nodiscard]] rpl::producer<not_null<UserData*>> userIsBotChanges() const;
|
||||||
|
@ -339,32 +339,42 @@ public:
|
||||||
void applyUpdate(const MTPDupdateChatDefaultBannedRights &update);
|
void applyUpdate(const MTPDupdateChatDefaultBannedRights &update);
|
||||||
|
|
||||||
void applyDialogs(
|
void applyDialogs(
|
||||||
Data::Folder *requestFolder,
|
Folder *requestFolder,
|
||||||
const QVector<MTPMessage> &messages,
|
const QVector<MTPMessage> &messages,
|
||||||
const QVector<MTPDialog> &dialogs,
|
const QVector<MTPDialog> &dialogs,
|
||||||
std::optional<int> count = std::nullopt);
|
std::optional<int> count = std::nullopt);
|
||||||
|
|
||||||
int pinnedCanPin(
|
[[nodiscard]] bool pinnedCanPin(not_null<Thread*> thread) const;
|
||||||
Data::Folder *folder,
|
[[nodiscard]] bool pinnedCanPin(
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
not_null<History*> history) const;
|
not_null<History*> history) const;
|
||||||
int pinnedChatsLimit(
|
[[nodiscard]] int pinnedChatsLimit(Folder *folder) const;
|
||||||
Data::Folder *folder,
|
[[nodiscard]] int pinnedChatsLimit(FilterId filterId) const;
|
||||||
|
[[nodiscard]] int pinnedChatsLimit(not_null<Forum*> forum) const;
|
||||||
|
[[nodiscard]] rpl::producer<int> maxPinnedChatsLimitValue(
|
||||||
|
Folder *folder) const;
|
||||||
|
[[nodiscard]] rpl::producer<int> maxPinnedChatsLimitValue(
|
||||||
FilterId filterId) const;
|
FilterId filterId) const;
|
||||||
rpl::producer<int> maxPinnedChatsLimitValue(
|
[[nodiscard]] rpl::producer<int> maxPinnedChatsLimitValue(
|
||||||
Data::Folder *folder,
|
not_null<Forum*> forum) const;
|
||||||
FilterId filterId) const;
|
[[nodiscard]] const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
||||||
const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
Folder *folder) const;
|
||||||
Data::Folder *folder,
|
[[nodiscard]] const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
||||||
|
not_null<Forum*> forum) const;
|
||||||
|
[[nodiscard]] const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
||||||
FilterId filterId) const;
|
FilterId filterId) const;
|
||||||
void setChatPinned(
|
void setChatPinned(
|
||||||
const Dialogs::Key &key,
|
const Dialogs::Key &key,
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
bool pinned);
|
bool pinned);
|
||||||
void clearPinnedChats(Data::Folder *folder);
|
void setPinnedFromEntryList(const Dialogs::Key &key, bool pinned);
|
||||||
|
void clearPinnedChats(Folder *folder);
|
||||||
void applyPinnedChats(
|
void applyPinnedChats(
|
||||||
Data::Folder *folder,
|
Folder *folder,
|
||||||
const QVector<MTPDialogPeer> &list);
|
const QVector<MTPDialogPeer> &list);
|
||||||
|
void applyPinnedTopics(
|
||||||
|
not_null<Data::Forum*> forum,
|
||||||
|
const QVector<MTPint> &list);
|
||||||
void reorderTwoPinnedChats(
|
void reorderTwoPinnedChats(
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
const Dialogs::Key &key1,
|
const Dialogs::Key &key1,
|
||||||
|
@ -572,7 +582,7 @@ public:
|
||||||
not_null<PollData*> processPoll(const MTPPoll &data);
|
not_null<PollData*> processPoll(const MTPPoll &data);
|
||||||
not_null<PollData*> processPoll(const MTPDmessageMediaPoll &data);
|
not_null<PollData*> processPoll(const MTPDmessageMediaPoll &data);
|
||||||
|
|
||||||
[[nodiscard]] not_null<Data::CloudImage*> location(
|
[[nodiscard]] not_null<CloudImage*> location(
|
||||||
const LocationPoint &point);
|
const LocationPoint &point);
|
||||||
|
|
||||||
void registerPhotoItem(
|
void registerPhotoItem(
|
||||||
|
@ -655,9 +665,9 @@ public:
|
||||||
[[nodiscard]] not_null<Dialogs::MainList*> chatsListFor(
|
[[nodiscard]] not_null<Dialogs::MainList*> chatsListFor(
|
||||||
not_null<Dialogs::Entry*> entry);
|
not_null<Dialogs::Entry*> entry);
|
||||||
[[nodiscard]] not_null<Dialogs::MainList*> chatsList(
|
[[nodiscard]] not_null<Dialogs::MainList*> chatsList(
|
||||||
Data::Folder *folder = nullptr);
|
Folder *folder = nullptr);
|
||||||
[[nodiscard]] not_null<const Dialogs::MainList*> chatsList(
|
[[nodiscard]] not_null<const Dialogs::MainList*> chatsList(
|
||||||
Data::Folder *folder = nullptr) const;
|
Folder *folder = nullptr) const;
|
||||||
[[nodiscard]] not_null<Dialogs::IndexedList*> contactsList();
|
[[nodiscard]] not_null<Dialogs::IndexedList*> contactsList();
|
||||||
[[nodiscard]] not_null<Dialogs::IndexedList*> contactsNoChatsList();
|
[[nodiscard]] not_null<Dialogs::IndexedList*> contactsNoChatsList();
|
||||||
|
|
||||||
|
@ -727,9 +737,9 @@ private:
|
||||||
int computeUnreadBadge(const Dialogs::UnreadState &state) const;
|
int computeUnreadBadge(const Dialogs::UnreadState &state) const;
|
||||||
bool computeUnreadBadgeMuted(const Dialogs::UnreadState &state) const;
|
bool computeUnreadBadgeMuted(const Dialogs::UnreadState &state) const;
|
||||||
|
|
||||||
void applyDialog(Data::Folder *requestFolder, const MTPDdialog &data);
|
void applyDialog(Folder *requestFolder, const MTPDdialog &data);
|
||||||
void applyDialog(
|
void applyDialog(
|
||||||
Data::Folder *requestFolder,
|
Folder *requestFolder,
|
||||||
const MTPDdialogFolder &data);
|
const MTPDdialogFolder &data);
|
||||||
|
|
||||||
const Messages *messagesList(PeerId peerId) const;
|
const Messages *messagesList(PeerId peerId) const;
|
||||||
|
@ -818,8 +828,6 @@ private:
|
||||||
PhotoData *photo,
|
PhotoData *photo,
|
||||||
DocumentData *document);
|
DocumentData *document);
|
||||||
|
|
||||||
void setPinnedFromDialog(const Dialogs::Key &key, bool pinned);
|
|
||||||
|
|
||||||
template <typename Method>
|
template <typename Method>
|
||||||
void enumerateItemViews(
|
void enumerateItemViews(
|
||||||
not_null<const HistoryItem*> item,
|
not_null<const HistoryItem*> item,
|
||||||
|
@ -843,8 +851,8 @@ private:
|
||||||
QPointer<Ui::BoxContent> _exportSuggestion;
|
QPointer<Ui::BoxContent> _exportSuggestion;
|
||||||
|
|
||||||
rpl::variable<bool> _contactsLoaded = false;
|
rpl::variable<bool> _contactsLoaded = false;
|
||||||
rpl::event_stream<Data::Folder*> _chatsListLoadedEvents;
|
rpl::event_stream<Folder*> _chatsListLoadedEvents;
|
||||||
rpl::event_stream<Data::Folder*> _chatsListChanged;
|
rpl::event_stream<Folder*> _chatsListChanged;
|
||||||
rpl::event_stream<not_null<UserData*>> _userIsBotChanges;
|
rpl::event_stream<not_null<UserData*>> _userIsBotChanges;
|
||||||
rpl::event_stream<not_null<PeerData*>> _botCommandsChanges;
|
rpl::event_stream<not_null<PeerData*>> _botCommandsChanges;
|
||||||
rpl::event_stream<ItemVisibilityQuery> _itemVisibilityQueries;
|
rpl::event_stream<ItemVisibilityQuery> _itemVisibilityQueries;
|
||||||
|
@ -916,7 +924,7 @@ private:
|
||||||
base::flat_set<not_null<ViewElement*>>> _webpageViews;
|
base::flat_set<not_null<ViewElement*>>> _webpageViews;
|
||||||
std::unordered_map<
|
std::unordered_map<
|
||||||
LocationPoint,
|
LocationPoint,
|
||||||
std::unique_ptr<Data::CloudImage>> _locations;
|
std::unique_ptr<CloudImage>> _locations;
|
||||||
std::unordered_map<
|
std::unordered_map<
|
||||||
PollId,
|
PollId,
|
||||||
std::unique_ptr<PollData>> _polls;
|
std::unique_ptr<PollData>> _polls;
|
||||||
|
|
|
@ -1255,6 +1255,13 @@ void InnerWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
mousePressReleased(e->globalPos(), e->button(), e->modifiers());
|
mousePressReleased(e->globalPos(), e->button(), e->modifiers());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const std::vector<Key> &InnerWidget::pinnedChatsOrder() const {
|
||||||
|
return _openedForum
|
||||||
|
? session().data().pinnedChatsOrder(_openedForum)
|
||||||
|
: _filterId
|
||||||
|
? session().data().pinnedChatsOrder(_filterId)
|
||||||
|
: session().data().pinnedChatsOrder(_openedFolder);
|
||||||
|
}
|
||||||
|
|
||||||
void InnerWidget::checkReorderPinnedStart(QPoint localPosition) {
|
void InnerWidget::checkReorderPinnedStart(QPoint localPosition) {
|
||||||
if (!_pressed || _dragging || _state != WidgetState::Default) {
|
if (!_pressed || _dragging || _state != WidgetState::Default) {
|
||||||
|
@ -1262,16 +1269,12 @@ void InnerWidget::checkReorderPinnedStart(QPoint localPosition) {
|
||||||
} else if (qAbs(localPosition.y() - _dragStart.y())
|
} else if (qAbs(localPosition.y() - _dragStart.y())
|
||||||
< style::ConvertScale(kStartReorderThreshold)) {
|
< style::ConvertScale(kStartReorderThreshold)) {
|
||||||
return;
|
return;
|
||||||
} else if (_openedForum) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
_dragging = _pressed;
|
_dragging = _pressed;
|
||||||
if (updateReorderIndexGetCount() < 2) {
|
if (updateReorderIndexGetCount() < 2) {
|
||||||
_dragging = nullptr;
|
_dragging = nullptr;
|
||||||
} else {
|
} else {
|
||||||
const auto &order = session().data().pinnedChatsOrder(
|
const auto &order = pinnedChatsOrder();
|
||||||
_openedFolder,
|
|
||||||
_filterId);
|
|
||||||
_pinnedOnDragStart = base::flat_set<Key>{
|
_pinnedOnDragStart = base::flat_set<Key>{
|
||||||
order.begin(),
|
order.begin(),
|
||||||
order.end()
|
order.end()
|
||||||
|
@ -1301,12 +1304,7 @@ int InnerWidget::countPinnedIndex(Row *ofRow) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::savePinnedOrder() {
|
void InnerWidget::savePinnedOrder() {
|
||||||
if (_openedForum) {
|
const auto &newOrder = pinnedChatsOrder();
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto &newOrder = session().data().pinnedChatsOrder(
|
|
||||||
_openedFolder,
|
|
||||||
_filterId);
|
|
||||||
if (newOrder.size() != _pinnedOnDragStart.size()) {
|
if (newOrder.size() != _pinnedOnDragStart.size()) {
|
||||||
return; // Something has changed in the set of pinned chats.
|
return; // Something has changed in the set of pinned chats.
|
||||||
}
|
}
|
||||||
|
@ -1315,7 +1313,9 @@ void InnerWidget::savePinnedOrder() {
|
||||||
return; // Something has changed in the set of pinned chats.
|
return; // Something has changed in the set of pinned chats.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_filterId) {
|
if (_openedForum) {
|
||||||
|
session().api().savePinnedOrder(_openedForum);
|
||||||
|
} else if (_filterId) {
|
||||||
Api::SaveNewFilterPinned(&session(), _filterId);
|
Api::SaveNewFilterPinned(&session(), _filterId);
|
||||||
} else {
|
} else {
|
||||||
session().api().savePinnedOrder(_openedFolder);
|
session().api().savePinnedOrder(_openedFolder);
|
||||||
|
|
|
@ -346,6 +346,7 @@ private:
|
||||||
|
|
||||||
[[nodiscard]] not_null<IndexedList*> shownDialogs() const;
|
[[nodiscard]] not_null<IndexedList*> shownDialogs() const;
|
||||||
|
|
||||||
|
[[nodiscard]] const std::vector<Key> &pinnedChatsOrder() const;
|
||||||
void checkReorderPinnedStart(QPoint localPosition);
|
void checkReorderPinnedStart(QPoint localPosition);
|
||||||
int updateReorderIndexGetCount();
|
int updateReorderIndexGetCount();
|
||||||
bool updateReorderPinned(QPoint localPosition);
|
bool updateReorderPinned(QPoint localPosition);
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "dialogs/dialogs_entry.h"
|
#include "dialogs/dialogs_entry.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_forum.h"
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
|
||||||
|
@ -97,6 +98,15 @@ void PinnedList::applyList(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PinnedList::applyList(
|
||||||
|
not_null<Data::Forum*> forum,
|
||||||
|
const QVector<MTPint> &list) {
|
||||||
|
clear();
|
||||||
|
for (const auto &topicId : list) {
|
||||||
|
addPinned(forum->topicFor(topicId.v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PinnedList::applyList(const std::vector<not_null<History*>> &list) {
|
void PinnedList::applyList(const std::vector<not_null<History*>> &list) {
|
||||||
Expects(_filterId != 0);
|
Expects(_filterId != 0);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ class History;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Session;
|
class Session;
|
||||||
|
class Forum;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
@ -35,6 +36,9 @@ public:
|
||||||
void applyList(
|
void applyList(
|
||||||
not_null<Data::Session*> owner,
|
not_null<Data::Session*> owner,
|
||||||
const QVector<MTPDialogPeer> &list);
|
const QVector<MTPDialogPeer> &list);
|
||||||
|
void applyList(
|
||||||
|
not_null<Data::Forum*> forum,
|
||||||
|
const QVector<MTPint> &list);
|
||||||
void applyList(const std::vector<not_null<History*>> &list);
|
void applyList(const std::vector<not_null<History*>> &list);
|
||||||
void reorder(const Key &key1, const Key &key2);
|
void reorder(const Key &key1, const Key &key2);
|
||||||
|
|
||||||
|
|
|
@ -386,9 +386,7 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
|
||||||
if (index == result) {
|
if (index == result) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto &order = _session->data().pinnedChatsOrder(
|
const auto &order = _session->data().pinnedChatsOrder(nullptr);
|
||||||
nullptr,
|
|
||||||
FilterId());
|
|
||||||
const auto d = (index < result) ? 1 : -1; // Direction.
|
const auto d = (index < result) ? 1 : -1; // Direction.
|
||||||
for (auto i = index; i != result; i += d) {
|
for (auto i = index; i != result; i += d) {
|
||||||
_session->data().chatsList()->pinned()->reorder(
|
_session->data().chatsList()->pinned()->reorder(
|
||||||
|
@ -634,7 +632,7 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
|
||||||
|
|
||||||
const auto updatePinnedChats = [=] {
|
const auto updatePinnedChats = [=] {
|
||||||
_pins = ranges::views::zip(
|
_pins = ranges::views::zip(
|
||||||
_session->data().pinnedChatsOrder(nullptr, FilterId()),
|
_session->data().pinnedChatsOrder(nullptr),
|
||||||
ranges::views::ints(0, ranges::unreachable)
|
ranges::views::ints(0, ranges::unreachable)
|
||||||
) | ranges::views::transform([=](const auto &pair) {
|
) | ranges::views::transform([=](const auto &pair) {
|
||||||
const auto index = pair.second;
|
const auto index = pair.second;
|
||||||
|
|
|
@ -315,7 +315,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
History *FindWastedPin(not_null<Data::Session*> data, Data::Folder *folder) {
|
History *FindWastedPin(not_null<Data::Session*> data, Data::Folder *folder) {
|
||||||
const auto &order = data->pinnedChatsOrder(folder, FilterId());
|
const auto &order = data->pinnedChatsOrder(folder);
|
||||||
for (const auto &pinned : order) {
|
for (const auto &pinned : order) {
|
||||||
if (const auto history = pinned.history()) {
|
if (const auto history = pinned.history()) {
|
||||||
if (history->peer->isChat()
|
if (history->peer->isChat()
|
||||||
|
@ -336,24 +336,22 @@ void AddChatMembers(
|
||||||
|
|
||||||
bool PinnedLimitReached(
|
bool PinnedLimitReached(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<History*> history,
|
not_null<Data::Thread*> thread) {
|
||||||
FilterId filterId) {
|
const auto owner = &thread->owner();
|
||||||
Expects(filterId != 0 || history->folderKnown());
|
if (owner->pinnedCanPin(thread)) {
|
||||||
|
|
||||||
const auto owner = &history->owner();
|
|
||||||
const auto folder = history->folder();
|
|
||||||
if (owner->pinnedCanPin(folder, filterId, history)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Some old chat, that was converted, maybe is still pinned.
|
// Some old chat, that was converted, maybe is still pinned.
|
||||||
const auto wasted = filterId ? nullptr : FindWastedPin(owner, folder);
|
const auto history = thread->asHistory();
|
||||||
|
if (!history) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const auto folder = history->folder();
|
||||||
|
const auto wasted = FindWastedPin(owner, folder);
|
||||||
if (wasted) {
|
if (wasted) {
|
||||||
owner->setChatPinned(wasted, FilterId(), false);
|
owner->setChatPinned(wasted, FilterId(), false);
|
||||||
owner->setChatPinned(history, FilterId(), true);
|
owner->setChatPinned(history, FilterId(), true);
|
||||||
history->session().api().savePinnedOrder(folder);
|
history->session().api().savePinnedOrder(folder);
|
||||||
} else if (filterId) {
|
|
||||||
controller->show(
|
|
||||||
Box(FilterPinsLimitBox, &history->session(), filterId));
|
|
||||||
} else if (folder) {
|
} else if (folder) {
|
||||||
controller->show(Box(FolderPinsLimitBox, &history->session()));
|
controller->show(Box(FolderPinsLimitBox, &history->session()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -362,6 +360,19 @@ bool PinnedLimitReached(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PinnedLimitReached(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<History*> history,
|
||||||
|
FilterId filterId) {
|
||||||
|
const auto owner = &history->owner();
|
||||||
|
if (owner->pinnedCanPin(filterId, history)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
controller->show(
|
||||||
|
Box(FilterPinsLimitBox, &history->session(), filterId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void TogglePinnedThread(
|
void TogglePinnedThread(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<Data::Thread*> thread) {
|
not_null<Data::Thread*> thread) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue