mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-11 09:19:35 +00:00
Add support for pinned feeds management.
This commit is contained in:
parent
a2891807f8
commit
9d2239291d
@ -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) {
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
66
Telegram/SourceFiles/dialogs/dialogs_key.cpp
Normal file
66
Telegram/SourceFiles/dialogs/dialogs_key.cpp
Normal 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
|
85
Telegram/SourceFiles/dialogs/dialogs_key.h
Normal file
85
Telegram/SourceFiles/dialogs/dialogs_key.h
Normal 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
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user