From 3c28e7b5851fdd808994df0e7564626fb4568960 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 14 Jul 2023 11:24:13 +0400 Subject: [PATCH] Mark as read recent stories in profile top bar. --- Telegram/SourceFiles/data/data_changes.h | 45 ++++++++++--------- Telegram/SourceFiles/data/data_stories.cpp | 5 ++- .../dialogs/ui/dialogs_stories_content.cpp | 34 +++++++++++++- 3 files changed, 59 insertions(+), 25 deletions(-) diff --git a/Telegram/SourceFiles/data/data_changes.h b/Telegram/SourceFiles/data/data_changes.h index 754f12ef3..3f0e587dd 100644 --- a/Telegram/SourceFiles/data/data_changes.h +++ b/Telegram/SourceFiles/data/data_changes.h @@ -148,19 +148,19 @@ struct TopicUpdate { enum class Flag : uint32 { None = 0, - UnreadView = (1U << 1), - UnreadMentions = (1U << 2), + UnreadView = (1U << 1), + UnreadMentions = (1U << 2), UnreadReactions = (1U << 3), - Notifications = (1U << 4), - Title = (1U << 5), - IconId = (1U << 6), - ColorId = (1U << 7), - CloudDraft = (1U << 8), - Closed = (1U << 9), - Creator = (1U << 10), - Destroyed = (1U << 11), + Notifications = (1U << 4), + Title = (1U << 5), + IconId = (1U << 6), + ColorId = (1U << 7), + CloudDraft = (1U << 8), + Closed = (1U << 9), + Creator = (1U << 10), + Destroyed = (1U << 11), - LastUsedBit = (1U << 11), + LastUsedBit = (1U << 11), }; using Flags = base::flags; friend inline constexpr auto is_flag_type(Flag) { return true; } @@ -199,14 +199,14 @@ struct EntryUpdate { enum class Flag : uint32 { None = 0, - Repaint = (1U << 0), + Repaint = (1U << 0), HasPinnedMessages = (1U << 1), - ForwardDraft = (1U << 2), - LocalDraftSet = (1U << 3), - Height = (1U << 4), - Destroyed = (1U << 5), + ForwardDraft = (1U << 2), + LocalDraftSet = (1U << 3), + Height = (1U << 4), + Destroyed = (1U << 5), - LastUsedBit = (1U << 5), + LastUsedBit = (1U << 5), }; using Flags = base::flags; friend inline constexpr auto is_flag_type(Flag) { return true; } @@ -220,12 +220,13 @@ struct StoryUpdate { enum class Flag : uint32 { None = 0, - Edited = (1U << 0), - Destroyed = (1U << 1), - NewAdded = (1U << 2), - ViewsAdded = (1U << 3), + Edited = (1U << 0), + Destroyed = (1U << 1), + NewAdded = (1U << 2), + ViewsAdded = (1U << 3), + MarkRead = (1U << 4), - LastUsedBit = (1U << 3), + LastUsedBit = (1U << 4), }; using Flags = base::flags; friend inline constexpr auto is_flag_type(Flag) { return true; } diff --git a/Telegram/SourceFiles/data/data_stories.cpp b/Telegram/SourceFiles/data/data_stories.cpp index add13494f..19ff73eb2 100644 --- a/Telegram/SourceFiles/data/data_stories.cpp +++ b/Telegram/SourceFiles/data/data_stories.cpp @@ -928,7 +928,10 @@ bool Stories::bumpReadTill(PeerId peerId, StoryId maxReadTill) { refreshItems = ranges::make_subrange( i->second.lower_bound(from + 1), i->second.lower_bound(till + 1) - ) | ranges::views::transform([](const auto &pair) { + ) | ranges::views::transform([=](const auto &pair) { + _owner->session().changes().storyUpdated( + pair.second.get(), + StoryUpdate::Flag::MarkRead); return pair.first; }) | ranges::to_vector; } diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp index 2f6c55dd1..ed723b55e 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp @@ -402,17 +402,25 @@ rpl::producer LastForPeer(not_null peer) { } return rpl::make_producer([=](auto consumer) { auto lifetime = rpl::lifetime(); + if (ids.empty()) { + consumer.put_next(Content()); + consumer.put_done(); + return lifetime; + } struct State { Fn check; base::has_weak_ptr guard; + int readTill = StoryId(); bool pushed = false; }; const auto state = lifetime.make_state(); + state->readTill = readTill; state->check = [=] { if (state->pushed) { return; } + auto done = true; auto resolving = false; auto result = Content{}; for (const auto id : ids) { @@ -420,13 +428,17 @@ rpl::producer LastForPeer(not_null peer) { const auto maybe = stories->lookup(storyId); if (maybe) { if (!resolving) { + const auto unread = (id > state->readTill); result.elements.reserve(ids.size()); result.elements.push_back({ .id = uint64(id), .thumbnail = MakeStoryThumbnail(*maybe), .count = 1U, - .unreadCount = (id > readTill) ? 1U : 0U, + .unreadCount = unread ? 1U : 0U, }); + if (unread) { + done = false; + } } } else if (maybe.error() == Data::NoStory::Unknown) { resolving = true; @@ -440,12 +452,30 @@ rpl::producer LastForPeer(not_null peer) { } state->pushed = true; consumer.put_next(std::move(result)); - consumer.put_done(); + if (done) { + consumer.put_done(); + } }; + rpl::single(peerId) | rpl::then( stories->itemsChanged() | rpl::filter(_1 == peerId) ) | rpl::start_with_next(state->check, lifetime); + stories->session().changes().storyUpdates( + Data::StoryUpdate::Flag::MarkRead + ) | rpl::start_with_next([=](const Data::StoryUpdate &update) { + if (update.story->peer()->id == peerId) { + if (update.story->id() > state->readTill) { + state->readTill = update.story->id(); + if (ranges::contains(ids, state->readTill) + || state->readTill > ids.front()) { + state->pushed = false; + state->check(); + } + } + } + }, lifetime); + return lifetime; }); }) | rpl::flatten_latest();