Respect window active state on mark as read.

This commit is contained in:
John Preston 2022-11-02 20:03:42 +04:00
parent ff352d7647
commit 9d4840c0de
23 changed files with 156 additions and 107 deletions

View file

@ -57,11 +57,7 @@ void SendBotCallbackData(
const auto bot = item->getMessageBot();
const auto fullId = item->fullId();
const auto getButton = [=] {
return HistoryMessageMarkupButton::Get(
owner,
fullId,
row,
column);
return HistoryMessageMarkupButton::Get(owner, fullId, row, column);
};
const auto button = getButton();
if (!button || button->requestId) {

View file

@ -194,7 +194,7 @@ object_ptr<ShareBox> ShareInviteLinkBox(
showToast(tr::lng_share_done(tr::now));
};
auto filterCallback = [](not_null<Data::Thread*> thread) {
return thread->canWrite(); // #TODO forum share
return thread->canWrite();
};
const auto scheduleStyle = [&] {

View file

@ -255,9 +255,6 @@ void Forum::requestSomeStale() {
const auto rootId = *i;
i = _staleRootIds.erase(i);
if (_topicRequests.contains(rootId)) {
continue;
}
rootIds.push_back(MTP_int(rootId));
if (rootIds.size() == kStalePerRequest) {
break;
@ -279,10 +276,12 @@ void Forum::requestSomeStale() {
channel()->inputChannel,
MTP_vector<MTPint>(rootIds))
).done([=](const MTPmessages_ForumTopics &result) {
_staleRequestId = 0;
applyReceivedTopics(result);
call();
finish();
}).fail([=] {
_staleRequestId = 0;
call();
finish();
}).send();
@ -301,35 +300,19 @@ void Forum::finishTopicRequest(MsgId rootId) {
}
void Forum::requestTopic(MsgId rootId, Fn<void()> done) {
_staleRootIds.remove(rootId);
auto &request = _topicRequests[rootId];
if (done) {
request.callbacks.push_back(std::move(done));
}
if (request.id) {
return;
if (!request.id
&& _staleRootIds.emplace(rootId).second
&& (_staleRootIds.size() == 1)) {
crl::on_main(&session(), [peer = channel()] {
if (const auto forum = peer->forum()) {
forum->requestSomeStale();
}
});
}
const auto call = [=] {
finishTopicRequest(rootId);
};
const auto type = Histories::RequestType::History;
auto &histories = owner().histories();
request.id = histories.sendRequest(_history, type, [=](
Fn<void()> finish) {
return session().api().request(
MTPchannels_GetForumTopicsByID(
channel()->inputChannel,
MTP_vector<MTPint>(1, MTP_int(rootId.bare)))
).done([=](const MTPmessages_ForumTopics &result) {
applyReceivedTopics(result);
call();
finish();
}).fail([=] {
call();
finish();
}).send();
});
}
ForumTopic *Forum::applyTopicAdded(

View file

@ -86,7 +86,7 @@ RepliesList::RepliesList(not_null<History*> history, MsgId rootId)
| MessageUpdate::Flag::Destroyed
) | rpl::filter([=](const MessageUpdate &update) {
return applyUpdate(update);
}) | rpl::to_empty | rpl::start_to_stream(_listChanges, _lifetime);
}) | rpl::to_empty | rpl::start_to_stream(_instantChanges, _lifetime);
_history->owner().channelDifferenceTooLong(
) | rpl::filter([=](not_null<ChannelData*> channel) {
@ -114,12 +114,18 @@ rpl::producer<MessagesSlice> RepliesList::source(
auto lifetime = rpl::lifetime();
const auto viewer = lifetime.make_state<Viewer>();
const auto push = [=] {
viewer->scheduled = false;
if (buildFromData(viewer)) {
appendClientSideMessages(viewer->slice);
consumer.put_next_copy(viewer->slice);
if (viewer->scheduled) {
viewer->scheduled = false;
if (buildFromData(viewer)) {
appendClientSideMessages(viewer->slice);
consumer.put_next_copy(viewer->slice);
}
}
};
const auto pushInstant = [=] {
viewer->scheduled = true;
push();
};
const auto pushDelayed = [=] {
if (!viewer->scheduled) {
viewer->scheduled = true;
@ -144,7 +150,10 @@ rpl::producer<MessagesSlice> RepliesList::source(
_listChanges.events(
) | rpl::start_with_next(pushDelayed, lifetime);
push();
_instantChanges.events(
) | rpl::start_with_next(pushInstant, lifetime);
pushInstant();
return lifetime;
};
}

View file

@ -105,6 +105,7 @@ private:
std::optional<int> _skippedAfter;
rpl::variable<std::optional<int>> _fullCount;
rpl::event_stream<> _listChanges;
rpl::event_stream<> _instantChanges;
std::optional<MsgId> _loadingAround;
rpl::variable<std::optional<int>> _unreadCount;
MsgId _inboxReadTillId = 0;

View file

@ -975,10 +975,10 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
auto readTill = (HistoryItem*)nullptr;
auto readContents = base::flat_set<not_null<HistoryItem*>>();
const auto guard = gsl::finally([&] {
if (readTill && _widget->doWeReadServerHistory()) {
if (readTill && _widget->markingMessagesRead()) {
session().data().histories().readInboxTill(readTill);
}
if (!readContents.empty() && _widget->doWeReadMentions()) {
if (!readContents.empty() && _widget->markingContentsRead()) {
session().api().markContentsRead(readContents);
}
_userpicsCache.clear();
@ -2796,8 +2796,8 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) {
}
}
void HistoryInner::checkHistoryActivation() {
if (!_widget->doWeReadServerHistory()) {
void HistoryInner::checkActivation() {
if (!_widget->markingMessagesRead()) {
return;
}
adjustCurrent(_visibleAreaBottom);
@ -3020,7 +3020,7 @@ void HistoryInner::visibleAreaUpdated(int top, int bottom) {
from,
till);
}
checkHistoryActivation();
checkActivation();
_emojiInteractions->visibleAreaUpdated(
_visibleAreaTop,

View file

@ -108,7 +108,7 @@ public:
void setItemsRevealHeight(int revealHeight);
void changeItemsRevealHeight(int revealHeight);
void checkHistoryActivation();
void checkActivation();
void recountHistoryGeometry();
void updateSize();

View file

@ -2879,10 +2879,10 @@ void HistoryWidget::newItemAdded(not_null<HistoryItem*> item) {
}
// If we get here in non-resized state we can't rely on results of
// doWeReadServerHistory() and mark chat as read.
// markingMessagesRead() and mark chat as read.
// If we receive N messages being not at bottom:
// - on first message we set unreadcount += 1, firstUnreadMessage.
// - on second we get wrong doWeReadServerHistory() and read both.
// - on second we get wrong markingMessagesRead() and read both.
session().data().sendHistoryChangeNotifications();
if (item->isSending()) {
@ -2892,7 +2892,7 @@ void HistoryWidget::newItemAdded(not_null<HistoryItem*> item) {
}
if (item->showNotification()) {
destroyUnreadBar();
if (doWeReadServerHistory()) {
if (markingMessagesRead()) {
if (item->isUnreadMention() && !item->isUnreadMedia()) {
session().api().markContentsRead(item);
}
@ -2916,7 +2916,7 @@ void HistoryWidget::maybeMarkReactionsRead(not_null<HistoryItem*> item) {
}
const auto view = item->mainView();
const auto itemTop = _list->itemTop(view);
if (itemTop <= 0 || !doWeReadMentions()) {
if (itemTop <= 0 || !markingContentsRead()) {
return;
}
const auto reactionCenter
@ -3050,7 +3050,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
_preloadDownRequest = 0;
preloadHistoryIfNeeded();
if (_history->loadedAtBottom()) {
checkHistoryActivation();
checkActivation();
}
} else if (_firstLoadRequest == requestId) {
if (toMigrated) {
@ -3114,23 +3114,23 @@ void HistoryWidget::windowShown() {
updateControlsGeometry();
}
bool HistoryWidget::doWeReadServerHistory() const {
return doWeReadMentions() && !session().supportMode();
bool HistoryWidget::markingMessagesRead() const {
return markingContentsRead() && !session().supportMode();
}
bool HistoryWidget::doWeReadMentions() const {
bool HistoryWidget::markingContentsRead() const {
return _history
&& _list
&& _historyInited
&& !_firstLoadRequest
&& !_delayedShowAtRequest
&& !_a_show.animating()
&& controller()->widget()->doWeMarkAsRead();
&& controller()->widget()->markingAsRead();
}
void HistoryWidget::checkHistoryActivation() {
void HistoryWidget::checkActivation() {
if (_list) {
_list->checkHistoryActivation();
_list->checkActivation();
}
}
@ -3980,7 +3980,7 @@ void HistoryWidget::doneShow() {
if (_requestsBar) {
_requestsBar->finishAnimating();
}
checkHistoryActivation();
checkActivation();
controller()->widget()->setInnerFocus();
_preserveScrollTop = false;
checkSuggestToGigagroup();

View file

@ -129,10 +129,10 @@ public:
void setGeometryWithTopMoved(const QRect &newGeometry, int topDelta);
void windowShown();
[[nodiscard]] bool doWeReadServerHistory() const;
[[nodiscard]] bool doWeReadMentions() const;
[[nodiscard]] bool markingMessagesRead() const;
[[nodiscard]] bool markingContentsRead() const;
bool skipItemRepaint();
void checkHistoryActivation();
void checkActivation();
void leaveToChildEvent(QEvent *e, QWidget *child) override;

View file

@ -429,11 +429,13 @@ not_null<ListDelegate*> ListWidget::delegate() const {
void ListWidget::refreshViewer() {
_viewerLifetime.destroy();
_refreshingViewer = true;
_delegate->listSource(
_aroundPosition,
_idsLimit,
_idsLimit
) | rpl::start_with_next([=](Data::MessagesSlice &&slice) {
_refreshingViewer = false;
std::swap(_slice, slice);
refreshRows(slice);
}, _viewerLifetime);
@ -453,6 +455,7 @@ void ListWidget::refreshRows(const Data::MessagesSlice &old) {
) - 1;
auto destroyingBarElement = _bar.element;
_resizePending = true;
_items.clear();
_items.reserve(_slice.ids.size());
auto nearestIndex = -1;
@ -486,7 +489,7 @@ void ListWidget::refreshRows(const Data::MessagesSlice &old) {
if (_emptyInfo) {
_emptyInfo->setVisible(isEmpty());
}
_delegate->listContentRefreshed();
checkActivation();
}
std::optional<int> ListWidget::scrollTopForPosition(
@ -1728,6 +1731,7 @@ void ListWidget::updateItemsGeometry() {
void ListWidget::updateSize() {
resizeToWidth(width(), _minHeight);
updateVisibleTopItem();
_resizePending = false;
}
void ListWidget::resizeToWidth(int newWidth, int minHeight) {
@ -1936,6 +1940,43 @@ Ui::ChatPaintContext ListWidget::preparePaintContext(
});
}
bool ListWidget::markingContentsRead() const {
return _showFinished
&& !_refreshingViewer
&& controller()->widget()->markingAsRead();
}
bool ListWidget::markingMessagesRead() const {
return markingContentsRead() && !session().supportMode();
}
void ListWidget::showFinished() {
_showFinished = true;
checkActivation();
}
void ListWidget::checkActivation() {
if (_resizePending
|| _visibleTop >= _visibleBottom
|| !markingMessagesRead()) {
return;
}
const auto h = height();
const auto t = _visibleTop;
const auto b = _visibleBottom;
const auto r = _itemsRevealHeight;
auto a = 0;
for (const auto &view : _itemRevealPending) {
a += view->height();
}
for (const auto &view : ranges::views::reverse(_items)) {
const auto bottom = itemTop(view) + view->height();
if (_visibleBottom + _itemsRevealHeight >= bottom) {
delegate()->listMarkReadTill(view->data());
}
}
}
void ListWidget::paintEvent(QPaintEvent *e) {
if (Ui::skipPaintEvent(this, e)) {
return;
@ -1944,10 +1985,10 @@ void ListWidget::paintEvent(QPaintEvent *e) {
auto readTill = (HistoryItem*)nullptr;
auto readContents = base::flat_set<not_null<HistoryItem*>>();
const auto guard = gsl::finally([&] {
if (readTill) {
if (readTill && markingMessagesRead()) {
_delegate->listMarkReadTill(readTill);
}
if (!readContents.empty()) {
if (!readContents.empty() && markingContentsRead()) {
_delegate->listMarkContentsRead(readContents);
}
_userpicsCache.clear();
@ -2137,7 +2178,7 @@ void ListWidget::paintEvent(QPaintEvent *e) {
void ListWidget::maybeMarkReactionsRead(not_null<HistoryItem*> item) {
const auto view = viewForItem(item);
if (!view) {
if (!view || !markingContentsRead()) {
return;
}
const auto top = itemTop(view);
@ -3592,8 +3633,10 @@ void ListWidget::refreshAttachmentsAtIndex(int index) {
void ListWidget::refreshAttachmentsFromTill(int from, int till) {
Expects(from >= 0 && from <= till && till <= int(_items.size()));
if (from == till) {
const auto guard = gsl::finally([&] {
updateSize();
});
if (from == till) {
return;
}
auto view = _items[from].get();

View file

@ -245,6 +245,11 @@ public:
[[nodiscard]] bool loadedAtBottom() const;
[[nodiscard]] bool isEmpty() const;
[[nodiscard]] bool markingContentsRead() const;
[[nodiscard]] bool markingMessagesRead() const;
void showFinished();
void checkActivation();
[[nodiscard]] bool hasCopyRestriction(HistoryItem *item = nullptr) const;
[[nodiscard]] bool hasCopyMediaRestriction(
not_null<HistoryItem*> item) const;
@ -692,6 +697,9 @@ private:
Qt::CursorShape _cursor = style::cur_default;
bool _isChatWide = false;
bool _refreshingViewer = false;
bool _showFinished = false;
bool _resizePending = false;
// _menu must be destroyed before _whoReactedMenuLifetime.
rpl::lifetime _whoReactedMenuLifetime;

View file

@ -261,6 +261,10 @@ QPixmap PinnedWidget::grabForShowAnimation(const Window::SectionSlideParams &par
return result;
}
void PinnedWidget::checkActivation() {
_inner->checkActivation();
}
void PinnedWidget::doSetInnerFocus() {
_inner->setFocus();
}
@ -421,6 +425,7 @@ void PinnedWidget::showAnimatedHook(
void PinnedWidget::showFinishedHook() {
_topBar->setAnimatingMode(false);
_inner->showFinished();
}
bool PinnedWidget::floatPlayerHandleWheelEvent(QEvent *e) {

View file

@ -138,7 +138,7 @@ public:
bool cornerButtonsUnreadMayBeShown() override;
bool cornerButtonsHas(CornerButtonType type) override;
protected:
private:
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
@ -146,8 +146,8 @@ protected:
const Window::SectionSlideParams &params) override;
void showFinishedHook() override;
void doSetInnerFocus() override;
void checkActivation() override;
private:
void onScroll();
void updateInnerVisibleArea();
void updateControlsGeometry();

View file

@ -1872,6 +1872,10 @@ QPixmap RepliesWidget::grabForShowAnimation(const Window::SectionSlideParams &pa
return result;
}
void RepliesWidget::checkActivation() {
_inner->checkActivation();
}
void RepliesWidget::doSetInnerFocus() {
if (!_inner->getSelectedText().rich.text.isEmpty()
|| !_inner->getSelectedItems().empty()
@ -2236,6 +2240,7 @@ void RepliesWidget::showFinishedHook() {
} else {
_composeControls->showFinished();
}
_inner->showFinished();
if (_rootView) {
_rootView->show();
}
@ -2338,16 +2343,12 @@ void RepliesWidget::listSelectionChanged(SelectedItems &&items) {
}
void RepliesWidget::listMarkReadTill(not_null<HistoryItem*> item) {
if (true/*doWeReadServerHistory()*/) { // #TODO forum active
_replies->readTill(item);
}
_replies->readTill(item);
}
void RepliesWidget::listMarkContentsRead(
const base::flat_set<not_null<HistoryItem*>> &items) {
if (true/*doWeReadMentions()*/) { // #TODO forum active
session().api().markContentsRead(items);
}
session().api().markContentsRead(items);
}
MessagesBarData RepliesWidget::listMessagesBar(

View file

@ -182,16 +182,16 @@ public:
bool cornerButtonsUnreadMayBeShown() override;
bool cornerButtonsHas(CornerButtonType type) override;
protected:
private:
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void showAnimatedHook(
const Window::SectionSlideParams &params) override;
void showFinishedHook() override;
void checkActivation() override;
void doSetInnerFocus() override;
private:
void onScroll();
void updateInnerVisibleArea();
void updateControlsGeometry();

View file

@ -895,6 +895,10 @@ QPixmap ScheduledWidget::grabForShowAnimation(const Window::SectionSlideParams &
return result;
}
void ScheduledWidget::checkActivation() {
_inner->checkActivation();
}
void ScheduledWidget::doSetInnerFocus() {
_composeControls->focus();
}
@ -1031,6 +1035,7 @@ void ScheduledWidget::showAnimatedHook(
void ScheduledWidget::showFinishedHook() {
_topBar->setAnimatingMode(false);
_composeControls->showFinished();
_inner->showFinished();
// We should setup the drag area only after
// the section animation is finished,

View file

@ -162,7 +162,7 @@ public:
bool cornerButtonsUnreadMayBeShown() override;
bool cornerButtonsHas(CornerButtonType type) override;
protected:
private:
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
@ -170,8 +170,8 @@ protected:
const Window::SectionSlideParams &params) override;
void showFinishedHook() override;
void doSetInnerFocus() override;
void checkActivation() override;
private:
void onScroll();
void updateInnerVisibleArea();
void updateControlsGeometry();

View file

@ -2060,8 +2060,11 @@ void MainWidget::dialogsToUp() {
}
}
void MainWidget::checkHistoryActivation() {
_history->checkHistoryActivation();
void MainWidget::checkActivation() {
_history->checkActivation();
if (_mainSection) {
_mainSection->checkActivation();
}
}
void MainWidget::showAnimated(const QPixmap &bgAnimCache, bool back) {
@ -2223,7 +2226,7 @@ void MainWidget::showAll() {
updateControlsGeometry();
floatPlayerCheckVisibility();
_controller->widget()->checkHistoryActivation();
_controller->widget()->checkActivation();
}
void MainWidget::resizeEvent(QResizeEvent *e) {
@ -2778,14 +2781,8 @@ void MainWidget::activate() {
_controller->widget()->fixOrder();
}
bool MainWidget::isActive() const {
return isVisible()
&& !_a_show.animating()
&& !session().updates().isIdle();
}
bool MainWidget::doWeMarkAsRead() const {
return isActive() && !_mainSection;
bool MainWidget::animatingShow() const {
return _a_show.animating();
}
bool MainWidget::isOneColumn() const {

View file

@ -144,7 +144,7 @@ public:
void windowShown();
void dialogsToUp();
void checkHistoryActivation();
void checkActivation();
[[nodiscard]] PeerData *peer() const;
[[nodiscard]] Ui::ChatTheme *customChatTheme() const;
@ -167,8 +167,7 @@ public:
not_null<DocumentData*> document,
Api::SendOptions options);
bool isActive() const;
[[nodiscard]] bool doWeMarkAsRead() const;
[[nodiscard]] bool animatingShow() const;
void showForwardLayer(Data::ForwardDraft &&draft);
void showSendPathsLayer();

View file

@ -114,7 +114,7 @@ void MainWindow::initHook() {
windowHandle(),
&QWindow::activeChanged,
this,
[=] { checkHistoryActivation(); },
[=] { checkActivation(); },
Qt::QueuedConnection);
if (Media::SystemMediaControlsManager::Supported()) {
@ -395,7 +395,7 @@ void MainWindow::destroyLayer() {
setInnerFocus();
}
InvokeQueued(this, [=] {
checkHistoryActivation();
checkActivation();
});
}
@ -459,7 +459,7 @@ void MainWindow::showLayer(
showBoxOrLayer(std::move(layer), options, animated);
}
bool MainWindow::ui_isLayerShown() {
bool MainWindow::ui_isLayerShown() const {
return _layer != nullptr;
}
@ -539,17 +539,19 @@ void MainWindow::themeUpdated(const Window::Theme::BackgroundUpdate &data) {
}
}
bool MainWindow::doWeMarkAsRead() {
if (!_main || Ui::isLayerShown()) {
return false;
}
return isActive() && _main->doWeMarkAsRead();
bool MainWindow::markingAsRead() const {
return _main
&& !_main->isHidden()
&& !_main->animatingShow()
&& !_layer
&& isActive()
&& !_main->session().updates().isIdle();
}
void MainWindow::checkHistoryActivation() {
void MainWindow::checkActivation() {
updateIsActive();
if (_main) {
_main->checkHistoryActivation();
_main->checkActivation();
}
}

View file

@ -62,13 +62,11 @@ public:
MainWidget *sessionContent() const;
[[nodiscard]] bool doWeMarkAsRead();
void checkActivation();
[[nodiscard]] bool markingAsRead() const;
bool takeThirdSectionFromLayer();
void checkHistoryActivation();
void sendPaths();
bool contentOverlapped(const QRect &globalRect);
@ -98,7 +96,7 @@ public:
anim::type animated);
void ui_hideSettingsAndLayer(anim::type animated);
void ui_removeLayerBlackout();
bool ui_isLayerShown();
[[nodiscard]] bool ui_isLayerShown() const;
bool showMediaPreview(
Data::FileOrigin origin,
not_null<DocumentData*> document);

View file

@ -165,6 +165,8 @@ public:
void setInnerFocus() {
doSetInnerFocus();
}
virtual void checkActivation() {
}
[[nodiscard]] virtual rpl::producer<int> desiredHeight() const;
[[nodiscard]] virtual rpl::producer<> removeRequests() const {

View file

@ -113,7 +113,7 @@ void Controller::showAccount(
) | rpl::filter([=](bool idle) {
return !idle;
}) | rpl::start_with_next([=] {
widget()->checkHistoryActivation();
widget()->checkActivation();
}, _sessionController->lifetime());
session->termsLockValue(