We only ever mark a channel read when we are drawing. This keeps the logic very simple: We must be at the bottom of the viewport, have unread messages, and have focus.
···7878 ctx: ?*vxfw.EventContext,
7979 last_height: u16,
80808181+ /// Whether the application has focus or not
8282+ has_focus: bool,
8383+8184 const default_rhs: vxfw.Text = .{ .text = "TODO: update this text" };
82858386 /// initialize vaxis, lua state
···115118 .title_buf = undefined,
116119 .ctx = null,
117120 .last_height = 0,
121121+ .has_focus = true,
118122 };
119123120124 self.lua = try Lua.init(&self.alloc);
···242246 }
243247 }
244248 },
249249+ .focus_out => self.has_focus = false,
250250+ .focus_in => self.has_focus = true,
251251+245252 else => {},
246253 }
247254 }
···329336 }
330337331338 pub fn nextChannel(self: *App) void {
332332- // When leaving a channel we mark it as read, so we make sure that's done
333333- // before we change to the new channel.
334334- self.markSelectedChannelRead();
335339 if (self.ctx) |ctx| {
336340 self.buffer_list.nextItem(ctx);
337341 if (self.selectedBuffer()) |buffer| {
···348352 }
349353350354 pub fn prevChannel(self: *App) void {
351351- // When leaving a channel we mark it as read, so we make sure that's done
352352- // before we change to the new channel.
353353- self.markSelectedChannelRead();
354355 if (self.ctx) |ctx| {
355356 self.buffer_list.prevItem(ctx);
356357 if (self.selectedBuffer()) |buffer| {
···555556 }
556557557558 pub fn selectBuffer(self: *App, buffer: irc.Buffer) void {
558558- self.markSelectedChannelRead();
559559 var i: u32 = 0;
560560 switch (buffer) {
561561 .client => |target| {
···589589 }
590590 }
591591 },
592592- }
593593- }
594594-595595- pub fn markSelectedChannelRead(self: *App) void {
596596- const buffer = self.selectedBuffer() orelse return;
597597-598598- switch (buffer) {
599599- .channel => |channel| {
600600- if (channel.messageViewIsAtBottom()) channel.markRead() catch return;
601601- },
602602- else => {},
603592 }
604593 }
605594};
+13-9
src/irc.zig
···126126 // The location of the last read indicator. This doesn't necessarily match the state of
127127 // last_read
128128 last_read_indicator: u32 = 0,
129129- scroll_to_last_read: bool = true,
129129+ scroll_to_last_read: bool = false,
130130 has_unread: bool = false,
131131 has_unread_highlight: bool = false,
132132···382382 pub fn doSelect(self: *Channel) void {
383383 // Set the state of the last_read_indicator
384384 self.last_read_indicator = self.last_read;
385385+ if (self.has_unread) {
386386+ self.scroll_to_last_read = true;
387387+ }
385388 }
386389387390 fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {
···912915 // True when we *don't* need to scroll to last message. False if we do. We will turn this
913916 // true when we have it the last message
914917 var did_scroll_to_last_read = !self.scroll_to_last_read;
918918+ // We track whether we need to reposition the viewport based on the position of the
919919+ // last_read scroll
920920+ var needs_reposition = true;
915921 while (iter.next()) |msg| {
922922+ if (row >= 0 and did_scroll_to_last_read) {
923923+ needs_reposition = false;
924924+ }
916925 // Break if we have gone past the top of the screen
917926 if (row < 0 and did_scroll_to_last_read) break;
918927···11571166 // check that we have messages, and if we do that the top message is outside the viewport.
11581167 // If we don't have messages, or the top message is within the viewport, we don't have to
11591168 // reposition
11601160- if (self.scroll_to_last_read and
11691169+ if (needs_reposition and
11611170 children.items.len > 0 and
11621171 children.getLast().origin.row < 0)
11631172 {
···11751184 self.scroll_to_last_read = false;
11761185 }
1177118611781178- if (self.has_unread and self.messageViewIsAtBottom()) {
11871187+ if (self.has_unread and self.client.app.has_focus and self.messageViewIsAtBottom()) {
11791188 try self.markRead();
11801189 }
11811190···22252234 channel.has_unread_highlight = has_highlight;
22262235 channel.has_unread = true;
22272236 }
22282228- // If we get a message from the current user mark the channel as
22292229- // read, since they must have just sent the message.
22302230- const sender = msg2.senderNick() orelse "";
22312231- if (std.mem.eql(u8, sender, client.nickname())) {
22322232- self.app.markSelectedChannelRead();
22332233- }
2234223722352238 // Set the typing time to 0
22392239+ const sender = msg2.senderNick() orelse "";
22362240 for (channel.members.items) |*member| {
22372241 if (!std.mem.eql(u8, member.user.nick, sender)) {
22382242 continue;