mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Implement jump-to-date in topics.
This commit is contained in:
parent
ee8f997c14
commit
5d76415a5d
7 changed files with 182 additions and 59 deletions
|
@ -2834,13 +2834,16 @@ void ApiWrap::resolveJumpToDate(
|
|||
const QDate &date,
|
||||
Fn<void(not_null<PeerData*>, MsgId)> callback) {
|
||||
if (const auto peer = chat.peer()) {
|
||||
resolveJumpToHistoryDate(peer, date, std::move(callback));
|
||||
const auto topic = chat.topic();
|
||||
const auto rootId = topic ? topic->rootId() : 0;
|
||||
resolveJumpToHistoryDate(peer, rootId, date, std::move(callback));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void ApiWrap::requestMessageAfterDate(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
const QDate &date,
|
||||
Callback &&callback) {
|
||||
// API returns a message with date <= offset_date.
|
||||
|
@ -2853,75 +2856,95 @@ void ApiWrap::requestMessageAfterDate(
|
|||
const auto maxId = 0;
|
||||
const auto minId = 0;
|
||||
const auto historyHash = uint64(0);
|
||||
request(MTPmessages_GetHistory(
|
||||
peer->input,
|
||||
MTP_int(offsetId),
|
||||
MTP_int(offsetDate),
|
||||
MTP_int(addOffset),
|
||||
MTP_int(limit),
|
||||
MTP_int(maxId),
|
||||
MTP_int(minId),
|
||||
MTP_long(historyHash)
|
||||
)).done([
|
||||
=,
|
||||
callback = std::forward<Callback>(callback)
|
||||
](const MTPmessages_Messages &result) {
|
||||
auto getMessagesList = [&]() -> const QVector<MTPMessage>* {
|
||||
auto handleMessages = [&](auto &messages) {
|
||||
|
||||
auto send = [&](auto &&serialized) {
|
||||
request(std::move(serialized)).done([
|
||||
=,
|
||||
callback = std::forward<Callback>(callback)
|
||||
](const MTPmessages_Messages &result) {
|
||||
const auto handleMessages = [&](auto &messages) {
|
||||
_session->data().processUsers(messages.vusers());
|
||||
_session->data().processChats(messages.vchats());
|
||||
return &messages.vmessages().v;
|
||||
};
|
||||
switch (result.type()) {
|
||||
case mtpc_messages_messages:
|
||||
const auto list = result.match([&](
|
||||
const MTPDmessages_messages &data) {
|
||||
return handleMessages(result.c_messages_messages());
|
||||
case mtpc_messages_messagesSlice:
|
||||
}, [&](const MTPDmessages_messagesSlice &data) {
|
||||
return handleMessages(result.c_messages_messagesSlice());
|
||||
case mtpc_messages_channelMessages: {
|
||||
auto &messages = result.c_messages_channelMessages();
|
||||
}, [&](const MTPDmessages_channelMessages &data) {
|
||||
const auto &messages = result.c_messages_channelMessages();
|
||||
if (peer && peer->isChannel()) {
|
||||
peer->asChannel()->ptsReceived(messages.vpts().v);
|
||||
} else {
|
||||
LOG(("API Error: received messages.channelMessages when no channel was passed! (ApiWrap::jumpToDate)"));
|
||||
LOG(("API Error: received messages.channelMessages when "
|
||||
"no channel was passed! (ApiWrap::jumpToDate)"));
|
||||
}
|
||||
return handleMessages(messages);
|
||||
} break;
|
||||
case mtpc_messages_messagesNotModified: {
|
||||
LOG(("API Error: received messages.messagesNotModified! (ApiWrap::jumpToDate)"));
|
||||
} break;
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
if (const auto list = getMessagesList()) {
|
||||
_session->data().processMessages(*list, NewMessageType::Existing);
|
||||
for (const auto &message : *list) {
|
||||
if (DateFromMessage(message) >= offsetDate) {
|
||||
callback(IdFromMessage(message));
|
||||
return;
|
||||
}, [&](const MTPDmessages_messagesNotModified &) {
|
||||
LOG(("API Error: received messages.messagesNotModified! "
|
||||
"(ApiWrap::jumpToDate)"));
|
||||
return (const QVector<MTPMessage>*)nullptr;
|
||||
});
|
||||
if (list) {
|
||||
_session->data().processMessages(
|
||||
*list,
|
||||
NewMessageType::Existing);
|
||||
for (const auto &message : *list) {
|
||||
if (DateFromMessage(message) >= offsetDate) {
|
||||
callback(IdFromMessage(message));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
callback(ShowAtUnreadMsgId);
|
||||
}).send();
|
||||
callback(ShowAtUnreadMsgId);
|
||||
}).send();
|
||||
};
|
||||
if (topicRootId) {
|
||||
send(MTPmessages_GetReplies(
|
||||
peer->input,
|
||||
MTP_int(topicRootId),
|
||||
MTP_int(offsetId),
|
||||
MTP_int(offsetDate),
|
||||
MTP_int(addOffset),
|
||||
MTP_int(limit),
|
||||
MTP_int(maxId),
|
||||
MTP_int(minId),
|
||||
MTP_long(historyHash)));
|
||||
} else {
|
||||
send(MTPmessages_GetHistory(
|
||||
peer->input,
|
||||
MTP_int(offsetId),
|
||||
MTP_int(offsetDate),
|
||||
MTP_int(addOffset),
|
||||
MTP_int(limit),
|
||||
MTP_int(maxId),
|
||||
MTP_int(minId),
|
||||
MTP_long(historyHash)));
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::resolveJumpToHistoryDate(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
const QDate &date,
|
||||
Fn<void(not_null<PeerData*>, MsgId)> callback) {
|
||||
if (const auto channel = peer->migrateTo()) {
|
||||
return resolveJumpToHistoryDate(channel, date, std::move(callback));
|
||||
return resolveJumpToHistoryDate(
|
||||
channel,
|
||||
topicRootId,
|
||||
date,
|
||||
std::move(callback));
|
||||
}
|
||||
const auto jumpToDateInPeer = [=] {
|
||||
requestMessageAfterDate(peer, date, [=](MsgId resultId) {
|
||||
callback(peer, resultId);
|
||||
requestMessageAfterDate(peer, topicRootId, date, [=](MsgId itemId) {
|
||||
callback(peer, itemId);
|
||||
});
|
||||
};
|
||||
if (const auto chat = peer->migrateFrom()) {
|
||||
requestMessageAfterDate(chat, date, [=](MsgId resultId) {
|
||||
if (resultId) {
|
||||
callback(chat, resultId);
|
||||
if (const auto chat = topicRootId ? nullptr : peer->migrateFrom()) {
|
||||
requestMessageAfterDate(chat, 0, date, [=](MsgId itemId) {
|
||||
if (itemId) {
|
||||
callback(chat, itemId);
|
||||
} else {
|
||||
jumpToDateInPeer();
|
||||
}
|
||||
|
|
|
@ -454,11 +454,13 @@ private:
|
|||
|
||||
void resolveJumpToHistoryDate(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
const QDate &date,
|
||||
Fn<void(not_null<PeerData*>, MsgId)> callback);
|
||||
template <typename Callback>
|
||||
void requestMessageAfterDate(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
const QDate &date,
|
||||
Callback &&callback);
|
||||
|
||||
|
|
|
@ -223,7 +223,9 @@ void Forum::applyReceivedTopics(
|
|||
}
|
||||
|
||||
void Forum::requestSomeStale() {
|
||||
if (_staleRequestId || (!_offset.id && _requestId)) {
|
||||
if (_staleRequestId
|
||||
|| (!_offset.id && _requestId)
|
||||
|| _staleRootIds.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto type = Histories::RequestType::History;
|
||||
|
@ -241,6 +243,9 @@ void Forum::requestSomeStale() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (rootIds.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto call = [=] {
|
||||
for (const auto &id : rootIds) {
|
||||
finishTopicRequest(id.v);
|
||||
|
|
|
@ -779,7 +779,11 @@ void Widget::refreshTopBars() {
|
|||
_subsectionTopBar->searchQuery(
|
||||
) | rpl::start_with_next([=](QString query) {
|
||||
applyFilterUpdate();
|
||||
}, lifetime());
|
||||
}, _subsectionTopBar->lifetime());
|
||||
_subsectionTopBar->jumpToDateRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
showCalendar();
|
||||
}, _subsectionTopBar->lifetime());
|
||||
updateControlsGeometry();
|
||||
}
|
||||
const auto history = _openedForum
|
||||
|
@ -1386,14 +1390,16 @@ void Widget::searchTopics() {
|
|||
MTP_int(kSearchPerPage)
|
||||
)).done([=](const MTPmessages_ForumTopics &result) {
|
||||
_topicSearchRequest = 0;
|
||||
const auto savedTopicId = _topicSearchOffsetId;
|
||||
const auto savedTopicId = _topicSearchOffsetTopicId;
|
||||
const auto byCreation = result.data().is_order_by_create_date();
|
||||
_openedForum->forum()->applyReceivedTopics(result, [&](
|
||||
not_null<Data::ForumTopic*> topic) {
|
||||
_topicSearchOffsetTopicId = topic->rootId();
|
||||
if (byCreation) {
|
||||
_topicSearchOffsetId = _topicSearchOffsetTopicId;
|
||||
_topicSearchOffsetDate = topic->creationDate();
|
||||
if (const auto last = topic->lastServerMessage()) {
|
||||
_topicSearchOffsetId = last->id;
|
||||
}
|
||||
} else if (const auto last = topic->lastServerMessage()) {
|
||||
_topicSearchOffsetId = last->id;
|
||||
_topicSearchOffsetDate = last->date();
|
||||
|
@ -1899,6 +1905,10 @@ void Widget::setSearchInChat(Key chat, PeerData *from) {
|
|||
clearSearchCache();
|
||||
}
|
||||
_inner->searchInChat(_searchInChat, _searchFromAuthor);
|
||||
if (_subsectionTopBar) {
|
||||
_subsectionTopBar->searchEnableJumpToDate(
|
||||
_openedForum && _searchInChat);
|
||||
}
|
||||
if (_searchFromAuthor && _lastFilterText == SwitchToChooseFromQuery()) {
|
||||
cancelSearch();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/shortcuts.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
|
@ -880,8 +881,10 @@ int TopBarWidget::countSelectedButtonsTop(float64 selectedShown) {
|
|||
}
|
||||
|
||||
void TopBarWidget::updateSearchVisibility() {
|
||||
const auto historyMode = (_activeChat.section == Section::History);
|
||||
_search->setVisible(historyMode && !_chooseForReportReason);
|
||||
const auto searchAllowedMode = (_activeChat.section == Section::History)
|
||||
|| (_activeChat.section == Section::Replies
|
||||
&& _activeChat.key.topic());
|
||||
_search->setVisible(searchAllowedMode && !_chooseForReportReason);
|
||||
}
|
||||
|
||||
void TopBarWidget::updateControlsGeometry() {
|
||||
|
@ -894,6 +897,7 @@ void TopBarWidget::updateControlsGeometry() {
|
|||
if (!_searchMode && !_searchShown.animating() && _searchField) {
|
||||
_searchField.destroy();
|
||||
_searchCancel.destroy();
|
||||
_jumpToDate.destroy();
|
||||
}
|
||||
auto searchFieldTop = _searchField
|
||||
? countSelectedButtonsTop(_searchShown.value(_searchMode ? 1. : 0.))
|
||||
|
@ -966,6 +970,11 @@ void TopBarWidget::updateControlsGeometry() {
|
|||
_searchCancel->moveToLeft(
|
||||
right - _searchCancel->width(),
|
||||
_searchField->y());
|
||||
if (_jumpToDate) {
|
||||
_jumpToDate->moveToLeft(
|
||||
right - _jumpToDate->width(),
|
||||
_searchField->y());
|
||||
}
|
||||
right -= _searchCancel->width();
|
||||
}
|
||||
|
||||
|
@ -1054,6 +1063,19 @@ void TopBarWidget::updateControlsVisibility() {
|
|||
? (_activeChat.key.topic() != nullptr)
|
||||
: false);
|
||||
updateSearchVisibility();
|
||||
if (_searchMode) {
|
||||
const auto hasSearchQuery = _searchField
|
||||
&& !_searchField->getLastText().isEmpty();
|
||||
if (!_jumpToDate || hasSearchQuery) {
|
||||
_searchCancel->show(anim::type::normal);
|
||||
if (_jumpToDate) {
|
||||
_jumpToDate->hide(anim::type::normal);
|
||||
}
|
||||
} else {
|
||||
_searchCancel->hide(anim::type::normal);
|
||||
_jumpToDate->show(anim::type::normal);
|
||||
}
|
||||
}
|
||||
_menuToggle->setVisible(hasMenu
|
||||
&& !_chooseForReportReason
|
||||
&& !_narrowMode);
|
||||
|
@ -1201,7 +1223,13 @@ bool TopBarWidget::toggleSearch(bool shown, anim::type animated) {
|
|||
_searchSubmitted.fire({});
|
||||
});
|
||||
QObject::connect(_searchField, &Ui::InputField::changed, [=] {
|
||||
_searchQuery = _searchField->getLastText();
|
||||
const auto wasEmpty = _searchQuery.current().isEmpty();
|
||||
const auto query = _searchField->getLastText();
|
||||
const auto nowEmpty = query.isEmpty();
|
||||
if (_jumpToDate && nowEmpty != wasEmpty) {
|
||||
updateControlsVisibility();
|
||||
}
|
||||
_searchQuery = query;
|
||||
});
|
||||
} else {
|
||||
Assert(_searchField != nullptr);
|
||||
|
@ -1224,6 +1252,27 @@ bool TopBarWidget::toggleSearch(bool shown, anim::type animated) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void TopBarWidget::searchEnableJumpToDate(bool enable) {
|
||||
if (!_searchMode && !enable) {
|
||||
return;
|
||||
} else if (enable) {
|
||||
_jumpToDate.create(
|
||||
this,
|
||||
object_ptr<Ui::IconButton>(this, st::dialogsCalendar));
|
||||
_jumpToDate->toggle(
|
||||
_searchField->getLastText().isEmpty(),
|
||||
anim::type::instant);
|
||||
_jumpToDate->entity()->clicks(
|
||||
) | rpl::to_empty | rpl::start_to_stream(
|
||||
_jumpToDateRequests,
|
||||
_jumpToDate->lifetime());
|
||||
} else {
|
||||
_jumpToDate.destroy();
|
||||
}
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
bool TopBarWidget::searchSetFocus() {
|
||||
if (!_searchMode) {
|
||||
return false;
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
void clearChooseMessagesForReport();
|
||||
|
||||
bool toggleSearch(bool shown, anim::type animated);
|
||||
void searchEnableJumpToDate(bool enable);
|
||||
bool searchSetFocus();
|
||||
[[nodiscard]] bool searchHasFocus() const;
|
||||
[[nodiscard]] rpl::producer<> searchCancelled() const;
|
||||
|
@ -100,6 +101,9 @@ public:
|
|||
[[nodiscard]] rpl::producer<> cancelChooseForReportRequest() const {
|
||||
return _cancelChooseForReport.events();
|
||||
}
|
||||
[[nodiscard]] rpl::producer<> jumpToDateRequest() const {
|
||||
return _jumpToDateRequests.events();
|
||||
}
|
||||
[[nodiscard]] rpl::producer<> searchRequest() const;
|
||||
|
||||
protected:
|
||||
|
@ -198,6 +202,7 @@ private:
|
|||
rpl::variable<QString> _searchQuery;
|
||||
rpl::event_stream<> _searchCancelled;
|
||||
rpl::event_stream<> _searchSubmitted;
|
||||
rpl::event_stream<> _jumpToDateRequests;
|
||||
|
||||
object_ptr<Ui::IconButton> _back;
|
||||
object_ptr<Ui::IconButton> _cancelChoose;
|
||||
|
|
|
@ -1396,12 +1396,18 @@ void SessionController::startOrJoinGroupCall(
|
|||
}
|
||||
|
||||
void SessionController::showCalendar(Dialogs::Key chat, QDate requestedDate) {
|
||||
const auto history = chat.history();
|
||||
const auto topic = chat.topic();
|
||||
const auto history = chat.owningHistory();
|
||||
if (!history) {
|
||||
return;
|
||||
}
|
||||
const auto currentPeerDate = [&] {
|
||||
if (history->scrollTopItem) {
|
||||
if (topic) {
|
||||
if (const auto item = topic->lastMessage()) {
|
||||
return base::unixtime::parse(item->date()).date();
|
||||
}
|
||||
return QDate();
|
||||
} else if (history->scrollTopItem) {
|
||||
return history->scrollTopItem->dateTime().date();
|
||||
} else if (history->loadedAtTop()
|
||||
&& !history->isEmpty()
|
||||
|
@ -1419,6 +1425,12 @@ void SessionController::showCalendar(Dialogs::Key chat, QDate requestedDate) {
|
|||
return QDate();
|
||||
}();
|
||||
const auto maxPeerDate = [&] {
|
||||
if (topic) {
|
||||
if (const auto item = topic->lastMessage()) {
|
||||
return base::unixtime::parse(item->date()).date();
|
||||
}
|
||||
return QDate();
|
||||
}
|
||||
const auto check = history->peer->migrateTo()
|
||||
? history->owner().historyLoaded(history->peer->migrateTo())
|
||||
: history;
|
||||
|
@ -1428,11 +1440,13 @@ void SessionController::showCalendar(Dialogs::Key chat, QDate requestedDate) {
|
|||
return QDate();
|
||||
}();
|
||||
const auto minPeerDate = [&] {
|
||||
const auto startDate = [] {
|
||||
const auto startDate = [&] {
|
||||
// Telegram was launched in August 2013 :)
|
||||
return QDate(2013, 8, 1);
|
||||
};
|
||||
if (const auto chat = history->peer->migrateFrom()) {
|
||||
if (topic) {
|
||||
return base::unixtime::parse(topic->creationDate()).date();
|
||||
} else if (const auto chat = history->peer->migrateFrom()) {
|
||||
if (const auto history = chat->owner().historyLoaded(chat)) {
|
||||
if (history->loadedAtTop()) {
|
||||
if (!history->isEmpty()) {
|
||||
|
@ -1515,13 +1529,28 @@ void SessionController::showCalendar(Dialogs::Key chat, QDate requestedDate) {
|
|||
}
|
||||
};
|
||||
const auto weak = base::make_weak(this);
|
||||
const auto weakTopic = base::make_weak(topic);
|
||||
const auto jump = [=](const QDate &date) {
|
||||
const auto open = [=](not_null<PeerData*> peer, MsgId id) {
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->showPeerHistory(peer, SectionShow::Way::Forward, id);
|
||||
if (!topic) {
|
||||
strong->showPeerHistory(
|
||||
peer,
|
||||
SectionShow::Way::Forward,
|
||||
id);
|
||||
} else if (const auto strongTopic = weakTopic.get()) {
|
||||
strong->showRepliesForMessage(
|
||||
strongTopic->history(),
|
||||
strongTopic->rootId(),
|
||||
id,
|
||||
SectionShow::Way::Forward);
|
||||
strong->hideLayer(anim::type::normal);
|
||||
}
|
||||
}
|
||||
};
|
||||
session().api().resolveJumpToDate(chat, date, open);
|
||||
if (!topic || weakTopic) {
|
||||
session().api().resolveJumpToDate(chat, date, open);
|
||||
}
|
||||
};
|
||||
show(Box<Ui::CalendarBox>(Ui::CalendarBoxArgs{
|
||||
.month = highlighted,
|
||||
|
|
Loading…
Add table
Reference in a new issue