diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 876f26827..fe63c860f 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -517,7 +517,7 @@ backgroundScroll: ScrollArea(boxLayerScroll) { } calendarTitleHeight: boxTitleHeight; -calendarLeft: IconButton { +calendarPrevious: IconButton { width: calendarTitleHeight; height: calendarTitleHeight; @@ -530,9 +530,11 @@ calendarLeft: IconButton { color: windowBgOver; } } -calendarRight: IconButton(calendarLeft) { +calendarPreviousDisabled: icon {{ "title_back", menuIconFg }}; +calendarNext: IconButton(calendarPrevious) { icon: icon {{ "title_back-flip_horizontal", boxTitleFg }}; } +calendarNextDisabled: icon {{ "title_back-flip_horizontal", menuIconFg }}; calendarTitleFont: boxTitleFont; calendarDaysFont: normalFont; calendarDaysFg: boxTitleAdditionalFg; diff --git a/Telegram/SourceFiles/boxes/calendarbox.cpp b/Telegram/SourceFiles/boxes/calendarbox.cpp index dcfe4bb59..a4a2720f9 100644 --- a/Telegram/SourceFiles/boxes/calendarbox.cpp +++ b/Telegram/SourceFiles/boxes/calendarbox.cpp @@ -40,6 +40,16 @@ public: _month.setForced(_month.value(), true); } + void setMinDate(QDate date); + void setMaxDate(QDate date); + + int minDayIndex() const { + return _minDayIndex; + } + int maxDayIndex() const { + return _maxDayIndex; + } + void skipMonth(int skip); void showMonth(QDate month); @@ -56,7 +66,7 @@ public: return _daysCount; } bool isEnabled(int index) const { - return (_currentDayIndex < 0) || (index <= _currentDayIndex); + return (index >= _minDayIndex) && (index <= _maxDayIndex); } const base::Variable &month() { @@ -67,14 +77,18 @@ public: QString labelFromIndex(int index) const; private: + void applyMonth(const QDate &month, bool forced = false); + static int daysShiftForMonth(QDate month); static int rowsCountForMonth(QDate month); base::Variable _month; + QDate _min, _max; QDate _highlighted; int _highlightedIndex = 0; - int _currentDayIndex = 0; + int _minDayIndex = 0; + int _maxDayIndex = 0; int _daysCount = 0; int _daysShift = 0; int _rowsCount = 0; @@ -85,18 +99,37 @@ CalendarBox::Context::Context(QDate month, QDate highlighted) : _highlighted(hig showMonth(month); } +void CalendarBox::Context::setMinDate(QDate date) { + _min = date; + applyMonth(_month.value(), true); +} + +void CalendarBox::Context::setMaxDate(QDate date) { + _max = date; + applyMonth(_month.value(), true); +} + void CalendarBox::Context::showMonth(QDate month) { if (month.day() != 1) { month = QDate(month.year(), month.month(), 1); } - _month.set(month); + applyMonth(month); +} + +void CalendarBox::Context::applyMonth(const QDate &month, bool forced) { + if (forced) { + _month.setForced(month); + } else { + _month.set(month); + } _daysCount = month.daysInMonth(); _daysShift = daysShiftForMonth(month); _rowsCount = rowsCountForMonth(month); auto yearIndex = month.year(); auto monthIndex = month.month(); _highlightedIndex = month.daysTo(_highlighted); - _currentDayIndex = month.daysTo(QDate::currentDate()); + _minDayIndex = _min.isNull() ? INT_MIN : month.daysTo(_min); + _maxDayIndex = _max.isNull() ? INT_MAX : month.daysTo(_max); } void CalendarBox::Context::skipMonth(int skip) { @@ -235,7 +268,7 @@ void CalendarBox::Inner::paintDayNames(Painter &p, QRect clip) { p.setFont(st::calendarDaysFont); p.setPen(st::calendarDaysFg); auto y = st::calendarPadding.top(); - auto x = st::calendarPadding.left(); + auto x = rowsLeft(); if (!myrtlrect(x, y, st::calendarCellSize.width() * kDaysInWeek, st::calendarDaysHeight).intersects(clip)) { return; } @@ -402,17 +435,29 @@ CalendarBox::CalendarBox(QWidget*, QDate month, QDate highlighted, base::lambda< : _context(std::make_unique(month, highlighted)) , _inner(this, _context.get()) , _title(this, _context.get()) -, _left(this, st::calendarLeft) -, _right(this, st::calendarRight) +, _previous(this, st::calendarPrevious) +, _next(this, st::calendarNext) , _callback(std::move(callback)) { } +void CalendarBox::setMinDate(QDate date) { + _context->setMinDate(date); +} + +void CalendarBox::setMaxDate(QDate date) { + _context->setMaxDate(date); +} + void CalendarBox::prepare() { - _left->setClickedCallback([this] { - _context->skipMonth(-1); + _previous->setClickedCallback([this] { + if (isPreviousEnabled()) { + _context->skipMonth(-1); + } }); - _right->setClickedCallback([this] { - _context->skipMonth(1); + _next->setClickedCallback([this] { + if (isNextEnabled()) { + _context->skipMonth(1); + } }); // _inner = setInnerWidget(object_ptr(this, _context.get()), st::calendarScroll, st::calendarTitleHeight); @@ -425,14 +470,30 @@ void CalendarBox::prepare() { _context->start(); } +bool CalendarBox::isPreviousEnabled() const { + return (_context->minDayIndex() < 0); +} + +bool CalendarBox::isNextEnabled() const { + return (_context->maxDayIndex() >= _context->daysCount()); +} + void CalendarBox::monthChanged(QDate month) { setDimensions(st::boxWideWidth, st::calendarTitleHeight + _inner->countHeight()); + auto previousEnabled = isPreviousEnabled(); + _previous->setIconOverride(previousEnabled ? nullptr : &st::calendarPreviousDisabled); + _previous->setRippleColorOverride(previousEnabled ? nullptr : &st::boxBg); + _previous->setCursor(previousEnabled ? style::cur_pointer : style::cur_default); + auto nextEnabled = isNextEnabled(); + _next->setIconOverride(nextEnabled ? nullptr : &st::calendarNextDisabled); + _next->setRippleColorOverride(nextEnabled ? nullptr : &st::boxBg); + _next->setCursor(nextEnabled ? style::cur_pointer : style::cur_default); } void CalendarBox::resizeEvent(QResizeEvent *e) { - _left->moveToLeft(0, 0); - _right->moveToRight(0, 0); - _title->setGeometryToLeft(_left->width(), 0, width() - _left->width() - _right->width(), st::calendarTitleHeight); + _previous->moveToLeft(0, 0); + _next->moveToRight(0, 0); + _title->setGeometryToLeft(_previous->width(), 0, width() - _previous->width() - _next->width(), st::calendarTitleHeight); _inner->setGeometryToLeft(0, st::calendarTitleHeight, width(), height() - st::calendarTitleHeight); BoxContent::resizeEvent(e); } diff --git a/Telegram/SourceFiles/boxes/calendarbox.h b/Telegram/SourceFiles/boxes/calendarbox.h index ee488421e..d038af028 100644 --- a/Telegram/SourceFiles/boxes/calendarbox.h +++ b/Telegram/SourceFiles/boxes/calendarbox.h @@ -29,6 +29,10 @@ class IconButton; class CalendarBox : public BoxContent { public: CalendarBox(QWidget*, QDate month, QDate highlighted, base::lambda callback); + + void setMinDate(QDate date); + void setMaxDate(QDate date); + ~CalendarBox(); protected: @@ -39,6 +43,9 @@ protected: private: void monthChanged(QDate month); + bool isPreviousEnabled() const; + bool isNextEnabled() const; + class Context; std::unique_ptr _context; @@ -47,8 +54,8 @@ private: class Title; object_ptr _title; - object_ptr<Ui::IconButton> _left; - object_ptr<Ui::IconButton> _right; + object_ptr<Ui::IconButton> _previous; + object_ptr<Ui::IconButton> _next; base::lambda<void(QDate date)> _callback; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 5205ce068..ffecb5dd5 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -2765,20 +2765,55 @@ void MainWidget::showJumpToDate(PeerData *peer) { if (auto history = App::historyLoaded(peer)) { if (history->scrollTopItem) { return history->scrollTopItem->date.date(); + } else if (history->loadedAtTop() && !history->isEmpty() && history->peer->migrateFrom()) { + if (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. + return history->blocks.front()->items.front()->date.date(); + } + } } else if (!history->lastMsgDate.isNull()) { return history->lastMsgDate.date(); } } return QDate::currentDate(); }; + auto maxPeerDate = [peer] { + if (auto history = App::historyLoaded(peer)) { + if (!history->lastMsgDate.isNull()) { + return history->lastMsgDate.date(); + } + } + return QDate::currentDate(); + }; + auto minPeerDate = [peer] { + if (auto history = App::historyLoaded(peer)) { + if (history->loadedAtTop()) { + if (history->isEmpty()) { + return QDate::currentDate(); + } + return history->blocks.front()->items.front()->date.date(); + } + } + return QDate(2013, 8, 1); // Telegram was launched in August 2013 :) + }; auto highlighted = currentPeerDate(), month = highlighted; - Ui::show(Box<CalendarBox>(month, highlighted, [this, peer](const QDate &date) { jumpToDate(peer, date); })); + auto box = Box<CalendarBox>(month, highlighted, [this, peer](const QDate &date) { jumpToDate(peer, date); }); + box->setMinDate(minPeerDate()); + box->setMaxDate(maxPeerDate()); + Ui::show(std::move(box)); } void MainWidget::jumpToDate(PeerData *peer, const QDate &date) { - auto time = static_cast<int>(QDateTime(date).toTime_t()); + // 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. + auto offset_date = static_cast<int>(QDateTime(date).toTime_t()) - 1; + auto add_offset = -1; + auto limit = 1; auto flags = MTPmessages_Search::Flags(0); - auto request = MTPmessages_GetHistory(peer->input, MTP_int(0), MTP_int(time), MTP_int(-1), MTP_int(1), MTP_int(0), MTP_int(0)); + auto request = MTPmessages_GetHistory(peer->input, MTP_int(0), MTP_int(offset_date), MTP_int(add_offset), MTP_int(limit), MTP_int(0), MTP_int(0)); MTP::send(request, ::rpcDone([peer](const MTPmessages_Messages &result) { auto getMessagesList = [&result, peer]() -> const QVector<MTPMessage>* { auto handleMessages = [](auto &messages) {