Allow select time when jumping to date in chat
This commit is contained in:
parent
a4bb624c3f
commit
49fe365add
14 changed files with 124 additions and 49 deletions
BIN
Telegram/Resources/icons/menu/to_beginning.png
Normal file
BIN
Telegram/Resources/icons/menu/to_beginning.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 195 B |
BIN
Telegram/Resources/icons/menu/to_beginning@2x.png
Normal file
BIN
Telegram/Resources/icons/menu/to_beginning@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 313 B |
BIN
Telegram/Resources/icons/menu/to_beginning@3x.png
Normal file
BIN
Telegram/Resources/icons/menu/to_beginning@3x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 418 B |
|
|
@ -260,5 +260,9 @@
|
|||
"ktg_settings_compress_images_default": "Compress images by default",
|
||||
"ktg_pip_not_supported": "Sorry, Picture-in-Picture mode is not supported here.",
|
||||
"ktg_forward_quiz_unquoted": "Sorry, quizzes that are currently open and unvoted on cannot be forwarded unquoted.",
|
||||
"ktg_jump_to_date_title": "Jump to...",
|
||||
"ktg_jump_to_date_button": "Jump",
|
||||
"ktg_jump_to_beginning": "Jump to beginning",
|
||||
"ktg_show_calendar": "Show calendar",
|
||||
"dummy_last_string": ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,5 +259,9 @@
|
|||
"ktg_settings_remember_compress_images": "Запоминать сжатие изображений",
|
||||
"ktg_settings_compress_images_default": "Сжимать изображения по умолчанию",
|
||||
"ktg_pip_not_supported": "К сожалению, режим «Картинка-в-картинке» здесь не поддерживается.",
|
||||
"ktg_jump_to_date_title": "Перейти к...",
|
||||
"ktg_jump_to_date_button": "Перейти",
|
||||
"ktg_jump_to_beginning": "Перейти в начало",
|
||||
"ktg_show_calendar": "Показать календарь",
|
||||
"dummy_last_string": ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2813,7 +2813,7 @@ void ApiWrap::readFeaturedSets() {
|
|||
}
|
||||
}
|
||||
|
||||
void ApiWrap::jumpToDate(Dialogs::Key chat, const QDate &date) {
|
||||
void ApiWrap::jumpToDate(Dialogs::Key chat, const QDateTime &date) {
|
||||
if (const auto peer = chat.peer()) {
|
||||
jumpToHistoryDate(peer, date);
|
||||
}
|
||||
|
|
@ -2822,13 +2822,13 @@ void ApiWrap::jumpToDate(Dialogs::Key chat, const QDate &date) {
|
|||
template <typename Callback>
|
||||
void ApiWrap::requestMessageAfterDate(
|
||||
not_null<PeerData*> peer,
|
||||
const QDate &date,
|
||||
const QDateTime &date,
|
||||
Callback &&callback) {
|
||||
// API returns a message with date <= offset_date.
|
||||
// So we request a message with offset_date = desired_date - 1 and add_offset = -1.
|
||||
// This should give us the first message with date >= desired_date.
|
||||
const auto offsetId = 0;
|
||||
const auto offsetDate = static_cast<int>(date.startOfDay().toSecsSinceEpoch()) - 1;
|
||||
const auto offsetDate = static_cast<int>(date.toSecsSinceEpoch()) - 1;
|
||||
const auto addOffset = -1;
|
||||
const auto limit = 1;
|
||||
const auto maxId = 0;
|
||||
|
|
@ -2887,7 +2887,7 @@ void ApiWrap::requestMessageAfterDate(
|
|||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::jumpToHistoryDate(not_null<PeerData*> peer, const QDate &date) {
|
||||
void ApiWrap::jumpToHistoryDate(not_null<PeerData*> peer, const QDateTime &date) {
|
||||
if (const auto channel = peer->migrateTo()) {
|
||||
jumpToHistoryDate(channel, date);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ public:
|
|||
|
||||
bool isQuitPrevent();
|
||||
|
||||
void jumpToDate(Dialogs::Key chat, const QDate &date);
|
||||
void jumpToDate(Dialogs::Key chat, const QDateTime &date);
|
||||
|
||||
void preloadEnoughUnreadMentions(not_null<History*> history);
|
||||
void checkForUnreadMentions(
|
||||
|
|
@ -442,11 +442,11 @@ private:
|
|||
void requestSavedGifs(TimeId now);
|
||||
void readFeaturedSets();
|
||||
|
||||
void jumpToHistoryDate(not_null<PeerData*> peer, const QDate &date);
|
||||
void jumpToHistoryDate(not_null<PeerData*> peer, const QDateTime &date);
|
||||
template <typename Callback>
|
||||
void requestMessageAfterDate(
|
||||
not_null<PeerData*> peer,
|
||||
const QDate &date,
|
||||
const QDateTime &date,
|
||||
Callback &&callback);
|
||||
|
||||
void sharedMediaDone(
|
||||
|
|
|
|||
|
|
@ -1466,7 +1466,7 @@ void Widget::clearSearchCache() {
|
|||
|
||||
void Widget::showCalendar() {
|
||||
if (_searchInChat) {
|
||||
controller()->showCalendar(_searchInChat, QDate());
|
||||
controller()->showCalendar(_searchInChat, QDateTime());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3120,9 +3120,9 @@ void HistoryInner::mouseActionUpdate() {
|
|||
|
||||
if (point.x() >= dateLeft && point.x() < dateLeft + dateWidth) {
|
||||
if (!_scrollDateLink) {
|
||||
_scrollDateLink = std::make_shared<Window::DateClickHandler>(item->history(), view->dateTime().date());
|
||||
_scrollDateLink = std::make_shared<Window::DateClickHandler>(item->history(), view->dateTime());
|
||||
} else {
|
||||
static_cast<Window::DateClickHandler*>(_scrollDateLink.get())->setDate(view->dateTime().date());
|
||||
static_cast<Window::DateClickHandler*>(_scrollDateLink.get())->setDate(view->dateTime());
|
||||
}
|
||||
dragState = TextState(
|
||||
nullptr,
|
||||
|
|
|
|||
|
|
@ -1932,7 +1932,7 @@ void HistoryWidget::setupShortcuts() {
|
|||
return true;
|
||||
});
|
||||
request->check(Command::JumpToDate, 1) && request->handle([=] {
|
||||
controller()->showCalendar(Dialogs::Key(_history), QDate());
|
||||
controller()->showCalendar(Dialogs::Key(_history), QDateTime());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Ui {
|
|||
namespace {
|
||||
|
||||
constexpr auto kMinimalSchedule = TimeId(10);
|
||||
|
||||
/*
|
||||
tr::phrase<> MonthDay(int index) {
|
||||
switch (index) {
|
||||
case 1: return tr::lng_month_day1;
|
||||
|
|
@ -40,14 +40,10 @@ tr::phrase<> MonthDay(int index) {
|
|||
}
|
||||
Unexpected("Index in MonthDay.");
|
||||
}
|
||||
*/
|
||||
|
||||
QString DayString(const QDate &date) {
|
||||
return tr::lng_month_day(
|
||||
tr::now,
|
||||
lt_month,
|
||||
MonthDay(date.month())(tr::now),
|
||||
lt_day,
|
||||
QString::number(date.day()));
|
||||
return langDayOfMonthFull(date);
|
||||
}
|
||||
|
||||
QString TimeString(QTime time) {
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ menuIconSettings: icon {{ "menu/settings", menuSubmenuArrowFg }};
|
|||
menuIconSearch: icon {{ "menu/search", menuSubmenuArrowFg }};
|
||||
menuIconHide: icon {{ "menu/hide", menuSubmenuArrowFg }};
|
||||
menuIconMention: icon {{ "menu/mention", menuSubmenuArrowFg }};
|
||||
menuIconToBeginning: icon {{ "menu/to_beginning", menuSubmenuArrowFg }};
|
||||
|
||||
mediaMenuIconStickers: icon {{ "menu/stickers", mediaviewMenuFg }};
|
||||
mediaMenuIconCancel: icon {{ "menu/cancel", mediaviewMenuFg }};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "window/window_session_controller.h"
|
||||
|
||||
#include "kotato/kotato_lang.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
#include "boxes/peers/edit_peer_info_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
|
|
@ -55,8 +56,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/toasts/common_toasts.h"
|
||||
#include "calls/calls_instance.h" // Core::App().calls().inCall().
|
||||
#include "calls/group/calls_group_call.h"
|
||||
#include "ui/boxes/choose_date_time.h"
|
||||
#include "ui/boxes/calendar_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "main/main_domain.h"
|
||||
|
|
@ -74,6 +77,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_layers.h" // st::boxLabel
|
||||
#include "styles/style_chat.h" // st::historyMessageRadius
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
namespace Window {
|
||||
namespace {
|
||||
|
|
@ -125,6 +130,53 @@ constexpr auto kNightBaseFile = ":/gui/night-custom-base.tdesktop-theme"_cs;
|
|||
};
|
||||
}
|
||||
|
||||
void ChooseJumpDateTimeBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
QDateTime minDate,
|
||||
QDateTime maxDate,
|
||||
QDateTime highlighted,
|
||||
Fn<void(TimeId)> onDone,
|
||||
Fn<void()> onBegnning,
|
||||
Fn<void()> onCalendar,
|
||||
bool hasCalendar) {
|
||||
|
||||
auto descriptor = Ui::ChooseDateTimeBox(box,
|
||||
Ui::ChooseDateTimeBoxArgs{
|
||||
.title = rktr("ktg_jump_to_date_title"),
|
||||
.submit = rktr("ktg_jump_to_date_button"),
|
||||
.done = std::move(onDone),
|
||||
.min = [=] { return base::unixtime::serialize(minDate); },
|
||||
.time = base::unixtime::serialize(highlighted),
|
||||
.max = [=] { return base::unixtime::serialize(maxDate); },
|
||||
});
|
||||
const auto topMenuButton = box->addTopButton(st::infoTopBarMenu);
|
||||
const auto menu = std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
|
||||
topMenuButton.data()->setClickedCallback([=] {
|
||||
*menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
topMenuButton.data(),
|
||||
st::popupMenuWithIcons);
|
||||
(*menu)->addAction(
|
||||
ktr("ktg_jump_to_beginning"),
|
||||
std::move(onBegnning),
|
||||
&st::menuIconToBeginning);
|
||||
if (hasCalendar) {
|
||||
(*menu)->addAction(
|
||||
ktr("ktg_show_calendar"),
|
||||
std::move(onCalendar),
|
||||
&st::menuIconSchedule);
|
||||
}
|
||||
|
||||
(*menu)->setForcedOrigin(Ui::PanelAnimation::Origin::TopRight);
|
||||
const auto buttonTopLeft = topMenuButton.data()->mapToGlobal(QPoint());
|
||||
const auto buttonRect = QRect(buttonTopLeft, topMenuButton.data()->size());
|
||||
const auto pos = QPoint(
|
||||
buttonRect.x() + buttonRect.width(),
|
||||
buttonRect.y() + buttonRect.height());
|
||||
(*menu)->popup(pos);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ActivateWindow(not_null<SessionController*> controller) {
|
||||
|
|
@ -142,12 +194,12 @@ bool operator!=(const PeerThemeOverride &a, const PeerThemeOverride &b) {
|
|||
return !(a == b);
|
||||
}
|
||||
|
||||
DateClickHandler::DateClickHandler(Dialogs::Key chat, QDate date)
|
||||
DateClickHandler::DateClickHandler(Dialogs::Key chat, QDateTime date)
|
||||
: _chat(chat)
|
||||
, _date(date) {
|
||||
}
|
||||
|
||||
void DateClickHandler::setDate(QDate date) {
|
||||
void DateClickHandler::setDate(QDateTime date) {
|
||||
_date = date;
|
||||
}
|
||||
|
||||
|
|
@ -1202,14 +1254,14 @@ void SessionController::startOrJoinGroupCall(
|
|||
}
|
||||
}
|
||||
|
||||
void SessionController::showCalendar(Dialogs::Key chat, QDate requestedDate) {
|
||||
void SessionController::showCalendar(Dialogs::Key chat, QDateTime requestedDateTime) {
|
||||
const auto history = chat.history();
|
||||
if (!history) {
|
||||
return;
|
||||
}
|
||||
const auto currentPeerDate = [&] {
|
||||
if (history->scrollTopItem) {
|
||||
return history->scrollTopItem->dateTime().date();
|
||||
return history->scrollTopItem->dateTime();
|
||||
} else if (history->loadedAtTop()
|
||||
&& !history->isEmpty()
|
||||
&& history->peer->migrateFrom()) {
|
||||
|
|
@ -1217,33 +1269,33 @@ void SessionController::showCalendar(Dialogs::Key chat, QDate requestedDate) {
|
|||
if (migrated->scrollTopItem) {
|
||||
// We're up in the migrated history.
|
||||
// So current date is the date of first message here.
|
||||
return history->blocks.front()->messages.front()->dateTime().date();
|
||||
return history->blocks.front()->messages.front()->dateTime();
|
||||
}
|
||||
}
|
||||
} else if (const auto item = history->lastMessage()) {
|
||||
return base::unixtime::parse(item->date()).date();
|
||||
return base::unixtime::parse(item->date());
|
||||
}
|
||||
return QDate();
|
||||
return QDateTime();
|
||||
}();
|
||||
const auto maxPeerDate = [&] {
|
||||
const auto check = history->peer->migrateTo()
|
||||
? history->owner().historyLoaded(history->peer->migrateTo())
|
||||
: history;
|
||||
if (const auto item = check ? check->lastMessage() : nullptr) {
|
||||
return base::unixtime::parse(item->date()).date();
|
||||
return base::unixtime::parse(item->date());
|
||||
}
|
||||
return QDate();
|
||||
return QDateTime();
|
||||
}();
|
||||
const auto minPeerDate = [&] {
|
||||
const auto startDate = [] {
|
||||
// Telegram was launched in August 2013 :)
|
||||
return QDate(2013, 8, 1);
|
||||
return QDate(2013, 8, 1).startOfDay();
|
||||
};
|
||||
if (const auto chat = history->peer->migrateFrom()) {
|
||||
if (const auto history = chat->owner().historyLoaded(chat)) {
|
||||
if (history->loadedAtTop()) {
|
||||
if (!history->isEmpty()) {
|
||||
return history->blocks.front()->messages.front()->dateTime().date();
|
||||
return history->blocks.front()->messages.front()->dateTime();
|
||||
}
|
||||
} else {
|
||||
return startDate();
|
||||
|
|
@ -1252,17 +1304,18 @@ void SessionController::showCalendar(Dialogs::Key chat, QDate requestedDate) {
|
|||
}
|
||||
if (history->loadedAtTop()) {
|
||||
if (!history->isEmpty()) {
|
||||
return history->blocks.front()->messages.front()->dateTime().date();
|
||||
return history->blocks.front()->messages.front()->dateTime();
|
||||
}
|
||||
return QDate::currentDate();
|
||||
return QDateTime::currentDateTime();
|
||||
}
|
||||
return startDate();
|
||||
}();
|
||||
const auto highlighted = !requestedDate.isNull()
|
||||
? requestedDate
|
||||
const auto highlighted = !requestedDateTime.isNull()
|
||||
? requestedDateTime
|
||||
: !currentPeerDate.isNull()
|
||||
? currentPeerDate
|
||||
: QDate::currentDate();
|
||||
: QDateTime::currentDateTime();
|
||||
|
||||
struct ButtonState {
|
||||
enum class Type {
|
||||
None,
|
||||
|
|
@ -1321,17 +1374,34 @@ void SessionController::showCalendar(Dialogs::Key chat, QDate requestedDate) {
|
|||
button->setPointerCursor(false);
|
||||
}
|
||||
};
|
||||
show(Box<Ui::CalendarBox>(Ui::CalendarBoxArgs{
|
||||
.month = highlighted,
|
||||
.highlighted = highlighted,
|
||||
.callback = [=](const QDate &date) {
|
||||
session().api().jumpToDate(chat, date);
|
||||
},
|
||||
.minDate = minPeerDate,
|
||||
.maxDate = maxPeerDate,
|
||||
.allowsSelection = history->peer->isUser(),
|
||||
.selectionChanged = selectionChanged,
|
||||
}));
|
||||
|
||||
const auto showCalendarCallback = [=] {
|
||||
show(Box<Ui::CalendarBox>(Ui::CalendarBoxArgs{
|
||||
.month = highlighted.date(),
|
||||
.highlighted = highlighted.date(),
|
||||
.callback = [=](const QDate &date) {
|
||||
session().api().jumpToDate(chat, date.startOfDay());
|
||||
},
|
||||
.minDate = minPeerDate.date(),
|
||||
.maxDate = maxPeerDate.date(),
|
||||
.allowsSelection = history->peer->isUser(),
|
||||
.selectionChanged = selectionChanged,
|
||||
}), Ui::LayerOption::CloseOther);
|
||||
};
|
||||
|
||||
show(Box(ChooseJumpDateTimeBox,
|
||||
minPeerDate,
|
||||
maxPeerDate,
|
||||
highlighted,
|
||||
[=](TimeId result) {
|
||||
session().api().jumpToDate(chat, base::unixtime::parse(result));
|
||||
},
|
||||
[=] {
|
||||
session().api().jumpToDate(chat, minPeerDate);
|
||||
},
|
||||
std::move(showCalendarCallback),
|
||||
history->peer->isUser()),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
void SessionController::showPassportForm(const Passport::FormRequest &request) {
|
||||
|
|
|
|||
|
|
@ -84,14 +84,14 @@ bool operator!=(const PeerThemeOverride &a, const PeerThemeOverride &b);
|
|||
|
||||
class DateClickHandler : public ClickHandler {
|
||||
public:
|
||||
DateClickHandler(Dialogs::Key chat, QDate date);
|
||||
DateClickHandler(Dialogs::Key chat, QDateTime date);
|
||||
|
||||
void setDate(QDate date);
|
||||
void setDate(QDateTime date);
|
||||
void onClick(ClickContext context) const override;
|
||||
|
||||
private:
|
||||
Dialogs::Key _chat;
|
||||
QDate _date;
|
||||
QDateTime _date;
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -366,7 +366,7 @@ public:
|
|||
|
||||
void showCalendar(
|
||||
Dialogs::Key chat,
|
||||
QDate requestedDate);
|
||||
QDateTime requestedDateTime);
|
||||
|
||||
void showAddContact();
|
||||
void showNewGroup();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue