Skip to content

Commit 83d4a7f

Browse files
committed
narrow: Support MentionsNarrow.
Because of how narrow interacts with the entire app, there are test updates all over the place. The way I checked for the completeness of this change is by looking at places where CombinedFeedNarrow is referenced. Signed-off-by: Zixuan James Li <[email protected]>
1 parent d55c5aa commit 83d4a7f

15 files changed

+198
-7
lines changed

assets/l10n/app_en.arb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,10 @@
344344
"@loginErrorMissingUsername": {
345345
"description": "Error message when an empty username was provided."
346346
},
347+
"mentionsPageTitle": "Mentions",
348+
"@mentionsPageTitle": {
349+
"description": "Title for the page of @-mentions."
350+
},
347351
"topicValidationErrorTooLong": "Topic length shouldn't be greater than 60 characters.",
348352
"@topicValidationErrorTooLong": {
349353
"description": "Topic validation error when topic is too long."

lib/model/autocomplete.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ class MentionAutocompleteView extends ChangeNotifier {
188188
required Narrow narrow,
189189
}) {
190190
assert(narrow is! CombinedFeedNarrow);
191+
assert(narrow is! MentionsNarrow);
191192
return store.users.values.toList()
192193
..sort((userA, userB) => compareByDms(userA, userB, store: store));
193194
}

lib/model/message_list.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ class MessageListView with ChangeNotifier, _MessageSequence {
370370

371371
case TopicNarrow():
372372
case DmNarrow():
373+
case MentionsNarrow():
373374
return true;
374375
}
375376
}
@@ -385,6 +386,7 @@ class MessageListView with ChangeNotifier, _MessageSequence {
385386

386387
case TopicNarrow():
387388
case DmNarrow():
389+
case MentionsNarrow():
388390
return true;
389391
}
390392
}

lib/model/narrow.dart

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,4 +286,27 @@ class DmNarrow extends Narrow implements SendableNarrow {
286286
int get hashCode => Object.hash('DmNarrow', _key);
287287
}
288288

289-
// TODO other narrow types: starred, mentioned; searches; arbitrary
289+
class MentionsNarrow extends Narrow {
290+
const MentionsNarrow();
291+
292+
@override
293+
bool containsMessage(Message message) {
294+
return message.flags.any((flag) =>
295+
flag == MessageFlag.mentioned || flag == MessageFlag.wildcardMentioned);
296+
}
297+
298+
@override
299+
ApiNarrow apiEncode() => [ApiNarrowIsMentioned()];
300+
301+
@override
302+
bool operator ==(Object other) {
303+
if (other is! MentionsNarrow) return false;
304+
// Conceptually there's only one value of this type.
305+
return true;
306+
}
307+
308+
@override
309+
int get hashCode => 'MentionedNarrow'.hashCode;
310+
}
311+
312+
// TODO other narrow types: starred; searches; arbitrary

lib/model/unreads.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ class Unreads extends ChangeNotifier {
193193

194194
int countInDmNarrow(DmNarrow narrow) => dms[narrow]?.length ?? 0;
195195

196+
int countInMentionsNarrow() => mentions.length;
197+
196198
int countInNarrow(Narrow narrow) {
197199
switch (narrow) {
198200
case CombinedFeedNarrow():
@@ -203,6 +205,8 @@ class Unreads extends ChangeNotifier {
203205
return countInTopicNarrow(narrow.streamId, narrow.topic);
204206
case DmNarrow():
205207
return countInDmNarrow(narrow);
208+
case MentionsNarrow():
209+
return countInMentionsNarrow();
206210
}
207211
}
208212

lib/widgets/compose_box.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -967,7 +967,7 @@ class ComposeBox extends StatelessWidget {
967967
return _FixedDestinationComposeBox(key: controllerKey, narrow: narrow);
968968
} else if (narrow is DmNarrow) {
969969
return _FixedDestinationComposeBox(key: controllerKey, narrow: narrow);
970-
} else if (narrow is CombinedFeedNarrow) {
970+
} else if (narrow is CombinedFeedNarrow || narrow is MentionsNarrow) {
971971
return const SizedBox.shrink();
972972
} else {
973973
throw Exception("impossible narrow"); // TODO(dart-3): show this statically

lib/widgets/message_list.dart

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class _MessageListPageState extends State<MessageListPage> {
6363
bool removeAppBarBottomBorder = false;
6464
switch(widget.narrow) {
6565
case CombinedFeedNarrow():
66+
case MentionsNarrow():
6667
appBarBackgroundColor = null; // i.e., inherit
6768

6869
case StreamNarrow(:final streamId):
@@ -109,7 +110,8 @@ class _MessageListPageState extends State<MessageListPage> {
109110
// if those details get complicated, refactor to avoid copying.
110111
// TODO(#311) If we have a bottom nav, it will pad the bottom
111112
// inset, and this should always be true.
112-
removeBottom: widget.narrow is! CombinedFeedNarrow,
113+
removeBottom: widget.narrow is! CombinedFeedNarrow
114+
&& widget.narrow is! MentionsNarrow,
113115

114116
child: Expanded(
115117
child: MessageList(narrow: widget.narrow))),
@@ -170,6 +172,9 @@ class MessageListAppBarTitle extends StatelessWidget {
170172
final names = otherRecipientIds.map((id) => store.users[id]?.fullName ?? '(unknown user)');
171173
return Text("DMs with ${names.join(", ")}"); // TODO show avatars
172174
}
175+
176+
case MentionsNarrow():
177+
return Text(zulipLocalizations.mentionsPageTitle);
173178
}
174179
}
175180
}
@@ -340,7 +345,7 @@ class _MessageListState extends State<MessageList> with PerAccountStoreAwareStat
340345
return _buildItem(data, i);
341346
}));
342347

