diff --git a/build.zig.zon b/build.zig.zon index 4356f6b..4da4df6 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -7,8 +7,8 @@ .hash = "1220affeb3fe37ef09411b5a213b5fdf9bb6568e9913bade204694648983a8b2776d", }, .vaxis = .{ - .url = "git+https://github.com/rockorager/libvaxis#bcc1d027cb2ede571bb76669441d2e09944bd3d3", - .hash = "1220fca568653885767394bc659714e0e9ccda935e5c02d4333b1d60b064bc6ac0bc", + .url = "git+https://github.com/rockorager/libvaxis#72f1e223332aa15b48d606570f7af0b686325403", + .hash = "1220e7560c2499f2edca94a918c4b0fadb31c85b92ec4164bef4d39bf762c17b23b2", }, .zeit = .{ .url = "git+https://github.com/rockorager/zeit?ref=main#d943bc4bfe9e18490460dfdd64f48e997065eba8", diff --git a/src/app.zig b/src/app.zig index 06c31bd..a59b214 100644 --- a/src/app.zig +++ b/src/app.zig @@ -78,6 +78,9 @@ pub const App = struct { ctx: ?*vxfw.EventContext, last_height: u16, + /// Whether the application has focus or not + has_focus: bool, + const default_rhs: vxfw.Text = .{ .text = "TODO: update this text" }; /// initialize vaxis, lua state @@ -115,6 +118,7 @@ pub const App = struct { .title_buf = undefined, .ctx = null, .last_height = 0, + .has_focus = true, }; self.lua = try Lua.init(&self.alloc); @@ -242,6 +246,9 @@ pub const App = struct { } } }, + .focus_out => self.has_focus = false, + .focus_in => self.has_focus = true, + else => {}, } } @@ -329,9 +336,6 @@ pub const App = struct { } pub fn nextChannel(self: *App) void { - // When leaving a channel we mark it as read, so we make sure that's done - // before we change to the new channel. - self.markSelectedChannelRead(); if (self.ctx) |ctx| { self.buffer_list.nextItem(ctx); if (self.selectedBuffer()) |buffer| { @@ -348,9 +352,6 @@ pub const App = struct { } pub fn prevChannel(self: *App) void { - // When leaving a channel we mark it as read, so we make sure that's done - // before we change to the new channel. - self.markSelectedChannelRead(); if (self.ctx) |ctx| { self.buffer_list.prevItem(ctx); if (self.selectedBuffer()) |buffer| { @@ -555,7 +556,6 @@ pub const App = struct { } pub fn selectBuffer(self: *App, buffer: irc.Buffer) void { - self.markSelectedChannelRead(); var i: u32 = 0; switch (buffer) { .client => |target| { @@ -591,17 +591,6 @@ pub const App = struct { }, } } - - pub fn markSelectedChannelRead(self: *App) void { - const buffer = self.selectedBuffer() orelse return; - - switch (buffer) { - .channel => |channel| { - if (channel.messageViewIsAtBottom()) channel.markRead() catch return; - }, - else => {}, - } - } }; /// this loop is run in a separate thread and handles writes to all clients. diff --git a/src/irc.zig b/src/irc.zig index 8ef9fde..cc1f76e 100644 --- a/src/irc.zig +++ b/src/irc.zig @@ -126,7 +126,7 @@ pub const Channel = struct { // The location of the last read indicator. This doesn't necessarily match the state of // last_read last_read_indicator: u32 = 0, - scroll_to_last_read: bool = true, + scroll_to_last_read: bool = false, has_unread: bool = false, has_unread_highlight: bool = false, @@ -382,6 +382,9 @@ pub const Channel = struct { pub fn doSelect(self: *Channel) void { // Set the state of the last_read_indicator self.last_read_indicator = self.last_read; + if (self.has_unread) { + self.scroll_to_last_read = true; + } } fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void { @@ -912,7 +915,13 @@ pub const Channel = struct { // True when we *don't* need to scroll to last message. False if we do. We will turn this // true when we have it the last message var did_scroll_to_last_read = !self.scroll_to_last_read; + // We track whether we need to reposition the viewport based on the position of the + // last_read scroll + var needs_reposition = true; while (iter.next()) |msg| { + if (row >= 0 and did_scroll_to_last_read) { + needs_reposition = false; + } // Break if we have gone past the top of the screen if (row < 0 and did_scroll_to_last_read) break; @@ -1157,7 +1166,7 @@ pub const Channel = struct { // check that we have messages, and if we do that the top message is outside the viewport. // If we don't have messages, or the top message is within the viewport, we don't have to // reposition - if (self.scroll_to_last_read and + if (needs_reposition and children.items.len > 0 and children.getLast().origin.row < 0) { @@ -1175,7 +1184,7 @@ pub const Channel = struct { self.scroll_to_last_read = false; } - if (self.has_unread and self.messageViewIsAtBottom()) { + if (self.has_unread and self.client.app.has_focus and self.messageViewIsAtBottom()) { try self.markRead(); } @@ -2225,14 +2234,9 @@ pub const Client = struct { channel.has_unread_highlight = has_highlight; channel.has_unread = true; } - // If we get a message from the current user mark the channel as - // read, since they must have just sent the message. - const sender = msg2.senderNick() orelse ""; - if (std.mem.eql(u8, sender, client.nickname())) { - self.app.markSelectedChannelRead(); - } // Set the typing time to 0 + const sender = msg2.senderNick() orelse ""; for (channel.members.items) |*member| { if (!std.mem.eql(u8, member.user.nick, sender)) { continue;