~rockorager/comlink

ui: add highlight to unread messages v1 PROPOSED

Kristófer R: 1
 ui: add highlight to unread messages

 1 files changed, 45 insertions(+), 3 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~rockorager/comlink/patches/56068/mbox | git am -3
Learn more about email & git

[PATCH] ui: add highlight to unread messages Export this patch

All unread messages are highlighted with a gray background. This is
currently the same color used on mouse hover, simply because it was easy
to copy.

A channel is marked read when:

* You switch channel (either via mouse or keyboard); or
* you send a message.

This means that new messages _from others in the channel_ will remain
unread until you either:

* send a message; or
* change the current channel.

Future improvements:

* Add a keybinding to mark the channel read (easy-ish)
* Mark a message as read as soon as it's received if the terminal window
  (and thus comlink itself) is focused (harder).
* Mark a channel read on window focus (easy-ish).
    - This might actually not be nice? I wouldn't want a channel to be
      marked read as soon as I focus the window in case there's a long
      scrollback I want to catch up on.
---
 src/app.zig | 48 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 45 insertions(+), 3 deletions(-)

diff --git a/src/app.zig b/src/app.zig
index c774a3d..444390c 100644
--- a/src/app.zig
+++ b/src/app.zig
@@ -760,6 +760,19 @@ pub const App = struct {
                                        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: []const u8 = blk: {
                                    const src = msg2.source() orelse break :blk "";
                                    const l = std.mem.indexOfScalar(u8, src, '!') orelse
                                        std.mem.indexOfScalar(u8, src, '@') orelse
                                        src.len;
                                    break :blk src[0..l];
                                };
                                if (std.mem.eql(u8, sender, client.config.nick)) {
                                    self.markSelectedChannelRead();
                                }
                            },
                        }
                    },
@@ -773,6 +786,10 @@ 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();

        const state = self.state.buffers;
        if (state.selected_idx >= state.count - 1)
            self.state.buffers.selected_idx = 0
@@ -781,6 +798,10 @@ 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();

        switch (self.state.buffers.selected_idx) {
            0 => self.state.buffers.selected_idx = self.state.buffers.count - 1,
            else => self.state.buffers.selected_idx -|= 1,
@@ -1000,9 +1021,6 @@ pub const App = struct {
            .client => {}, // nothing to do

            .channel => |channel| {
                // Mark the channel as read
                try channel.markRead();

                // Request WHO if we don't already have it
                if (!channel.who_requested) try channel.client.whox(channel);

@@ -1353,6 +1371,16 @@ pub const App = struct {
                        item.style.fg = .{ .index = 3 };
                }
            }

            // Color the background of unread messages gray.
            if (message.localTime(&self.tz)) |instant| {
                if (instant.unixTimestamp() > channel.last_read) {
                    for (segments.items) |*item| {
                        item.style.bg = .{ .index = 8 };
                    }
                }
            }

            _ = try content_win.print(
                segments.items,
                .{
@@ -1531,6 +1559,9 @@ pub const App = struct {
                });
                if (channel_win.hasMouse(self.state.mouse)) |mouse| {
                    if (mouse.type == .press and mouse.button == .left) {
                        // 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();
                        self.state.buffers.selected_idx = row;
                    }
                }
@@ -1865,6 +1896,17 @@ pub const App = struct {
            });
        }
    }

    fn markSelectedChannelRead(self: *App) void {
        const buffer = self.selectedBuffer() orelse return;

        switch (buffer) {
            .channel => |channel| {
                channel.markRead() catch return;
            },
            else => {},
        }
    }
};

/// this loop is run in a separate thread and handles writes to all clients.
-- 
2.39.5 (Apple Git-154)