From 5a20014b1aa104d10ec68d88affc31c178417db1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 25 Aug 2017 18:17:46 +0300 Subject: [PATCH] Highlight all mentions when marking them read. --- .../history/history_inner_widget.cpp | 2 + Telegram/SourceFiles/history/history_item.cpp | 11 +- Telegram/SourceFiles/history/history_item.h | 11 +- .../SourceFiles/history/history_message.cpp | 8 +- .../history/history_service_layout.cpp | 14 +- .../history/history_service_layout.h | 6 +- .../SourceFiles/history/history_widget.cpp | 146 ++++++++++++------ Telegram/SourceFiles/history/history_widget.h | 23 +-- Telegram/SourceFiles/mainwidget.cpp | 8 +- Telegram/SourceFiles/mainwidget.h | 3 +- Telegram/SourceFiles/mediaview.cpp | 4 +- 11 files changed, 150 insertions(+), 86 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index dee46fee48..bd06d725f1 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -432,6 +432,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { } if (item->mentionsMe() && item->isMediaUnread()) { readMentions.insert(item); + _widget->enqueueMessageHighlight(item); } int32 h = item->height(); @@ -482,6 +483,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { } if (item->mentionsMe() && item->isMediaUnread()) { readMentions.insert(item); + _widget->enqueueMessageHighlight(item); } } p.translate(0, h); diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index de972840d7..6b345ce0de 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -600,9 +600,14 @@ TextSelection shiftSelection(TextSelection selection, uint16 byLength) { } // namespace internal -HistoryItem::HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from) : HistoryElement() -, id(msgId) -, date(msgDate) +HistoryItem::HistoryItem( + not_null history, + MsgId id, + MTPDmessage::Flags flags, + QDateTime date, + UserId from) : HistoryElement() +, id(id) +, date(date) , _history(history) , _from(from ? App::user(from) : history->peer) , _flags(flags | MTPDmessage_ClientFlag::f_pending_init_dimensions | MTPDmessage_ClientFlag::f_pending_resize) diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index d34ed37e8d..8d9bc34640 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -526,7 +526,7 @@ public: } void addLogEntryOriginal(WebPageId localId, const QString &label, const TextWithEntities &content); - History *history() const { + not_null history() const { return _history; } PeerData *from() const { @@ -921,7 +921,12 @@ public: ~HistoryItem(); protected: - HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from); + HistoryItem( + not_null history, + MsgId id, + MTPDmessage::Flags flags, + QDateTime date, + UserId from); // To completely create history item we need to call // a virtual method, it can not be done from constructor. @@ -938,7 +943,7 @@ protected: void finishEdition(int oldKeyboardTop); void finishEditionToEmpty(); - not_null _history; + const not_null _history; not_null _from; HistoryBlock *_block = nullptr; int _indexInBlock = -1; diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 98ee11feff..3cfec00f72 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -1613,12 +1613,10 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM } } - auto fullAnimMs = App::main() ? App::main()->animActiveTimeStart(this) : 0LL; + auto fullAnimMs = App::main() ? App::main()->highlightStartTime(this) : 0LL; if (fullAnimMs > 0 && fullAnimMs <= ms) { - int animms = ms - fullAnimMs; - if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) { - App::main()->stopAnimActive(); - } else { + auto animms = ms - fullAnimMs; + if (animms < st::activeFadeInDuration + st::activeFadeOutDuration) { auto top = marginTop(); auto bottom = marginBottom(); auto fill = qMin(top, bottom); diff --git a/Telegram/SourceFiles/history/history_service_layout.cpp b/Telegram/SourceFiles/history/history_service_layout.cpp index 4a43b0f0fc..7b7b28f5fb 100644 --- a/Telegram/SourceFiles/history/history_service_layout.cpp +++ b/Telegram/SourceFiles/history/history_service_layout.cpp @@ -188,16 +188,18 @@ int WideChatWidth() { return st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left(); } -void ServiceMessagePainter::paint(Painter &p, const HistoryService *message, const PaintContext &context, int height) { +void ServiceMessagePainter::paint( + Painter &p, + not_null message, + const PaintContext &context, + int height) { auto g = message->countGeometry(); if (g.width() < 1) return; - auto fullAnimMs = App::main() ? App::main()->animActiveTimeStart(message) : 0LL; + auto fullAnimMs = App::main() ? App::main()->highlightStartTime(message) : 0LL; if (fullAnimMs > 0 && fullAnimMs <= context.ms) { - int animms = context.ms - fullAnimMs; - if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) { - App::main()->stopAnimActive(); - } else { + auto animms = context.ms - fullAnimMs; + if (animms < st::activeFadeInDuration + st::activeFadeOutDuration) { auto top = st::msgServiceMargin.top(); auto bottom = st::msgServiceMargin.bottom(); auto fill = qMin(top, bottom); diff --git a/Telegram/SourceFiles/history/history_service_layout.h b/Telegram/SourceFiles/history/history_service_layout.h index 55b3bbf2a9..67f3ff74f3 100644 --- a/Telegram/SourceFiles/history/history_service_layout.h +++ b/Telegram/SourceFiles/history/history_service_layout.h @@ -39,7 +39,11 @@ struct PaintContext { class ServiceMessagePainter { public: - static void paint(Painter &p, const HistoryService *message, const PaintContext &context, int height); + static void paint( + Painter &p, + not_null message, + const PaintContext &context, + int height); static void paintDate(Painter &p, const QDateTime &date, int y, int w); static void paintDate(Painter &p, const QString &dateText, int dateTextWidth, int y, int w); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 0eba2e2c27..b753fc0217 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -680,8 +680,7 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null cont _sendActionStopTimer.setSingleShot(true); - _animActiveTimer.setSingleShot(false); - connect(&_animActiveTimer, SIGNAL(timeout()), this, SLOT(onAnimActiveStep())); + _highlightTimer.setCallback([this] { updateHighlightedMessage(); }); _membersDropdownShowTimer.setSingleShot(true); connect(&_membersDropdownShowTimer, SIGNAL(timeout()), this, SLOT(onMembersDropdownShow())); @@ -948,24 +947,108 @@ void HistoryWidget::scrollToAnimationCallback(FullMsgId attachToId) { } } -void HistoryWidget::highlightMessage(HistoryItem *context) { - Expects(_list != nullptr); +void HistoryWidget::enqueueMessageHighlight(not_null item) { + auto enqueueMessageId = [this](MsgId universalId) { + if (_highlightQueue.empty() && !_highlightTimer.isActive()) { + highlightMessage(universalId); + } else if (_highlightedMessageId != universalId + && !base::contains(_highlightQueue, universalId)) { + _highlightQueue.push_back(universalId); + checkNextHighlight(); + } + }; + if (item->history() == _history) { + enqueueMessageId(item->id); + } else if (item->history() == _migrated) { + enqueueMessageId(-item->id); + } +} - _animActiveStart = getms(); - _animActiveTimer.start(AnimationTimerDelta); - _activeAnimMsgId = _showAtMsgId; - if (context - && context->history() == _history - && context->isGroupMigrate() +void HistoryWidget::highlightMessage(MsgId universalMessageId) { + _highlightStart = getms(); + _highlightedMessageId = universalMessageId; + _highlightTimer.callEach(AnimationTimerDelta); + + adjustHighlightedMessageToMigrated(); +} + +void HistoryWidget::adjustHighlightedMessageToMigrated() { + if (_history + && _highlightTimer.isActive() + && _highlightedMessageId > 0 && _migrated && !_migrated->isEmpty() && _migrated->loadedAtBottom() && _migrated->blocks.back()->items.back()->isGroupMigrate() && _list->historyTop() != _list->historyDrawTop()) { - _activeAnimMsgId = -_migrated->blocks.back()->items.back()->id; + auto highlighted = App::histItemById( + _history->channelId(), + _highlightedMessageId); + if (highlighted && highlighted->isGroupMigrate()) { + _highlightedMessageId = -_migrated->blocks.back()->items.back()->id; + } } } +void HistoryWidget::checkNextHighlight() { + if (_highlightTimer.isActive()) { + return; + } + auto nextHighlight = [this] { + while (!_highlightQueue.empty()) { + auto msgId = _highlightQueue.front(); + _highlightQueue.pop_front(); + auto item = getItemFromHistoryOrMigrated(msgId); + if (item && !item->detached()) { + return msgId; + } + } + return 0; + }(); + if (!nextHighlight) { + return; + } + highlightMessage(nextHighlight); +} + +void HistoryWidget::updateHighlightedMessage() { + auto item = getItemFromHistoryOrMigrated(_highlightedMessageId); + if (!item || item->detached()) { + return stopMessageHighlight(); + } + auto duration = st::activeFadeInDuration + st::activeFadeOutDuration; + if (getms() - _highlightStart > duration) { + return stopMessageHighlight(); + } + + Ui::repaintHistoryItem(item); +} + +TimeMs HistoryWidget::highlightStartTime(not_null item) const { + auto isHighlighted = [this](not_null item) { + if (item->id == _highlightedMessageId) { + return (item->history() == _history); + } else if (item->id == -_highlightedMessageId) { + return (item->history() == _migrated); + } + return false; + }; + return (isHighlighted(item) && _highlightTimer.isActive()) + ? _highlightStart + : 0; +} + +void HistoryWidget::stopMessageHighlight() { + _highlightTimer.cancel(); + _highlightedMessageId = 0; + checkNextHighlight(); +} + +void HistoryWidget::clearHighlightMessages() { + _highlightQueue.clear(); + stopMessageHighlight(); +} + int HistoryWidget::itemTopForHighlight(not_null item) const { auto itemTop = _list->itemTop(item); Assert(itemTop >= 0); @@ -1644,6 +1727,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re showAtMsgId = ShowAtTheEndMsgId; } + clearHighlightMessages(); if (_history) { if (_peer->id == peerId && !reload) { updateForwarding(); @@ -1676,7 +1760,6 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re auto item = getItemFromHistoryOrMigrated(_showAtMsgId); animatedScrollToY(countInitialScrollTop(), item); - highlightMessage(item); } else { historyLoaded(); } @@ -4808,7 +4891,7 @@ int HistoryWidget::countInitialScrollTop() { return countInitialScrollTop(); } else { result = itemTopForHighlight(item); - highlightMessage(item); + enqueueMessageHighlight(item); } } else if (_history->unreadBar || (_migrated && _migrated->unreadBar)) { result = unreadBarTop(); @@ -4974,12 +5057,7 @@ void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector _list->messagesReceived(peer, messages); if (!_firstLoadRequest) { updateHistoryGeometry(); - if (_animActiveTimer.isActive() && _activeAnimMsgId > 0 && _migrated && !_migrated->isEmpty() && _migrated->loadedAtBottom() && _migrated->blocks.back()->items.back()->isGroupMigrate() && _list->historyTop() != _list->historyDrawTop() && _history) { - auto animActiveItem = App::histItemById(_history->channelId(), _activeAnimMsgId); - if (animActiveItem && animActiveItem->isGroupMigrate()) { - _activeAnimMsgId = -_migrated->blocks.back()->items.back()->id; - } - } + adjustHighlightedMessageToMigrated(); updateBotKeyboard(); } } @@ -6147,36 +6225,6 @@ HistoryItem *HistoryWidget::getItemFromHistoryOrMigrated(MsgId genericMsgId) con return App::histItemById(_channel, genericMsgId); } -void HistoryWidget::onAnimActiveStep() { - if (!_history || !_activeAnimMsgId || (_activeAnimMsgId < 0 && (!_migrated || -_activeAnimMsgId >= ServerMaxMsgId))) { - return _animActiveTimer.stop(); - } - - auto item = getItemFromHistoryOrMigrated(_activeAnimMsgId); - if (!item || item->detached()) { - return _animActiveTimer.stop(); - } - - if (getms() - _animActiveStart > st::activeFadeInDuration + st::activeFadeOutDuration) { - stopAnimActive(); - } else { - Ui::repaintHistoryItem(item); - } -} - -uint64 HistoryWidget::animActiveTimeStart(const HistoryItem *msg) const { - if (!msg) return 0; - if ((msg->history() == _history && msg->id == _activeAnimMsgId) || (_migrated && msg->history() == _migrated && msg->id == -_activeAnimMsgId)) { - return _animActiveTimer.isActive() ? _animActiveStart : 0; - } - return 0; -} - -void HistoryWidget::stopAnimActive() { - _animActiveTimer.stop(); - _activeAnimMsgId = 0; -} - SelectedItemSet HistoryWidget::getSelectedItems() const { return _list ? _list->getSelectedItems() : SelectedItemSet(); } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 8664ae88ba..c97a49a7ff 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -262,8 +262,8 @@ public: bool touchScroll(const QPoint &delta); - uint64 animActiveTimeStart(const HistoryItem *msg) const; - void stopAnimActive(); + void enqueueMessageHighlight(not_null item); + TimeMs highlightStartTime(not_null item) const; SelectedItemSet getSelectedItems() const; void itemEdited(HistoryItem *item); @@ -445,8 +445,6 @@ public slots: void onForwardSelected(); void onClearSelected(); - void onAnimActiveStep(); - void onDraftSaveDelayed(); void onDraftSave(bool delayed = false); void onCloudDraftSave(); @@ -492,6 +490,13 @@ private: void showNextUnreadMention(); void handlePeerUpdate(); + void highlightMessage(MsgId universalMessageId); + void adjustHighlightedMessageToMigrated(); + void checkNextHighlight(); + void updateHighlightedMessage(); + void clearHighlightMessages(); + void stopMessageHighlight(); + void animationCallback(); void updateOverStates(QPoint pos); void recordStartCallback(); @@ -701,7 +706,7 @@ private: HistoryItem *getItemFromHistoryOrMigrated(MsgId genericMsgId) const; void animatedScrollToItem(MsgId msgId); void animatedScrollToY(int scrollTo, HistoryItem *attachTo = nullptr); - void highlightMessage(HistoryItem *context); + void updateDragAreas(); // when scroll position or scroll area size changed this method @@ -729,8 +734,6 @@ private: MsgId _delayedShowAtMsgId = -1; // wtf? mtpRequestId _delayedShowAtRequest = 0; - MsgId _activeAnimMsgId = 0; - object_ptr _backAnimationButton = { nullptr }; object_ptr _topBar; object_ptr _scroll; @@ -846,8 +849,10 @@ private: QTimer _scrollTimer; int32 _scrollDelta = 0; - QTimer _animActiveTimer; - float64 _animActiveStart = 0; + MsgId _highlightedMessageId = 0; + std::deque _highlightQueue; + base::Timer _highlightTimer; + TimeMs _highlightStart = 0; QMap, mtpRequestId> _sendActionRequests; QTimer _sendActionStopTimer; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 09ae9be1f9..076f3d2cd9 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1529,12 +1529,8 @@ void MainWidget::unreadCountChanged(History *history) { _history->unreadCountChanged(history); } -TimeMs MainWidget::animActiveTimeStart(const HistoryItem *msg) const { - return _history->animActiveTimeStart(msg); -} - -void MainWidget::stopAnimActive() { - _history->stopAnimActive(); +TimeMs MainWidget::highlightStartTime(not_null item) const { + return _history->highlightStartTime(item); } void MainWidget::sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo) { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 4c56f61967..e8578466e4 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -309,8 +309,7 @@ public: void readServerHistory(History *history, ReadServerHistoryChecks checks = ReadServerHistoryChecks::OnlyIfUnread); void unreadCountChanged(History *history); - TimeMs animActiveTimeStart(const HistoryItem *msg) const; - void stopAnimActive(); + TimeMs highlightStartTime(not_null item) const; void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo); void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo); diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 6b8701927b..f530946ff1 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -1026,7 +1026,7 @@ void MediaView::onCopy() { } void MediaView::showPhoto(PhotoData *photo, HistoryItem *context) { - _history = context ? context->history() : nullptr; + _history = context ? context->history().get() : nullptr; _migrated = nullptr; if (_history) { if (_history->peer->migrateFrom()) { @@ -1144,7 +1144,7 @@ void MediaView::showPhoto(PhotoData *photo, PeerData *context) { void MediaView::showDocument(DocumentData *doc, HistoryItem *context) { _photo = 0; - _history = context ? context->history() : nullptr; + _history = context ? context->history().get() : nullptr; _migrated = nullptr; if (_history) { if (_history->peer->migrateFrom()) {