mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Support pinned saved sublists.
This commit is contained in:
parent
d2565dc944
commit
9392550c01
11 changed files with 301 additions and 82 deletions
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mtproto/mtproto_dc_options.h"
|
#include "mtproto/mtproto_dc_options.h"
|
||||||
#include "data/notify/data_notify_settings.h"
|
#include "data/notify/data_notify_settings.h"
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
|
#include "data/data_saved_messages.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_chat.h"
|
#include "data/data_chat.h"
|
||||||
|
@ -2208,6 +2209,16 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case mtpc_updatePinnedSavedDialogs: {
|
||||||
|
session().data().savedMessages().apply(
|
||||||
|
update.c_updatePinnedSavedDialogs());
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_updateSavedDialogPinned: {
|
||||||
|
session().data().savedMessages().apply(
|
||||||
|
update.c_updateSavedDialogPinned());
|
||||||
|
} break;
|
||||||
|
|
||||||
case mtpc_updateChannel: {
|
case mtpc_updateChannel: {
|
||||||
auto &d = update.c_updateChannel();
|
auto &d = update.c_updateChannel();
|
||||||
if (const auto channel = session().data().channelLoaded(d.vchannel_id())) {
|
if (const auto channel = session().data().channelLoaded(d.vchannel_id())) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#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_forum.h"
|
||||||
|
#include "data/data_saved_sublist.h"
|
||||||
#include "data/data_search_controller.h"
|
#include "data/data_search_controller.h"
|
||||||
#include "data/data_scheduled_messages.h"
|
#include "data/data_scheduled_messages.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
@ -443,8 +444,8 @@ void ApiWrap::savePinnedOrder(not_null<Data::Forum*> forum) {
|
||||||
void ApiWrap::savePinnedOrder(not_null<Data::SavedMessages*> saved) {
|
void ApiWrap::savePinnedOrder(not_null<Data::SavedMessages*> saved) {
|
||||||
const auto &order = _session->data().pinnedChatsOrder(saved);
|
const auto &order = _session->data().pinnedChatsOrder(saved);
|
||||||
const auto input = [](Dialogs::Key key) {
|
const auto input = [](Dialogs::Key key) {
|
||||||
if (const auto history = key.history()) {
|
if (const auto sublist = key.sublist()) {
|
||||||
return MTP_inputDialogPeer(history->peer->input);
|
return MTP_inputDialogPeer(sublist->peer()->input);
|
||||||
}
|
}
|
||||||
Unexpected("Key type in pinnedDialogsOrder().");
|
Unexpected("Key type in pinnedDialogsOrder().");
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_forum.h"
|
#include "data/data_forum.h"
|
||||||
|
#include "data/data_saved_messages.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
#include "data/data_premium_limits.h"
|
#include "data/data_premium_limits.h"
|
||||||
|
@ -882,6 +883,18 @@ void PinsLimitBox(
|
||||||
limits.dialogsPinnedPremium(),
|
limits.dialogsPinnedPremium(),
|
||||||
PinsCount(session->data().chatsList()));
|
PinsCount(session->data().chatsList()));
|
||||||
}
|
}
|
||||||
|
void SublistsPinsLimitBox(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
not_null<Main::Session*> session) {
|
||||||
|
const auto limits = Data::PremiumLimits(session);
|
||||||
|
SimplePinsLimitBox(
|
||||||
|
box,
|
||||||
|
session,
|
||||||
|
"saved_dialog_pinned",
|
||||||
|
limits.savedSublistsPinnedDefault(),
|
||||||
|
limits.savedSublistsPinnedPremium(),
|
||||||
|
PinsCount(session->data().savedMessages().chatsList()));
|
||||||
|
}
|
||||||
|
|
||||||
void ForumPinsLimitBox(
|
void ForumPinsLimitBox(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
|
|
|
@ -60,6 +60,9 @@ void PinsLimitBox(
|
||||||
void ForumPinsLimitBox(
|
void ForumPinsLimitBox(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
not_null<Data::Forum*> forum);
|
not_null<Data::Forum*> forum);
|
||||||
|
void SublistsPinsLimitBox(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
not_null<Main::Session*> session);
|
||||||
void CaptionLimitBox(
|
void CaptionLimitBox(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
|
|
|
@ -62,54 +62,19 @@ not_null<SavedSublist*> SavedMessages::sublist(not_null<PeerData*> peer) {
|
||||||
void SavedMessages::loadMore() {
|
void SavedMessages::loadMore() {
|
||||||
if (_loadMoreRequestId || _chatsList.loaded()) {
|
if (_loadMoreRequestId || _chatsList.loaded()) {
|
||||||
return;
|
return;
|
||||||
|
} else if (!_pinnedLoaded) {
|
||||||
|
loadPinned();
|
||||||
}
|
}
|
||||||
_loadMoreRequestId = _owner->session().api().request(
|
_loadMoreRequestId = _owner->session().api().request(
|
||||||
MTPmessages_GetSavedDialogs(
|
MTPmessages_GetSavedDialogs(
|
||||||
MTP_flags(0),
|
MTP_flags(MTPmessages_GetSavedDialogs::Flag::f_exclude_pinned),
|
||||||
MTP_int(_offsetDate),
|
MTP_int(_offsetDate),
|
||||||
MTP_int(_offsetId),
|
MTP_int(_offsetId),
|
||||||
_offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(),
|
_offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(),
|
||||||
MTP_int(kPerPage),
|
MTP_int(kPerPage),
|
||||||
MTP_long(0)) // hash
|
MTP_long(0)) // hash
|
||||||
).done([=](const MTPmessages_SavedDialogs &result) {
|
).done([=](const MTPmessages_SavedDialogs &result) {
|
||||||
auto list = (const QVector<MTPSavedDialog>*)nullptr;
|
apply(result, false);
|
||||||
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) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
|
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
|
||||||
_unsupported = true;
|
_unsupported = true;
|
||||||
|
@ -119,6 +84,24 @@ void SavedMessages::loadMore() {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SavedMessages::loadPinned() {
|
||||||
|
if (_pinnedRequestId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_pinnedRequestId = _owner->session().api().request(
|
||||||
|
MTPmessages_GetPinnedSavedDialogs()
|
||||||
|
).done([=](const MTPmessages_SavedDialogs &result) {
|
||||||
|
apply(result, true);
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
|
||||||
|
_unsupported = true;
|
||||||
|
} else {
|
||||||
|
_pinnedLoaded = true;
|
||||||
|
}
|
||||||
|
_pinnedRequestId = 0;
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
void SavedMessages::loadMore(not_null<SavedSublist*> sublist) {
|
void SavedMessages::loadMore(not_null<SavedSublist*> sublist) {
|
||||||
if (_loadMoreRequests.contains(sublist) || sublist->isFullLoaded()) {
|
if (_loadMoreRequests.contains(sublist) || sublist->isFullLoaded()) {
|
||||||
return;
|
return;
|
||||||
|
@ -185,4 +168,109 @@ void SavedMessages::loadMore(not_null<SavedSublist*> sublist) {
|
||||||
_loadMoreRequests[sublist] = requestId;
|
_loadMoreRequests[sublist] = requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SavedMessages::apply(
|
||||||
|
const MTPmessages_SavedDialogs &result,
|
||||||
|
bool pinned) {
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
if (pinned) {
|
||||||
|
_pinnedRequestId = 0;
|
||||||
|
_pinnedLoaded = true;
|
||||||
|
} else {
|
||||||
|
_loadMoreRequestId = 0;
|
||||||
|
}
|
||||||
|
if (!list) {
|
||||||
|
if (!pinned) {
|
||||||
|
_chatsList.setLoaded();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto lastValid = false;
|
||||||
|
auto offsetDate = TimeId();
|
||||||
|
auto offsetId = MsgId();
|
||||||
|
auto offsetPeer = (PeerData*)nullptr;
|
||||||
|
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;
|
||||||
|
const auto entry = sublist(peer);
|
||||||
|
const auto entryPinned = pinned || data.is_pinned();
|
||||||
|
entry->applyMaybeLast(item);
|
||||||
|
_owner->setPinnedFromEntryList(entry, entryPinned);
|
||||||
|
} else {
|
||||||
|
lastValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pinned) {
|
||||||
|
} else if (!lastValid) {
|
||||||
|
LOG(("API Error: Unknown message in the end of a slice."));
|
||||||
|
_chatsList.setLoaded();
|
||||||
|
} else if (result.type() == mtpc_messages_savedDialogs) {
|
||||||
|
_chatsList.setLoaded();
|
||||||
|
} else if (offsetDate < _offsetDate
|
||||||
|
|| (offsetDate == _offsetDate && offsetId == _offsetId && offsetPeer == _offsetPeer)) {
|
||||||
|
LOG(("API Error: Bad order in messages.savedDialogs."));
|
||||||
|
_chatsList.setLoaded();
|
||||||
|
} else {
|
||||||
|
_offsetDate = offsetDate;
|
||||||
|
_offsetId = offsetId;
|
||||||
|
_offsetPeer = offsetPeer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavedMessages::apply(const MTPDupdatePinnedSavedDialogs &update) {
|
||||||
|
const auto list = update.vorder();
|
||||||
|
if (!list) {
|
||||||
|
loadPinned();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto &order = list->v;
|
||||||
|
const auto notLoaded = [&](const MTPDialogPeer &peer) {
|
||||||
|
return peer.match([&](const MTPDdialogPeer &data) {
|
||||||
|
const auto peer = _owner->peer(peerFromMTP(data.vpeer()));
|
||||||
|
return !_sublists.contains(peer);
|
||||||
|
}, [&](const MTPDdialogPeerFolder &data) {
|
||||||
|
LOG(("API Error: "
|
||||||
|
"updatePinnedSavedDialogs has folders."));
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (!ranges::none_of(order, notLoaded)) {
|
||||||
|
loadPinned();
|
||||||
|
} else {
|
||||||
|
_chatsList.pinned()->applyList(_owner, order);
|
||||||
|
_owner->notifyPinnedDialogsOrderUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavedMessages::apply(const MTPDupdateSavedDialogPinned &update) {
|
||||||
|
update.vpeer().match([&](const MTPDdialogPeer &data) {
|
||||||
|
const auto peer = _owner->peer(peerFromMTP(data.vpeer()));
|
||||||
|
const auto i = _sublists.find(peer);
|
||||||
|
if (i != end(_sublists)) {
|
||||||
|
const auto entry = i->second.get();
|
||||||
|
_owner->setChatPinned(entry, FilterId(), update.is_pinned());
|
||||||
|
} else {
|
||||||
|
loadPinned();
|
||||||
|
}
|
||||||
|
}, [&](const MTPDdialogPeerFolder &data) {
|
||||||
|
DEBUG_LOG(("API Error: Folder in updateSavedDialogPinned."));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -34,7 +34,13 @@ public:
|
||||||
void loadMore();
|
void loadMore();
|
||||||
void loadMore(not_null<SavedSublist*> sublist);
|
void loadMore(not_null<SavedSublist*> sublist);
|
||||||
|
|
||||||
|
void apply(const MTPDupdatePinnedSavedDialogs &update);
|
||||||
|
void apply(const MTPDupdateSavedDialogPinned &update);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void loadPinned();
|
||||||
|
void apply(const MTPmessages_SavedDialogs &result, bool pinned);
|
||||||
|
|
||||||
const not_null<Session*> _owner;
|
const not_null<Session*> _owner;
|
||||||
|
|
||||||
Dialogs::MainList _chatsList;
|
Dialogs::MainList _chatsList;
|
||||||
|
@ -44,11 +50,13 @@ private:
|
||||||
|
|
||||||
base::flat_map<not_null<SavedSublist*>, mtpRequestId> _loadMoreRequests;
|
base::flat_map<not_null<SavedSublist*>, mtpRequestId> _loadMoreRequests;
|
||||||
mtpRequestId _loadMoreRequestId = 0;
|
mtpRequestId _loadMoreRequestId = 0;
|
||||||
|
mtpRequestId _pinnedRequestId = 0;
|
||||||
|
|
||||||
TimeId _offsetDate = 0;
|
TimeId _offsetDate = 0;
|
||||||
MsgId _offsetId = 0;
|
MsgId _offsetId = 0;
|
||||||
PeerData *_offsetPeer = nullptr;
|
PeerData *_offsetPeer = nullptr;
|
||||||
|
|
||||||
|
bool _pinnedLoaded = false;
|
||||||
bool _unsupported = false;
|
bool _unsupported = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -2107,13 +2107,17 @@ void Session::applyDialog(
|
||||||
setPinnedFromEntryList(folder, data.is_pinned());
|
setPinnedFromEntryList(folder, data.is_pinned());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Session::pinnedCanPin(not_null<Data::Thread*> thread) const {
|
bool Session::pinnedCanPin(not_null<Dialogs::Entry*> entry) const {
|
||||||
if (const auto topic = thread->asTopic()) {
|
if (const auto sublist = entry->asSublist()) {
|
||||||
|
const auto saved = &savedMessages();
|
||||||
|
return pinnedChatsOrder(saved).size() < pinnedChatsLimit(saved);
|
||||||
|
} else if (const auto topic = entry->asTopic()) {
|
||||||
const auto forum = topic->forum();
|
const auto forum = topic->forum();
|
||||||
return pinnedChatsOrder(forum).size() < pinnedChatsLimit(forum);
|
return pinnedChatsOrder(forum).size() < pinnedChatsLimit(forum);
|
||||||
|
} else {
|
||||||
|
const auto folder = entry->folder();
|
||||||
|
return pinnedChatsOrder(folder).size() < pinnedChatsLimit(folder);
|
||||||
}
|
}
|
||||||
const auto folder = thread->folder();
|
|
||||||
return pinnedChatsOrder(folder).size() < pinnedChatsLimit(folder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Session::pinnedCanPin(
|
bool Session::pinnedCanPin(
|
||||||
|
@ -2240,7 +2244,7 @@ void Session::reorderTwoPinnedChats(
|
||||||
? topic->forum()->topicsList()
|
? topic->forum()->topicsList()
|
||||||
: filterId
|
: filterId
|
||||||
? chatsFilters().chatsList(filterId)
|
? chatsFilters().chatsList(filterId)
|
||||||
: chatsList(key1.entry()->folder());
|
: chatsListFor(key1.entry());
|
||||||
list->pinned()->reorder(key1, key2);
|
list->pinned()->reorder(key1, key2);
|
||||||
notifyPinnedDialogsOrderUpdated();
|
notifyPinnedDialogsOrderUpdated();
|
||||||
}
|
}
|
||||||
|
|
|
@ -349,7 +349,7 @@ public:
|
||||||
const QVector<MTPDialog> &dialogs,
|
const QVector<MTPDialog> &dialogs,
|
||||||
std::optional<int> count = std::nullopt);
|
std::optional<int> count = std::nullopt);
|
||||||
|
|
||||||
[[nodiscard]] bool pinnedCanPin(not_null<Thread*> thread) const;
|
[[nodiscard]] bool pinnedCanPin(not_null<Dialogs::Entry*> entry) const;
|
||||||
[[nodiscard]] bool pinnedCanPin(
|
[[nodiscard]] bool pinnedCanPin(
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
not_null<History*> history) const;
|
not_null<History*> history) const;
|
||||||
|
|
|
@ -12,10 +12,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "dialogs/dialogs_inner_widget.h"
|
#include "dialogs/dialogs_inner_widget.h"
|
||||||
#include "history/view/history_view_sublist_section.h"
|
#include "history/view/history_view_sublist_section.h"
|
||||||
|
#include "info/media/info_media_buttons.h"
|
||||||
|
#include "info/profile/info_profile_icon.h"
|
||||||
#include "info/info_controller.h"
|
#include "info/info_controller.h"
|
||||||
#include "info/info_memento.h"
|
#include "info/info_memento.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
#include "ui/widgets/box_content_divider.h"
|
||||||
|
#include "ui/wrap/slide_wrap.h"
|
||||||
|
#include "ui/wrap/vertical_layout.h"
|
||||||
|
#include "styles/style_info.h"
|
||||||
|
|
||||||
namespace Info::Saved {
|
namespace Info::Saved {
|
||||||
|
|
||||||
|
@ -41,24 +47,27 @@ SublistsMemento::~SublistsMemento() = default;
|
||||||
SublistsWidget::SublistsWidget(
|
SublistsWidget::SublistsWidget(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<Controller*> controller)
|
not_null<Controller*> controller)
|
||||||
: ContentWidget(parent, controller) {
|
: ContentWidget(parent, controller)
|
||||||
_inner = setInnerWidget(object_ptr<Dialogs::InnerWidget>(
|
, _layout(setInnerWidget(object_ptr<Ui::VerticalLayout>(this))) {
|
||||||
|
setupOtherTypes();
|
||||||
|
|
||||||
|
_list = _layout->add(object_ptr<Dialogs::InnerWidget>(
|
||||||
this,
|
this,
|
||||||
controller->parentController(),
|
controller->parentController(),
|
||||||
rpl::single(Dialogs::InnerWidget::ChildListShown())));
|
rpl::single(Dialogs::InnerWidget::ChildListShown())));
|
||||||
_inner->showSavedSublists();
|
_list->showSavedSublists();
|
||||||
_inner->setNarrowRatio(0.);
|
_list->setNarrowRatio(0.);
|
||||||
|
|
||||||
_inner->chosenRow() | rpl::start_with_next([=](Dialogs::ChosenRow row) {
|
_list->chosenRow() | rpl::start_with_next([=](Dialogs::ChosenRow row) {
|
||||||
if (const auto sublist = row.key.sublist()) {
|
if (const auto sublist = row.key.sublist()) {
|
||||||
controller->showSection(
|
controller->showSection(
|
||||||
std::make_shared<HistoryView::SublistMemento>(sublist),
|
std::make_shared<HistoryView::SublistMemento>(sublist),
|
||||||
Window::SectionShow::Way::Forward);
|
Window::SectionShow::Way::Forward);
|
||||||
}
|
}
|
||||||
}, _inner->lifetime());
|
}, _list->lifetime());
|
||||||
|
|
||||||
const auto saved = &controller->session().data().savedMessages();
|
const auto saved = &controller->session().data().savedMessages();
|
||||||
_inner->heightValue() | rpl::start_with_next([=] {
|
_list->heightValue() | rpl::start_with_next([=] {
|
||||||
if (!saved->supported()) {
|
if (!saved->supported()) {
|
||||||
crl::on_main(controller, [=] {
|
crl::on_main(controller, [=] {
|
||||||
controller->showSection(
|
controller->showSection(
|
||||||
|
@ -68,11 +77,61 @@ SublistsWidget::SublistsWidget(
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_inner->setLoadMoreCallback([=] {
|
_list->setLoadMoreCallback([=] {
|
||||||
saved->loadMore();
|
saved->loadMore();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SublistsWidget::setupOtherTypes() {
|
||||||
|
auto wrap = _layout->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
_layout,
|
||||||
|
object_ptr<Ui::VerticalLayout>(_layout)));
|
||||||
|
auto content = wrap->entity();
|
||||||
|
content->add(object_ptr<Ui::FixedHeightWidget>(
|
||||||
|
content,
|
||||||
|
st::infoProfileSkip));
|
||||||
|
|
||||||
|
using Type = Media::Type;
|
||||||
|
auto tracker = Ui::MultiSlideTracker();
|
||||||
|
const auto peer = controller()->session().user();
|
||||||
|
const auto addMediaButton = [&](
|
||||||
|
Type buttonType,
|
||||||
|
const style::icon &icon) {
|
||||||
|
auto result = Media::AddButton(
|
||||||
|
content,
|
||||||
|
controller(),
|
||||||
|
peer,
|
||||||
|
MsgId(), // topicRootId
|
||||||
|
nullptr, // migrated
|
||||||
|
buttonType,
|
||||||
|
tracker);
|
||||||
|
object_ptr<Profile::FloatingIcon>(
|
||||||
|
result,
|
||||||
|
icon,
|
||||||
|
st::infoSharedMediaButtonIconPosition)->show();
|
||||||
|
};
|
||||||
|
|
||||||
|
addMediaButton(Type::Photo, st::infoIconMediaPhoto);
|
||||||
|
addMediaButton(Type::Video, st::infoIconMediaVideo);
|
||||||
|
addMediaButton(Type::File, st::infoIconMediaFile);
|
||||||
|
addMediaButton(Type::MusicFile, st::infoIconMediaAudio);
|
||||||
|
addMediaButton(Type::Link, st::infoIconMediaLink);
|
||||||
|
addMediaButton(Type::RoundVoiceFile, st::infoIconMediaVoice);
|
||||||
|
addMediaButton(Type::GIF, st::infoIconMediaGif);
|
||||||
|
|
||||||
|
content->add(object_ptr<Ui::FixedHeightWidget>(
|
||||||
|
content,
|
||||||
|
st::infoProfileSkip));
|
||||||
|
wrap->toggleOn(tracker.atLeastOneShownValue());
|
||||||
|
wrap->finishAnimating();
|
||||||
|
|
||||||
|
_layout->add(object_ptr<Ui::BoxContentDivider>(_layout));
|
||||||
|
_layout->add(object_ptr<Ui::FixedHeightWidget>(
|
||||||
|
content,
|
||||||
|
st::infoProfileSkip));
|
||||||
|
}
|
||||||
|
|
||||||
rpl::producer<QString> SublistsWidget::title() {
|
rpl::producer<QString> SublistsWidget::title() {
|
||||||
return tr::lng_saved_messages();
|
return tr::lng_saved_messages();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,10 @@ namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class VerticalLayout;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Info::Saved {
|
namespace Info::Saved {
|
||||||
|
|
||||||
class SublistsMemento final : public ContentMemento {
|
class SublistsMemento final : public ContentMemento {
|
||||||
|
@ -58,7 +62,10 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<ContentMemento> doCreateMemento() override;
|
std::shared_ptr<ContentMemento> doCreateMemento() override;
|
||||||
|
|
||||||
Dialogs::InnerWidget *_inner = nullptr;
|
void setupOtherTypes();
|
||||||
|
|
||||||
|
const not_null<Ui::VerticalLayout*> _layout;
|
||||||
|
Dialogs::InnerWidget *_list = nullptr;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_forum.h"
|
#include "data/data_forum.h"
|
||||||
#include "data/data_forum_topic.h"
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
#include "data/data_saved_sublist.h"
|
||||||
#include "data/data_scheduled_messages.h"
|
#include "data/data_scheduled_messages.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
#include "data/data_chat_filters.h"
|
#include "data/data_chat_filters.h"
|
||||||
|
@ -244,6 +245,7 @@ private:
|
||||||
void fillRepliesActions();
|
void fillRepliesActions();
|
||||||
void fillScheduledActions();
|
void fillScheduledActions();
|
||||||
void fillArchiveActions();
|
void fillArchiveActions();
|
||||||
|
void fillSavedSublistActions();
|
||||||
void fillContextMenuActions();
|
void fillContextMenuActions();
|
||||||
|
|
||||||
void addHidePromotion();
|
void addHidePromotion();
|
||||||
|
@ -293,6 +295,7 @@ private:
|
||||||
Data::ForumTopic *_topic = nullptr;
|
Data::ForumTopic *_topic = nullptr;
|
||||||
PeerData *_peer = nullptr;
|
PeerData *_peer = nullptr;
|
||||||
Data::Folder *_folder = nullptr;
|
Data::Folder *_folder = nullptr;
|
||||||
|
Data::SavedSublist *_sublist = nullptr;
|
||||||
const PeerMenuCallback &_addAction;
|
const PeerMenuCallback &_addAction;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -319,17 +322,21 @@ void AddChatMembers(
|
||||||
|
|
||||||
bool PinnedLimitReached(
|
bool PinnedLimitReached(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<Data::Thread*> thread) {
|
not_null<Dialogs::Entry*> entry) {
|
||||||
const auto owner = &thread->owner();
|
const auto owner = &entry->owner();
|
||||||
if (owner->pinnedCanPin(thread)) {
|
if (owner->pinnedCanPin(entry)) {
|
||||||
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 history = thread->asHistory();
|
if (const auto sublist = entry->asSublist()) {
|
||||||
if (!history) {
|
controller->show(Box(SublistsPinsLimitBox, &sublist->session()));
|
||||||
controller->show(Box(ForumPinsLimitBox, thread->asTopic()->forum()));
|
return true;
|
||||||
|
} else if (const auto topic = entry->asTopic()) {
|
||||||
|
controller->show(Box(ForumPinsLimitBox, topic->forum()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
const auto history = entry->asHistory();
|
||||||
|
Assert(history != nullptr);
|
||||||
const auto folder = history->folder();
|
const auto folder = history->folder();
|
||||||
const auto wasted = FindWastedPin(owner, folder);
|
const auto wasted = FindWastedPin(owner, folder);
|
||||||
if (wasted) {
|
if (wasted) {
|
||||||
|
@ -359,18 +366,18 @@ bool PinnedLimitReached(
|
||||||
|
|
||||||
void TogglePinnedThread(
|
void TogglePinnedThread(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<Data::Thread*> thread) {
|
not_null<Dialogs::Entry*> entry) {
|
||||||
if (!thread->folderKnown()) {
|
if (!entry->folderKnown()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto owner = &thread->owner();
|
const auto owner = &entry->owner();
|
||||||
const auto isPinned = !thread->isPinnedDialog(FilterId());
|
const auto isPinned = !entry->isPinnedDialog(FilterId());
|
||||||
if (isPinned && PinnedLimitReached(controller, thread)) {
|
if (isPinned && PinnedLimitReached(controller, entry)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
owner->setChatPinned(thread, FilterId(), isPinned);
|
owner->setChatPinned(entry, FilterId(), isPinned);
|
||||||
if (const auto history = thread->asHistory()) {
|
if (const auto history = entry->asHistory()) {
|
||||||
const auto flags = isPinned
|
const auto flags = isPinned
|
||||||
? MTPmessages_ToggleDialogPin::Flag::f_pinned
|
? MTPmessages_ToggleDialogPin::Flag::f_pinned
|
||||||
: MTPmessages_ToggleDialogPin::Flag(0);
|
: MTPmessages_ToggleDialogPin::Flag(0);
|
||||||
|
@ -383,7 +390,7 @@ void TogglePinnedThread(
|
||||||
if (isPinned) {
|
if (isPinned) {
|
||||||
controller->content()->dialogsToUp();
|
controller->content()->dialogsToUp();
|
||||||
}
|
}
|
||||||
} else if (const auto topic = thread->asTopic()) {
|
} else if (const auto topic = entry->asTopic()) {
|
||||||
owner->session().api().request(MTPchannels_UpdatePinnedForumTopic(
|
owner->session().api().request(MTPchannels_UpdatePinnedForumTopic(
|
||||||
topic->channel()->inputChannel,
|
topic->channel()->inputChannel,
|
||||||
MTP_int(topic->rootId()),
|
MTP_int(topic->rootId()),
|
||||||
|
@ -391,17 +398,30 @@ void TogglePinnedThread(
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
owner->session().api().applyUpdates(result);
|
owner->session().api().applyUpdates(result);
|
||||||
}).send();
|
}).send();
|
||||||
|
} else if (const auto sublist = entry->asSublist()) {
|
||||||
|
const auto flags = isPinned
|
||||||
|
? MTPmessages_ToggleSavedDialogPin::Flag::f_pinned
|
||||||
|
: MTPmessages_ToggleSavedDialogPin::Flag(0);
|
||||||
|
owner->session().api().request(MTPmessages_ToggleSavedDialogPin(
|
||||||
|
MTP_flags(flags),
|
||||||
|
MTP_inputDialogPeer(sublist->peer()->input)
|
||||||
|
)).done([=] {
|
||||||
|
owner->notifyPinnedDialogsOrderUpdated();
|
||||||
|
}).send();
|
||||||
|
//if (isPinned) {
|
||||||
|
// controller->content()->dialogsToUp();
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TogglePinnedThread(
|
void TogglePinnedThread(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<Data::Thread*> thread,
|
not_null<Dialogs::Entry*> entry,
|
||||||
FilterId filterId) {
|
FilterId filterId) {
|
||||||
if (!filterId) {
|
if (!filterId) {
|
||||||
return TogglePinnedThread(controller, thread);
|
return TogglePinnedThread(controller, entry);
|
||||||
}
|
}
|
||||||
const auto history = thread->asHistory();
|
const auto history = entry->asHistory();
|
||||||
if (!history) {
|
if (!history) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -438,6 +458,7 @@ Filler::Filler(
|
||||||
, _topic(request.key.topic())
|
, _topic(request.key.topic())
|
||||||
, _peer(request.key.peer())
|
, _peer(request.key.peer())
|
||||||
, _folder(request.key.folder())
|
, _folder(request.key.folder())
|
||||||
|
, _sublist(request.key.sublist())
|
||||||
, _addAction(addAction) {
|
, _addAction(addAction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,21 +492,21 @@ void Filler::addToggleTopicClosed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Filler::addTogglePin() {
|
void Filler::addTogglePin() {
|
||||||
if (!_peer || (_topic && !_topic->canTogglePinned())) {
|
if ((!_sublist && !_peer) || (_topic && !_topic->canTogglePinned())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto controller = _controller;
|
const auto controller = _controller;
|
||||||
const auto filterId = _request.filterId;
|
const auto filterId = _request.filterId;
|
||||||
const auto thread = _request.key.thread();
|
const auto entry = _thread ? (Dialogs::Entry*)_thread : _sublist;
|
||||||
if (!thread || thread->fixedOnTopIndex()) {
|
if (!entry || entry->fixedOnTopIndex()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto pinText = [=] {
|
const auto pinText = [=] {
|
||||||
return thread->isPinnedDialog(filterId)
|
return entry->isPinnedDialog(filterId)
|
||||||
? tr::lng_context_unpin_from_top(tr::now)
|
? tr::lng_context_unpin_from_top(tr::now)
|
||||||
: tr::lng_context_pin_to_top(tr::now);
|
: tr::lng_context_pin_to_top(tr::now);
|
||||||
};
|
};
|
||||||
const auto weak = base::make_weak(thread);
|
const auto weak = base::make_weak(entry);
|
||||||
const auto pinToggle = [=] {
|
const auto pinToggle = [=] {
|
||||||
if (const auto strong = weak.get()) {
|
if (const auto strong = weak.get()) {
|
||||||
TogglePinnedThread(controller, strong, filterId);
|
TogglePinnedThread(controller, strong, filterId);
|
||||||
|
@ -494,7 +515,7 @@ void Filler::addTogglePin() {
|
||||||
_addAction(
|
_addAction(
|
||||||
pinText(),
|
pinText(),
|
||||||
pinToggle,
|
pinToggle,
|
||||||
(thread->isPinnedDialog(filterId)
|
(entry->isPinnedDialog(filterId)
|
||||||
? &st::menuIconUnpin
|
? &st::menuIconUnpin
|
||||||
: &st::menuIconPin));
|
: &st::menuIconPin));
|
||||||
}
|
}
|
||||||
|
@ -1116,9 +1137,9 @@ void Filler::addGiftPremium() {
|
||||||
void Filler::fill() {
|
void Filler::fill() {
|
||||||
if (_folder) {
|
if (_folder) {
|
||||||
fillArchiveActions();
|
fillArchiveActions();
|
||||||
return;
|
} else if (_sublist) {
|
||||||
}
|
fillSavedSublistActions();
|
||||||
switch (_request.section) {
|
} else switch (_request.section) {
|
||||||
case Section::ChatsList: fillChatsListActions(); break;
|
case Section::ChatsList: fillChatsListActions(); break;
|
||||||
case Section::History: fillHistoryActions(); break;
|
case Section::History: fillHistoryActions(); break;
|
||||||
case Section::Profile: fillProfileActions(); break;
|
case Section::Profile: fillProfileActions(); break;
|
||||||
|
@ -1353,6 +1374,10 @@ void Filler::fillArchiveActions() {
|
||||||
}, &st::menuIconManage);
|
}, &st::menuIconManage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Filler::fillSavedSublistActions() {
|
||||||
|
addTogglePin();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void PeerMenuExportChat(not_null<PeerData*> peer) {
|
void PeerMenuExportChat(not_null<PeerData*> peer) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue