mirror of https://github.com/procxx/kepka.git
Support pinned chats in folders.
This commit is contained in:
parent
607655941d
commit
58519300ea
|
@ -433,21 +433,24 @@ void ApiWrap::applyUpdates(
|
||||||
App::main()->feedUpdates(updates, sentMessageRandomId);
|
App::main()->feedUpdates(updates, sentMessageRandomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::savePinnedOrder() {
|
void ApiWrap::savePinnedOrder(FolderId folderId) {
|
||||||
const auto &order = _session->data().pinnedDialogsOrder();
|
const auto &order = _session->data().pinnedChatsOrder(folderId);
|
||||||
|
const auto input = [](const Dialogs::Key &key) {
|
||||||
|
if (const auto history = key.history()) {
|
||||||
|
return MTP_inputDialogPeer(history->peer->input);
|
||||||
|
} else if (const auto folder = key.folder()) {
|
||||||
|
return MTP_inputDialogPeerFolder(MTP_int(folder->id()));
|
||||||
|
}
|
||||||
|
Unexpected("Key type in pinnedDialogsOrder().");
|
||||||
|
};
|
||||||
auto peers = QVector<MTPInputDialogPeer>();
|
auto peers = QVector<MTPInputDialogPeer>();
|
||||||
peers.reserve(order.size());
|
peers.reserve(order.size());
|
||||||
for (const auto &pinned : ranges::view::reverse(order)) {
|
ranges::transform(
|
||||||
if (const auto history = pinned.history()) {
|
order,
|
||||||
peers.push_back(MTP_inputDialogPeer(history->peer->input));
|
ranges::back_inserter(peers),
|
||||||
// } else if (const auto feed = pinned.feed()) { // #feed
|
input);
|
||||||
// peers.push_back(MTP_inputDialogPeerFeed(MTP_int(feed->id())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const auto folderId = 0;
|
|
||||||
const auto flags = MTPmessages_ReorderPinnedDialogs::Flag::f_force;
|
|
||||||
request(MTPmessages_ReorderPinnedDialogs(
|
request(MTPmessages_ReorderPinnedDialogs(
|
||||||
MTP_flags(flags),
|
MTP_flags(MTPmessages_ReorderPinnedDialogs::Flag::f_force),
|
||||||
MTP_int(folderId),
|
MTP_int(folderId),
|
||||||
MTP_vector(peers)
|
MTP_vector(peers)
|
||||||
)).send();
|
)).send();
|
||||||
|
@ -704,12 +707,8 @@ void ApiWrap::requestContacts() {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::requestDialogs() {
|
void ApiWrap::requestDialogs(FolderId folderId) {
|
||||||
requestMoreDialogs(FolderId(0));
|
if (folderId && !_foldersLoadState.contains(folderId)) {
|
||||||
}
|
|
||||||
|
|
||||||
void ApiWrap::requestFolderDialogs(FolderId folderId) {
|
|
||||||
if (!_foldersLoadState.contains(folderId)) {
|
|
||||||
_foldersLoadState.emplace(folderId, DialogsLoadState());
|
_foldersLoadState.emplace(folderId, DialogsLoadState());
|
||||||
}
|
}
|
||||||
requestMoreDialogs(folderId);
|
requestMoreDialogs(folderId);
|
||||||
|
@ -744,11 +743,15 @@ void ApiWrap::requestMoreDialogs(FolderId folderId) {
|
||||||
MTP_int(loadCount),
|
MTP_int(loadCount),
|
||||||
MTP_int(hash)
|
MTP_int(hash)
|
||||||
)).done([=](const MTPmessages_Dialogs &result) {
|
)).done([=](const MTPmessages_Dialogs &result) {
|
||||||
|
const auto state = dialogsLoadState(folderId);
|
||||||
result.match([](const MTPDmessages_dialogsNotModified & data) {
|
result.match([](const MTPDmessages_dialogsNotModified & data) {
|
||||||
LOG(("API Error: not-modified received for requested dialogs."));
|
LOG(("API Error: not-modified received for requested dialogs."));
|
||||||
}, [&](const auto &data) {
|
}, [&](const auto &data) {
|
||||||
if constexpr (data.Is<MTPDmessages_dialogs>()) {
|
if constexpr (data.Is<MTPDmessages_dialogs>()) {
|
||||||
dialogsLoadFinish(folderId);
|
if (state) {
|
||||||
|
state->listReceived = true;
|
||||||
|
dialogsLoadFinish(folderId); // may kill 'state'.
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updateDialogsOffset(
|
updateDialogsOffset(
|
||||||
folderId,
|
folderId,
|
||||||
|
@ -764,9 +767,11 @@ void ApiWrap::requestMoreDialogs(FolderId folderId) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!folderId) {
|
if (!folderId) {
|
||||||
requestDialogs();
|
requestDialogs(folderId);
|
||||||
requestContacts();
|
requestContacts();
|
||||||
if (!_dialogsLoadState || !_dialogsLoadState->requestId) {
|
if (!_dialogsLoadState
|
||||||
|
|| (!_dialogsLoadState->listReceived
|
||||||
|
&& !_dialogsLoadState->requestId)) {
|
||||||
refreshDialogsLoadBlocked();
|
refreshDialogsLoadBlocked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -774,16 +779,21 @@ void ApiWrap::requestMoreDialogs(FolderId folderId) {
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
dialogsLoadState(folderId)->requestId = 0;
|
dialogsLoadState(folderId)->requestId = 0;
|
||||||
}).send();
|
}).send();
|
||||||
if (!_pinnedDialogsReceived) {
|
|
||||||
requestPinnedDialogs();
|
if (!state->pinnedReceived) {
|
||||||
|
requestPinnedDialogs(folderId);
|
||||||
}
|
}
|
||||||
|
if (!folderId) {
|
||||||
refreshDialogsLoadBlocked();
|
refreshDialogsLoadBlocked();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ApiWrap::refreshDialogsLoadBlocked() {
|
void ApiWrap::refreshDialogsLoadBlocked() {
|
||||||
_dialogsLoadMayBlockByDate = _dialogsLoadState
|
_dialogsLoadMayBlockByDate = _dialogsLoadState
|
||||||
|
&& !_dialogsLoadState->listReceived
|
||||||
&& (_dialogsLoadTill > 0);
|
&& (_dialogsLoadTill > 0);
|
||||||
_dialogsLoadBlockedByDate = _dialogsLoadState
|
_dialogsLoadBlockedByDate = _dialogsLoadState
|
||||||
|
&& !_dialogsLoadState->listReceived
|
||||||
&& !_dialogsLoadState->requestId
|
&& !_dialogsLoadState->requestId
|
||||||
&& (_dialogsLoadTill > 0)
|
&& (_dialogsLoadTill > 0)
|
||||||
&& (_dialogsLoadState->offsetDate > 0)
|
&& (_dialogsLoadState->offsetDate > 0)
|
||||||
|
@ -824,17 +834,18 @@ void ApiWrap::updateDialogsOffset(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lastDate) {
|
|
||||||
if (const auto state = dialogsLoadState(folderId)) {
|
if (const auto state = dialogsLoadState(folderId)) {
|
||||||
|
if (lastDate) {
|
||||||
state->offsetDate = lastDate;
|
state->offsetDate = lastDate;
|
||||||
state->offsetId = lastMsgId;
|
state->offsetId = lastMsgId;
|
||||||
state->offsetPeer = _session->data().peer(lastPeer);
|
state->offsetPeer = _session->data().peer(lastPeer);
|
||||||
state->requestId = 0;
|
state->requestId = 0;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
state->listReceived = true;
|
||||||
dialogsLoadFinish(folderId);
|
dialogsLoadFinish(folderId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto ApiWrap::dialogsLoadState(FolderId folderId) -> DialogsLoadState* {
|
auto ApiWrap::dialogsLoadState(FolderId folderId) -> DialogsLoadState* {
|
||||||
if (!folderId) {
|
if (!folderId) {
|
||||||
|
@ -850,47 +861,48 @@ void ApiWrap::dialogsLoadFinish(FolderId folderId) {
|
||||||
_session->data().chatsListDone(folderId);
|
_session->data().chatsListDone(folderId);
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
const auto state = dialogsLoadState(folderId);
|
||||||
|
if (!state || !state->listReceived || !state->pinnedReceived) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (folderId) {
|
if (folderId) {
|
||||||
_foldersLoadState.remove(folderId);
|
_foldersLoadState.remove(folderId);
|
||||||
notify();
|
notify();
|
||||||
} else {
|
} else {
|
||||||
_dialogsLoadState = nullptr;
|
_dialogsLoadState = nullptr;
|
||||||
if (_pinnedDialogsReceived) {
|
|
||||||
notify();
|
notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void ApiWrap::requestPinnedDialogs() {
|
void ApiWrap::requestPinnedDialogs(FolderId folderId) {
|
||||||
if (_pinnedDialogsRequestId) {
|
const auto state = dialogsLoadState(folderId);
|
||||||
|
if (!state || state->pinnedReceived || state->pinnedRequestId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto folderId = FolderId(0);
|
const auto finalize = [=] {
|
||||||
_pinnedDialogsRequestId = request(MTPmessages_GetPinnedDialogs(
|
if (const auto state = dialogsLoadState(folderId)) {
|
||||||
|
state->pinnedRequestId = 0;
|
||||||
|
state->pinnedReceived = true;
|
||||||
|
dialogsLoadFinish(folderId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
state->pinnedRequestId = request(MTPmessages_GetPinnedDialogs(
|
||||||
MTP_int(folderId)
|
MTP_int(folderId)
|
||||||
)).done([=](const MTPmessages_PeerDialogs &result) {
|
)).done([=](const MTPmessages_PeerDialogs &result) {
|
||||||
|
finalize();
|
||||||
result.match([&](const MTPDmessages_peerDialogs &data) {
|
result.match([&](const MTPDmessages_peerDialogs &data) {
|
||||||
const auto folderId = FolderId(0);
|
|
||||||
|
|
||||||
_session->data().processUsers(data.vusers);
|
_session->data().processUsers(data.vusers);
|
||||||
_session->data().processChats(data.vchats);
|
_session->data().processChats(data.vchats);
|
||||||
_session->data().clearPinnedDialogs();
|
_session->data().clearPinnedChats(folderId);
|
||||||
_session->data().applyDialogs(
|
_session->data().applyDialogs(
|
||||||
folderId,
|
folderId,
|
||||||
data.vmessages.v,
|
data.vmessages.v,
|
||||||
data.vdialogs.v);
|
data.vdialogs.v);
|
||||||
|
|
||||||
_pinnedDialogsRequestId = 0;
|
|
||||||
_pinnedDialogsReceived = true;
|
|
||||||
|
|
||||||
_session->data().chatsListChanged(folderId);
|
_session->data().chatsListChanged(folderId);
|
||||||
if (!_dialogsLoadState) {
|
|
||||||
_session->data().chatsListDone(folderId);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
_pinnedDialogsRequestId = 0;
|
finalize();
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,7 +914,7 @@ void ApiWrap::requestMoreBlockedByDateDialogs() {
|
||||||
_dialogsLoadTill = _dialogsLoadState->offsetDate
|
_dialogsLoadTill = _dialogsLoadState->offsetDate
|
||||||
? (_dialogsLoadState->offsetDate - max)
|
? (_dialogsLoadState->offsetDate - max)
|
||||||
: (unixtime() - max);
|
: (unixtime() - max);
|
||||||
requestDialogs();
|
requestDialogs(FolderId(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<bool> ApiWrap::dialogsLoadMayBlockByDate() const {
|
rpl::producer<bool> ApiWrap::dialogsLoadMayBlockByDate() const {
|
||||||
|
@ -932,29 +944,6 @@ void ApiWrap::requestDialogEntry(not_null<Data::Folder*> folder) {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
//void ApiWrap::requestFeedDialogsEntries(not_null<Data::Feed*> feed) {
|
|
||||||
// if (_dialogFeedRequests.contains(feed)) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// _dialogFeedRequests.emplace(feed);
|
|
||||||
//
|
|
||||||
// const auto hash = 0;
|
|
||||||
// request(MTPmessages_GetDialogs(
|
|
||||||
// MTP_flags(MTPmessages_GetDialogs::Flag::f_feed_id),
|
|
||||||
// MTP_int(feed->id()),
|
|
||||||
// MTP_int(0), // offset_date
|
|
||||||
// MTP_int(0), // offset_id
|
|
||||||
// MTP_inputPeerEmpty(), // offset_peer
|
|
||||||
// MTP_int(Data::Feed::kChannelsLimit),
|
|
||||||
// MTP_int(hash)
|
|
||||||
// )).done([=](const MTPmessages_Dialogs &result) {
|
|
||||||
// applyFeedDialogs(feed, result);
|
|
||||||
// _dialogFeedRequests.remove(feed);
|
|
||||||
// }).fail([=](const RPCError &error) {
|
|
||||||
// _dialogFeedRequests.remove(feed);
|
|
||||||
// }).send();
|
|
||||||
//}
|
|
||||||
|
|
||||||
void ApiWrap::requestDialogEntry(
|
void ApiWrap::requestDialogEntry(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
Fn<void()> callback) {
|
Fn<void()> callback) {
|
||||||
|
@ -1054,45 +1043,6 @@ void ApiWrap::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) {
|
||||||
}
|
}
|
||||||
_session->data().sendHistoryChangeNotifications();
|
_session->data().sendHistoryChangeNotifications();
|
||||||
}
|
}
|
||||||
// // #feed
|
|
||||||
//void ApiWrap::applyFeedDialogs(
|
|
||||||
// not_null<Data::Feed*> feed,
|
|
||||||
// const MTPmessages_Dialogs &dialogs) {
|
|
||||||
// if (dialogs.type() == mtpc_messages_dialogsNotModified) {
|
|
||||||
// LOG(("API Error: "
|
|
||||||
// "messages.dialogsNotModified in ApiWrap::applyFeedDialogs."));
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// auto channels = std::vector<not_null<ChannelData*>>();
|
|
||||||
// dialogs.match([&](const MTPDmessages_dialogsNotModified &) {
|
|
||||||
// Unexpected("Type in ApiWrap::applyFeedDialogs.");
|
|
||||||
// }, [&](const auto &data) {
|
|
||||||
// _session->data().processUsers(data.vusers);
|
|
||||||
// _session->data().processChats(data.vchats);
|
|
||||||
// App::feedMsgs(data.vmessages.v, NewMessageLast);
|
|
||||||
// channels.reserve(data.vdialogs.v.size());
|
|
||||||
// for (const auto &dialog : data.vdialogs.v) {
|
|
||||||
// dialog.match([&](const MTPDdialog &data) {
|
|
||||||
// if (const auto peerId = peerFromMTP(data.vpeer)) {
|
|
||||||
// if (peerIsChannel(peerId)) { // #TODO archive
|
|
||||||
// const auto history = _session->data().history(peerId);
|
|
||||||
// history->applyDialog(data);
|
|
||||||
// channels.emplace_back(history->peer->asChannel());
|
|
||||||
// } else {
|
|
||||||
// LOG(("API Error: "
|
|
||||||
// "Unexpected peer in folder dialogs list."));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }, [&](const MTPDdialogFolder &data) {
|
|
||||||
// LOG(("API Error: "
|
|
||||||
// "Unexpected dialogFolder in folder dialogs list."));
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// feed->setChannels(channels);
|
|
||||||
// _session->data().sendHistoryChangeNotifications();
|
|
||||||
//}
|
|
||||||
|
|
||||||
void ApiWrap::changeDialogUnreadMark(
|
void ApiWrap::changeDialogUnreadMark(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
|
|
|
@ -64,7 +64,7 @@ public:
|
||||||
|
|
||||||
void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0);
|
void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0);
|
||||||
|
|
||||||
void savePinnedOrder();
|
void savePinnedOrder(FolderId folderId);
|
||||||
void toggleHistoryArchived(
|
void toggleHistoryArchived(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
bool archived,
|
bool archived,
|
||||||
|
@ -79,15 +79,13 @@ public:
|
||||||
QString exportDirectMessageLink(not_null<HistoryItem*> item);
|
QString exportDirectMessageLink(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
void requestContacts();
|
void requestContacts();
|
||||||
void requestDialogs();
|
void requestDialogs(FolderId folderId);
|
||||||
void requestFolderDialogs(FolderId folderId);
|
void requestPinnedDialogs(FolderId folderId);
|
||||||
void requestPinnedDialogs();
|
|
||||||
void requestMoreBlockedByDateDialogs();
|
void requestMoreBlockedByDateDialogs();
|
||||||
rpl::producer<bool> dialogsLoadMayBlockByDate() const;
|
rpl::producer<bool> dialogsLoadMayBlockByDate() const;
|
||||||
rpl::producer<bool> dialogsLoadBlockedByDate() const;
|
rpl::producer<bool> dialogsLoadBlockedByDate() const;
|
||||||
|
|
||||||
void requestDialogEntry(not_null<Data::Folder*> folder);
|
void requestDialogEntry(not_null<Data::Folder*> folder);
|
||||||
//void requestFeedDialogsEntries(not_null<Data::Feed*> feed); // #feed
|
|
||||||
void requestDialogEntry(
|
void requestDialogEntry(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
Fn<void()> callback = nullptr);
|
Fn<void()> callback = nullptr);
|
||||||
|
@ -460,6 +458,10 @@ private:
|
||||||
MsgId offsetId = 0;
|
MsgId offsetId = 0;
|
||||||
PeerData *offsetPeer = nullptr;
|
PeerData *offsetPeer = nullptr;
|
||||||
mtpRequestId requestId = 0;
|
mtpRequestId requestId = 0;
|
||||||
|
bool listReceived = false;
|
||||||
|
|
||||||
|
mtpRequestId pinnedRequestId = 0;
|
||||||
|
bool pinnedReceived = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
void setupSupportMode();
|
void setupSupportMode();
|
||||||
|
@ -485,9 +487,6 @@ private:
|
||||||
QVector<MTPInputMessage> collectMessageIds(const MessageDataRequests &requests);
|
QVector<MTPInputMessage> collectMessageIds(const MessageDataRequests &requests);
|
||||||
MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
|
MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
|
||||||
void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs);
|
void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs);
|
||||||
//void applyFeedDialogs( // #feed
|
|
||||||
// not_null<Data::Feed*> feed,
|
|
||||||
// const MTPmessages_Dialogs &dialogs);
|
|
||||||
|
|
||||||
void gotChatFull(
|
void gotChatFull(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
|
@ -762,9 +761,6 @@ private:
|
||||||
rpl::variable<bool> _dialogsLoadMayBlockByDate = false;
|
rpl::variable<bool> _dialogsLoadMayBlockByDate = false;
|
||||||
rpl::variable<bool> _dialogsLoadBlockedByDate = false;
|
rpl::variable<bool> _dialogsLoadBlockedByDate = false;
|
||||||
|
|
||||||
bool _pinnedDialogsReceived = false;
|
|
||||||
mtpRequestId _pinnedDialogsRequestId = 0;
|
|
||||||
|
|
||||||
base::flat_map<FolderId, DialogsLoadState> _foldersLoadState;
|
base::flat_map<FolderId, DialogsLoadState> _foldersLoadState;
|
||||||
|
|
||||||
rpl::event_stream<SendOptions> _sendActions;
|
rpl::event_stream<SendOptions> _sendActions;
|
||||||
|
|
|
@ -593,7 +593,7 @@ void Application::allKeysDestroyed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::suggestMainDcId(MTP::DcId mainDcId) {
|
void Application::suggestMainDcId(MTP::DcId mainDcId) {
|
||||||
Assert(_mtproto != nullptr);
|
Expects(_mtproto != nullptr);
|
||||||
|
|
||||||
_mtproto->suggestMainDcId(mainDcId);
|
_mtproto->suggestMainDcId(mainDcId);
|
||||||
if (_private->mtpConfig.mainDcId != MTP::Instance::Config::kNotSetMainDc) {
|
if (_private->mtpConfig.mainDcId != MTP::Instance::Config::kNotSetMainDc) {
|
||||||
|
@ -602,7 +602,7 @@ void Application::suggestMainDcId(MTP::DcId mainDcId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::destroyStaleAuthorizationKeys() {
|
void Application::destroyStaleAuthorizationKeys() {
|
||||||
Assert(_mtproto != nullptr);
|
Expects(_mtproto != nullptr);
|
||||||
|
|
||||||
for (const auto &key : _mtproto->getKeysForWrite()) {
|
for (const auto &key : _mtproto->getKeysForWrite()) {
|
||||||
// Disable this for now.
|
// Disable this for now.
|
||||||
|
@ -616,6 +616,14 @@ void Application::destroyStaleAuthorizationKeys() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::configUpdated() {
|
||||||
|
_configUpdates.fire({});
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> Application::configUpdates() const {
|
||||||
|
return _configUpdates.events();
|
||||||
|
}
|
||||||
|
|
||||||
void Application::resetAuthorizationKeys() {
|
void Application::resetAuthorizationKeys() {
|
||||||
_mtproto = nullptr;
|
_mtproto = nullptr;
|
||||||
startMtp();
|
startMtp();
|
||||||
|
|
|
@ -140,6 +140,8 @@ public:
|
||||||
}
|
}
|
||||||
void suggestMainDcId(MTP::DcId mainDcId);
|
void suggestMainDcId(MTP::DcId mainDcId);
|
||||||
void destroyStaleAuthorizationKeys();
|
void destroyStaleAuthorizationKeys();
|
||||||
|
void configUpdated();
|
||||||
|
[[nodiscard]] rpl::producer<> configUpdates() const;
|
||||||
|
|
||||||
// Databases
|
// Databases
|
||||||
Storage::Databases &databases() {
|
Storage::Databases &databases() {
|
||||||
|
@ -276,6 +278,7 @@ private:
|
||||||
std::unique_ptr<MTP::DcOptions> _dcOptions;
|
std::unique_ptr<MTP::DcOptions> _dcOptions;
|
||||||
std::unique_ptr<MTP::Instance> _mtproto;
|
std::unique_ptr<MTP::Instance> _mtproto;
|
||||||
std::unique_ptr<MTP::Instance> _mtprotoForKeysDestroy;
|
std::unique_ptr<MTP::Instance> _mtprotoForKeysDestroy;
|
||||||
|
rpl::event_stream<> _configUpdates;
|
||||||
std::unique_ptr<AuthSession> _authSession;
|
std::unique_ptr<AuthSession> _authSession;
|
||||||
base::Observable<void> _authSessionChanged;
|
base::Observable<void> _authSessionChanged;
|
||||||
base::Observable<void> _passcodedChanged;
|
base::Observable<void> _passcodedChanged;
|
||||||
|
|
|
@ -42,6 +42,7 @@ Folder::Folder(not_null<Data::Session*> owner, FolderId id)
|
||||||
, _id(id)
|
, _id(id)
|
||||||
, _chatsList(Dialogs::SortMode::Date)
|
, _chatsList(Dialogs::SortMode::Date)
|
||||||
, _importantChatsList(Dialogs::SortMode::Date)
|
, _importantChatsList(Dialogs::SortMode::Date)
|
||||||
|
, _pinnedChatsList(Global::PinnedDialogsInFolderMax())
|
||||||
, _name(lang(lng_archived_chats)) {
|
, _name(lang(lng_archived_chats)) {
|
||||||
indexNameParts();
|
indexNameParts();
|
||||||
}
|
}
|
||||||
|
@ -234,6 +235,36 @@ void Folder::requestChatListMessage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Folder::setPinnedChatsLimit(int limit) {
|
||||||
|
_pinnedChatsList.setLimit(limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::setChatPinned(const Dialogs::Key &key, bool pinned) {
|
||||||
|
_pinnedChatsList.setPinned(key, pinned);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::addPinnedChat(const Dialogs::Key &key) {
|
||||||
|
_pinnedChatsList.addPinned(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::applyPinnedChats(const QVector<MTPDialogPeer> &list) {
|
||||||
|
_pinnedChatsList.applyList(&owner(), list);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Dialogs::Key> &Folder::pinnedChatsOrder() const {
|
||||||
|
return _pinnedChatsList.order();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::clearPinnedChats() {
|
||||||
|
_pinnedChatsList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::reorderTwoPinnedChats(
|
||||||
|
const Dialogs::Key &key1,
|
||||||
|
const Dialogs::Key &key2) {
|
||||||
|
_pinnedChatsList.reorder(key1, key2);
|
||||||
|
}
|
||||||
|
|
||||||
TimeId Folder::adjustedChatListTimeId() const {
|
TimeId Folder::adjustedChatListTimeId() const {
|
||||||
return _chatsList.empty()
|
return _chatsList.empty()
|
||||||
? TimeId(0)
|
? TimeId(0)
|
||||||
|
@ -286,10 +317,18 @@ void Folder::applyDialog(const MTPDdialogFolder &data) {
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if (_chatsList.size() < kLoadedChatsMinCount) {
|
if (_chatsList.size() < kLoadedChatsMinCount) {
|
||||||
session().api().requestFolderDialogs(_id);
|
session().api().requestDialogs(_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Folder::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
|
||||||
|
const auto folderId = data.has_folder_id() ? data.vfolder_id.v : 0;
|
||||||
|
if (folderId != 0) {
|
||||||
|
LOG(("API Error: Nested folders detected."));
|
||||||
|
}
|
||||||
|
owner().setChatPinned(this, data.is_pinned());
|
||||||
|
}
|
||||||
|
|
||||||
void Folder::changedInChatListHook(Dialogs::Mode list, bool added) {
|
void Folder::changedInChatListHook(Dialogs::Mode list, bool added) {
|
||||||
if (list != Dialogs::Mode::All) {
|
if (list != Dialogs::Mode::All) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "dialogs/dialogs_entry.h"
|
#include "dialogs/dialogs_entry.h"
|
||||||
#include "dialogs/dialogs_indexed_list.h"
|
#include "dialogs/dialogs_indexed_list.h"
|
||||||
|
#include "dialogs/dialogs_pinned_list.h"
|
||||||
#include "data/data_messages.h"
|
#include "data/data_messages.h"
|
||||||
|
|
||||||
class ChannelData;
|
class ChannelData;
|
||||||
|
@ -45,6 +46,8 @@ public:
|
||||||
not_null<Dialogs::IndexedList*> chatsList(Dialogs::Mode list);
|
not_null<Dialogs::IndexedList*> chatsList(Dialogs::Mode list);
|
||||||
|
|
||||||
void applyDialog(const MTPDdialogFolder &data);
|
void applyDialog(const MTPDdialogFolder &data);
|
||||||
|
void applyPinnedUpdate(const MTPDupdateDialogPinned &data);
|
||||||
|
|
||||||
void setUnreadCounts(int unreadNonMutedCount, int unreadMutedCount);
|
void setUnreadCounts(int unreadNonMutedCount, int unreadMutedCount);
|
||||||
//void setUnreadPosition(const MessagePosition &position); // #feed
|
//void setUnreadPosition(const MessagePosition &position); // #feed
|
||||||
void unreadCountChanged(
|
void unreadCountChanged(
|
||||||
|
@ -58,6 +61,22 @@ public:
|
||||||
//bool unreadMark() const;
|
//bool unreadMark() const;
|
||||||
//int unreadCountForBadge() const; // unreadCount || unreadMark ? 1 : 0.
|
//int unreadCountForBadge() const; // unreadCount || unreadMark ? 1 : 0.
|
||||||
|
|
||||||
|
void setPinnedChatsLimit(int limit);
|
||||||
|
|
||||||
|
// Places on the last place in the list otherwise.
|
||||||
|
// Does nothing if already pinned.
|
||||||
|
void addPinnedChat(const Dialogs::Key &key);
|
||||||
|
|
||||||
|
// if (pinned) places on the first place in the list.
|
||||||
|
void setChatPinned(const Dialogs::Key &key, bool pinned);
|
||||||
|
|
||||||
|
void applyPinnedChats(const QVector<MTPDialogPeer> &list);
|
||||||
|
const std::vector<Dialogs::Key> &pinnedChatsOrder() const;
|
||||||
|
void clearPinnedChats();
|
||||||
|
void reorderTwoPinnedChats(
|
||||||
|
const Dialogs::Key &key1,
|
||||||
|
const Dialogs::Key &key2);
|
||||||
|
|
||||||
TimeId adjustedChatListTimeId() const override;
|
TimeId adjustedChatListTimeId() const override;
|
||||||
int unreadCount() const;
|
int unreadCount() const;
|
||||||
bool unreadCountKnown() const;
|
bool unreadCountKnown() const;
|
||||||
|
@ -100,6 +119,7 @@ private:
|
||||||
FolderId _id = 0;
|
FolderId _id = 0;
|
||||||
Dialogs::IndexedList _chatsList;
|
Dialogs::IndexedList _chatsList;
|
||||||
Dialogs::IndexedList _importantChatsList;
|
Dialogs::IndexedList _importantChatsList;
|
||||||
|
Dialogs::PinnedList _pinnedChatsList;
|
||||||
bool _chatsListLoaded = false;
|
bool _chatsListLoaded = false;
|
||||||
|
|
||||||
QString _name;
|
QString _name;
|
||||||
|
|
|
@ -154,6 +154,7 @@ Session::Session(not_null<AuthSession*> session)
|
||||||
, _importantChatsList(Dialogs::SortMode::Date)
|
, _importantChatsList(Dialogs::SortMode::Date)
|
||||||
, _contactsList(Dialogs::SortMode::Name)
|
, _contactsList(Dialogs::SortMode::Name)
|
||||||
, _contactsNoChatsList(Dialogs::SortMode::Name)
|
, _contactsNoChatsList(Dialogs::SortMode::Name)
|
||||||
|
, _pinnedChatsList(Global::PinnedDialogsCountMax())
|
||||||
, _selfDestructTimer([=] { checkSelfDestructItems(); })
|
, _selfDestructTimer([=] { checkSelfDestructItems(); })
|
||||||
, _sendActionsAnimation([=](crl::time now) {
|
, _sendActionsAnimation([=](crl::time now) {
|
||||||
return sendActionsAnimationCallback(now);
|
return sendActionsAnimationCallback(now);
|
||||||
|
@ -167,6 +168,14 @@ Session::Session(not_null<AuthSession*> session)
|
||||||
setupChannelLeavingViewer();
|
setupChannelLeavingViewer();
|
||||||
setupPeerNameViewer();
|
setupPeerNameViewer();
|
||||||
setupUserIsContactViewer();
|
setupUserIsContactViewer();
|
||||||
|
|
||||||
|
Core::App().configUpdates(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_pinnedChatsList.setLimit(Global::PinnedDialogsCountMax());
|
||||||
|
for (const auto &[folderId, folder] : _folders) {
|
||||||
|
folder->setPinnedChatsLimit(Global::PinnedDialogsInFolderMax());
|
||||||
|
}
|
||||||
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::clear() {
|
void Session::clear() {
|
||||||
|
@ -731,7 +740,9 @@ History *Session::historyLoaded(const PeerData *peer) {
|
||||||
void Session::deleteConversationLocally(not_null<PeerData*> peer) {
|
void Session::deleteConversationLocally(not_null<PeerData*> peer) {
|
||||||
const auto history = historyLoaded(peer);
|
const auto history = historyLoaded(peer);
|
||||||
if (history) {
|
if (history) {
|
||||||
setPinnedDialog(history, false);
|
if (history->folderKnown()) {
|
||||||
|
setChatPinned(history, false);
|
||||||
|
}
|
||||||
App::main()->removeDialog(history);
|
App::main()->removeDialog(history);
|
||||||
history->clear(peer->isChannel()
|
history->clear(peer->isChannel()
|
||||||
? History::ClearType::Unload
|
? History::ClearType::Unload
|
||||||
|
@ -1341,37 +1352,61 @@ MessageIdsList Session::itemOrItsGroup(not_null<HistoryItem*> item) const {
|
||||||
return { 1, item->fullId() };
|
return { 1, item->fullId() };
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::setPinnedDialog(const Dialogs::Key &key, bool pinned) {
|
void Session::setChatPinned(const Dialogs::Key &key, bool pinned) {
|
||||||
setIsPinned(key, pinned);
|
Expects(key.entry()->folderKnown());
|
||||||
|
|
||||||
|
if (const auto folder = key.entry()->folder()) {
|
||||||
|
folder->setChatPinned(key, pinned);
|
||||||
|
} else {
|
||||||
|
_pinnedChatsList.setPinned(key, pinned);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::applyPinnedDialogs(const QVector<MTPDialogPeer> &list) {
|
void Session::setPinnedFromDialog(const Dialogs::Key &key, bool pinned) {
|
||||||
clearPinnedDialogs();
|
Expects(key.entry()->folderKnown());
|
||||||
for (auto i = list.size(); i != 0;) {
|
|
||||||
list[--i].match([&](const MTPDdialogPeer &data) {
|
if (const auto folder = key.entry()->folder()) {
|
||||||
if (const auto peerId = peerFromMTP(data.vpeer)) {
|
if (pinned) {
|
||||||
setPinnedDialog(history(peerId), true);
|
folder->addPinnedChat(key);
|
||||||
|
} else {
|
||||||
|
folder->setChatPinned(key, false);
|
||||||
|
}
|
||||||
|
} else if (pinned) {
|
||||||
|
_pinnedChatsList.addPinned(key);
|
||||||
|
} else {
|
||||||
|
_pinnedChatsList.setPinned(key, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::applyPinnedChats(
|
||||||
|
FolderId folderId,
|
||||||
|
const QVector<MTPDialogPeer> &list) {
|
||||||
|
const auto folder = folderId ? this->folder(folderId).get() : nullptr;
|
||||||
|
for (const auto &peer : list) {
|
||||||
|
peer.match([&](const MTPDdialogPeer &data) {
|
||||||
|
const auto history = this->history(peerFromMTP(data.vpeer));
|
||||||
|
if (folder) {
|
||||||
|
history->setFolder(folder);
|
||||||
|
} else {
|
||||||
|
history->clearFolder();
|
||||||
}
|
}
|
||||||
}, [&](const MTPDdialogPeerFolder &data) {
|
}, [&](const MTPDdialogPeerFolder &data) {
|
||||||
const auto folderId = data.vfolder_id.v;
|
if (folder) {
|
||||||
setPinnedDialog(folder(folderId), true);
|
LOG(("API Error: Nested folders detected."));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (folder) {
|
||||||
|
folder->applyPinnedChats(list);
|
||||||
|
} else {
|
||||||
|
_pinnedChatsList.applyList(this, list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::applyDialogs(
|
void Session::applyDialogs(
|
||||||
FolderId requestFolderId,
|
FolderId requestFolderId,
|
||||||
const QVector<MTPMessage> &messages,
|
const QVector<MTPMessage> &messages,
|
||||||
const QVector<MTPDialog> &dialogs) {
|
const QVector<MTPDialog> &dialogs) {
|
||||||
for (const auto &dialog : dialogs | ranges::view::reverse) {
|
|
||||||
dialog.match([&](const MTPDdialog &data) {
|
|
||||||
if (const auto peer = peerFromMTP(data.vpeer)) {
|
|
||||||
setPinnedDialog(history(peer), data.is_pinned());
|
|
||||||
}
|
|
||||||
}, [&](const MTPDdialogFolder &data) {
|
|
||||||
setPinnedDialog(processFolder(data.vfolder), data.is_pinned());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
App::feedMsgs(messages, NewMessageLast);
|
App::feedMsgs(messages, NewMessageLast);
|
||||||
for (const auto &dialog : dialogs) {
|
for (const auto &dialog : dialogs) {
|
||||||
dialog.match([&](const auto &data) {
|
dialog.match([&](const auto &data) {
|
||||||
|
@ -1388,6 +1423,7 @@ void Session::applyDialog(FolderId requestFolderId, const MTPDdialog &data) {
|
||||||
|
|
||||||
const auto history = session().data().history(peerId);
|
const auto history = session().data().history(peerId);
|
||||||
history->applyDialog(requestFolderId, data);
|
history->applyDialog(requestFolderId, data);
|
||||||
|
setPinnedFromDialog(history, data.is_pinned());
|
||||||
|
|
||||||
if (!history->fixedOnTopIndex() && !history->isPinnedDialog()) {
|
if (!history->fixedOnTopIndex() && !history->isPinnedDialog()) {
|
||||||
const auto date = history->chatListTimeId();
|
const auto date = history->chatListTimeId();
|
||||||
|
@ -1408,12 +1444,13 @@ void Session::applyDialog(FolderId requestFolderId, const MTPDdialog &data) {
|
||||||
|
|
||||||
void Session::applyDialog(
|
void Session::applyDialog(
|
||||||
FolderId requestFolderId,
|
FolderId requestFolderId,
|
||||||
const MTPDdialogFolder &dialog) {
|
const MTPDdialogFolder &data) {
|
||||||
if (requestFolderId != 0) {
|
if (requestFolderId != 0) {
|
||||||
LOG(("API Error: requestFolderId != 0 for dialogFolder."));
|
LOG(("API Error: requestFolderId != 0 for dialogFolder."));
|
||||||
}
|
}
|
||||||
const auto folder = processFolder(dialog.vfolder);
|
const auto folder = processFolder(data.vfolder);
|
||||||
folder->applyDialog(dialog);
|
folder->applyDialog(data);
|
||||||
|
setPinnedFromDialog(folder, data.is_pinned());
|
||||||
|
|
||||||
if (!folder->fixedOnTopIndex() && !folder->isPinnedDialog()) {
|
if (!folder->fixedOnTopIndex() && !folder->isPinnedDialog()) {
|
||||||
const auto date = folder->chatListTimeId();
|
const auto date = folder->chatListTimeId();
|
||||||
|
@ -1441,69 +1478,49 @@ void Session::addAllSavedPeers() {
|
||||||
addSavedPeersAfter(QDateTime());
|
addSavedPeersAfter(QDateTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
int Session::pinnedDialogsCount() const {
|
int Session::pinnedChatsCount(FolderId folderId) const {
|
||||||
return _pinnedDialogs.size();
|
return pinnedChatsOrder(folderId).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::deque<Dialogs::Key> &Session::pinnedDialogsOrder() const {
|
int Session::pinnedChatsLimit(FolderId folderId) const {
|
||||||
return _pinnedDialogs;
|
return folderId
|
||||||
|
? Global::PinnedDialogsInFolderMax()
|
||||||
|
: Global::PinnedDialogsCountMax();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::clearPinnedDialogs() {
|
const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
|
||||||
while (!_pinnedDialogs.empty()) {
|
FolderId folderId) const {
|
||||||
setPinnedDialog(_pinnedDialogs.back(), false);
|
if (folderId) {
|
||||||
|
if (const auto folder = folderLoaded(folderId)) {
|
||||||
|
return folder->pinnedChatsOrder();
|
||||||
|
}
|
||||||
|
static const auto result = std::vector<Dialogs::Key>();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return _pinnedChatsList.order();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::clearPinnedChats(FolderId folderId) {
|
||||||
|
if (folderId) {
|
||||||
|
if (const auto folder = folderLoaded(folderId)) {
|
||||||
|
folder->clearPinnedChats();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_pinnedChatsList.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::reorderTwoPinnedDialogs(
|
void Session::reorderTwoPinnedChats(
|
||||||
const Dialogs::Key &key1,
|
const Dialogs::Key &key1,
|
||||||
const Dialogs::Key &key2) {
|
const Dialogs::Key &key2) {
|
||||||
const auto &order = pinnedDialogsOrder();
|
Expects(key1.entry()->folderKnown() && key2.entry()->folderKnown());
|
||||||
const auto index1 = ranges::find(order, key1) - begin(order);
|
Expects(key1.entry()->folder() == key2.entry()->folder());
|
||||||
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.entry()->cachePinnedIndex(index2 + 1);
|
|
||||||
key2.entry()->cachePinnedIndex(index1 + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::setIsPinned(const Dialogs::Key &key, bool pinned) {
|
const auto folder = key1.entry()->folder();
|
||||||
const auto already = ranges::find(_pinnedDialogs, key);
|
if (folder) {
|
||||||
if (pinned) {
|
folder->reorderTwoPinnedChats(key1, key2);
|
||||||
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].entry()->cachePinnedIndex(index);
|
|
||||||
}
|
|
||||||
_pinnedDialogs.back() = std::move(saved);
|
|
||||||
_pinnedDialogs.back().entry()->cachePinnedIndex(count);
|
|
||||||
} else {
|
} else {
|
||||||
_pinnedDialogs.push_back(key);
|
_pinnedChatsList.reorder(key1, key2);
|
||||||
if (_pinnedDialogs.size() > Global::PinnedDialogsCountMax()) {
|
|
||||||
_pinnedDialogs.front().entry()->cachePinnedIndex(0);
|
|
||||||
_pinnedDialogs.pop_front();
|
|
||||||
|
|
||||||
auto index = 0;
|
|
||||||
for (const auto &pinned : _pinnedDialogs) {
|
|
||||||
pinned.entry()->cachePinnedIndex(++index);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
key.entry()->cachePinnedIndex(_pinnedDialogs.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (!pinned && already != end(_pinnedDialogs)) {
|
|
||||||
key.entry()->cachePinnedIndex(0);
|
|
||||||
_pinnedDialogs.erase(already);
|
|
||||||
auto index = 0;
|
|
||||||
for (const auto &pinned : _pinnedDialogs) {
|
|
||||||
pinned.entry()->cachePinnedIndex(++index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2937,7 +2954,7 @@ not_null<Folder*> Session::folder(FolderId id) {
|
||||||
return it->second.get();
|
return it->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Folder *Session::folderLoaded(FolderId id) {
|
Folder *Session::folderLoaded(FolderId id) const {
|
||||||
const auto it = _folders.find(id);
|
const auto it = _folders.find(id);
|
||||||
return (it == end(_folders)) ? nullptr : it->second.get();
|
return (it == end(_folders)) ? nullptr : it->second.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "chat_helpers/stickers.h"
|
#include "chat_helpers/stickers.h"
|
||||||
#include "dialogs/dialogs_key.h"
|
#include "dialogs/dialogs_key.h"
|
||||||
#include "dialogs/dialogs_indexed_list.h"
|
#include "dialogs/dialogs_indexed_list.h"
|
||||||
|
#include "dialogs/dialogs_pinned_list.h"
|
||||||
#include "data/data_groups.h"
|
#include "data/data_groups.h"
|
||||||
#include "data/data_notify_settings.h"
|
#include "data/data_notify_settings.h"
|
||||||
#include "history/history_location_manager.h"
|
#include "history/history_location_manager.h"
|
||||||
|
@ -304,12 +305,16 @@ public:
|
||||||
void addSavedPeersAfter(const QDateTime &date);
|
void addSavedPeersAfter(const QDateTime &date);
|
||||||
void addAllSavedPeers();
|
void addAllSavedPeers();
|
||||||
|
|
||||||
int pinnedDialogsCount() const;
|
int pinnedChatsCount(FolderId folderId) const;
|
||||||
const std::deque<Dialogs::Key> &pinnedDialogsOrder() const;
|
int pinnedChatsLimit(FolderId folderId) const;
|
||||||
void setPinnedDialog(const Dialogs::Key &key, bool pinned);
|
const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
||||||
void clearPinnedDialogs();
|
FolderId folderId) const;
|
||||||
void applyPinnedDialogs(const QVector<MTPDialogPeer> &list);
|
void setChatPinned(const Dialogs::Key &key, bool pinned);
|
||||||
void reorderTwoPinnedDialogs(
|
void clearPinnedChats(FolderId folderId);
|
||||||
|
void applyPinnedChats(
|
||||||
|
FolderId folderId,
|
||||||
|
const QVector<MTPDialogPeer> &list);
|
||||||
|
void reorderTwoPinnedChats(
|
||||||
const Dialogs::Key &key1,
|
const Dialogs::Key &key1,
|
||||||
const Dialogs::Key &key2);
|
const Dialogs::Key &key2);
|
||||||
|
|
||||||
|
@ -513,7 +518,7 @@ public:
|
||||||
void unregisterItemView(not_null<ViewElement*> view);
|
void unregisterItemView(not_null<ViewElement*> view);
|
||||||
|
|
||||||
[[nodiscard]] not_null<Folder*> folder(FolderId id);
|
[[nodiscard]] not_null<Folder*> folder(FolderId id);
|
||||||
[[nodiscard]] Folder *folderLoaded(FolderId id);
|
[[nodiscard]] Folder *folderLoaded(FolderId id) const;
|
||||||
not_null<Folder*> processFolder(const MTPFolder &data);
|
not_null<Folder*> processFolder(const MTPFolder &data);
|
||||||
not_null<Folder*> processFolder(const MTPDfolder &data);
|
not_null<Folder*> processFolder(const MTPDfolder &data);
|
||||||
//void setDefaultFeedId(FeedId id); // #feed
|
//void setDefaultFeedId(FeedId id); // #feed
|
||||||
|
@ -694,7 +699,7 @@ private:
|
||||||
}
|
}
|
||||||
void userIsContactUpdated(not_null<UserData*> user);
|
void userIsContactUpdated(not_null<UserData*> user);
|
||||||
|
|
||||||
void setIsPinned(const Dialogs::Key &key, bool pinned);
|
void setPinnedFromDialog(const Dialogs::Key &key, bool pinned);
|
||||||
|
|
||||||
NotifySettings &defaultNotifySettings(not_null<const PeerData*> peer);
|
NotifySettings &defaultNotifySettings(not_null<const PeerData*> peer);
|
||||||
const NotifySettings &defaultNotifySettings(
|
const NotifySettings &defaultNotifySettings(
|
||||||
|
@ -777,6 +782,7 @@ private:
|
||||||
Dialogs::IndexedList _importantChatsList;
|
Dialogs::IndexedList _importantChatsList;
|
||||||
Dialogs::IndexedList _contactsList;
|
Dialogs::IndexedList _contactsList;
|
||||||
Dialogs::IndexedList _contactsNoChatsList;
|
Dialogs::IndexedList _contactsNoChatsList;
|
||||||
|
Dialogs::PinnedList _pinnedChatsList;
|
||||||
|
|
||||||
base::Timer _selfDestructTimer;
|
base::Timer _selfDestructTimer;
|
||||||
std::vector<FullMsgId> _selfDestructItems;
|
std::vector<FullMsgId> _selfDestructItems;
|
||||||
|
@ -835,7 +841,6 @@ private:
|
||||||
base::flat_set<not_null<GameData*>> _gamesUpdated;
|
base::flat_set<not_null<GameData*>> _gamesUpdated;
|
||||||
base::flat_set<not_null<PollData*>> _pollsUpdated;
|
base::flat_set<not_null<PollData*>> _pollsUpdated;
|
||||||
|
|
||||||
std::deque<Dialogs::Key> _pinnedDialogs;
|
|
||||||
base::flat_map<FolderId, std::unique_ptr<Folder>> _folders;
|
base::flat_map<FolderId, std::unique_ptr<Folder>> _folders;
|
||||||
//rpl::variable<FeedId> _defaultFeedId = FeedId(); // #feed
|
//rpl::variable<FeedId> _defaultFeedId = FeedId(); // #feed
|
||||||
Groups _groups;
|
Groups _groups;
|
||||||
|
|
|
@ -34,7 +34,7 @@ uint64 FixedOnTopDialogPos(int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 PinnedDialogPos(int pinnedIndex) {
|
uint64 PinnedDialogPos(int pinnedIndex) {
|
||||||
return 0xFFFFFFFF00000000ULL + pinnedIndex;
|
return 0xFFFFFFFF000000FFULL - pinnedIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -81,7 +81,7 @@ void IndexedList::movePinned(Row *row, int deltaSign) {
|
||||||
Assert(swapPinnedIndexWith != cbegin());
|
Assert(swapPinnedIndexWith != cbegin());
|
||||||
--swapPinnedIndexWith;
|
--swapPinnedIndexWith;
|
||||||
}
|
}
|
||||||
Auth().data().reorderTwoPinnedDialogs(
|
Auth().data().reorderTwoPinnedChats(
|
||||||
row->key(),
|
row->key(),
|
||||||
(*swapPinnedIndexWith)->key());
|
(*swapPinnedIndexWith)->key());
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,13 +275,28 @@ int DialogsInner::openedFolderSkip() const {
|
||||||
return st::dialogsSearchInHeight;
|
return st::dialogsSearchInHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DialogsInner::openFolder(not_null<Data::Folder*> folder) {
|
||||||
|
return changeOpenedFolder(folder);
|
||||||
|
}
|
||||||
|
|
||||||
bool DialogsInner::cancelFolder() {
|
bool DialogsInner::cancelFolder() {
|
||||||
if (!_openedFolder) {
|
return changeOpenedFolder(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DialogsInner::changeOpenedFolder(Data::Folder *folder) {
|
||||||
|
if (_openedFolder == folder) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
stopReorderPinned();
|
||||||
clearSelection();
|
clearSelection();
|
||||||
_openedFolder = nullptr;
|
_openedFolder = folder;
|
||||||
_closeOpenedFolder->hide();
|
_closeOpenedFolder->setVisible(folder != nullptr);
|
||||||
|
if (folder) {
|
||||||
|
_openedFolderText.setText(
|
||||||
|
st::msgNameStyle,
|
||||||
|
folder->chatListName(),
|
||||||
|
Ui::DialogTextOptions());
|
||||||
|
}
|
||||||
refresh();
|
refresh();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -920,20 +935,27 @@ void DialogsInner::mousePressEvent(QMouseEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsInner::checkReorderPinnedStart(QPoint localPosition) {
|
void DialogsInner::checkReorderPinnedStart(QPoint localPosition) {
|
||||||
if (_pressed != nullptr && !_dragging && _state == State::Default) {
|
if (!_pressed || _dragging || _state != State::Default) {
|
||||||
if (qAbs(localPosition.y() - _dragStart.y()) >= ConvertScale(kStartReorderThreshold)) {
|
return;
|
||||||
|
} else if (qAbs(localPosition.y() - _dragStart.y())
|
||||||
|
< ConvertScale(kStartReorderThreshold)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
_dragging = _pressed;
|
_dragging = _pressed;
|
||||||
if (updateReorderIndexGetCount() < 2) {
|
if (updateReorderIndexGetCount() < 2) {
|
||||||
_dragging = nullptr;
|
_dragging = nullptr;
|
||||||
} else {
|
} else {
|
||||||
_pinnedOrder = session().data().pinnedDialogsOrder();
|
const auto folderId = _openedFolder ? _openedFolder->id() : 0;
|
||||||
|
const auto &order = session().data().pinnedChatsOrder(folderId);
|
||||||
|
_pinnedOnDragStart = base::flat_set<Dialogs::Key>{
|
||||||
|
order.begin(),
|
||||||
|
order.end()
|
||||||
|
};
|
||||||
_pinnedRows[_draggingIndex].yadd = anim::value(0, localPosition.y() - _dragStart.y());
|
_pinnedRows[_draggingIndex].yadd = anim::value(0, localPosition.y() - _dragStart.y());
|
||||||
_pinnedRows[_draggingIndex].animStartTime = crl::now();
|
_pinnedRows[_draggingIndex].animStartTime = crl::now();
|
||||||
_pinnedShiftAnimation.start();
|
_pinnedShiftAnimation.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int DialogsInner::shownPinnedCount() const {
|
int DialogsInner::shownPinnedCount() const {
|
||||||
auto result = 0;
|
auto result = 0;
|
||||||
|
@ -967,16 +989,17 @@ int DialogsInner::countPinnedIndex(Dialogs::Row *ofRow) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsInner::savePinnedOrder() {
|
void DialogsInner::savePinnedOrder() {
|
||||||
const auto &newOrder = session().data().pinnedDialogsOrder();
|
const auto folderId = _openedFolder ? _openedFolder->id() : 0;
|
||||||
if (newOrder.size() != _pinnedOrder.size()) {
|
const auto &newOrder = session().data().pinnedChatsOrder(folderId);
|
||||||
|
if (newOrder.size() != _pinnedOnDragStart.size()) {
|
||||||
return; // Something has changed in the set of pinned chats.
|
return; // Something has changed in the set of pinned chats.
|
||||||
}
|
}
|
||||||
for (const auto &pinned : newOrder) {
|
for (const auto &key : newOrder) {
|
||||||
if (!base::contains(_pinnedOrder, pinned)) {
|
if (!_pinnedOnDragStart.contains(key)) {
|
||||||
return; // Something has changed in the set of pinned chats.
|
return; // Something has changed in the set of pinned chats.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session().api().savePinnedOrder();
|
session().api().savePinnedOrder(folderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsInner::finishReorderPinned() {
|
void DialogsInner::finishReorderPinned() {
|
||||||
|
@ -1769,7 +1792,7 @@ void DialogsInner::clearSearchResults(bool clearPeerSearchResults) {
|
||||||
_searchResults.clear();
|
_searchResults.clear();
|
||||||
_searchedCount = _searchedMigratedCount = 0;
|
_searchedCount = _searchedMigratedCount = 0;
|
||||||
_lastSearchDate = 0;
|
_lastSearchDate = 0;
|
||||||
_lastSearchPeer = 0;
|
_lastSearchPeer = nullptr;
|
||||||
_lastSearchId = _lastSearchMigratedId = 0;
|
_lastSearchId = _lastSearchMigratedId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2457,14 +2480,7 @@ bool DialogsInner::chooseRow() {
|
||||||
? ShowAtUnreadMsgId
|
? ShowAtUnreadMsgId
|
||||||
: chosen.message.fullId.msg));
|
: chosen.message.fullId.msg));
|
||||||
} else if (const auto folder = chosen.key.folder()) {
|
} else if (const auto folder = chosen.key.folder()) {
|
||||||
clearSelection();
|
openFolder(folder);
|
||||||
_openedFolder = folder;
|
|
||||||
_closeOpenedFolder->show();
|
|
||||||
_openedFolderText.setText(
|
|
||||||
st::msgNameStyle,
|
|
||||||
folder->chatListName(),
|
|
||||||
Ui::DialogTextOptions());
|
|
||||||
refresh();
|
|
||||||
}
|
}
|
||||||
if (openSearchResult && !session().supportMode()) {
|
if (openSearchResult && !session().supportMode()) {
|
||||||
emit clearSearchQuery();
|
emit clearSearchQuery();
|
||||||
|
|
|
@ -50,6 +50,7 @@ public:
|
||||||
|
|
||||||
void activate();
|
void activate();
|
||||||
|
|
||||||
|
bool openFolder(not_null<Data::Folder*> folder);
|
||||||
bool cancelFolder();
|
bool cancelFolder();
|
||||||
void selectSkip(int32 direction);
|
void selectSkip(int32 direction);
|
||||||
void selectSkipPage(int32 pixels, int32 direction);
|
void selectSkipPage(int32 pixels, int32 direction);
|
||||||
|
@ -273,6 +274,8 @@ private:
|
||||||
bool pinnedShiftAnimationCallback(crl::time now);
|
bool pinnedShiftAnimationCallback(crl::time now);
|
||||||
void handleChatMigration(not_null<ChatData*> chat);
|
void handleChatMigration(not_null<ChatData*> chat);
|
||||||
|
|
||||||
|
bool changeOpenedFolder(Data::Folder *folder);
|
||||||
|
|
||||||
not_null<Window::Controller*> _controller;
|
not_null<Window::Controller*> _controller;
|
||||||
|
|
||||||
bool _mouseSelection = false;
|
bool _mouseSelection = false;
|
||||||
|
@ -298,7 +301,7 @@ private:
|
||||||
};
|
};
|
||||||
std::vector<PinnedRow> _pinnedRows;
|
std::vector<PinnedRow> _pinnedRows;
|
||||||
Ui::Animations::Basic _pinnedShiftAnimation;
|
Ui::Animations::Basic _pinnedShiftAnimation;
|
||||||
std::deque<Dialogs::Key> _pinnedOrder;
|
base::flat_set<Dialogs::Key> _pinnedOnDragStart;
|
||||||
|
|
||||||
// Remember the last currently dragged row top shift for updating area.
|
// Remember the last currently dragged row top shift for updating area.
|
||||||
int _aboveTopShift = -1;
|
int _aboveTopShift = -1;
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
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_pinned_list.h"
|
||||||
|
|
||||||
|
#include "dialogs/dialogs_key.h"
|
||||||
|
#include "dialogs/dialogs_entry.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
|
||||||
|
PinnedList::PinnedList(int limit) : _limit(limit) {
|
||||||
|
Expects(limit > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedList::setLimit(int limit) {
|
||||||
|
Expects(limit > 0);
|
||||||
|
|
||||||
|
if (_limit == limit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_limit = limit;
|
||||||
|
applyLimit(_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedList::addPinned(const Key &key) {
|
||||||
|
Expects(key.entry()->folderKnown());
|
||||||
|
|
||||||
|
addPinnedGetPosition(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PinnedList::addPinnedGetPosition(const Key &key) {
|
||||||
|
const auto already = ranges::find(_data, key);
|
||||||
|
if (already != end(_data)) {
|
||||||
|
return already - begin(_data);
|
||||||
|
}
|
||||||
|
applyLimit(_limit - 1);
|
||||||
|
const auto position = int(_data.size());
|
||||||
|
_data.push_back(key);
|
||||||
|
key.entry()->cachePinnedIndex(position);
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedList::setPinned(const Key &key, bool pinned) {
|
||||||
|
Expects(key.entry()->folderKnown());
|
||||||
|
|
||||||
|
if (pinned) {
|
||||||
|
const int position = addPinnedGetPosition(key);
|
||||||
|
if (position) {
|
||||||
|
const auto begin = _data.begin();
|
||||||
|
std::rotate(begin, begin + position, begin + position + 1);
|
||||||
|
for (auto i = 0; i != position + 1; ++i) {
|
||||||
|
_data[i].entry()->cachePinnedIndex(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (const auto it = ranges::find(_data, key); it != end(_data)) {
|
||||||
|
const auto index = (it - begin(_data));
|
||||||
|
_data.erase(it);
|
||||||
|
key.entry()->cachePinnedIndex(0);
|
||||||
|
for (auto i = index, count = int(size(_data)); i != count; ++i) {
|
||||||
|
_data[i].entry()->cachePinnedIndex(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedList::applyLimit(int limit) {
|
||||||
|
Expects(limit >= 0);
|
||||||
|
|
||||||
|
while (_data.size() > limit) {
|
||||||
|
setPinned(_data.back(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedList::clear() {
|
||||||
|
applyLimit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedList::applyList(
|
||||||
|
not_null<Data::Session*> owner,
|
||||||
|
const QVector<MTPDialogPeer> &list) {
|
||||||
|
clear();
|
||||||
|
for (const auto &peer : ranges::view::reverse(list)) {
|
||||||
|
peer.match([&](const MTPDdialogPeer &data) {
|
||||||
|
if (const auto peerId = peerFromMTP(data.vpeer)) {
|
||||||
|
setPinned(owner->history(peerId), true);
|
||||||
|
}
|
||||||
|
}, [&](const MTPDdialogPeerFolder &data) {
|
||||||
|
const auto folderId = data.vfolder_id.v;
|
||||||
|
setPinned(owner->folder(folderId), true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedList::reorder(const Key &key1, const Key &key2) {
|
||||||
|
const auto index1 = ranges::find(_data, key1) - begin(_data);
|
||||||
|
const auto index2 = ranges::find(_data, key2) - begin(_data);
|
||||||
|
Assert(index1 >= 0 && index1 < _data.size());
|
||||||
|
Assert(index2 >= 0 && index2 < _data.size());
|
||||||
|
Assert(index1 != index2);
|
||||||
|
std::swap(_data[index1], _data[index2]);
|
||||||
|
key1.entry()->cachePinnedIndex(index2 + 1);
|
||||||
|
key2.entry()->cachePinnedIndex(index1 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dialogs
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class Session;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
|
||||||
|
class Key;
|
||||||
|
|
||||||
|
class PinnedList {
|
||||||
|
public:
|
||||||
|
explicit PinnedList(int limit);
|
||||||
|
|
||||||
|
void setLimit(int limit);
|
||||||
|
|
||||||
|
// Places on the last place in the list otherwise.
|
||||||
|
// Does nothing if already pinned.
|
||||||
|
void addPinned(const Key &key);
|
||||||
|
|
||||||
|
// if (pinned) places on the first place in the list.
|
||||||
|
void setPinned(const Key &key, bool pinned);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void applyList(
|
||||||
|
not_null<Data::Session*> owner,
|
||||||
|
const QVector<MTPDialogPeer> &list);
|
||||||
|
void reorder(const Key &key1, const Key &key2);
|
||||||
|
|
||||||
|
const std::vector<Key> &order() const {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int addPinnedGetPosition(const Key &key);
|
||||||
|
void applyLimit(int limit);
|
||||||
|
|
||||||
|
int _limit = 0;
|
||||||
|
std::vector<Key> _data;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dialogs
|
|
@ -247,7 +247,11 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
|
||||||
&& !_searchFullMigrated))) {
|
&& !_searchFullMigrated))) {
|
||||||
onSearchMore();
|
onSearchMore();
|
||||||
} else {
|
} else {
|
||||||
session().api().requestDialogs();
|
const auto folder = _inner->shownFolder();
|
||||||
|
const auto folderId = folder ? folder->id() : FolderId(0);
|
||||||
|
if (!folderId || !folder->chatsListLoaded()) {
|
||||||
|
session().api().requestDialogs(folderId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_inner->listBottomReached(
|
_inner->listBottomReached(
|
||||||
|
@ -1063,14 +1067,6 @@ void DialogsWidget::onListScroll() {
|
||||||
|
|
||||||
// Fix button rendering glitch, Qt bug with WA_OpaquePaintEvent widgets.
|
// Fix button rendering glitch, Qt bug with WA_OpaquePaintEvent widgets.
|
||||||
_scrollToTop->update();
|
_scrollToTop->update();
|
||||||
|
|
||||||
if (const auto folder = _inner->shownFolder()) {
|
|
||||||
if (!folder->chatsListLoaded()
|
|
||||||
&& (scrollTop + height() * PreloadHeightsCount
|
|
||||||
>= _scroll->scrollTopMax())) {
|
|
||||||
session().api().requestFolderDialogs(folder->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsWidget::applyFilterUpdate(bool force) {
|
void DialogsWidget::applyFilterUpdate(bool force) {
|
||||||
|
|
|
@ -391,6 +391,7 @@ struct Data {
|
||||||
int32 StickersRecentLimit = 30;
|
int32 StickersRecentLimit = 30;
|
||||||
int32 StickersFavedLimit = 5;
|
int32 StickersFavedLimit = 5;
|
||||||
int32 PinnedDialogsCountMax = 5;
|
int32 PinnedDialogsCountMax = 5;
|
||||||
|
int32 PinnedDialogsInFolderMax = 100;
|
||||||
QString InternalLinksDomain = qsl("https://t.me/");
|
QString InternalLinksDomain = qsl("https://t.me/");
|
||||||
int32 ChannelsReadMediaPeriod = 86400 * 7;
|
int32 ChannelsReadMediaPeriod = 86400 * 7;
|
||||||
int32 CallReceiveTimeoutMs = 20000;
|
int32 CallReceiveTimeoutMs = 20000;
|
||||||
|
@ -525,6 +526,7 @@ DefineVar(Global, bool, RevokePrivateInbox);
|
||||||
DefineVar(Global, int32, StickersRecentLimit);
|
DefineVar(Global, int32, StickersRecentLimit);
|
||||||
DefineVar(Global, int32, StickersFavedLimit);
|
DefineVar(Global, int32, StickersFavedLimit);
|
||||||
DefineVar(Global, int32, PinnedDialogsCountMax);
|
DefineVar(Global, int32, PinnedDialogsCountMax);
|
||||||
|
DefineVar(Global, int32, PinnedDialogsInFolderMax);
|
||||||
DefineVar(Global, QString, InternalLinksDomain);
|
DefineVar(Global, QString, InternalLinksDomain);
|
||||||
DefineVar(Global, int32, ChannelsReadMediaPeriod);
|
DefineVar(Global, int32, ChannelsReadMediaPeriod);
|
||||||
DefineVar(Global, int32, CallReceiveTimeoutMs);
|
DefineVar(Global, int32, CallReceiveTimeoutMs);
|
||||||
|
|
|
@ -248,6 +248,7 @@ DeclareVar(bool, RevokePrivateInbox);
|
||||||
DeclareVar(int32, StickersRecentLimit);
|
DeclareVar(int32, StickersRecentLimit);
|
||||||
DeclareVar(int32, StickersFavedLimit);
|
DeclareVar(int32, StickersFavedLimit);
|
||||||
DeclareVar(int32, PinnedDialogsCountMax);
|
DeclareVar(int32, PinnedDialogsCountMax);
|
||||||
|
DeclareVar(int32, PinnedDialogsInFolderMax);
|
||||||
DeclareVar(QString, InternalLinksDomain);
|
DeclareVar(QString, InternalLinksDomain);
|
||||||
DeclareVar(int32, ChannelsReadMediaPeriod);
|
DeclareVar(int32, ChannelsReadMediaPeriod);
|
||||||
DeclareVar(int32, CallReceiveTimeoutMs);
|
DeclareVar(int32, CallReceiveTimeoutMs);
|
||||||
|
|
|
@ -1835,6 +1835,9 @@ void History::setFolderPointer(Data::Folder *folder) {
|
||||||
if (_folder == folder) {
|
if (_folder == folder) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (isPinnedDialog()) {
|
||||||
|
owner().setChatPinned(this, false);
|
||||||
|
}
|
||||||
const auto wasKnown = folderKnown();
|
const auto wasKnown = folderKnown();
|
||||||
const auto wasInAll = inChatList(Mode::All);
|
const auto wasInAll = inChatList(Mode::All);
|
||||||
const auto wasInImportant = wasInAll && inChatList(Mode::Important);
|
const auto wasInImportant = wasInAll && inChatList(Mode::Important);
|
||||||
|
@ -1864,6 +1867,18 @@ void History::setFolderPointer(Data::Folder *folder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void History::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
|
||||||
|
const auto folderId = data.has_folder_id() ? data.vfolder_id.v : 0;
|
||||||
|
if (!folderKnown()) {
|
||||||
|
if (folderId) {
|
||||||
|
setFolder(owner().folder(folderId));
|
||||||
|
} else {
|
||||||
|
clearFolder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
owner().setChatPinned(this, data.is_pinned());
|
||||||
|
}
|
||||||
|
|
||||||
TimeId History::adjustedChatListTimeId() const {
|
TimeId History::adjustedChatListTimeId() const {
|
||||||
const auto result = chatListTimeId();
|
const auto result = chatListTimeId();
|
||||||
if (const auto draft = cloudDraft()) {
|
if (const auto draft = cloudDraft()) {
|
||||||
|
|
|
@ -192,6 +192,7 @@ public:
|
||||||
void unknownMessageDeleted(MsgId messageId);
|
void unknownMessageDeleted(MsgId messageId);
|
||||||
void applyDialogTopMessage(MsgId topMessageId);
|
void applyDialogTopMessage(MsgId topMessageId);
|
||||||
void applyDialog(FolderId requestFolderId, const MTPDdialog &data);
|
void applyDialog(FolderId requestFolderId, const MTPDdialog &data);
|
||||||
|
void applyPinnedUpdate(const MTPDupdateDialogPinned &data);
|
||||||
void applyDialogFields(
|
void applyDialogFields(
|
||||||
int unreadCount,
|
int unreadCount,
|
||||||
MsgId maxInboxRead,
|
MsgId maxInboxRead,
|
||||||
|
|
|
@ -2931,7 +2931,7 @@ void MainWidget::gotState(const MTPupdates_State &state) {
|
||||||
_noUpdatesTimer.callOnce(kNoUpdatesTimeout);
|
_noUpdatesTimer.callOnce(kNoUpdatesTimeout);
|
||||||
_ptsWaiter.setRequesting(false);
|
_ptsWaiter.setRequesting(false);
|
||||||
|
|
||||||
session().api().requestDialogs();
|
session().api().requestDialogs(FolderId(0));
|
||||||
updateOnline();
|
updateOnline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4269,7 +4269,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||||
|
|
||||||
case mtpc_updatePinnedDialogs: {
|
case mtpc_updatePinnedDialogs: {
|
||||||
const auto &d = update.c_updatePinnedDialogs();
|
const auto &d = update.c_updatePinnedDialogs();
|
||||||
if (d.has_order()) {
|
const auto folderId = d.has_folder_id() ? d.vfolder_id.v : 0;
|
||||||
|
const auto done = [&] {
|
||||||
|
if (!d.has_order()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const auto &order = d.vorder.v;
|
const auto &order = d.vorder.v;
|
||||||
const auto notLoaded = [&](const MTPDialogPeer &peer) {
|
const auto notLoaded = [&](const MTPDialogPeer &peer) {
|
||||||
return peer.match([&](const MTPDdialogPeer &data) {
|
return peer.match([&](const MTPDdialogPeer &data) {
|
||||||
|
@ -4281,41 +4285,52 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||||
};
|
};
|
||||||
const auto allLoaded = ranges::find_if(order, notLoaded)
|
const auto allLoaded = ranges::find_if(order, notLoaded)
|
||||||
== order.end();
|
== order.end();
|
||||||
if (allLoaded) {
|
if (!allLoaded) {
|
||||||
session().data().applyPinnedDialogs(order);
|
return false;
|
||||||
} else {
|
|
||||||
session().api().requestPinnedDialogs();
|
|
||||||
}
|
}
|
||||||
} else {
|
session().data().applyPinnedChats(folderId, order);
|
||||||
session().api().requestPinnedDialogs();
|
return true;
|
||||||
|
}();
|
||||||
|
if (!done) {
|
||||||
|
session().api().requestPinnedDialogs(folderId);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mtpc_updateDialogPinned: {
|
case mtpc_updateDialogPinned: {
|
||||||
const auto &d = update.c_updateDialogPinned();
|
const auto &d = update.c_updateDialogPinned();
|
||||||
d.vpeer.match([&](const MTPDdialogPeer &data) {
|
const auto folderId = d.has_folder_id() ? d.vfolder_id.v : 0;
|
||||||
|
const auto done = d.vpeer.match([&](const MTPDdialogPeer &data) {
|
||||||
const auto id = peerFromMTP(data.vpeer);
|
const auto id = peerFromMTP(data.vpeer);
|
||||||
if (const auto history = session().data().historyLoaded(id)) {
|
if (const auto history = session().data().historyLoaded(id)) {
|
||||||
session().data().setPinnedDialog(history, d.is_pinned());
|
history->applyPinnedUpdate(d);
|
||||||
} else {
|
return true;
|
||||||
DEBUG_LOG(("API Error: "
|
|
||||||
"pinned chat not loaded for peer %1"
|
|
||||||
).arg(id
|
|
||||||
));
|
|
||||||
session().api().requestPinnedDialogs();
|
|
||||||
}
|
}
|
||||||
|
DEBUG_LOG(("API Error: "
|
||||||
|
"pinned chat not loaded for peer %1, folder: %2"
|
||||||
|
).arg(id
|
||||||
|
).arg(folderId
|
||||||
|
));
|
||||||
|
return false;
|
||||||
}, [&](const MTPDdialogPeerFolder &data) {
|
}, [&](const MTPDdialogPeerFolder &data) {
|
||||||
|
if (folderId != 0) {
|
||||||
|
DEBUG_LOG(("API Error: Nested folders updateDialogPinned."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const auto id = data.vfolder_id.v;
|
const auto id = data.vfolder_id.v;
|
||||||
if (const auto folder = session().data().folderLoaded(id)) {
|
if (const auto folder = session().data().folderLoaded(id)) {
|
||||||
session().data().setPinnedDialog(folder, d.is_pinned());
|
folder->applyPinnedUpdate(d);
|
||||||
} else {
|
return true;
|
||||||
DEBUG_LOG(("API Error: "
|
|
||||||
"pinned folder not loaded for folderId %1"
|
|
||||||
).arg(id
|
|
||||||
));
|
|
||||||
session().api().requestPinnedDialogs();
|
|
||||||
}
|
}
|
||||||
|
DEBUG_LOG(("API Error: "
|
||||||
|
"pinned folder not loaded for folderId %1, folder: %2"
|
||||||
|
).arg(id
|
||||||
|
).arg(folderId
|
||||||
|
));
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
if (!done) {
|
||||||
|
session().api().requestPinnedDialogs(folderId);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mtpc_updateChannel: {
|
case mtpc_updateChannel: {
|
||||||
|
|
|
@ -773,7 +773,10 @@ void Instance::Private::configLoadDone(const MTPConfig &result) {
|
||||||
Global::SetRevokePrivateInbox(data.is_revoke_pm_inbox());
|
Global::SetRevokePrivateInbox(data.is_revoke_pm_inbox());
|
||||||
Global::SetStickersRecentLimit(data.vstickers_recent_limit.v);
|
Global::SetStickersRecentLimit(data.vstickers_recent_limit.v);
|
||||||
Global::SetStickersFavedLimit(data.vstickers_faved_limit.v);
|
Global::SetStickersFavedLimit(data.vstickers_faved_limit.v);
|
||||||
Global::SetPinnedDialogsCountMax(data.vpinned_dialogs_count_max.v);
|
Global::SetPinnedDialogsCountMax(
|
||||||
|
std::max(data.vpinned_dialogs_count_max.v, 1));
|
||||||
|
Global::SetPinnedDialogsInFolderMax(
|
||||||
|
std::max(data.vpinned_infolder_count_max.v, 1));
|
||||||
Core::App().setInternalLinkDomain(qs(data.vme_url_prefix));
|
Core::App().setInternalLinkDomain(qs(data.vme_url_prefix));
|
||||||
Global::SetChannelsReadMediaPeriod(data.vchannels_read_media_period.v);
|
Global::SetChannelsReadMediaPeriod(data.vchannels_read_media_period.v);
|
||||||
Global::SetWebFileDcId(data.vwebfile_dc_id.v);
|
Global::SetWebFileDcId(data.vwebfile_dc_id.v);
|
||||||
|
@ -801,6 +804,8 @@ void Instance::Private::configLoadDone(const MTPConfig &result) {
|
||||||
? data.vbase_lang_pack_version.v
|
? data.vbase_lang_pack_version.v
|
||||||
: 0));
|
: 0));
|
||||||
|
|
||||||
|
Core::App().configUpdated();
|
||||||
|
|
||||||
if (data.has_autoupdate_url_prefix()) {
|
if (data.has_autoupdate_url_prefix()) {
|
||||||
Local::writeAutoupdatePrefix(qs(data.vautoupdate_url_prefix));
|
Local::writeAutoupdatePrefix(qs(data.vautoupdate_url_prefix));
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,12 +80,12 @@ public:
|
||||||
void fill();
|
void fill();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool showInfo();
|
//bool showInfo();
|
||||||
void addPinToggle();
|
//void addPinToggle();
|
||||||
void addInfo();
|
//void addInfo();
|
||||||
void addSearch();
|
//void addSearch();
|
||||||
void addNotifications();
|
//void addNotifications();
|
||||||
void addUngroup();
|
//void addUngroup();
|
||||||
|
|
||||||
not_null<Controller*> _controller;
|
not_null<Controller*> _controller;
|
||||||
not_null<Data::Folder*> _folder;
|
not_null<Data::Folder*> _folder;
|
||||||
|
@ -94,8 +94,8 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
History *FindWastedPin() {
|
History *FindWastedPin(FolderId folderId) {
|
||||||
const auto &order = Auth().data().pinnedDialogsOrder();
|
const auto &order = Auth().data().pinnedChatsOrder(folderId);
|
||||||
for (const auto &pinned : order) {
|
for (const auto &pinned : order) {
|
||||||
if (const auto history = pinned.history()) {
|
if (const auto history = pinned.history()) {
|
||||||
if (history->peer->isChat()
|
if (history->peer->isChat()
|
||||||
|
@ -113,16 +113,20 @@ void AddChatMembers(not_null<ChatData*> chat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PinnedLimitReached(Dialogs::Key key) {
|
bool PinnedLimitReached(Dialogs::Key key) {
|
||||||
const auto pinnedCount = Auth().data().pinnedDialogsCount();
|
Expects(key.entry()->folderKnown());
|
||||||
const auto pinnedMax = Global::PinnedDialogsCountMax();
|
|
||||||
|
const auto folder = key.entry()->folder();
|
||||||
|
const auto folderId = folder ? folder->id() : 0;
|
||||||
|
const auto pinnedCount = Auth().data().pinnedChatsCount(folderId);
|
||||||
|
const auto pinnedMax = Auth().data().pinnedChatsLimit(folderId);
|
||||||
if (pinnedCount < pinnedMax) {
|
if (pinnedCount < pinnedMax) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Some old chat, that was converted, maybe is still pinned.
|
// Some old chat, that was converted, maybe is still pinned.
|
||||||
if (const auto wasted = FindWastedPin()) {
|
if (const auto wasted = FindWastedPin(folderId)) {
|
||||||
Auth().data().setPinnedDialog(wasted, false);
|
Auth().data().setChatPinned(wasted, false);
|
||||||
Auth().data().setPinnedDialog(key, true);
|
Auth().data().setChatPinned(key, true);
|
||||||
Auth().api().savePinnedOrder();
|
Auth().api().savePinnedOrder(folderId);
|
||||||
} else {
|
} else {
|
||||||
auto errorText = lng_error_pinned_max(
|
auto errorText = lng_error_pinned_max(
|
||||||
lt_count,
|
lt_count,
|
||||||
|
@ -133,32 +137,34 @@ bool PinnedLimitReached(Dialogs::Key key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TogglePinnedDialog(Dialogs::Key key) {
|
void TogglePinnedDialog(Dialogs::Key key) {
|
||||||
|
if (!key.entry()->folderKnown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto isPinned = !key.entry()->isPinnedDialog();
|
const auto isPinned = !key.entry()->isPinnedDialog();
|
||||||
if (isPinned && PinnedLimitReached(key)) {
|
if (isPinned && PinnedLimitReached(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth().data().setPinnedDialog(key, isPinned);
|
Auth().data().setChatPinned(key, isPinned);
|
||||||
auto flags = MTPmessages_ToggleDialogPin::Flags(0);
|
const auto flags = isPinned
|
||||||
if (isPinned) {
|
? MTPmessages_ToggleDialogPin::Flag::f_pinned
|
||||||
flags |= MTPmessages_ToggleDialogPin::Flag::f_pinned;
|
: MTPmessages_ToggleDialogPin::Flag(0);
|
||||||
}
|
if (const auto history = key.history()) {
|
||||||
//MTP::send(MTPmessages_ToggleDialogPin( // #feed
|
history->session().api().request(MTPmessages_ToggleDialogPin(
|
||||||
// MTP_flags(flags),
|
|
||||||
// key.history()
|
|
||||||
// ? MTP_inputDialogPeer(key.history()->peer->input)
|
|
||||||
// : MTP_inputDialogPeerFeed(MTP_int(key.feed()->id()))));
|
|
||||||
if (key.history()) {
|
|
||||||
MTP::send(MTPmessages_ToggleDialogPin(
|
|
||||||
MTP_flags(flags),
|
MTP_flags(flags),
|
||||||
MTP_inputDialogPeer(key.history()->peer->input)));
|
MTP_inputDialogPeer(key.history()->peer->input)
|
||||||
|
)).send();
|
||||||
|
} else if (const auto folder = key.folder()) {
|
||||||
|
folder->session().api().request(MTPmessages_ToggleDialogPin(
|
||||||
|
MTP_flags(flags),
|
||||||
|
MTP_inputDialogPeerFolder(MTP_int(folder->id()))
|
||||||
|
)).send();
|
||||||
}
|
}
|
||||||
if (isPinned) {
|
if (isPinned) {
|
||||||
if (const auto main = App::main()) {
|
if (const auto main = App::main()) {
|
||||||
main->dialogsToUp();
|
main->dialogsToUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Filler::Filler(
|
Filler::Filler(
|
||||||
|
|
|
@ -228,6 +228,8 @@
|
||||||
<(src_loc)/dialogs/dialogs_layout.h
|
<(src_loc)/dialogs/dialogs_layout.h
|
||||||
<(src_loc)/dialogs/dialogs_list.cpp
|
<(src_loc)/dialogs/dialogs_list.cpp
|
||||||
<(src_loc)/dialogs/dialogs_list.h
|
<(src_loc)/dialogs/dialogs_list.h
|
||||||
|
<(src_loc)/dialogs/dialogs_pinned_list.cpp
|
||||||
|
<(src_loc)/dialogs/dialogs_pinned_list.h
|
||||||
<(src_loc)/dialogs/dialogs_row.cpp
|
<(src_loc)/dialogs/dialogs_row.cpp
|
||||||
<(src_loc)/dialogs/dialogs_row.h
|
<(src_loc)/dialogs/dialogs_row.h
|
||||||
<(src_loc)/dialogs/dialogs_search_from_controllers.cpp
|
<(src_loc)/dialogs/dialogs_search_from_controllers.cpp
|
||||||
|
|
Loading…
Reference in New Issue