╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1509 .user => switch (self) { │ │1510 .user_repos => |u| .{ .user_repos = .{ .name = u.name } }, │ │1511 .user_forks => |u| .{ .user_repos = .{ .name = u.name } }, │ │1460 - .user_repo_new, .user_user_new, .user_user => |name| .{ .user_repos = .{ .name = name } },│ │1512 + .user_repo_new, .user_user_new => |name| .{ .user_repos = .{ .name = name } }, │ │1513 + .user_user => |u| .{ .user_repos = .{ .name = u.name } }, │ │1514 else => self, │ │1515 }, │ │1516 // every repo route stores the same identity, so it always fits │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1547 fn isNewTail(segments: *std.mem.SplitIterator(u8, .scalar)) bool { │ │1548 const next = segments.next() orelse return false; │ │1549 return std.mem.eql(u8, next, "new") and segments.next() == null; │ │1550 + } │ │1551 + │ │1552 + // the tail after a page's "user": none or "notifications" with an optional │ │1553 + // "start:<n>", "settings", or "new" │ │1554 + fn userTail(segments: *std.mem.SplitIterator(u8, .scalar)) ?union(enum) { new, tab: UserTab } {│ │1555 + const word = segments.next() orelse return .{ .tab = .{} }; │ │1556 + if (std.mem.eql(u8, word, "new")) return if (segments.next() == null) .new else null; │ │1557 + return switch (std.meta.stringToEnum(UserView, word) orelse return null) { │ │1558 + .settings => if (segments.next() == null) .{ .tab = .{ .view = .settings } } else null,│ │1559 + .notifications => .{ .tab = .{ .start = listStart(segments) orelse return null } }, │ │1560 + }; │ │1561 } │ │1562 │ │1563 fn listStart(segments: *std.mem.SplitIterator(u8, .scalar)) ?usize { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1601 } │ │1602 return if (isNewTail(&segments)) .{ .repo_repo_new = Array(repo_route_max_len).from(pair) orelse return null } else null; │ │1603 } │ │1540 - if (std.mem.eql(u8, tab, "user")) return if (segments.peek() == null) .{ .repo_user = Array(repo_route_max_len).from(pair) orelse return null } else if (isNewTail(&segments)) .{ .repo_user_new = Array(repo_route_max_len).from(pair) orelse return null } else null;│ │1604 + if (std.mem.eql(u8, tab, "user")) return switch (userTail(&segments) orelse return null) { │ │1605 + .new => .{ .repo_user_new = Array(repo_route_max_len).from(pair) orelse return null }, │ │1606 + .tab => |user_tab| .{ .repo_user = .{ .name = Array(repo_route_max_len).from(pair) orelse return null, .tab = user_tab } }, │ │1607 + }; │ │1608 if (std.mem.eql(u8, tab, "refs")) { │ │1609 const word = params.scanTail(&segments) catch return null; │ │1610 if (word != null or !params.only(&.{ .branch, .tag, .search })) return null; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1857 if (std.meta.activeTag(a) != std.meta.activeTag(b)) return false; │ │1858 return switch (a) { │ │1859 .home_users => |a_u| a_u.start == b.home_users.start and std.mem.eql(u8, a_u.search.slice(), b.home_users.search.slice()), │ │1860 + .home_user => |a_t| std.meta.eql(a_t, b.home_user), │ │1861 .user_repos => |a_u| std.mem.eql(u8, a_u.name.slice(), b.user_repos.name.slice()) and a_u.start == b.user_repos.start and std.mem.eql(u8, a_u.search.slice(), b.user_repos.search.slice()),│ │1862 .user_forks => |a_u| std.mem.eql(u8, a_u.name.slice(), b.user_forks.name.slice()) and a_u.start == b.user_forks.start, │ │1863 .user_repo_new => |a_name| std.mem.eql(u8, a_name.slice(), b.user_repo_new.slice()), │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1864 .user_user_new => |a_name| std.mem.eql(u8, a_name.slice(), b.user_user_new.slice()), │ │1797 - .user_user => |a_name| std.mem.eql(u8, a_name.slice(), b.user_user.slice()), │ │1865 + .user_user => |a_u| std.mem.eql(u8, a_u.name.slice(), b.user_user.name.slice()) and std.meta.eql(a_u.tab, b.user_user.tab),│ │1866 .repo_files => |a_f| std.mem.eql(u8, a_f.name.slice(), b.repo_files.name.slice()) and │ │1867 a_f.ref_kind == b.repo_files.ref_kind and │ │1868 std.mem.eql(u8, a_f.ref_value.slice(), b.repo_files.ref_value.slice()) and │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1923 .repo_roles => |a_r| std.mem.eql(u8, a_r.name.slice(), b.repo_roles.name.slice()) and │ │1924 a_r.start == b.repo_roles.start and │ │1925 std.mem.eql(u8, a_r.user.slice(), b.repo_roles.user.slice()), │ │1858 - .repo_user => |a_name| std.mem.eql(u8, a_name.slice(), b.repo_user.slice()), │ │1926 + .repo_user => |a_u| std.mem.eql(u8, a_u.name.slice(), b.repo_user.name.slice()) and std.meta.eql(a_u.tab, b.repo_user.tab), │ │1927 .fork_patch => |a_f| std.mem.eql(u8, a_f.name.slice(), b.fork_patch.name.slice()) and std.mem.eql(u8, a_f.id.slice(), b.fork_patch.id.slice()),│ │1928 .fork_diff => |a_d| std.mem.eql(u8, a_d.fork.name.slice(), b.fork_diff.fork.name.slice()) and │ │1929 std.mem.eql(u8, a_d.fork.id.slice(), b.fork_diff.fork.id.slice()) and │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1942 a_c.message == b.fork_commits.message, │ │1943 .fork_repo_new => |a_f| std.mem.eql(u8, a_f.name.slice(), b.fork_repo_new.name.slice()) and std.mem.eql(u8, a_f.id.slice(), b.fork_repo_new.id.slice()),│ │1944 .fork_user_new => |a_f| std.mem.eql(u8, a_f.name.slice(), b.fork_user_new.name.slice()) and std.mem.eql(u8, a_f.id.slice(), b.fork_user_new.id.slice()),│ │1877 - .fork_user => |a_f| std.mem.eql(u8, a_f.name.slice(), b.fork_user.name.slice()) and std.mem.eql(u8, a_f.id.slice(), b.fork_user.id.slice()), │ │1945 + .fork_user => |a_u| std.mem.eql(u8, a_u.fork.name.slice(), b.fork_user.fork.name.slice()) and │ │1946 + std.mem.eql(u8, a_u.fork.id.slice(), b.fork_user.fork.id.slice()) and │ │1947 + std.meta.eql(a_u.tab, b.fork_user.tab), │ │1948 else => true, │ │1949 }; │ │1950 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1976 .user_forks => |bb| std.mem.eql(u8, aa.name.slice(), bb.name.slice()) and aa.start != bb.start,│ │1977 else => false, │ │1978 }, │ │1979 + .user_user => |aa| switch (b) { │ │1980 + .user_user => |bb| std.mem.eql(u8, aa.name.slice(), bb.name.slice()) and !a.eql(b), │ │1981 + else => false, │ │1982 + }, │ │1983 else => false, │ │1984 }; │ │1985 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────╮ │1993 .home_users => !a.eql(b),│ │1994 else => false, │ │1995 }, │ │1996 + .home_user => switch (b) { │ │1997 + .home_user => !a.eql(b), │ │1998 + else => false, │ │1999 + }, │ │2000 else => false, │ │2001 }; │ │2002 } │ ╰───────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │2171 }; │ │2172 │ │2173 // who a write acts as and the role they hold in its repo │ │2174 +// the thread button that changes the viewer's notifications, named by its label│ │2175 +pub const NotifyAction = enum { subscribe, mute }; │ │2176 + │ │2177 pub const Actor = struct { │ │2178 author: evt.CommitAuthor, │ │2179 // local mode has no accounts, so it has no user id │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