Mark as read recent stories in profile top bar.

This commit is contained in:
John Preston 2023-07-14 11:24:13 +04:00
parent 74014d18a5
commit 3c28e7b585
3 changed files with 59 additions and 25 deletions

View file

@ -148,19 +148,19 @@ struct TopicUpdate {
enum class Flag : uint32 { enum class Flag : uint32 {
None = 0, None = 0,
UnreadView = (1U << 1), UnreadView = (1U << 1),
UnreadMentions = (1U << 2), UnreadMentions = (1U << 2),
UnreadReactions = (1U << 3), UnreadReactions = (1U << 3),
Notifications = (1U << 4), Notifications = (1U << 4),
Title = (1U << 5), Title = (1U << 5),
IconId = (1U << 6), IconId = (1U << 6),
ColorId = (1U << 7), ColorId = (1U << 7),
CloudDraft = (1U << 8), CloudDraft = (1U << 8),
Closed = (1U << 9), Closed = (1U << 9),
Creator = (1U << 10), Creator = (1U << 10),
Destroyed = (1U << 11), Destroyed = (1U << 11),
LastUsedBit = (1U << 11), LastUsedBit = (1U << 11),
}; };
using Flags = base::flags<Flag>; using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; } friend inline constexpr auto is_flag_type(Flag) { return true; }
@ -199,14 +199,14 @@ struct EntryUpdate {
enum class Flag : uint32 { enum class Flag : uint32 {
None = 0, None = 0,
Repaint = (1U << 0), Repaint = (1U << 0),
HasPinnedMessages = (1U << 1), HasPinnedMessages = (1U << 1),
ForwardDraft = (1U << 2), ForwardDraft = (1U << 2),
LocalDraftSet = (1U << 3), LocalDraftSet = (1U << 3),
Height = (1U << 4), Height = (1U << 4),
Destroyed = (1U << 5), Destroyed = (1U << 5),
LastUsedBit = (1U << 5), LastUsedBit = (1U << 5),
}; };
using Flags = base::flags<Flag>; using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; } friend inline constexpr auto is_flag_type(Flag) { return true; }
@ -220,12 +220,13 @@ struct StoryUpdate {
enum class Flag : uint32 { enum class Flag : uint32 {
None = 0, None = 0,
Edited = (1U << 0), Edited = (1U << 0),
Destroyed = (1U << 1), Destroyed = (1U << 1),
NewAdded = (1U << 2), NewAdded = (1U << 2),
ViewsAdded = (1U << 3), ViewsAdded = (1U << 3),
MarkRead = (1U << 4),
LastUsedBit = (1U << 3), LastUsedBit = (1U << 4),
}; };
using Flags = base::flags<Flag>; using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; } friend inline constexpr auto is_flag_type(Flag) { return true; }

View file

@ -928,7 +928,10 @@ bool Stories::bumpReadTill(PeerId peerId, StoryId maxReadTill) {
refreshItems = ranges::make_subrange( refreshItems = ranges::make_subrange(
i->second.lower_bound(from + 1), i->second.lower_bound(from + 1),
i->second.lower_bound(till + 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; return pair.first;
}) | ranges::to_vector; }) | ranges::to_vector;
} }

View file

@ -402,17 +402,25 @@ rpl::producer<Content> LastForPeer(not_null<PeerData*> peer) {
} }
return rpl::make_producer<Content>([=](auto consumer) { return rpl::make_producer<Content>([=](auto consumer) {
auto lifetime = rpl::lifetime(); auto lifetime = rpl::lifetime();
if (ids.empty()) {
consumer.put_next(Content());
consumer.put_done();
return lifetime;
}
struct State { struct State {
Fn<void()> check; Fn<void()> check;
base::has_weak_ptr guard; base::has_weak_ptr guard;
int readTill = StoryId();
bool pushed = false; bool pushed = false;
}; };
const auto state = lifetime.make_state<State>(); const auto state = lifetime.make_state<State>();
state->readTill = readTill;
state->check = [=] { state->check = [=] {
if (state->pushed) { if (state->pushed) {
return; return;
} }
auto done = true;
auto resolving = false; auto resolving = false;
auto result = Content{}; auto result = Content{};
for (const auto id : ids) { for (const auto id : ids) {
@ -420,13 +428,17 @@ rpl::producer<Content> LastForPeer(not_null<PeerData*> peer) {
const auto maybe = stories->lookup(storyId); const auto maybe = stories->lookup(storyId);
if (maybe) { if (maybe) {
if (!resolving) { if (!resolving) {
const auto unread = (id > state->readTill);
result.elements.reserve(ids.size()); result.elements.reserve(ids.size());
result.elements.push_back({ result.elements.push_back({
.id = uint64(id), .id = uint64(id),
.thumbnail = MakeStoryThumbnail(*maybe), .thumbnail = MakeStoryThumbnail(*maybe),
.count = 1U, .count = 1U,
.unreadCount = (id > readTill) ? 1U : 0U, .unreadCount = unread ? 1U : 0U,
}); });
if (unread) {
done = false;
}
} }
} else if (maybe.error() == Data::NoStory::Unknown) { } else if (maybe.error() == Data::NoStory::Unknown) {
resolving = true; resolving = true;
@ -440,12 +452,30 @@ rpl::producer<Content> LastForPeer(not_null<PeerData*> peer) {
} }
state->pushed = true; state->pushed = true;
consumer.put_next(std::move(result)); consumer.put_next(std::move(result));
consumer.put_done(); if (done) {
consumer.put_done();
}
}; };
rpl::single(peerId) | rpl::then( rpl::single(peerId) | rpl::then(
stories->itemsChanged() | rpl::filter(_1 == peerId) stories->itemsChanged() | rpl::filter(_1 == peerId)
) | rpl::start_with_next(state->check, lifetime); ) | 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; return lifetime;
}); });
}) | rpl::flatten_latest(); }) | rpl::flatten_latest();