Add support for pinned feeds management.

This commit is contained in:
John Preston 2018-01-04 22:54:35 +03:00
parent a2891807f8
commit 9d2239291d
22 changed files with 388 additions and 246 deletions

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_drafts.h"
#include "data/data_photo.h"
#include "data/data_web_page.h"
#include "data/data_feed.h"
#include "core/tl_help.h"
#include "base/overload.h"
#include "observer_peer.h"
@ -147,27 +148,22 @@ void ApiWrap::applyUpdates(
App::main()->feedUpdates(updates, sentMessageRandomId);
}
void ApiWrap::applyDialogsPinned(const QVector<MTPDialog> &list) {
for (auto i = list.size(); i != 0;) {
const auto &dialog = list[--i];
switch (dialog.type()) {
case mtpc_dialog: {
const auto &dialogData = dialog.c_dialog();
if (const auto peer = peerFromMTP(dialogData.vpeer)) {
const auto history = App::history(peer);
history->setPinnedDialog(dialogData.is_pinned());
}
} break;
case mtpc_dialogFeed: {
const auto &feedData = dialog.c_dialogFeed();
const auto feedId = feedData.vfeed_id.v;
// #TODO feeds
} break;
default: Unexpected("Type in ApiWrap::applyDialogsPinned.");
void ApiWrap::savePinnedOrder() {
const auto &order = _session->data().pinnedDialogsOrder();
auto peers = QVector<MTPInputDialogPeer>();
peers.reserve(order.size());
for (const auto pinned : base::reversed(order)) {
if (const auto history = pinned.history()) {
peers.push_back(MTP_inputDialogPeer(history->peer->input));
} else if (const auto feed = pinned.feed()) {
peers.push_back(MTP_inputDialogPeerFeed(MTP_int(feed->id())));
}
}
auto flags = MTPmessages_ReorderPinnedDialogs::Flag::f_force;
request(MTPmessages_ReorderPinnedDialogs(
MTP_flags(flags),
MTP_vector(peers)
)).send();
}
void ApiWrap::sendMessageFail(const RPCError &error) {

View File

@ -45,7 +45,7 @@ public:
void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0);
void applyDialogsPinned(const QVector<MTPDialog> &list);
void savePinnedOrder();
using RequestMessageDataCallback = base::lambda<void(ChannelData*, MsgId)>;
void requestMessageData(

View File

@ -208,9 +208,10 @@ void GifsListWidget::inlineResultsDone(const MTPmessages_BotResults &result) {
auto it = _inlineCache.find(_inlineQuery);
auto adding = (it != _inlineCache.cend());
// #TODO layer 72 feed users
if (result.type() == mtpc_messages_botResults) {
auto &d = result.c_messages_botResults();
App::feedUsers(d.vusers);
auto &v = d.vresults.v;
auto queryId = d.vquery_id.v;

View File

@ -25,4 +25,14 @@ void Feed::setUnreadCounts(int unreadCount, int unreadMutedCount) {
_unreadMutedCount = unreadMutedCount;
}
void Feed::cachePinnedIndex(int index) {
_pinnedIndex = index;
}
uint64 Feed::sortKeyInChatList() const {
return 0ULL;/* isPinnedDialog()
? pinnedDialogPos(_pinnedIndex)
: dialogPosFromDate(chatListDate());*/
}
} // namespace Data

View File

@ -15,16 +15,26 @@ class Feed {
public:
Feed(FeedId id);
FeedId id() const {
return _id;
}
void registerOne(not_null<ChannelData*> channel);
void unregisterOne(not_null<ChannelData*> channel);
void setUnreadCounts(int unreadCount, int unreadMutedCount);
bool isPinnedDialog() const {
return _pinnedIndex > 0;
}
void cachePinnedIndex(int index);
uint64 sortKeyInChatList() const;
private:
FeedId _id = 0;
base::flat_set<not_null<ChannelData*>> _channels;
int _unreadCount = 0;
int _unreadMutedCount = 0;
int _pinnedIndex = 0;
bool _complete = false;
};

View File

@ -164,6 +164,114 @@ MessageIdsList Session::groupToIds(
return result;
}
void Session::setPinnedDialog(const Dialogs::Key &key, bool pinned) {
setIsPinned(key, pinned);
}
void Session::applyPinnedDialogs(const QVector<MTPDialog> &list) {
clearPinnedDialogs();
for (auto i = list.size(); i != 0;) {
const auto &dialog = list[--i];
switch (dialog.type()) {
case mtpc_dialog: {
const auto &dialogData = dialog.c_dialog();
if (const auto peer = peerFromMTP(dialogData.vpeer)) {
setPinnedDialog(App::history(peer), true);
}
} break;
case mtpc_dialogFeed: {
const auto &feedData = dialog.c_dialogFeed();
const auto feedId = feedData.vfeed_id.v;
setPinnedDialog(feed(feedId), true);
} break;
default: Unexpected("Type in ApiWrap::applyDialogsPinned.");
}
}
}
void Session::applyPinnedDialogs(const QVector<MTPDialogPeer> &list) {
clearPinnedDialogs();
for (auto i = list.size(); i != 0;) {
const auto &dialogPeer = list[--i];
switch (dialogPeer.type()) {
case mtpc_dialogPeer: {
const auto &peerData = dialogPeer.c_dialogPeer();
if (const auto peerId = peerFromMTP(peerData.vpeer)) {
setPinnedDialog(App::history(peerId), true);
}
} break;
case mtpc_dialogPeerFeed: {
const auto &feedData = dialogPeer.c_dialogPeerFeed();
const auto feedId = feedData.vfeed_id.v;
setPinnedDialog(feed(feedId), true);
} break;
}
}
}
int Session::pinnedDialogsCount() const {
return _pinnedDialogs.size();
}
const std::deque<Dialogs::Key> &Session::pinnedDialogsOrder() const {
return _pinnedDialogs;
}
void Session::clearPinnedDialogs() {
while (!_pinnedDialogs.empty()) {
setPinnedDialog(_pinnedDialogs.back(), false);
}
}
void Session::reorderTwoPinnedDialogs(
const Dialogs::Key &key1,
const Dialogs::Key &key2) {
const auto &order = pinnedDialogsOrder();
const auto index1 = ranges::find(order, key1) - begin(order);
const auto index2 = ranges::find(order, key2) - begin(order);
Assert(index1 >= 0 && index1 < order.size());
Assert(index2 >= 0 && index2 < order.size());
Assert(index1 != index2);
std::swap(_pinnedDialogs[index1], _pinnedDialogs[index2]);
key1.cachePinnedIndex(index2 + 1);
key2.cachePinnedIndex(index1 + 1);
}
void Session::setIsPinned(const Dialogs::Key &key, bool pinned) {
const auto already = ranges::find(_pinnedDialogs, key);
if (pinned) {
if (already != end(_pinnedDialogs)) {
auto saved = std::move(*already);
const auto alreadyIndex = already - end(_pinnedDialogs);
const auto count = int(size(_pinnedDialogs));
Assert(alreadyIndex < count);
for (auto index = alreadyIndex + 1; index != count; ++index) {
_pinnedDialogs[index - 1] = std::move(_pinnedDialogs[index]);
_pinnedDialogs[index - 1].cachePinnedIndex(index);
}
_pinnedDialogs.back() = std::move(saved);
_pinnedDialogs.back().cachePinnedIndex(count);
} else {
_pinnedDialogs.push_back(key);
if (_pinnedDialogs.size() > Global::PinnedDialogsCountMax()) {
_pinnedDialogs.front().cachePinnedIndex(0);
_pinnedDialogs.pop_front();
auto index = 0;
for (const auto &pinned : _pinnedDialogs) {
pinned.cachePinnedIndex(++index);
}
} else {
key.cachePinnedIndex(_pinnedDialogs.size());
}
}
} else if (!pinned && already != _pinnedDialogs.end()) {
_pinnedDialogs.erase(already);
}
}
not_null<Data::Feed*> Session::feed(FeedId id) {
if (const auto result = feedLoaded(id)) {
return result;

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "chat_helpers/stickers.h"
#include "dialogs/dialogs_key.h"
namespace Data {
@ -142,6 +143,15 @@ public:
MessageIdsList itemsToIds(const HistoryItemsList &items) const;
MessageIdsList groupToIds(not_null<HistoryMessageGroup*> group) const;
int pinnedDialogsCount() const;
const std::deque<Dialogs::Key> &pinnedDialogsOrder() const;
void setPinnedDialog(const Dialogs::Key &key, bool pinned);
void applyPinnedDialogs(const QVector<MTPDialog> &list);
void applyPinnedDialogs(const QVector<MTPDialogPeer> &list);
void reorderTwoPinnedDialogs(
const Dialogs::Key &key1,
const Dialogs::Key &key2);
not_null<Data::Feed*> feed(FeedId id);
Data::Feed *feedLoaded(FeedId id);
@ -153,6 +163,9 @@ private:
}
void userIsContactUpdated(not_null<UserData*> user);
void clearPinnedDialogs();
void setIsPinned(const Dialogs::Key &key, bool pinned);
base::Variable<bool> _contactsLoaded = { false };
base::Variable<bool> _allChatsLoaded = { false };
base::Observable<void> _moreChatsLoaded;
@ -180,6 +193,7 @@ private:
Stickers::Order _archivedStickerSetsOrder;
Stickers::SavedGifs _savedGifs;
std::deque<Dialogs::Key> _pinnedDialogs;
base::flat_map<FeedId, std::unique_ptr<Data::Feed>> _feeds;
rpl::lifetime _lifetime;

View File

@ -7,6 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "dialogs/dialogs_indexed_list.h"
#include "auth_session.h"
#include "data/data_session.h"
namespace Dialogs {
IndexedList::IndexedList(SortMode sortMode)
@ -81,15 +84,9 @@ void IndexedList::movePinned(Row *row, int deltaSign) {
Assert(swapPinnedIndexWith != cbegin());
--swapPinnedIndexWith;
}
// #TODO feeds pinned
auto history1 = row->history();
auto history2 = (*swapPinnedIndexWith)->history();
Assert(history1->isPinnedDialog());
Assert(history2->isPinnedDialog());
auto index1 = history1->getPinnedIndex();
auto index2 = history2->getPinnedIndex();
history1->setPinnedIndex(index2);
history2->setPinnedIndex(index1);
Auth().data().reorderTwoPinnedDialogs(
row->key(),
(*swapPinnedIndexWith)->key());
}
void IndexedList::peerNameChanged(

View File

@ -736,7 +736,7 @@ void DialogsInner::checkReorderPinnedStart(QPoint localPosition) {
if (updateReorderIndexGetCount() < 2) {
_dragging = nullptr;
} else {
_pinnedOrder = App::histories().getPinnedOrder();
_pinnedOrder = Auth().data().pinnedDialogsOrder();
_pinnedRows[_draggingIndex].yadd = anim::value(0, localPosition.y() - _dragStart.y());
_pinnedRows[_draggingIndex].animStartTime = getms();
_a_pinnedShifting.start();
@ -748,8 +748,7 @@ void DialogsInner::checkReorderPinnedStart(QPoint localPosition) {
int DialogsInner::shownPinnedCount() const {
auto result = 0;
for_const (auto row, *shownDialogs()) {
// #TODO feeds pinned
if (!row->history()->isPinnedDialog()) {
if (!row->entry()->isPinnedDialog()) {
break;
}
++result;
@ -758,13 +757,12 @@ int DialogsInner::shownPinnedCount() const {
}
int DialogsInner::countPinnedIndex(Dialogs::Row *ofRow) {
// #TODO feeds pinned
if (!ofRow || !ofRow->history()->isPinnedDialog()) {
if (!ofRow || !ofRow->entry()->isPinnedDialog()) {
return -1;
}
auto result = 0;
for_const (auto row, *shownDialogs()) {
if (!row->history()->isPinnedDialog()) {
if (!row->entry()->isPinnedDialog()) {
break;
} else if (row == ofRow) {
return result;
@ -775,16 +773,16 @@ int DialogsInner::countPinnedIndex(Dialogs::Row *ofRow) {
}
void DialogsInner::savePinnedOrder() {
auto newOrder = App::histories().getPinnedOrder();
const auto &newOrder = Auth().data().pinnedDialogsOrder();
if (newOrder.size() != _pinnedOrder.size()) {
return; // Something has changed in the set of pinned chats.
}
for_const (auto history, newOrder) {
if (_pinnedOrder.indexOf(history) < 0) {
for (const auto &pinned : newOrder) {
if (!base::contains(_pinnedOrder, pinned)) {
return; // Something has changed in the set of pinned chats.
}
}
App::histories().savePinnedToServer();
Auth().api().savePinnedOrder();
}
void DialogsInner::finishReorderPinned() {
@ -2246,7 +2244,7 @@ void DialogsInner::destroyData() {
Dialogs::RowDescriptor DialogsInner::chatListEntryBefore(
const Dialogs::RowDescriptor &which) const {
if (!which.key.value) {
if (!which.key) {
return Dialogs::RowDescriptor();
}
if (_state == DefaultState) {
@ -2323,7 +2321,7 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryBefore(
Dialogs::RowDescriptor DialogsInner::chatListEntryAfter(
const Dialogs::RowDescriptor &which) const {
if (!which.key.value) {
if (!which.key) {
return Dialogs::RowDescriptor();
}
if (_state == DefaultState) {

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "dialogs/dialogs_widget.h"
#include "dialogs/dialogs_key.h"
#include "base/flags.h"
namespace Dialogs {
@ -276,7 +277,7 @@ private:
};
std::vector<PinnedRow> _pinnedRows;
BasicAnimation _a_pinnedShifting;
QList<History*> _pinnedOrder;
std::deque<Dialogs::Key> _pinnedOrder;
// Remember the last currently dragged row top shift for updating area.
int _aboveTopShift = -1;

View File

@ -0,0 +1,66 @@
/*
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 "dialogs/dialogs_key.h"
#include "data/data_feed.h"
namespace Dialogs {
const QString &Key::name() const {
if (const auto h = history()) {
return h->peer->name;
}
// #TODO feeds name
static const auto empty = QString();
return empty;
}
const PeerData::NameFirstChars &Key::nameFirstChars() const {
if (const auto h = history()) {
return h->peer->nameFirstChars();
}
// #TODO feeds name
static const auto empty = PeerData::NameFirstChars();
return empty;
}
uint64 Key::sortKey() const {
if (const auto h = history()) {
return h->sortKeyInChatList();
} else if (const auto f = feed()) {
return f->sortKeyInChatList();
} else {
Unexpected("Key value in Key::sortKey");
}
}
void Key::cachePinnedIndex(int index) const {
if (const auto h = history()) {
h->cachePinnedIndex(index);
} else if (const auto f = feed()) {
f->cachePinnedIndex(index);
} else {
Unexpected("Key value in Key::setPinnedIndex");
}
}
History *Key::history() const {
if (const auto p = base::get_if<not_null<History*>>(&_value)) {
return *p;
}
return nullptr;
}
Data::Feed *Key::feed() const {
if (const auto p = base::get_if<not_null<Data::Feed*>>(&_value)) {
return *p;
}
return nullptr;
}
} // namespace Dialogs

View File

@ -0,0 +1,85 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/value_ordering.h"
namespace Data {
class Feed;
} // namespace Data
namespace Dialogs {
class Key {
public:
Key() = default;
Key(History *history) : _value(history) {
}
Key(not_null<History*> history) : _value(history) {
}
Key(Data::Feed *feed) : _value(feed) {
}
Key(not_null<Data::Feed*> feed) : _value(feed) {
}
explicit operator bool() const {
return !!_value;
}
History *history() const;
Data::Feed *feed() const;
const QString &name() const;
const PeerData::NameFirstChars &nameFirstChars() const;
uint64 sortKey() const;
void cachePinnedIndex(int index) const;
inline bool operator<(const Key &other) const {
return _value < other._value;
}
inline bool operator>(const Key &other) const {
return (other < *this);
}
inline bool operator<=(const Key &other) const {
return !(other < *this);
}
inline bool operator>=(const Key &other) const {
return !(*this < other);
}
inline bool operator==(const Key &other) const {
return _value == other._value;
}
inline bool operator!=(const Key &other) const {
return !(*this == other);
}
base::optional_variant<
not_null<History*>,
not_null<Data::Feed*>> raw() const {
return _value;
}
// Not working :(
//friend inline auto value_ordering_helper(const Key &key) {
// return key.value;
//}
private:
base::optional_variant<not_null<History*>, not_null<Data::Feed*>> _value;
};
struct RowDescriptor {
RowDescriptor() = default;
RowDescriptor(Key key, MsgId msgId) : key(key), msgId(msgId) {
}
Key key;
MsgId msgId = 0;
};
} // namespace Dialogs

View File

@ -8,15 +8,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "ui/text/text.h"
#include "base/value_ordering.h"
#include "dialogs/dialogs_key.h"
class History;
class HistoryItem;
namespace Data {
class Feed;
} // namespace Data
namespace Ui {
class RippleAnimation;
} // namespace Ui
@ -26,79 +22,6 @@ namespace Layout {
class RowPainter;
} // namespace Layout
struct Key {
Key() = default;
Key(History *history) : value(history) {
}
Key(not_null<History*> history) : value(history) {
}
Key(Data::Feed *feed) : value(feed) {
}
Key(not_null<Data::Feed*> feed) : value(feed) {
}
const QString &name() const {
if (const auto p = base::get_if<not_null<History*>>(&value)) {
return (*p)->peer->name;
}
// #TODO feeds name
static const auto empty = QString();
return empty;
}
const PeerData::NameFirstChars &nameFirstChars() const {
if (const auto p = base::get_if<not_null<History*>>(&value)) {
return (*p)->peer->nameFirstChars();
}
// #TODO feeds name
static const auto empty = PeerData::NameFirstChars();
return empty;
}
uint64 sortKey() const {
if (const auto p = base::get_if<not_null<History*>>(&value)) {
return (*p)->sortKeyInChatList();
}
// #TODO feeds sort in chats list
return 0ULL;
}
History *history() const {
if (const auto p = base::get_if<not_null<History*>>(&value)) {
return *p;
}
return nullptr;
}
Data::Feed *feed() const {
if (const auto p = base::get_if<not_null<Data::Feed*>>(&value)) {
return *p;
}
return nullptr;
}
inline bool operator<(const Key &other) const {
return value < other.value;
}
inline bool operator==(const Key &other) const {
return value == other.value;
}
// Not working :(
//friend inline auto value_ordering_helper(const Key &key) {
// return key.value;
//}
base::optional_variant<
not_null<History*>,
not_null<Data::Feed*>> value;
};
struct RowDescriptor {
RowDescriptor() = default;
RowDescriptor(Key key, MsgId msgId) : key(key), msgId(msgId) {
}
Key key;
MsgId msgId = 0;
};
class RippleRow {
public:
RippleRow();

View File

@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/dialogs_inner_widget.h"
#include "dialogs/dialogs_search_from_controllers.h"
#include "dialogs/dialogs_row.h"
#include "dialogs/dialogs_key.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/wrap/fade_wrap.h"
@ -400,12 +400,11 @@ void DialogsWidget::pinnedDialogsReceived(
if (_pinnedDialogsRequestId != requestId) return;
App::histories().clearPinned();
auto &data = result.c_messages_peerDialogs();
App::feedUsers(data.vusers);
App::feedChats(data.vchats);
Auth().data().applyPinnedDialogs(data.vdialogs.v);
applyReceivedDialogs(data.vdialogs.v, data.vmessages.v);
_pinnedDialogsRequestId = 0;
@ -420,7 +419,6 @@ void DialogsWidget::pinnedDialogsReceived(
void DialogsWidget::applyReceivedDialogs(
const QVector<MTPDialog> &dialogs,
const QVector<MTPMessage> &messages) {
Auth().api().applyDialogsPinned(dialogs);
App::feedMsgs(messages, NewMessageLast);
_inner->dialogsReceived(dialogs);
onListScroll();

View File

@ -47,8 +47,6 @@ constexpr auto kStatusShowClientsidePlayGame = 10000;
constexpr auto kSetMyActionForMs = 10000;
constexpr auto kNewBlockEachMessage = 50;
auto GlobalPinnedIndex = 0;
HistoryItem *createUnsupportedMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from) {
auto text = TextWithEntities { lng_message_unsupported(lt_link, qsl("https://desktop.telegram.org")) };
TextUtilities::ParseEntities(text, Ui::ItemTextNoMonoOptions().flags);
@ -516,7 +514,8 @@ void ChannelHistory::checkMaxReadMessageDate() {
if (!item->unread()) {
_maxReadMessageDate = item->date;
if (item->isGroupMigrate() && isMegagroup() && peer->migrateFrom()) {
_maxReadMessageDate = date(MTP_int(peer->asChannel()->date + 1)); // no report spam panel
// No report spam panel.
_maxReadMessageDate = date(MTP_int(peer->asChannel()->date + 1));
}
return;
}
@ -583,7 +582,6 @@ not_null<History*> Histories::findOrInsert(const PeerId &peerId, int32 unreadCou
void Histories::clear() {
App::historyClearMsgs();
_pinnedDialogs.clear();
auto temp = base::take(map);
for_const (auto history, temp) {
delete history;
@ -677,63 +675,6 @@ bool Histories::unreadOnlyMuted() const {
return Global::IncludeMuted() ? (_unreadMuted >= _unreadFull) : false;
}
void Histories::setIsPinned(History *history, bool isPinned) {
if (isPinned) {
_pinnedDialogs.insert(history);
if (_pinnedDialogs.size() > Global::PinnedDialogsCountMax()) {
auto minIndex = GlobalPinnedIndex + 1;
auto minIndexHistory = (History*)nullptr;
for_const (auto pinned, _pinnedDialogs) {
if (pinned->getPinnedIndex() < minIndex) {
minIndex = pinned->getPinnedIndex();
minIndexHistory = pinned;
}
}
Assert(minIndexHistory != nullptr);
minIndexHistory->setPinnedDialog(false);
}
} else {
_pinnedDialogs.remove(history);
}
}
void Histories::clearPinned() {
for (auto pinned : base::take(_pinnedDialogs)) {
pinned->setPinnedDialog(false);
}
}
int Histories::pinnedCount() const {
return _pinnedDialogs.size();
}
QList<History*> Histories::getPinnedOrder() const {
QMap<int, History*> sorter;
for_const (auto pinned, _pinnedDialogs) {
sorter.insert(pinned->getPinnedIndex(), pinned);
}
QList<History*> result;
for (auto i = sorter.cend(), e = sorter.cbegin(); i != e;) {
--i;
result.push_back(i.value());
}
return result;
}
void Histories::savePinnedToServer() const {
const auto order = getPinnedOrder();
auto peers = QVector<MTPInputDialogPeer>();
peers.reserve(order.size());
for (const auto history : order) {
peers.push_back(MTP_inputDialogPeer(history->peer->input));
}
auto flags = MTPmessages_ReorderPinnedDialogs::Flag::f_force;
MTP::send(
MTPmessages_ReorderPinnedDialogs(
MTP_flags(flags),
MTP_vector(peers)));
}
void Histories::selfDestructIn(not_null<HistoryItem*> item, TimeMs delay) {
_selfDestructItems.push_back(item->fullId());
if (!_selfDestructTimer.isActive() || _selfDestructTimer.remainingTime() > delay) {
@ -2262,8 +2203,10 @@ void History::setNotLoadedAtBottom() {
}
namespace {
uint32 _dialogsPosToTopShift = 0x80000000UL;
}
uint32 _dialogsPosToTopShift = 0x80000000UL;
} // namespace
inline uint64 dialogPosFromDate(const QDateTime &date) {
if (date.isNull()) return 0;
@ -2316,7 +2259,9 @@ void History::updateChatListSortPosition() {
return lastMsgDate;
};
_sortKeyInChatList = isPinnedDialog() ? pinnedDialogPos(_pinnedIndex) : dialogPosFromDate(chatListDate());
_sortKeyInChatList = isPinnedDialog()
? pinnedDialogPos(_pinnedIndex)
: dialogPosFromDate(chatListDate());
if (auto m = App::main()) {
if (needUpdateInChatList()) {
if (_sortKeyInChatList) {
@ -2602,20 +2547,17 @@ void History::updateChatListEntry() const {
}
}
void History::setPinnedDialog(bool isPinned) {
setPinnedIndex(isPinned ? (++GlobalPinnedIndex) : 0);
}
void History::setPinnedIndex(int pinnedIndex) {
void History::cachePinnedIndex(int pinnedIndex) {
if (_pinnedIndex != pinnedIndex) {
auto wasPinned = isPinnedDialog();
_pinnedIndex = pinnedIndex;
updateChatListSortPosition();
updateChatListEntry();
if (wasPinned != isPinnedDialog()) {
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::PinnedChanged);
Notify::peerUpdatedDelayed(
peer,
Notify::PeerUpdate::Flag::PinnedChanged);
}
App::histories().setIsPinned(this, isPinnedDialog());
}
}

View File

@ -75,12 +75,6 @@ public:
}
}
void setIsPinned(History *history, bool isPinned);
void clearPinned();
int pinnedCount() const;
QList<History*> getPinnedOrder() const;
void savePinnedToServer() const;
struct SendActionAnimationUpdate {
History *history;
int width;
@ -98,7 +92,6 @@ private:
int _unreadFull = 0;
int _unreadMuted = 0;
base::Observable<SendActionAnimationUpdate> _sendActionAnimationUpdated;
OrderedSet<History*> _pinnedDialogs;
base::Timer _selfDestructTimer;
std::vector<FullMsgId> _selfDestructItems;
@ -275,11 +268,7 @@ public:
bool isPinnedDialog() const {
return (_pinnedIndex > 0);
}
void setPinnedDialog(bool isPinned);
void setPinnedIndex(int newPinnedIndex);
int getPinnedIndex() const {
return _pinnedIndex;
}
void cachePinnedIndex(int newPinnedIndex);
MsgId minMsgId() const;
MsgId maxMsgId() const;

View File

@ -65,7 +65,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "inline_bots/inline_results_widget.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "core/crash_reports.h"
#include "dialogs/dialogs_row.h"
#include "dialogs/dialogs_key.h"
#include "styles/style_history.h"
#include "styles/style_dialogs.h"
#include "styles/style_window.h"

View File

@ -1008,9 +1008,10 @@ void Widget::inlineResultsDone(const MTPmessages_BotResults &result) {
auto it = _inlineCache.find(_inlineQuery);
auto adding = (it != _inlineCache.cend());
// #TODO layer 72 feed users
if (result.type() == mtpc_messages_botResults) {
auto &d = result.c_messages_botResults();
App::feedUsers(d.vusers);
auto &v = d.vresults.v;
auto queryId = d.vquery_id.v;

View File

@ -34,7 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "observer_peer.h"
#include "apiwrap.h"
#include "dialogs/dialogs_widget.h"
#include "dialogs/dialogs_row.h"
#include "dialogs/dialogs_key.h"
#include "history/history_widget.h"
#include "history/history_message.h"
#include "history/history_media.h"
@ -1100,7 +1100,7 @@ void MainWidget::deleteConversation(PeerData *peer, bool deleteHistory) {
Ui::showChatsList();
}
if (auto history = App::historyLoaded(peer->id)) {
history->setPinnedDialog(false);
Auth().data().setPinnedDialog(history, false);
removeDialog(history);
if (peer->isMegagroup() && peer->asChannel()->mgInfo->migrateFromPtr) {
if (auto migrated = App::historyLoaded(peer->asChannel()->mgInfo->migrateFromPtr->id)) {
@ -5330,31 +5330,20 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_dialogPeerFeed: {
const auto &feed = dialogPeer.c_dialogPeerFeed();
const auto feedId = feed.vfeed_id.v;
// #TODO feeds
if (!Auth().data().feedLoaded(feedId)) {
DEBUG_LOG(("API Error: "
"pinned feed not loaded for feedId %1"
).arg(feedId
));
return false;
}
} break;
}
}
return true;
}();
if (allLoaded) {
App::histories().clearPinned();
for (auto i = order.size(); i != 0;) {
const auto &dialogPeer = order[--i];
switch (dialogPeer.type()) {
case mtpc_dialogPeer: {
const auto &peer = dialogPeer.c_dialogPeer();
const auto peerId = peerFromMTP(peer.vpeer);
const auto history = App::historyLoaded(peerId);
Assert(history != nullptr);
history->setPinnedDialog(true);
} break;
case mtpc_dialogPeerFeed: {
const auto &feed = dialogPeer.c_dialogPeerFeed();
const auto feedId = feed.vfeed_id.v;
// #TODO feeds
} break;
}
}
Auth().data().applyPinnedDialogs(order);
} else {
_dialogs->loadPinnedDialogs();
}
@ -5369,7 +5358,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_dialogPeer: {
const auto peerId = peerFromMTP(d.vpeer.c_dialogPeer().vpeer);
if (const auto history = App::historyLoaded(peerId)) {
history->setPinnedDialog(d.is_pinned());
Auth().data().setPinnedDialog(history, d.is_pinned());
} else {
DEBUG_LOG(("API Error: "
"pinned chat not loaded for peer %1"
@ -5380,7 +5369,15 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break;
case mtpc_dialogPeerFeed: {
const auto feedId = d.vpeer.c_dialogPeerFeed().vfeed_id.v;
// #TODO feeds
if (const auto feed = Auth().data().feedLoaded(feedId)) {
Auth().data().setPinnedDialog(feed, d.is_pinned());
} else {
DEBUG_LOG(("API Error: "
"pinned feed not loaded for feedId %1"
).arg(feedId
));
_dialogs->loadPinnedDialogs();
}
} break;
}
} break;

View File

@ -222,7 +222,9 @@ void MainWindow::setupPasscode() {
}
void MainWindow::setupIntro() {
if (_intro && !_intro->isHidden() && !_main) return;
if (_intro && !_intro->isHidden() && !_main) {
return;
}
Ui::hideSettingsAndLayer(anim::type::instant);

View File

@ -65,12 +65,14 @@ private:
};
History *FindWastedPin() {
auto order = App::histories().getPinnedOrder();
for_const (auto pinned, order) {
if (pinned->peer->isChat()
&& pinned->peer->asChat()->isDeactivated()
&& !pinned->inChatList(Dialogs::Mode::All)) {
return pinned;
const auto &order = Auth().data().pinnedDialogsOrder();
for (const auto pinned : order) {
if (const auto history = pinned.history()) {
if (history->peer->isChat()
&& history->peer->asChat()->isDeactivated()
&& !history->inChatList(Dialogs::Mode::All)) {
return history;
}
}
}
return nullptr;
@ -116,14 +118,14 @@ void Filler::addPinToggle() {
auto pinToggle = [peer] {
auto history = App::history(peer);
auto isPinned = !history->isPinnedDialog();
auto pinnedCount = App::histories().pinnedCount();
auto pinnedMax = Global::PinnedDialogsCountMax();
const auto pinnedCount = Auth().data().pinnedDialogsCount();
const auto pinnedMax = Global::PinnedDialogsCountMax();
if (isPinned && pinnedCount >= pinnedMax) {
// Some old chat, that was converted to supergroup, maybe is still pinned.
if (auto wasted = FindWastedPin()) {
wasted->setPinnedDialog(false);
history->setPinnedDialog(isPinned);
App::histories().savePinnedToServer();
Auth().data().setPinnedDialog(wasted, false);
Auth().data().setPinnedDialog(history, true);
Auth().api().savePinnedOrder();
} else {
auto errorText = lng_error_pinned_max(
lt_count,
@ -133,7 +135,7 @@ void Filler::addPinToggle() {
return;
}
history->setPinnedDialog(isPinned);
Auth().data().setPinnedDialog(history, isPinned);
auto flags = MTPmessages_ToggleDialogPin::Flags(0);
if (isPinned) {
flags |= MTPmessages_ToggleDialogPin::Flag::f_pinned;

View File

@ -198,6 +198,8 @@
<(src_loc)/dialogs/dialogs_indexed_list.h
<(src_loc)/dialogs/dialogs_inner_widget.cpp
<(src_loc)/dialogs/dialogs_inner_widget.h
<(src_loc)/dialogs/dialogs_key.cpp
<(src_loc)/dialogs/dialogs_key.h
<(src_loc)/dialogs/dialogs_layout.cpp
<(src_loc)/dialogs/dialogs_layout.h
<(src_loc)/dialogs/dialogs_list.cpp