343-
if (widget.narrow is CombinedFeedNarrow) {
348+
if (widget.narrow is CombinedFeedNarrow || widget.narrow is MentionsNarrow) {
344349
// TODO(#311) If we have a bottom nav, it will pad the bottom
345350
// inset, and this shouldn't be necessary
346351
sliver = SliverSafeArea(sliver: sliver);
@@ -521,7 +526,7 @@ class RecipientHeader extends StatelessWidget {
521526
final message = this.message;
522527
return switch (message) {
523528
StreamMessage() => StreamMessageRecipientHeader(message: message,
524-
showStream: narrow is CombinedFeedNarrow),
529+
showStream: narrow is CombinedFeedNarrow || narrow is MentionsNarrow),
525530
DmMessage() => DmRecipientHeader(message: message),
526531
};
527532
}
@@ -1111,5 +1116,12 @@ Future<void> _legacyMarkNarrowAsRead(BuildContext context, Narrow narrow) async
11111116
messages: unreadDms,
11121117
op: UpdateMessageFlagsOp.add,
11131118
flag: MessageFlag.read);
1119+
case MentionsNarrow():
1120+
final unreadMentions = store.unreads.mentions.toList();
1121+
if (unreadMentions.isEmpty) return;
1122+
await updateMessageFlags(connection,
1123+
messages: unreadMentions,
1124+
op: UpdateMessageFlagsOp.add,
1125+
flag: MessageFlag.read);
11141126
}
11151127
}

test/api/route/messages_test.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ void main() {
188188
{'operator': 'stream', 'operand': 12},
189189
{'operator': 'topic', 'operand': 'stuff'},
190190
]));
191+
checkNarrow(const MentionsNarrow().apiEncode(), jsonEncode([
192+
{'operator': 'is', 'operand': 'mentioned'},
193+
]));
191194

192195
checkNarrow([ApiNarrowDm([123, 234])], jsonEncode([
193196
{'operator': 'dm', 'operand': [123, 234]},

test/model/autocomplete_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,15 @@ void main() {
472472
expected: [0, 1, 2, 3, 4])
473473
).throws();
474474
});
475+
476+
test('MentionsNarrow', () async {
477+
// As we do not expect a compose box in [MentionsNarrow], it should
478+
// not proceed to show any results.
479+
await check(checkResultsIn(
480+
const MentionsNarrow(),
481+
expected: [0, 1, 2, 3, 4])
482+
).throws();
483+
});
475484
});
476485
});
477486
}

test/model/compose_test.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,16 @@ hello
299299
'#narrow/pm-with/1,2-pm/near/12345');
300300
});
301301

302+
test('MentionsNarrow', () {
303+
final store = eg.store();
304+
check(narrowLink(store, const MentionsNarrow()))
305+
.equals(store.realmUrl.resolve('#narrow/is/mentioned'));
306+
check(narrowLink(store, const MentionsNarrow(), nearMessageId: 1))
307+
.equals(store.realmUrl.resolve('#narrow/is/mentioned/near/1'));
308+
});
309+
302310
// TODO other Narrow subclasses as we add them:
303-
// starred, mentioned; searches; arbitrary
311+
// starred; searches; arbitrary
304312
});
305313

306314
group('mention', () {

0 commit comments

Comments
 (0)