Add separate direct messages tab
b7df73e parent: 31683ce modified
flutter/test/nim_layout_test.dart +2 -2 | @@ -168,7 +168,7 @@ void main() { | ||
| 168 | 168 | }); |
| 169 | 169 | |
| 170 | 170 | group('discover and settings', () { |
| 171 | - for (final screen in ['discover', 'settings']) { | |
| 171 | + for (final screen in ['dms', 'discover', 'settings']) { | |
| 172 | 172 | for (final entry in sizes.entries) { |
| 173 | 173 | testWidgets('$screen lays out at ${entry.key}', (tester) async { |
| 174 | 174 | core.demoUi(); |
| @@ -194,7 +194,7 @@ void main() { | ||
| 194 | 194 | await tester.pump(); |
| 195 | 195 | } |
| 196 | 196 | |
| 197 | - for (final screen in ['chat', 'chats', 'discover', 'settings']) { | |
| 197 | + for (final screen in ['chat', 'chats', 'dms', 'discover', 'settings']) { | |
| 198 | 198 | // The platform has to be said out loud. A widget test runs as Android |
| 199 | 199 | // by default, where a SingleChildScrollView *is* primary and attaches |
| 200 | 200 | // to the very controller the scrollbar is looking at — so this passed |
| @@ -168,7 +168,7 @@ void main() { | |||
| 168 | }); | 168 | }); |
| 169 | 169 | ||
| 170 | group('discover and settings', () { | 170 | group('discover and settings', () { |
| 171 | - for (final screen in ['discover', 'settings']) { | 171 | + for (final screen in ['dms', 'discover', 'settings']) { |
| 172 | for (final entry in sizes.entries) { | 172 | for (final entry in sizes.entries) { |
| 173 | testWidgets('$screen lays out at ${entry.key}', (tester) async { | 173 | testWidgets('$screen lays out at ${entry.key}', (tester) async { |
| 174 | core.demoUi(); | 174 | core.demoUi(); |
| @@ -194,7 +194,7 @@ void main() { | |||
| 194 | await tester.pump(); | 194 | await tester.pump(); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | - for (final screen in ['chat', 'chats', 'discover', 'settings']) { | 197 | + for (final screen in ['chat', 'chats', 'dms', 'discover', 'settings']) { |
| 198 | // The platform has to be said out loud. A widget test runs as Android | 198 | // The platform has to be said out loud. A widget test runs as Android |
| 199 | // by default, where a SingleChildScrollView *is* primary and attaches | 199 | // by default, where a SingleChildScrollView *is* primary and attaches |
| 200 | // to the very controller the scrollbar is looking at — so this passed | 200 | // to the very controller the scrollbar is looking at — so this passed |
modified
nim/src/frq/cells.nim +1 -1 | @@ -16,7 +16,7 @@ import frq/[model] | ||
| 16 | 16 | type |
| 17 | 17 | Screen* = enum |
| 18 | 18 | scConnect = "connect", scChats = "chats", scChat = "chat", |
| 19 | - scDiscover = "discover", scSettings = "settings" | |
| 19 | + scDms = "dms", scDiscover = "discover", scSettings = "settings" | |
| 20 | 20 | |
| 21 | 21 | AuthMode* = enum |
| 22 | 22 | amGuest = "guest", amBluesky = "bluesky", amAppPassword = "app-password" |
| @@ -16,7 +16,7 @@ import frq/[model] | |||
| 16 | type | 16 | type |
| 17 | Screen* = enum | 17 | Screen* = enum |
| 18 | scConnect = "connect", scChats = "chats", scChat = "chat", | 18 | scConnect = "connect", scChats = "chats", scChat = "chat", |
| 19 | - scDiscover = "discover", scSettings = "settings" | 19 | + scDms = "dms", scDiscover = "discover", scSettings = "settings" |
| 20 | 20 | ||
| 21 | AuthMode* = enum | 21 | AuthMode* = enum |
| 22 | amGuest = "guest", amBluesky = "bluesky", amAppPassword = "app-password" | 22 | amGuest = "guest", amBluesky = "bluesky", amAppPassword = "app-password" |
modified
nim/src/frq/reducer.nim +1 -0 | @@ -496,6 +496,7 @@ proc dispatch*(event: JsonNode) = | ||
| 496 | 496 | # ------------------------------------------------------------- navigation |
| 497 | 497 | of "screen.connect": app.screen = scConnect |
| 498 | 498 | of "screen.chats": app.screen = scChats |
| 499 | + of "screen.dms": app.screen = scDms | |
| 499 | 500 | of "screen.discover": app.screen = scDiscover |
| 500 | 501 | of "screen.settings": app.screen = scSettings |
| 501 | 502 | |
| @@ -496,6 +496,7 @@ proc dispatch*(event: JsonNode) = | |||
| 496 | # ------------------------------------------------------------- navigation | 496 | # ------------------------------------------------------------- navigation |
| 497 | of "screen.connect": app.screen = scConnect | 497 | of "screen.connect": app.screen = scConnect |
| 498 | of "screen.chats": app.screen = scChats | 498 | of "screen.chats": app.screen = scChats |
| 499 | + of "screen.dms": app.screen = scDms | ||
| 499 | of "screen.discover": app.screen = scDiscover | 500 | of "screen.discover": app.screen = scDiscover |
| 500 | of "screen.settings": app.screen = scSettings | 501 | of "screen.settings": app.screen = scSettings |
| 501 | 502 | ||
modified
nim/src/frq/screens/chats.nim +21 -8 | @@ -4,7 +4,7 @@ | ||
| 4 | 4 | ## dropped rather than translated — there is no terminal frontend any more, so |
| 5 | 5 | ## `conversation-row`'s two layouts collapse to the one a window uses. |
| 6 | 6 | |
| 7 | -import std/[json, strutils] | |
| 7 | +import std/[json, sequtils, strutils] | |
| 8 | 8 | import frq/[ui, cells, model, rooms, textruns] |
| 9 | 9 | import frq/screens/[frame, connect] |
| 10 | 10 | |
| @@ -42,24 +42,30 @@ func conversationRow(r: Room): Node = | ||
| 42 | 42 | button("Open", "room.open:" & r.name), |
| 43 | 43 | button("Close", "room.leave:" & r.name)))]) |
| 44 | 44 | |
| 45 | -func chatsScreen*(s: State, connected: bool): Node = | |
| 46 | - let buffers = channelList(s.rooms, s.search) | |
| 45 | +func conversationListScreen(s: State, connected, direct: bool): Node = | |
| 46 | + ## The two kinds of conversation have their own tabs, but share the cards | |
| 47 | + ## and controls. A DM is identified by its name rather than by a second | |
| 48 | + ## collection in state, so it remains visible after reconnecting like rooms. | |
| 49 | + let buffers = channelList(s.rooms, s.search).filterIt(dm(it.name) == direct) | |
| 50 | + let section = if direct: "DMs" else: "Chats" | |
| 47 | 51 | |
| 48 | 52 | var head = vbox(%*{"key": "head", "spacing": 8, "marginRight": listGutter}, |
| 49 | - title(if connected: "Logged in as " & s.formNick else: "Chats"), | |
| 53 | + title(if connected: "Logged in as " & s.formNick else: section), | |
| 50 | 54 | errorNote(s)) |
| 51 | 55 | |
| 52 | 56 | # `@nick` opens a DM and `#room` joins a channel, and the button says which |
| 53 | 57 | # so the reader is not guessing what Enter will do. |
| 54 | 58 | var joinRow = hbox(%*{"spacing": 8, "align": "end"}, |
| 55 | - button(if s.joinInput.startsWith("@"): "Message" else: "Join", "join"), | |
| 56 | - entry("join-input", s.joinInput, "#channel or @nick", "join-input.change", | |
| 59 | + button(if direct or s.joinInput.startsWith("@"): "Message" else: "Join", "join"), | |
| 60 | + entry("join-input", s.joinInput, | |
| 61 | + if direct: "@nick" else: "#channel or @nick", "join-input.change", | |
| 57 | 62 | onSubmit = "join", verbatim = true)) |
| 58 | 63 | |
| 59 | 64 | var searchRow = hbox(%*{"spacing": 8, "align": "end"}) |
| 60 | 65 | if s.search.len > 0: |
| 61 | 66 | searchRow.children.add button("✕", "search.clear") |
| 62 | - searchRow.children.add entry("search", s.search, "Search channels", | |
| 67 | + searchRow.children.add entry("search", s.search, | |
| 68 | + if direct: "Search direct messages" else: "Search channels", | |
| 63 | 69 | "search.change") |
| 64 | 70 | |
| 65 | 71 | head.children.add card(vbox(%*{"spacing": 8}, joinRow, searchRow)) |
| @@ -71,7 +77,8 @@ func chatsScreen*(s: State, connected: bool): Node = | ||
| 71 | 77 | body.children.add conversationRow(b) |
| 72 | 78 | else: |
| 73 | 79 | body = n("vbox", %*{"marginRight": listGutter}, @[ |
| 74 | - card(dimLabel("No conversations yet — join a channel."))]) | |
| 80 | + card(dimLabel(if direct: "No direct messages yet — message someone." | |
| 81 | + else: "No conversations yet — join a channel."))]) | |
| 75 | 82 | |
| 76 | 83 | vbox(%*{"spacing": 8, "margin": 12, "expand": true}, |
| 77 | 84 | head, |
| @@ -80,3 +87,9 @@ func chatsScreen*(s: State, connected: bool): Node = | ||
| 80 | 87 | vbox(%*{"key": "foot", "spacing": 8}, |
| 81 | 88 | separator(), |
| 82 | 89 | tabBar(s))) |
| 90 | + | |
| 91 | +func chatsScreen*(s: State, connected: bool): Node = | |
| 92 | + conversationListScreen(s, connected, direct = false) | |
| 93 | + | |
| 94 | +func dmsScreen*(s: State, connected: bool): Node = | |
| 95 | + conversationListScreen(s, connected, direct = true) | |
| @@ -4,7 +4,7 @@ | |||
| 4 | ## dropped rather than translated — there is no terminal frontend any more, so | 4 | ## dropped rather than translated — there is no terminal frontend any more, so |
| 5 | ## `conversation-row`'s two layouts collapse to the one a window uses. | 5 | ## `conversation-row`'s two layouts collapse to the one a window uses. |
| 6 | 6 | ||
| 7 | -import std/[json, strutils] | 7 | +import std/[json, sequtils, strutils] |
| 8 | import frq/[ui, cells, model, rooms, textruns] | 8 | import frq/[ui, cells, model, rooms, textruns] |
| 9 | import frq/screens/[frame, connect] | 9 | import frq/screens/[frame, connect] |
| 10 | 10 | ||
| @@ -42,24 +42,30 @@ func conversationRow(r: Room): Node = | |||
| 42 | button("Open", "room.open:" & r.name), | 42 | button("Open", "room.open:" & r.name), |
| 43 | button("Close", "room.leave:" & r.name)))]) | 43 | button("Close", "room.leave:" & r.name)))]) |
| 44 | 44 | ||
| 45 | -func chatsScreen*(s: State, connected: bool): Node = | 45 | +func conversationListScreen(s: State, connected, direct: bool): Node = |
| 46 | - let buffers = channelList(s.rooms, s.search) | 46 | + ## The two kinds of conversation have their own tabs, but share the cards |
| 47 | + ## and controls. A DM is identified by its name rather than by a second | ||
| 48 | + ## collection in state, so it remains visible after reconnecting like rooms. | ||
| 49 | + let buffers = channelList(s.rooms, s.search).filterIt(dm(it.name) == direct) | ||
| 50 | + let section = if direct: "DMs" else: "Chats" | ||
| 47 | 51 | ||
| 48 | var head = vbox(%*{"key": "head", "spacing": 8, "marginRight": listGutter}, | 52 | var head = vbox(%*{"key": "head", "spacing": 8, "marginRight": listGutter}, |
| 49 | - title(if connected: "Logged in as " & s.formNick else: "Chats"), | 53 | + title(if connected: "Logged in as " & s.formNick else: section), |
| 50 | errorNote(s)) | 54 | errorNote(s)) |
| 51 | 55 | ||
| 52 | # `@nick` opens a DM and `#room` joins a channel, and the button says which | 56 | # `@nick` opens a DM and `#room` joins a channel, and the button says which |
| 53 | # so the reader is not guessing what Enter will do. | 57 | # so the reader is not guessing what Enter will do. |
| 54 | var joinRow = hbox(%*{"spacing": 8, "align": "end"}, | 58 | var joinRow = hbox(%*{"spacing": 8, "align": "end"}, |
| 55 | - button(if s.joinInput.startsWith("@"): "Message" else: "Join", "join"), | 59 | + button(if direct or s.joinInput.startsWith("@"): "Message" else: "Join", "join"), |
| 56 | - entry("join-input", s.joinInput, "#channel or @nick", "join-input.change", | 60 | + entry("join-input", s.joinInput, |
| 61 | + if direct: "@nick" else: "#channel or @nick", "join-input.change", | ||
| 57 | onSubmit = "join", verbatim = true)) | 62 | onSubmit = "join", verbatim = true)) |
| 58 | 63 | ||
| 59 | var searchRow = hbox(%*{"spacing": 8, "align": "end"}) | 64 | var searchRow = hbox(%*{"spacing": 8, "align": "end"}) |
| 60 | if s.search.len > 0: | 65 | if s.search.len > 0: |
| 61 | searchRow.children.add button("✕", "search.clear") | 66 | searchRow.children.add button("✕", "search.clear") |
| 62 | - searchRow.children.add entry("search", s.search, "Search channels", | 67 | + searchRow.children.add entry("search", s.search, |
| 68 | + if direct: "Search direct messages" else: "Search channels", | ||
| 63 | "search.change") | 69 | "search.change") |
| 64 | 70 | ||
| 65 | head.children.add card(vbox(%*{"spacing": 8}, joinRow, searchRow)) | 71 | head.children.add card(vbox(%*{"spacing": 8}, joinRow, searchRow)) |
| @@ -71,7 +77,8 @@ func chatsScreen*(s: State, connected: bool): Node = | |||
| 71 | body.children.add conversationRow(b) | 77 | body.children.add conversationRow(b) |
| 72 | else: | 78 | else: |
| 73 | body = n("vbox", %*{"marginRight": listGutter}, @[ | 79 | body = n("vbox", %*{"marginRight": listGutter}, @[ |
| 74 | - card(dimLabel("No conversations yet — join a channel."))]) | 80 | + card(dimLabel(if direct: "No direct messages yet — message someone." |
| 81 | + else: "No conversations yet — join a channel."))]) | ||
| 75 | 82 | ||
| 76 | vbox(%*{"spacing": 8, "margin": 12, "expand": true}, | 83 | vbox(%*{"spacing": 8, "margin": 12, "expand": true}, |
| 77 | head, | 84 | head, |
| @@ -80,3 +87,9 @@ func chatsScreen*(s: State, connected: bool): Node = | |||
| 80 | vbox(%*{"key": "foot", "spacing": 8}, | 87 | vbox(%*{"key": "foot", "spacing": 8}, |
| 81 | separator(), | 88 | separator(), |
| 82 | tabBar(s))) | 89 | tabBar(s))) |
| 90 | + | ||
| 91 | +func chatsScreen*(s: State, connected: bool): Node = | ||
| 92 | + conversationListScreen(s, connected, direct = false) | ||
| 93 | + | ||
| 94 | +func dmsScreen*(s: State, connected: bool): Node = | ||
| 95 | + conversationListScreen(s, connected, direct = true) | ||
modified
nim/src/frq/screens/frame.nim +3 -1 | @@ -8,7 +8,7 @@ import std/json | ||
| 8 | 8 | import frq/[ui, cells] |
| 9 | 9 | |
| 10 | 10 | func tabBar*(s: State): Node = |
| 11 | - ## The three screens, and the way between them. | |
| 11 | + ## The four screens, and the way between them. | |
| 12 | 12 | ## |
| 13 | 13 | ## Lit for a conversation as well as for the list, because a conversation is |
| 14 | 14 | ## what the Chats tab leads to — a bar with nothing lit on it reads as a bar |
| @@ -16,6 +16,8 @@ func tabBar*(s: State): Node = | ||
| 16 | 16 | hbox(%*{"spacing": 8}, |
| 17 | 17 | button("Chats", "screen.chats", |
| 18 | 18 | if s.screen in {scChats, scChat}: "primary" else: "default"), |
| 19 | + button("DMs", "screen.dms", | |
| 20 | + if s.screen == scDms: "primary" else: "default"), | |
| 19 | 21 | button("Discover", "screen.discover", |
| 20 | 22 | if s.screen == scDiscover: "primary" else: "default"), |
| 21 | 23 | button("Settings", "screen.settings", |
| @@ -8,7 +8,7 @@ import std/json | |||
| 8 | import frq/[ui, cells] | 8 | import frq/[ui, cells] |
| 9 | 9 | ||
| 10 | func tabBar*(s: State): Node = | 10 | func tabBar*(s: State): Node = |
| 11 | - ## The three screens, and the way between them. | 11 | + ## The four screens, and the way between them. |
| 12 | ## | 12 | ## |
| 13 | ## Lit for a conversation as well as for the list, because a conversation is | 13 | ## Lit for a conversation as well as for the list, because a conversation is |
| 14 | ## what the Chats tab leads to — a bar with nothing lit on it reads as a bar | 14 | ## what the Chats tab leads to — a bar with nothing lit on it reads as a bar |
| @@ -16,6 +16,8 @@ func tabBar*(s: State): Node = | |||
| 16 | hbox(%*{"spacing": 8}, | 16 | hbox(%*{"spacing": 8}, |
| 17 | button("Chats", "screen.chats", | 17 | button("Chats", "screen.chats", |
| 18 | if s.screen in {scChats, scChat}: "primary" else: "default"), | 18 | if s.screen in {scChats, scChat}: "primary" else: "default"), |
| 19 | + button("DMs", "screen.dms", | ||
| 20 | + if s.screen == scDms: "primary" else: "default"), | ||
| 19 | button("Discover", "screen.discover", | 21 | button("Discover", "screen.discover", |
| 20 | if s.screen == scDiscover: "primary" else: "default"), | 22 | if s.screen == scDiscover: "primary" else: "default"), |
| 21 | button("Settings", "screen.settings", | 23 | button("Settings", "screen.settings", |
modified
nim/src/frq_core.nim +1 -0 | @@ -172,6 +172,7 @@ proc currentTree(): string = | ||
| 172 | 172 | case app.screen |
| 173 | 173 | of scChat: scChatScreen.chatScreen(app, connected) |
| 174 | 174 | of scChats: scChatsScreen.chatsScreen(app, connected) |
| 175 | + of scDms: scChatsScreen.dmsScreen(app, connected) | |
| 175 | 176 | of scDiscover: scSettingsScreen.discoverScreen(app) |
| 176 | 177 | of scSettings: scSettingsScreen.settingsScreen(app, connected, true) |
| 177 | 178 | of scConnect: scConnectScreen.connectScreen(app) |
| @@ -172,6 +172,7 @@ proc currentTree(): string = | |||
| 172 | case app.screen | 172 | case app.screen |
| 173 | of scChat: scChatScreen.chatScreen(app, connected) | 173 | of scChat: scChatScreen.chatScreen(app, connected) |
| 174 | of scChats: scChatsScreen.chatsScreen(app, connected) | 174 | of scChats: scChatsScreen.chatsScreen(app, connected) |
| 175 | + of scDms: scChatsScreen.dmsScreen(app, connected) | ||
| 175 | of scDiscover: scSettingsScreen.discoverScreen(app) | 176 | of scDiscover: scSettingsScreen.discoverScreen(app) |
| 176 | of scSettings: scSettingsScreen.settingsScreen(app, connected, true) | 177 | of scSettings: scSettingsScreen.settingsScreen(app, connected, true) |
| 177 | of scConnect: scConnectScreen.connectScreen(app) | 178 | of scConnect: scConnectScreen.connectScreen(app) |
modified
nim/tests/tscreens.nim +24 -4 | @@ -9,6 +9,7 @@ import frq/[ui, cells, model] | ||
| 9 | 9 | import frq/screens/connect as cs |
| 10 | 10 | import frq/screens/settings as ss |
| 11 | 11 | import frq/screens/chat as cht |
| 12 | +import frq/screens/chats as ch | |
| 12 | 13 | import frq/[rooms] |
| 13 | 14 | |
| 14 | 15 | proc find*(node: Node, tag: string): seq[Node] = |
| @@ -139,6 +140,26 @@ suite "discover": | ||
| 139 | 140 | check "Discover" in sel |
| 140 | 141 | check t.find("scroll").len == 1 |
| 141 | 142 | |
| 143 | +suite "direct messages": | |
| 144 | + test "shows only direct-message buffers": | |
| 145 | + var s = initState() | |
| 146 | + var room = initRoom("#test"); room.joined = true | |
| 147 | + var direct = initRoom("alice") | |
| 148 | + s.rooms[room.name] = room | |
| 149 | + s.rooms[direct.name] = direct | |
| 150 | + let t = ch.dmsScreen(s, true) | |
| 151 | + check "alice" in t.labels("title-2") | |
| 152 | + check "#test" notin t.labels("title-2") | |
| 153 | + check "DMs" in t.labels("button") | |
| 154 | + | |
| 155 | + test "the DMs tab is selected": | |
| 156 | + var s = initState() | |
| 157 | + s.screen = scDms | |
| 158 | + let selected = ch.dmsScreen(s, false).find("button") | |
| 159 | + .filterIt(it.props{"kind"}.getStr() == "primary") | |
| 160 | + .mapIt(it.props{"label"}.getStr()) | |
| 161 | + check "DMs" in selected | |
| 162 | + | |
| 142 | 163 | suite "settings": |
| 143 | 164 | setup: |
| 144 | 165 | var s = initState() |
| @@ -179,8 +200,6 @@ suite "settings": | ||
| 179 | 200 | check not ss.settingsScreen(s, false, true).find("status")[0] |
| 180 | 201 | .props{"live"}.getBool() |
| 181 | 202 | |
| 182 | -import frq/screens/chats as ch | |
| 183 | - | |
| 184 | 203 | suite "previewLine": |
| 185 | 204 | test "collapses whitespace so a card reads as one line": |
| 186 | 205 | check ch.previewLine("a\n b\tc") == "a b c" |
| @@ -300,11 +319,12 @@ suite "the chat screen's panes": | ||
| 300 | 319 | check t.find("scroll").anyIt( |
| 301 | 320 | it.props{"scrollKey"}.getStr() == "messages-#test") |
| 302 | 321 | |
| 303 | - test "the way to Discover and Settings is on the screen": | |
| 322 | + test "the way to DMs, Discover and Settings is on the screen": | |
| 304 | 323 | # It was not: the chat screen never carried the tab bar, and on a wide |
| 305 | 324 | # window there is no back button either — the room list is a strip. So |
| 306 | - # from a conversation there was no way to either of them at all. | |
| 325 | + # from a conversation there was no way to any of them at all. | |
| 307 | 326 | let t = cht.chatScreen(s, true) |
| 327 | + check "DMs" in t.labels("button") | |
| 308 | 328 | check "Discover" in t.labels("button") |
| 309 | 329 | check "Settings" in t.labels("button") |
| 310 | 330 | |
| @@ -9,6 +9,7 @@ import frq/[ui, cells, model] | |||
| 9 | import frq/screens/connect as cs | 9 | import frq/screens/connect as cs |
| 10 | import frq/screens/settings as ss | 10 | import frq/screens/settings as ss |
| 11 | import frq/screens/chat as cht | 11 | import frq/screens/chat as cht |
| 12 | +import frq/screens/chats as ch | ||
| 12 | import frq/[rooms] | 13 | import frq/[rooms] |
| 13 | 14 | ||
| 14 | proc find*(node: Node, tag: string): seq[Node] = | 15 | proc find*(node: Node, tag: string): seq[Node] = |
| @@ -139,6 +140,26 @@ suite "discover": | |||
| 139 | check "Discover" in sel | 140 | check "Discover" in sel |
| 140 | check t.find("scroll").len == 1 | 141 | check t.find("scroll").len == 1 |
| 141 | 142 | ||
| 143 | +suite "direct messages": | ||
| 144 | + test "shows only direct-message buffers": | ||
| 145 | + var s = initState() | ||
| 146 | + var room = initRoom("#test"); room.joined = true | ||
| 147 | + var direct = initRoom("alice") | ||
| 148 | + s.rooms[room.name] = room | ||
| 149 | + s.rooms[direct.name] = direct | ||
| 150 | + let t = ch.dmsScreen(s, true) | ||
| 151 | + check "alice" in t.labels("title-2") | ||
| 152 | + check "#test" notin t.labels("title-2") | ||
| 153 | + check "DMs" in t.labels("button") | ||
| 154 | + | ||
| 155 | + test "the DMs tab is selected": | ||
| 156 | + var s = initState() | ||
| 157 | + s.screen = scDms | ||
| 158 | + let selected = ch.dmsScreen(s, false).find("button") | ||
| 159 | + .filterIt(it.props{"kind"}.getStr() == "primary") | ||
| 160 | + .mapIt(it.props{"label"}.getStr()) | ||
| 161 | + check "DMs" in selected | ||
| 162 | + | ||
| 142 | suite "settings": | 163 | suite "settings": |
| 143 | setup: | 164 | setup: |
| 144 | var s = initState() | 165 | var s = initState() |
| @@ -179,8 +200,6 @@ suite "settings": | |||
| 179 | check not ss.settingsScreen(s, false, true).find("status")[0] | 200 | check not ss.settingsScreen(s, false, true).find("status")[0] |
| 180 | .props{"live"}.getBool() | 201 | .props{"live"}.getBool() |
| 181 | 202 | ||
| 182 | -import frq/screens/chats as ch | ||
| 183 | - | ||
| 184 | suite "previewLine": | 203 | suite "previewLine": |
| 185 | test "collapses whitespace so a card reads as one line": | 204 | test "collapses whitespace so a card reads as one line": |
| 186 | check ch.previewLine("a\n b\tc") == "a b c" | 205 | check ch.previewLine("a\n b\tc") == "a b c" |
| @@ -300,11 +319,12 @@ suite "the chat screen's panes": | |||
| 300 | check t.find("scroll").anyIt( | 319 | check t.find("scroll").anyIt( |
| 301 | it.props{"scrollKey"}.getStr() == "messages-#test") | 320 | it.props{"scrollKey"}.getStr() == "messages-#test") |
| 302 | 321 | ||
| 303 | - test "the way to Discover and Settings is on the screen": | 322 | + test "the way to DMs, Discover and Settings is on the screen": |
| 304 | # It was not: the chat screen never carried the tab bar, and on a wide | 323 | # It was not: the chat screen never carried the tab bar, and on a wide |
| 305 | # window there is no back button either — the room list is a strip. So | 324 | # window there is no back button either — the room list is a strip. So |
| 306 | - # from a conversation there was no way to either of them at all. | 325 | + # from a conversation there was no way to any of them at all. |
| 307 | let t = cht.chatScreen(s, true) | 326 | let t = cht.chatScreen(s, true) |
| 327 | + check "DMs" in t.labels("button") | ||
| 308 | check "Discover" in t.labels("button") | 328 | check "Discover" in t.labels("button") |
| 309 | check "Settings" in t.labels("button") | 329 | check "Settings" in t.labels("button") |
| 310 | 330 | ||