diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index adbc122f91..0970634ba8 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -2293,7 +2293,7 @@ DialogsWidget::DialogsWidget(QWidget *parent) : TWidget(parent) subscribe(Adaptive::Changed(), [this] { updateForwardBar(); }); _cancelSearch->setClickedCallback([this] { onCancelSearch(); }); - _jumpToDate->entity()->setClickedCallback([this] { if (_searchInPeer) App::main()->showJumpToDate(_searchInPeer); }); + _jumpToDate->entity()->setClickedCallback([this] { if (_searchInPeer) App::main()->showJumpToDate(_searchInPeer, QDate()); }); _lockUnlock->setVisible(Global::LocalPasscode()); subscribe(Global::RefLocalPasscodeChanged(), [this] { updateLockUnlockVisibility(); }); _lockUnlock->setClickedCallback([this] { diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 5314b3534d..5fa17a572a 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -109,7 +109,7 @@ public: }; -constexpr int ScrollDateHideTimeout = 1000; +constexpr auto kScrollDateHideTimeout = 1000; ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() { return [](ChannelData *channel, MsgId msgId) { @@ -119,6 +119,26 @@ ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() { }; } +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::main()->showJumpToDate(_peer, _date); + } + +private: + PeerData *_peer = nullptr; + QDate _date; + +}; + + } // namespace // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html @@ -137,7 +157,7 @@ HistoryInner::HistoryInner(HistoryWidget *historyWidget, Ui::ScrollArea *scroll, _trippleClickTimer.setSingleShot(true); - connect(&_scrollDateHideTimer, SIGNAL(timeout()), this, SLOT(onScrollDateHide())); + connect(&_scrollDateHideTimer, SIGNAL(timeout()), this, SLOT(onScrollDateHideByTimer())); notifyIsBotChanged(); @@ -845,9 +865,13 @@ void HistoryInner::touchEvent(QTouchEvent *e) { } void HistoryInner::mouseMoveEvent(QMouseEvent *e) { - if (!(e->buttons() & (Qt::LeftButton | Qt::MiddleButton)) && _dragAction != NoDrag) { + auto buttonsPressed = (e->buttons() & (Qt::LeftButton | Qt::MiddleButton)); + if (!buttonsPressed && _dragAction != NoDrag) { mouseReleaseEvent(e); } + if (!buttonsPressed || ClickHandler::getPressed() == _scrollDateLink) { + keepScrollDateForNow(); + } dragActionUpdate(e->globalPos()); } @@ -1800,7 +1824,7 @@ void HistoryInner::onScrollDateCheck() { if (!newScrollDateItem) { _scrollDateLastItem = nullptr; _scrollDateLastItemTop = 0; - onScrollDateHide(); + scrollDateHide(); } else if (newScrollDateItem != _scrollDateLastItem || newScrollDateItemTop != _scrollDateLastItemTop) { // Show scroll date only if it is not the initial onScroll() event (with empty _scrollDateLastItem). if (_scrollDateLastItem && !_scrollDateShown) { @@ -1808,17 +1832,30 @@ void HistoryInner::onScrollDateCheck() { } _scrollDateLastItem = newScrollDateItem; _scrollDateLastItemTop = newScrollDateItemTop; - _scrollDateHideTimer.start(ScrollDateHideTimeout); + _scrollDateHideTimer.start(kScrollDateHideTimeout); } } -void HistoryInner::onScrollDateHide() { +void HistoryInner::onScrollDateHideByTimer() { _scrollDateHideTimer.stop(); + if (ClickHandler::getPressed() != _scrollDateLink) { + scrollDateHide(); + } +} + +void HistoryInner::scrollDateHide() { if (_scrollDateShown) { toggleScrollDateShown(); } } +void HistoryInner::keepScrollDateForNow() { + if (!_scrollDateShown && _scrollDateLastItem && _scrollDateOpacity.animating()) { + toggleScrollDateShown(); + } + _scrollDateHideTimer.start(kScrollDateHideTimeout); +} + void HistoryInner::toggleScrollDateShown() { _scrollDateShown = !_scrollDateShown; auto from = _scrollDateShown ? 0. : 1.; @@ -2086,31 +2123,82 @@ void HistoryInner::onUpdateSelected() { } } - HistoryStateRequest request; - if (_dragAction == Selecting) { - request.flags |= Text::StateRequest::Flag::LookupSymbol; - } else { - selectingText = false; - } - dragState = item->getState(m.x(), m.y(), request); - lnkhost = item; - if (!dragState.link && m.x() >= st::historyPhotoLeft && m.x() < st::historyPhotoLeft + st::msgPhotoSize) { - if (auto msg = item->toHistoryMessage()) { - if (msg->hasFromPhoto()) { - enumerateUserpics([&dragState, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool { - // stop enumeration if the userpic is below our point - if (userpicTop > point.y()) { - return false; - } + auto dateHeight = st::msgServicePadding.bottom() + st::msgServiceFont->height + st::msgServicePadding.top(); + auto scrollDateOpacity = _scrollDateOpacity.current(_scrollDateShown ? 1. : 0.); + enumerateDates([this, &dragState, &lnkhost, &point, scrollDateOpacity, dateHeight/*, lastDate, showFloatingBefore*/](HistoryItem *item, int itemtop, int dateTop) { + // stop enumeration if the date is above our point + if (dateTop + dateHeight <= point.y()) { + return false; + } - // stop enumeration if we've found a userpic under the cursor - if (point.y() >= userpicTop && point.y() < userpicTop + st::msgPhotoSize) { - dragState.link = message->from()->openLink(); - lnkhost = message; - return false; + bool displayDate = item->displayDate(); + bool dateInPlace = displayDate; + if (dateInPlace) { + int correctDateTop = itemtop + st::msgServiceMargin.top(); + dateInPlace = (dateTop < correctDateTop + dateHeight); + } + + // stop enumeration if we've found a date under the cursor + if (dateTop <= point.y()) { + auto opacity = (dateInPlace/* || noFloatingDate*/) ? 1. : scrollDateOpacity; + if (opacity > 0.) { + auto dateWidth = 0; + if (auto date = item->Get()) { + dateWidth = date->_width; + } else { + dateWidth = st::msgServiceFont->width(langDayOfMonthFull(item->date.date())); + } + dateWidth += st::msgServicePadding.left() + st::msgServicePadding.right(); + auto dateLeft = st::msgServiceMargin.left(); + auto maxwidth = item->history()->width; + if (Adaptive::ChatWide()) { + maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); + } + auto widthForDate = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left(); + + dateLeft += (widthForDate - dateWidth) / 2; + + if (point.x() >= dateLeft && point.x() < dateLeft + dateWidth) { + if (!_scrollDateLink) { + _scrollDateLink = MakeShared(item->history()->peer, item->date.date()); + } else { + static_cast(_scrollDateLink.data())->setDate(item->date.date()); } - return true; - }); + dragState.link = _scrollDateLink; + lnkhost = item; + } + } + return false; + } + return true; + }); + if (!dragState.link) { + HistoryStateRequest request; + if (_dragAction == Selecting) { + request.flags |= Text::StateRequest::Flag::LookupSymbol; + } else { + selectingText = false; + } + dragState = item->getState(m.x(), m.y(), request); + lnkhost = item; + if (!dragState.link && m.x() >= st::historyPhotoLeft && m.x() < st::historyPhotoLeft + st::msgPhotoSize) { + if (auto msg = item->toHistoryMessage()) { + if (msg->hasFromPhoto()) { + enumerateUserpics([&dragState, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool { + // stop enumeration if the userpic is below our point + if (userpicTop > point.y()) { + return false; + } + + // stop enumeration if we've found a userpic under the cursor + if (point.y() >= userpicTop && point.y() < userpicTop + st::msgPhotoSize) { + dragState.link = message->from()->openLink(); + lnkhost = message; + return false; + } + return true; + }); + } } } } diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 2b6743942e..34d9b58df5 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -152,7 +152,7 @@ public slots: private slots: void onScrollDateCheck(); - void onScrollDateHide(); + void onScrollDateHideByTimer(); private: void itemRemoved(HistoryItem *item); @@ -174,6 +174,8 @@ private: void toggleScrollDateShown(); void repaintScrollDateCallback(); bool displayScrollDate() const; + void scrollDateHide(); + void keepScrollDateForNow(); PeerData *_peer = nullptr; History *_migrated = nullptr; @@ -278,6 +280,7 @@ private: SingleTimer _scrollDateHideTimer; HistoryItem *_scrollDateLastItem = nullptr; int _scrollDateLastItemTop = 0; + ClickHandlerPtr _scrollDateLink; enum class EnumItemsDirection { TopToBottom, diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index ffecb5dd5e..20d52a4a40 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -2759,7 +2759,7 @@ void MainWidget::dlgUpdated(PeerData *peer, MsgId msgId) { } } -void MainWidget::showJumpToDate(PeerData *peer) { +void MainWidget::showJumpToDate(PeerData *peer, QDate requestedDate) { t_assert(peer != nullptr); auto currentPeerDate = [peer] { if (auto history = App::historyLoaded(peer)) { @@ -2798,7 +2798,8 @@ void MainWidget::showJumpToDate(PeerData *peer) { } return QDate(2013, 8, 1); // Telegram was launched in August 2013 :) }; - auto highlighted = currentPeerDate(), month = highlighted; + auto highlighted = requestedDate.isNull() ? currentPeerDate() : requestedDate; + auto month = highlighted; auto box = Box(month, highlighted, [this, peer](const QDate &date) { jumpToDate(peer, date); }); box->setMinDate(minPeerDate()); box->setMaxDate(maxPeerDate()); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index f1b88946cd..7d2fb04223 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -180,7 +180,7 @@ public: void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row); void dlgUpdated(PeerData *peer, MsgId msgId); - void showJumpToDate(PeerData *peer); + void showJumpToDate(PeerData *peer, QDate requestedDate); void windowShown();