From 3999bca8239f47a14b2190595d4d5211d4de5cd6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 10 Oct 2022 16:46:13 +0400 Subject: [PATCH] Support unread mentions / reactions in topics. --- .../SourceFiles/api/api_unread_things.cpp | 16 +- Telegram/SourceFiles/data/data_changes.cpp | 1 + .../history/history_inner_widget.cpp | 3 +- .../SourceFiles/history/history_widget.cpp | 2 +- Telegram/SourceFiles/history/history_widget.h | 2 +- .../view/history_view_corner_buttons.cpp | 5 +- .../view/history_view_corner_buttons.h | 2 +- .../history/view/history_view_list_widget.cpp | 80 +++++- .../history/view/history_view_list_widget.h | 5 +- .../view/history_view_pinned_section.cpp | 6 +- .../view/history_view_pinned_section.h | 4 +- .../view/history_view_replies_section.cpp | 228 ++++++++---------- .../view/history_view_replies_section.h | 40 +-- .../view/history_view_scheduled_section.cpp | 6 +- .../view/history_view_scheduled_section.h | 4 +- 15 files changed, 229 insertions(+), 175 deletions(-) diff --git a/Telegram/SourceFiles/api/api_unread_things.cpp b/Telegram/SourceFiles/api/api_unread_things.cpp index 9fc076973..5e8b624af 100644 --- a/Telegram/SourceFiles/api/api_unread_things.cpp +++ b/Telegram/SourceFiles/api/api_unread_things.cpp @@ -128,12 +128,12 @@ void UnreadThings::requestMentions( MTP_int(maxId), MTP_int(minId) )).done([=](const MTPmessages_Messages &result) { - _mentionsRequests.remove(history); - history->unreadMentions().addSlice(result, loaded); + _mentionsRequests.remove(entry); + entry->unreadMentions().addSlice(result, loaded); }).fail([=] { - _mentionsRequests.remove(history); + _mentionsRequests.remove(entry); }).send(); - _mentionsRequests.emplace(history, requestId); + _mentionsRequests.emplace(entry, requestId); } void UnreadThings::requestReactions( @@ -162,12 +162,12 @@ void UnreadThings::requestReactions( MTP_int(maxId), MTP_int(minId) )).done([=](const MTPmessages_Messages &result) { - _reactionsRequests.remove(history); - history->unreadReactions().addSlice(result, loaded); + _reactionsRequests.remove(entry); + entry->unreadReactions().addSlice(result, loaded); }).fail([=] { - _reactionsRequests.remove(history); + _reactionsRequests.remove(entry); }).send(); - _reactionsRequests.emplace(history, requestId); + _reactionsRequests.emplace(entry, requestId); } } // namespace UnreadThings diff --git a/Telegram/SourceFiles/data/data_changes.cpp b/Telegram/SourceFiles/data/data_changes.cpp index 58f973949..16b3fde77 100644 --- a/Telegram/SourceFiles/data/data_changes.cpp +++ b/Telegram/SourceFiles/data/data_changes.cpp @@ -271,6 +271,7 @@ void Changes::sendNotifications() { _historyChanges.sendNotifications(); _messageChanges.sendNotifications(); _entryChanges.sendNotifications(); + _topicChanges.sendNotifications(); } } // namespace Data diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 9def8115c..eb530da0d 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -914,7 +914,6 @@ void HistoryInner::paintEvent(QPaintEvent *e) { width(), std::min(st::msgMaxWidth / 2, width() / 2)); - const auto now = crl::now(); const auto historyDisplayedEmpty = _history->isDisplayedEmpty() && (!_migrated || _migrated->isDisplayedEmpty()); if (_botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) { @@ -1015,7 +1014,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { _widget->enqueueMessageHighlight(view); } } - session().data().reactions().poll(item, now); + session().data().reactions().poll(item, context.now); if (item->hasExtendedMediaPreview()) { session().api().views().pollExtendedMedia(item); } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 766ec38b9..9d0308461 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -5769,7 +5769,7 @@ bool HistoryWidget::cornerButtonsIgnoreVisibility() { return _a_show.animating(); } -bool HistoryWidget::cornerButtonsDownShown() { +std::optional HistoryWidget::cornerButtonsDownShown() { if (!_list || _firstLoadRequest) { return false; } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index e296c3eb2..91c1daede 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -328,7 +328,7 @@ private: Dialogs::Entry *cornerButtonsEntry() override; FullMsgId cornerButtonsCurrentId() override; bool cornerButtonsIgnoreVisibility() override; - bool cornerButtonsDownShown() override; + std::optional cornerButtonsDownShown() override; bool cornerButtonsUnreadMayBeShown() override; void checkSuggestToGigagroup(); diff --git a/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp b/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp index ab70d9e70..4fe297baf 100644 --- a/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp +++ b/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp @@ -251,8 +251,9 @@ void CornerButtons::updateUnreadThingsVisibility() { } void CornerButtons::updateJumpDownVisibility(std::optional counter) { - const auto shown = _delegate->cornerButtonsDownShown(); - updateVisibility(CornerButtonType::Down, shown); + if (const auto shown = _delegate->cornerButtonsDownShown()) { + updateVisibility(CornerButtonType::Down, *shown); + } if (counter) { down.widget->setUnreadCount(*counter); } diff --git a/Telegram/SourceFiles/history/view/history_view_corner_buttons.h b/Telegram/SourceFiles/history/view/history_view_corner_buttons.h index 4233744c3..8cdf0309e 100644 --- a/Telegram/SourceFiles/history/view/history_view_corner_buttons.h +++ b/Telegram/SourceFiles/history/view/history_view_corner_buttons.h @@ -53,7 +53,7 @@ public: [[nodiscard]] virtual Dialogs::Entry *cornerButtonsEntry() = 0; [[nodiscard]] virtual FullMsgId cornerButtonsCurrentId() = 0; [[nodiscard]] virtual bool cornerButtonsIgnoreVisibility() = 0; - [[nodiscard]] virtual bool cornerButtonsDownShown() = 0; + [[nodiscard]] virtual std::optional cornerButtonsDownShown() = 0; [[nodiscard]] virtual bool cornerButtonsUnreadMayBeShown() = 0; }; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index f72d2f26f..f9f953639 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/core_settings.h" #include "apiwrap.h" #include "api/api_who_reacted.h" +#include "api/api_views.h" #include "layout/layout_selection.h" #include "window/section_widget.h" #include "window/window_adaptive.h" @@ -54,6 +55,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/premium_preview_box.h" #include "boxes/peers/edit_participant_box.h" #include "data/data_session.h" +#include "data/data_sponsored_messages.h" +#include "data/data_changes.h" #include "data/data_folder.h" #include "data/data_media_types.h" #include "data/data_document.h" @@ -350,6 +353,13 @@ ListWidget::ListWidget( itemRemoved(item); }, lifetime()); + using MessageUpdateFlag = Data::MessageUpdate::Flag; + session().changes().realtimeMessageUpdates( + MessageUpdateFlag::NewUnreadReaction + ) | rpl::start_with_next([=](const Data::MessageUpdate &update) { + maybeMarkReactionsRead(update.item); + }, lifetime()); + session().data().itemVisibilityQueries( ) | rpl::start_with_next([=]( const Data::Session::ItemVisibilityQuery &query) { @@ -787,7 +797,6 @@ void ListWidget::visibleTopBottomUpdated( void ListWidget::applyUpdatedScrollState() { checkMoveToOtherViewer(); - _delegate->listVisibleItemsChanged(collectVisibleItems()); } void ListWidget::updateVisibleTopItem() { @@ -1764,7 +1773,15 @@ void ListWidget::paintEvent(QPaintEvent *e) { return; } + auto readTill = (HistoryItem*)nullptr; + auto readContents = base::flat_set>(); const auto guard = gsl::finally([&] { + if (readTill) { + _delegate->listMarkReadTill(readTill); + } + if (!readContents.empty()) { + _delegate->listMarkContentsRead(readContents); + } _userpicsCache.clear(); }); @@ -1787,23 +1804,61 @@ void ListWidget::paintEvent(QPaintEvent *e) { if (from != end(_items)) { _reactionsManager->startEffectsCollection(); + const auto session = &controller()->session(); auto top = itemTop(from->get()); auto context = preparePaintContext(clip).translated(0, -top); p.translate(0, top); const auto &sendingAnimation = _controller->sendingAnimation(); for (auto i = from; i != to; ++i) { const auto view = *i; - if (!sendingAnimation.hasAnimatedMessage(view->data())) { + const auto item = view->data(); + const auto height = view->height(); + if (!sendingAnimation.hasAnimatedMessage(item)) { context.reactionInfo = _reactionsManager->currentReactionPaintInfo(); context.outbg = view->hasOutLayout(); context.selection = itemRenderSelection(view); view->draw(p, context); } + const auto isSponsored = item->isSponsored(); + const auto isUnread = _delegate->listElementShownUnread(view) + && item->isRegular(); + const auto withReaction = item->hasUnreadReaction(); + const auto yShown = [&](int y) { + return (_visibleBottom >= y && _visibleTop <= y); + }; + const auto markShown = isSponsored + ? view->markSponsoredViewed(_visibleBottom - top) + : withReaction + ? yShown(top + context.reactionInfo->position.y()) + : isUnread + ? yShown(top + height) + : yShown(top + height / 2); + if (markShown) { + if (isSponsored) { + session->data().sponsoredMessages().view( + item->fullId()); + } else if (isUnread) { + readTill = item; + } + if (item->hasViews()) { + session->api().views().scheduleIncrement(item); + } + if (withReaction) { + readContents.insert(item); + } else if (item->isUnreadMention() + && !item->isUnreadMedia()) { + readContents.insert(item); + _highlighter.enqueue(view); + } + } + session->data().reactions().poll(item, context.now); + if (item->hasExtendedMediaPreview()) { + session->api().views().pollExtendedMedia(item); + } _reactionsManager->recordCurrentReactionEffect( - view->data()->fullId(), + item->fullId(), QPoint(0, top)); - const auto height = view->height(); top += height; context.translate(0, -height); p.translate(0, height); @@ -1847,7 +1902,7 @@ void ListWidget::paintEvent(QPaintEvent *e) { auto &v = _sponsoredUserpics[itemId.msg]; if (!info->customUserpic.isCurrentView(v)) { v = info->customUserpic.createView(); - info->customUserpic.load(&session(), itemId); + info->customUserpic.load(session, itemId); } } } @@ -1909,6 +1964,21 @@ void ListWidget::paintEvent(QPaintEvent *e) { } } +void ListWidget::maybeMarkReactionsRead(not_null item) { + const auto view = viewForItem(item); + if (!view) { + return; + } + const auto top = itemTop(view); + const auto reactionCenter + = view->reactionButtonParameters({}, {}).center.y(); + if (top + reactionCenter < _visibleTop + || top + view->height() > _visibleBottom) { + return; + } + _delegate->listMarkContentsRead({ item }); +} + bool ListWidget::eventHook(QEvent *e) { if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index aeabfc562..dfdd2dd0f 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -100,7 +100,9 @@ public: not_null first, not_null second) = 0; virtual void listSelectionChanged(SelectedItems &&items) = 0; - virtual void listVisibleItemsChanged(HistoryItemsList &&items) = 0; + virtual void listMarkReadTill(not_null item) = 0; + virtual void listMarkContentsRead( + const base::flat_set> &items) = 0; virtual MessagesBarData listMessagesBar( const std::vector> &elements) = 0; virtual void listContentRefreshed() = 0; @@ -529,6 +531,7 @@ private: void scrollToAnimationCallback(FullMsgId attachToId, int relativeTo); void startItemRevealAnimations(); void revealItemsCallback(); + void maybeMarkReactionsRead(not_null item); void startMessageSendingAnimation(not_null item); void showPremiumStickerTooltip( diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index 7ae95e74b..defd0887e 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -636,7 +636,11 @@ void PinnedWidget::listSelectionChanged(SelectedItems &&items) { _topBar->showSelected(state); } -void PinnedWidget::listVisibleItemsChanged(HistoryItemsList &&items) { +void PinnedWidget::listMarkReadTill(not_null item) { +} + +void PinnedWidget::listMarkContentsRead( + const base::flat_set> &items) { } MessagesBarData PinnedWidget::listMessagesBar( diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.h b/Telegram/SourceFiles/history/view/history_view_pinned_section.h index 9b370f39c..a1008c735 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.h @@ -90,7 +90,9 @@ public: not_null first, not_null second) override; void listSelectionChanged(SelectedItems &&items) override; - void listVisibleItemsChanged(HistoryItemsList &&items) override; + void listMarkReadTill(not_null item) override; + void listMarkContentsRead( + const base::flat_set> &items) override; MessagesBarData listMessagesBar( const std::vector> &elements) override; void listContentRefreshed() override; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index ae661b81e..66f3c3e7b 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_schedule_box.h" #include "history/view/history_view_pinned_bar.h" #include "history/view/history_view_sticker_toast.h" +#include "history/view/history_view_cursor_state.h" #include "history/history.h" #include "history/history_drag_area.h" #include "history/history_item_components.h" @@ -212,9 +213,10 @@ RepliesWidget::RepliesWidget( this, controller->chatStyle()->value(lifetime(), st::historyScroll), false)) -, _scrollDown( +, _cornerButtons( _scroll.get(), - controller->chatStyle()->value(lifetime(), st::historyToDown)) + controller->chatStyle(), + static_cast(this)) , _readRequestTimer([=] { sendReadTillRequest(); }) { controller->chatStyle()->paletteChanged( ) | rpl::start_with_next([=] { @@ -335,8 +337,8 @@ RepliesWidget::RepliesWidget( controller->showBackFromStack(); } } - while (update.item == _replyReturn) { - calculateNextReplyReturn(); + while (update.item == _cornerButtons.replyReturn()) { + _cornerButtons.calculateNextReplyReturn(); } }, lifetime()); @@ -347,7 +349,6 @@ RepliesWidget::RepliesWidget( _inner->update(); }, lifetime()); - setupScrollDownButton(); setupComposeControls(); orderWidgets(); } @@ -469,14 +470,34 @@ void RepliesWidget::setupTopicViewer() { _inner->update(); } }, lifetime()); + + if (_topic) { + subscribeToTopic(); + } +} + +void RepliesWidget::subscribeToTopic() { + using TopicUpdateFlag = Data::TopicUpdate::Flag; + session().changes().topicUpdates( + _topic, + (TopicUpdateFlag::UnreadMentions + | TopicUpdateFlag::UnreadReactions) + ) | rpl::start_with_next([=](const Data::TopicUpdate &update) { + _cornerButtons.updateUnreadThingsVisibility(); + }, _topicLifetime); } void RepliesWidget::setTopic(Data::ForumTopic *topic) { - if (_topic != topic) { - _topic = topic; - refreshReplies(); - refreshTopBarActiveChat(); - if (_topic && _rootView) { + if (_topic == topic) { + return; + } + _topicLifetime.destroy(); + _topic = topic; + refreshReplies(); + refreshTopBarActiveChat(); + if (_topic) { + subscribeToTopic(); + if (_rootView) { _rootView = nullptr; _rootViewHeight = 0; updateControlsGeometry(); @@ -684,7 +705,8 @@ void RepliesWidget::setupComposeControls() { _composeControls->lockShowStarts( ) | rpl::start_with_next([=] { - updateScrollDownVisibility(); + _cornerButtons.updateJumpDownVisibility(); + _cornerButtons.updateUnreadThingsVisibility(); }, lifetime()); _composeControls->viewportEvents( @@ -919,48 +941,21 @@ std::optional RepliesWidget::writeRestriction() const { void RepliesWidget::pushReplyReturn(not_null item) { if (item->history() == _history && item->inThread(_rootId)) { - _replyReturns.push_back(item->id); - } else { - return; - } - _replyReturn = item; - updateScrollDownVisibility(); -} - -void RepliesWidget::restoreReplyReturns(const std::vector &list) { - _replyReturns = list; - computeCurrentReplyReturn(); - if (!_replyReturn) { - calculateNextReplyReturn(); - } -} - -void RepliesWidget::computeCurrentReplyReturn() { - _replyReturn = _replyReturns.empty() - ? nullptr - : _history->owner().message(_history->peer, _replyReturns.back()); -} - -void RepliesWidget::calculateNextReplyReturn() { - _replyReturn = nullptr; - while (!_replyReturns.empty() && !_replyReturn) { - _replyReturns.pop_back(); - computeCurrentReplyReturn(); - } - if (!_replyReturn) { - updateScrollDownVisibility(); + _cornerButtons.pushReplyReturn(item); } } void RepliesWidget::checkReplyReturns() { const auto currentTop = _scroll->scrollTop(); - for (; _replyReturn != nullptr; calculateNextReplyReturn()) { - const auto position = _replyReturn->position(); + while (const auto replyReturn = _cornerButtons.replyReturn()) { + const auto position = replyReturn->position(); const auto scrollTop = _inner->scrollTopForPosition(position); - const auto scrolledBelow = scrollTop + const auto below = scrollTop ? (currentTop >= std::min(*scrollTop, _scroll->scrollTopMax())) : _inner->isBelowPosition(position); - if (!scrolledBelow) { + if (below) { + _cornerButtons.calculateNextReplyReturn(); + } else { break; } } @@ -1057,6 +1052,10 @@ void RepliesWidget::send(Api::SendOptions options) { return; } + if (!options.scheduled) { + _cornerButtons.clearReplyReturns(); + } + const auto webPageId = _composeControls->webPageId(); auto message = ApiWrap::MessageToSend(prepareSendAction(options)); @@ -1355,24 +1354,9 @@ MsgId RepliesWidget::replyToId() const { : _rootId; } -void RepliesWidget::setupScrollDownButton() { - _scrollDown->setClickedCallback([=] { - scrollDownClicked(); - }); - base::install_event_filter(_scrollDown, [=](not_null event) { - if (event->type() != QEvent::Wheel) { - return base::EventFilterResult::Continue; - } - return _scroll->viewportEvent(event) - ? base::EventFilterResult::Cancel - : base::EventFilterResult::Continue; - }); - updateScrollDownVisibility(); -} - void RepliesWidget::refreshUnreadCountBadge(std::optional count) { if (count.has_value()) { - _scrollDown->setUnreadCount(*count); + _cornerButtons.updateJumpDownVisibility(count); } else if (!_readRequestTimer.isActive() && !_readRequestId) { reloadUnreadCountIfNeeded(); } @@ -1389,14 +1373,39 @@ void RepliesWidget::reloadUnreadCountIfNeeded() { } } -void RepliesWidget::scrollDownClicked() { - if (base::IsCtrlPressed()) { - showAtEnd(); - } else if (_replyReturn) { - showAtPosition(_replyReturn->position()); - } else { - showAtEnd(); +void RepliesWidget::cornerButtonsShowAtPosition( + Data::MessagePosition position) { + showAtPosition(position); +} + +Dialogs::Entry *RepliesWidget::cornerButtonsEntry() { + return _topic; +} + +FullMsgId RepliesWidget::cornerButtonsCurrentId() { + return _lastShownAt; +} + +bool RepliesWidget::cornerButtonsIgnoreVisibility() { + return animatingShow(); +} + +std::optional RepliesWidget::cornerButtonsDownShown() { + if (_composeControls->isLockPresent()) { + return false; } + const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; + if (top < _scroll->scrollTopMax() || _cornerButtons.replyReturn()) { + return true; + } else if (_inner->loadedAtBottomKnown()) { + return !_inner->loadedAtBottom(); + } + return std::nullopt; +} + +bool RepliesWidget::cornerButtonsUnreadMayBeShown() { + return _inner->loadedAtBottomKnown() + && !_composeControls->isLockPresent(); } void RepliesWidget::showAtStart() { @@ -1435,9 +1444,7 @@ bool RepliesWidget::showAtPositionNow( : nullptr; const auto use = item ? item->position() : position; if (const auto scrollTop = _inner->scrollTopForPosition(use)) { - while (_replyReturn && use.fullId.msg == _replyReturn->id) { - calculateNextReplyReturn(); - } + _cornerButtons.skipReplyReturn(use.fullId); const auto currentScrollTop = _scroll->scrollTop(); const auto wanted = std::clamp( *scrollTop, @@ -1452,6 +1459,7 @@ bool RepliesWidget::showAtPositionNow( ? AnimatedScroll::Part : AnimatedScroll::Full; _inner->scrollTo(wanted, use, scrollDelta, type); + _lastShownAt = use.fullId; if (use != Data::MaxMessagePosition && use != Data::UnreadMessagePosition) { _inner->highlightMessage(use.fullId); @@ -1464,57 +1472,6 @@ bool RepliesWidget::showAtPositionNow( return false; } -void RepliesWidget::updateScrollDownVisibility() { - if (animatingShow()) { - return; - } - - const auto scrollDownIsVisible = [&]() -> std::optional { - if (_composeControls->isLockPresent()) { - return false; - } - const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; - if (top < _scroll->scrollTopMax() || _replyReturn) { - return true; - } else if (_inner->loadedAtBottomKnown()) { - return !_inner->loadedAtBottom(); - } - return std::nullopt; - }; - const auto scrollDownIsShown = scrollDownIsVisible(); - if (!scrollDownIsShown) { - return; - } - if (_scrollDownIsShown != *scrollDownIsShown) { - _scrollDownIsShown = *scrollDownIsShown; - _scrollDownShown.start( - [=] { updateScrollDownPosition(); }, - _scrollDownIsShown ? 0. : 1., - _scrollDownIsShown ? 1. : 0., - st::historyToDownDuration); - } -} - -void RepliesWidget::updateScrollDownPosition() { - // _scrollDown is a child widget of _scroll, not me. - auto top = anim::interpolate( - 0, - _scrollDown->height() + st::historyToDownPosition.y(), - _scrollDownShown.value(_scrollDownIsShown ? 1. : 0.)); - _scrollDown->moveToRight( - st::historyToDownPosition.x(), - _scroll->height() - top); - auto shouldBeHidden = !_scrollDownIsShown && !_scrollDownShown.animating(); - if (shouldBeHidden != _scrollDown->isHidden()) { - _scrollDown->setVisible(!shouldBeHidden); - } -} - -void RepliesWidget::scrollDownAnimationFinish() { - _scrollDownShown.stop(); - updateScrollDownPosition(); -} - void RepliesWidget::updateAdaptiveLayout() { _topBarShadow->moveToLeft( controller()->adaptive().isOneColumn() ? 0 : st::lineWidth, @@ -1662,7 +1619,8 @@ bool RepliesWidget::showMessage( if (!originMessage) { return false; } - const auto originItem = (!originMessage || _replyReturn == originMessage) + const auto originItem = (!originMessage + || _cornerButtons.replyReturn() == originMessage) ? nullptr : originMessage; showAtPosition(message->position(), originItem); @@ -1685,7 +1643,7 @@ void RepliesWidget::replyToMessage(FullMsgId itemId) { void RepliesWidget::saveState(not_null memento) { memento->setReplies(_replies); - memento->setReplyReturns(_replyReturns); + memento->setReplyReturns(_cornerButtons.replyReturns()); _inner->saveState(memento->list()); } @@ -1740,7 +1698,7 @@ void RepliesWidget::restoreState(not_null memento) { } else if (!_replies) { refreshReplies(); } - restoreReplyReturns(memento->replyReturns()); + _cornerButtons.setReplyReturns(memento->replyReturns()); _inner->restoreState(memento->list()); if (const auto highlight = memento->getHighlightId()) { const auto position = Data::MessagePosition{ @@ -1811,7 +1769,7 @@ void RepliesWidget::updateControlsGeometry() { _composeControls->move(0, bottom - controlsHeight); _composeControls->setAutocompleteBoundingRect(_scroll->geometry()); - updateScrollDownPosition(); + _cornerButtons.updatePositions(); } void RepliesWidget::paintEvent(QPaintEvent *e) { @@ -1842,7 +1800,8 @@ void RepliesWidget::updateInnerVisibleArea() { const auto scrollTop = _scroll->scrollTop(); _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); updatePinnedVisibility(); - updateScrollDownVisibility(); + _cornerButtons.updateJumpDownVisibility(); + _cornerButtons.updateUnreadThingsVisibility(); } void RepliesWidget::updatePinnedVisibility() { @@ -2024,11 +1983,16 @@ void RepliesWidget::readTill(not_null item) { } } -void RepliesWidget::listVisibleItemsChanged(HistoryItemsList &&items) { - const auto reversed = ranges::views::reverse(items); - const auto good = ranges::find_if(reversed, &HistoryItem::isRegular); - if (good != end(reversed)) { - readTill(*good); +void RepliesWidget::listMarkReadTill(not_null item) { + if (true/*doWeReadServerHistory()*/) { // #TODO forum active + readTill(item); + } +} + +void RepliesWidget::listMarkContentsRead( + const base::flat_set> &items) { + if (true/*doWeReadMentions()*/) { // #TODO forum active + session().api().markContentsRead(items); } } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index 80843ff07..50020e753 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/section_widget.h" #include "window/section_memento.h" +#include "history/view/history_view_corner_buttons.h" #include "history/view/history_view_list_widget.h" #include "data/data_messages.h" #include "base/timer.h" @@ -67,7 +68,8 @@ class StickerToast; class RepliesWidget final : public Window::SectionWidget - , private ListDelegate { + , private ListDelegate + , private CornerButtonsDelegate { public: RepliesWidget( QWidget *parent, @@ -128,7 +130,9 @@ public: not_null first, not_null second) override; void listSelectionChanged(SelectedItems &&items) override; - void listVisibleItemsChanged(HistoryItemsList &&items) override; + void listMarkReadTill(not_null item) override; + void listMarkContentsRead( + const base::flat_set> &items) override; MessagesBarData listMessagesBar( const std::vector> &elements) override; void listContentRefreshed() override; @@ -147,6 +151,15 @@ public: ->rpl::producer override; void listShowPremiumToast(not_null document) override; + // CornerButtonsDelegate delegate. + void cornerButtonsShowAtPosition( + Data::MessagePosition position) override; + Dialogs::Entry *cornerButtonsEntry() override; + FullMsgId cornerButtonsCurrentId() override; + bool cornerButtonsIgnoreVisibility() override; + std::optional cornerButtonsDownShown() override; + bool cornerButtonsUnreadMayBeShown() override; + protected: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; @@ -181,16 +194,13 @@ private: void setupRoot(); void setupRootView(); void setupTopicViewer(); + void subscribeToTopic(); void setTopic(Data::ForumTopic *topic); void setupDragArea(); void sendReadTillRequest(); void readTill(not_null item); - void setupScrollDownButton(); - void scrollDownClicked(); void scrollDownAnimationFinish(); - void updateScrollDownVisibility(); - void updateScrollDownPosition(); void updatePinnedVisibility(); void confirmDeleteSelected(); @@ -216,9 +226,6 @@ private: void orderWidgets(); void pushReplyReturn(not_null item); - void computeCurrentReplyReturn(); - void calculateNextReplyReturn(); - void restoreReplyReturns(const std::vector &list); void checkReplyReturns(); void recountChatWidth(); void replyToMessage(FullMsgId itemId); @@ -295,12 +302,9 @@ private: std::unique_ptr _scroll; std::unique_ptr _stickerToast; - std::vector _replyReturns; - HistoryItem *_replyReturn = nullptr; - - Ui::Animations::Simple _scrollDownShown; - bool _scrollDownIsShown = false; - object_ptr _scrollDown; + FullMsgId _lastShownAt; + HistoryView::CornerButtons _cornerButtons; + rpl::lifetime _topicLifetime; bool _choosingAttach = false; @@ -351,10 +355,10 @@ public: return _replies; } - void setReplyReturns(const std::vector &list) { + void setReplyReturns(const QVector &list) { _replyReturns = list; } - const std::vector &replyReturns() const { + const QVector &replyReturns() const { return _replyReturns; } @@ -373,7 +377,7 @@ private: const MsgId _highlightId = 0; ListMemento _list; std::shared_ptr _replies; - std::vector _replyReturns; + QVector _replyReturns; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 55fc9114f..c565be015 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -1258,7 +1258,11 @@ void ScheduledWidget::listSelectionChanged(SelectedItems &&items) { _topBar->showSelected(state); } -void ScheduledWidget::listVisibleItemsChanged(HistoryItemsList &&items) { +void ScheduledWidget::listMarkReadTill(not_null item) { +} + +void ScheduledWidget::listMarkContentsRead( + const base::flat_set> &items) { } MessagesBarData ScheduledWidget::listMessagesBar( diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h index a2787280e..6d09fb48e 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h @@ -112,7 +112,9 @@ public: not_null first, not_null second) override; void listSelectionChanged(SelectedItems &&items) override; - void listVisibleItemsChanged(HistoryItemsList &&items) override; + void listMarkReadTill(not_null item) override; + void listMarkContentsRead( + const base::flat_set> &items) override; MessagesBarData listMessagesBar( const std::vector> &elements) override; void listContentRefreshed() override;