Enable jump to date in feed.

This commit is contained in:
John Preston 2018-02-22 00:17:36 +03:00
parent e17dcbb8eb
commit f066f3f139
8 changed files with 174 additions and 71 deletions

View File

@ -12,6 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_web_page.h"
#include "data/data_feed.h"
#include "data/data_media_types.h"
#include "data/data_sparse_ids.h"
#include "data/data_search_controller.h"
#include "data/data_channel_admins.h"
#include "data/data_session.h"
#include "dialogs/dialogs_key.h"
#include "core/tl_help.h"
#include "base/overload.h"
#include "observer_peer.h"
@ -25,10 +30,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_message.h"
#include "history/history_media_types.h"
#include "history/history_item_components.h"
#include "history/feed/history_feed_section.h"
#include "storage/localstorage.h"
#include "auth_session.h"
#include "boxes/confirm_box.h"
#include "window/notifications_manager.h"
#include "window/window_controller.h"
#include "chat_helpers/message_field.h"
#include "chat_helpers/stickers.h"
#include "storage/localimageloader.h"
@ -37,10 +44,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/storage_user_photos.h"
#include "storage/storage_media_prepare.h"
#include "storage/storage_feed_messages.h"
#include "data/data_sparse_ids.h"
#include "data/data_search_controller.h"
#include "data/data_channel_admins.h"
#include "data/data_session.h"
namespace {
@ -2601,6 +2604,14 @@ void ApiWrap::applyUpdateNoPtsCheck(const MTPUpdate &update) {
}
}
void ApiWrap::jumpToDate(Dialogs::Key chat, const QDate &date) {
if (const auto peer = chat.peer()) {
jumpToHistoryDate(peer, date);
} else if (const auto feed = chat.feed()) {
jumpToFeedDate(feed, date);
}
}
template <typename Callback>
void ApiWrap::requestMessageAfterDate(
not_null<PeerData*> peer,
@ -2670,17 +2681,17 @@ void ApiWrap::requestMessageAfterDate(
}).send();
}
void ApiWrap::jumpToDate(not_null<PeerData*> peer, const QDate &date) {
if (auto channel = peer->migrateTo()) {
jumpToDate(channel, date);
void ApiWrap::jumpToHistoryDate(not_null<PeerData*> peer, const QDate &date) {
if (const auto channel = peer->migrateTo()) {
jumpToHistoryDate(channel, date);
return;
}
auto jumpToDateInPeer = [peer, date, this] {
requestMessageAfterDate(peer, date, [peer](MsgId resultId) {
const auto jumpToDateInPeer = [=] {
requestMessageAfterDate(peer, date, [=](MsgId resultId) {
Ui::showPeerHistory(peer, resultId);
});
};
if (auto chat = peer->migrateFrom()) {
if (const auto chat = peer->migrateFrom()) {
requestMessageAfterDate(chat, date, [=](MsgId resultId) {
if (resultId) {
Ui::showPeerHistory(chat, resultId);
@ -2693,6 +2704,63 @@ void ApiWrap::jumpToDate(not_null<PeerData*> peer, const QDate &date) {
}
}
template <typename Callback>
void ApiWrap::requestMessageAfterDate(
not_null<Data::Feed*> feed,
const QDate &date,
Callback &&callback) {
const auto offsetId = 0;
const auto offsetDate = static_cast<TimeId>(QDateTime(date).toTime_t());
const auto addOffset = -2;
const auto limit = 1;
const auto hash = 0;
request(MTPchannels_GetFeed(
MTP_flags(MTPchannels_GetFeed::Flag::f_offset_position),
MTP_int(feed->id()),
MTP_feedPosition(
MTP_int(offsetDate),
MTP_peerUser(MTP_int(_session->userId())),
MTP_int(0)),
MTP_int(addOffset),
MTP_int(limit),
MTPfeedPosition(), // max_id
MTPfeedPosition(), // min_id
MTP_int(hash)
)).done([
=,
callback = std::forward<Callback>(callback)
](const MTPmessages_FeedMessages &result) {
if (result.type() == mtpc_messages_feedMessagesNotModified) {
LOG(("API Error: "
"Unexpected messages.feedMessagesNotModified."));
callback(Data::UnreadMessagePosition);
return;
}
Assert(result.type() == mtpc_messages_feedMessages);
const auto &data = result.c_messages_feedMessages();
const auto &messages = data.vmessages.v;
const auto type = NewMessageExisting;
App::feedUsers(data.vusers);
App::feedChats(data.vchats);
for (const auto &msg : messages) {
if (const auto item = App::histories().addNewMessage(msg, type)) {
if (item->date() >= offsetDate || true) {
callback(item->position());
return;
}
}
}
callback(Data::UnreadMessagePosition);
}).send();
}
void ApiWrap::jumpToFeedDate(not_null<Data::Feed*> feed, const QDate &date) {
requestMessageAfterDate(feed, date, [=](Data::MessagePosition result) {
App::wnd()->controller()->showSection(
HistoryFeed::Memento(feed, result));
});
}
void ApiWrap::preloadEnoughUnreadMentions(not_null<History*> history) {
auto fullCount = history->getUnreadMentionsCount();
auto loadedCount = history->getUnreadMentionsLoadedCount();

View File

@ -27,6 +27,10 @@ enum class SharedMediaType : char;
struct PreparedList;
} // namespace Storage
namespace Dialogs {
class Key;
} // namespace Dialogs
namespace Api {
inline const MTPVector<MTPChat> *getChatsFromMessagesChats(const MTPmessages_Chats &chats) {
@ -152,7 +156,7 @@ public:
void applyUpdatesNoPtsCheck(const MTPUpdates &updates);
void applyUpdateNoPtsCheck(const MTPUpdate &update);
void jumpToDate(not_null<PeerData*> peer, const QDate &date);
void jumpToDate(Dialogs::Key chat, const QDate &date);
void preloadEnoughUnreadMentions(not_null<History*> history);
void checkForUnreadMentions(const base::flat_set<MsgId> &possiblyReadMentions, ChannelData *channel = nullptr);
@ -345,11 +349,19 @@ private:
not_null<ChannelData*> channel,
const QVector<MTPChannelParticipant> &participants);
void jumpToHistoryDate(not_null<PeerData*> peer, const QDate &date);
void jumpToFeedDate(not_null<Data::Feed*> feed, const QDate &date);
template <typename Callback>
void requestMessageAfterDate(
not_null<PeerData*> peer,
const QDate &date,
Callback &&callback);
template <typename Callback>
void requestMessageAfterDate(
not_null<Data::Feed*> feed,
const QDate &date,
Callback &&callback);
void sharedMediaDone(
not_null<PeerData*> peer,

View File

@ -128,11 +128,7 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
subscribe(Adaptive::Changed(), [this] { updateForwardBar(); });
_cancelSearch->setClickedCallback([this] { onCancelSearch(); });
_jumpToDate->entity()->setClickedCallback([this] {
if (const auto peer = _searchInChat.peer()) {
this->controller()->showJumpToDate(peer, QDate());
}
});
_jumpToDate->entity()->setClickedCallback([this] { showJumpToDate(); });
_chooseFromUser->entity()->setClickedCallback([this] { showSearchFrom(); });
_lockUnlock->setVisible(Global::LocalPasscode());
subscribe(Global::RefLocalPasscodeChanged(), [this] { updateLockUnlockVisibility(); });
@ -1036,6 +1032,12 @@ void DialogsWidget::clearSearchCache() {
MTP::cancel(base::take(_searchRequest));
}
void DialogsWidget::showJumpToDate() {
if (_searchInChat) {
this->controller()->showJumpToDate(_searchInChat, QDate());
}
}
void DialogsWidget::showSearchFrom() {
if (const auto peer = _searchInChat.peer()) {
const auto chat = _searchInChat;

View File

@ -156,6 +156,7 @@ private:
const QVector<MTPMessage> &messages);
void setSearchInChat(Dialogs::Key chat, UserData *from = nullptr);
void showJumpToDate();
void showSearchFrom();
void showMainMenu();
void clearSearchCache();

View File

@ -41,25 +41,6 @@ namespace {
constexpr auto kScrollDateHideTimeout = 1000;
class DateClickHandler : public ClickHandler {
public:
DateClickHandler(PeerData *peer, QDate date) : _peer(peer), _date(date) {
}
void setDate(QDate date) {
_date = date;
}
void onClick(Qt::MouseButton) const override {
App::wnd()->controller()->showJumpToDate(_peer, _date);
}
private:
PeerData *_peer = nullptr;
QDate _date;
};
// Helper binary search for an item in a list that is not completely
// above the given top of the visible area or below the given bottom of the visible area
// is applied once for blocks list in a history and once for items list in the found block.
@ -2401,9 +2382,9 @@ void HistoryInner::mouseActionUpdate() {
if (point.x() >= dateLeft && point.x() < dateLeft + dateWidth) {
if (!_scrollDateLink) {
_scrollDateLink = std::make_shared<DateClickHandler>(item->history()->peer, view->dateTime().date());
_scrollDateLink = std::make_shared<Window::DateClickHandler>(item->history(), view->dateTime().date());
} else {
static_cast<DateClickHandler*>(_scrollDateLink.get())->setDate(view->dateTime().date());
static_cast<Window::DateClickHandler*>(_scrollDateLink.get())->setDate(view->dateTime().date());
}
dragState = TextState(
nullptr,

View File

@ -242,7 +242,6 @@ public:
void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo);
bool insertBotCommand(const QString &cmd);
void jumpToDate(not_null<PeerData*> peer, const QDate &date);
void searchMessages(const QString &query, Dialogs::Key inChat);
void itemEdited(not_null<HistoryItem*> item);

View File

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_element.h"
#include "media/player/media_player_round_controller.h"
#include "data/data_session.h"
#include "data/data_feed.h"
#include "boxes/calendar_box.h"
#include "mainwidget.h"
#include "mainwindow.h"
@ -24,6 +25,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Window {
DateClickHandler::DateClickHandler(Dialogs::Key chat, QDate date)
: _chat(chat)
, _date(date) {
}
void DateClickHandler::setDate(QDate date) {
_date = date;
}
void DateClickHandler::onClick(Qt::MouseButton) const {
App::wnd()->controller()->showJumpToDate(_chat, _date);
}
Controller::Controller(not_null<MainWindow*> window)
: _window(window) {
Auth().data().animationPlayInlineRequest(
@ -304,14 +318,15 @@ void Controller::closeThirdSection() {
}
}
void Controller::showJumpToDate(not_null<PeerData*> peer, QDate requestedDate) {
Expects(peer != nullptr);
auto currentPeerDate = [peer] {
if (auto history = App::historyLoaded(peer)) {
void Controller::showJumpToDate(Dialogs::Key chat, QDate requestedDate) {
const auto currentPeerDate = [&] {
if (const auto history = chat.history()) {
if (history->scrollTopItem) {
return history->scrollTopItem->dateTime().date();
} else if (history->loadedAtTop() && !history->isEmpty() && history->peer->migrateFrom()) {
if (auto migrated = App::historyLoaded(history->peer->migrateFrom())) {
} else if (history->loadedAtTop()
&& !history->isEmpty()
&& history->peer->migrateFrom()) {
if (const auto migrated = App::historyLoaded(history->peer->migrateFrom())) {
if (migrated->scrollTopItem) {
// We're up in the migrated history.
// So current date is the date of first message here.
@ -321,59 +336,71 @@ void Controller::showJumpToDate(not_null<PeerData*> peer, QDate requestedDate) {
} else if (!history->chatsListDate().isNull()) {
return history->chatsListDate().date();
}
}
return QDate::currentDate();
};
auto maxPeerDate = [](not_null<PeerData*> peer) {
if (auto channel = peer->migrateTo()) {
peer = channel;
}
if (auto history = App::historyLoaded(peer)) {
if (!history->chatsListDate().isNull()) {
return history->chatsListDate().date();
} else if (const auto feed = chat.feed()) {
/*if (chatScrollPosition(feed)) {
} else */if (!feed->chatsListDate().isNull()) {
return feed->chatsListDate().date();
}
}
return QDate::currentDate();
};
auto minPeerDate = [](not_null<PeerData*> peer) {
const auto maxPeerDate = [](Dialogs::Key chat) {
if (auto history = chat.history()) {
if (const auto channel = history->peer->migrateTo()) {
history = App::historyLoaded(channel);
}
if (history && !history->chatsListDate().isNull()) {
return history->chatsListDate().date();
}
} else if (const auto feed = chat.feed()) {
if (!feed->chatsListDate().isNull()) {
return feed->chatsListDate().date();
}
}
return QDate::currentDate();
};
const auto minPeerDate = [](Dialogs::Key chat) {
const auto startDate = [] {
// Telegram was launched in August 2013 :)
return QDate(2013, 8, 1);
};
if (auto chat = peer->migrateFrom()) {
if (auto history = App::historyLoaded(chat)) {
if (history->loadedAtTop()) {
if (!history->isEmpty()) {
return history->blocks.front()->messages.front()->dateTime().date();
if (const auto history = chat.history()) {
if (const auto chat = history->peer->migrateFrom()) {
if (const auto history = App::historyLoaded(chat)) {
if (history->loadedAtTop()) {
if (!history->isEmpty()) {
return history->blocks.front()->messages.front()->dateTime().date();
}
} else {
return startDate();
}
} else {
return startDate();
}
}
}
if (auto history = App::historyLoaded(peer)) {
if (history->loadedAtTop()) {
if (!history->isEmpty()) {
return history->blocks.front()->messages.front()->dateTime().date();
}
return QDate::currentDate();
}
} else if (const auto feed = chat.feed()) {
return startDate();
}
return startDate();
};
auto highlighted = requestedDate.isNull()
const auto highlighted = requestedDate.isNull()
? currentPeerDate()
: requestedDate;
auto month = highlighted;
auto callback = [this, peer](const QDate &date) {
Auth().api().jumpToDate(peer, date);
const auto month = highlighted;
auto callback = [=](const QDate &date) {
Auth().api().jumpToDate(chat, date);
};
auto box = Box<CalendarBox>(
month,
highlighted,
std::move(callback));
box->setMinDate(minPeerDate(peer));
box->setMaxDate(maxPeerDate(peer));
box->setMinDate(minPeerDate(chat));
box->setMaxDate(maxPeerDate(chat));
Ui::show(std::move(box));
}

View File

@ -38,6 +38,19 @@ enum class GifPauseReason {
using GifPauseReasons = base::flags<GifPauseReason>;
inline constexpr bool is_flag_type(GifPauseReason) { return true; };
class DateClickHandler : public ClickHandler {
public:
DateClickHandler(Dialogs::Key chat, QDate date);
void setDate(QDate date);
void onClick(Qt::MouseButton) const override;
private:
Dialogs::Key _chat;
QDate _date;
};
struct SectionShow {
enum class Way {
Forward,
@ -184,7 +197,7 @@ public:
}
void showJumpToDate(
not_null<PeerData*> peer,
Dialogs::Key chat,
QDate requestedDate);
base::Variable<bool> &dialogsListFocused() {