Skip to content

Commit 9c5dd67

Browse files
committed
@-mentions wip.
Signed-off-by: Zixuan James Li <[email protected]>
1 parent 51e01f4 commit 9c5dd67

15 files changed

+81
-4
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/api/model/events.g.dart

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/api/model/model.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,9 @@ enum MessageFlag {
551551
starred,
552552
collapsed,
553553
mentioned,
554-
wildcardMentioned,
554+
wildcardMentioned, // TODO(server-8) deprecated FL 224
555+
channelWildcardMentioned,
556+
topicWildcardMentioned,
555557
hasAlertWord,
556558
historical,
557559
unknown;

lib/api/model/model.g.dart

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/api/model/narrow.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ sealed class ApiNarrowElement {
3434
};
3535
}
3636

37+
class ApiNarrowMentions extends ApiNarrowElement {
38+
@override String get operator => 'is';
39+
@override String get operand => 'mentioned';
40+
41+
ApiNarrowMentions({super.negated});
42+
}
43+
3744
class ApiNarrowStream extends ApiNarrowElement {
3845
@override String get operator => 'stream';
3946

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/internal_link.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ Uri narrowLink(PerAccountStore store, Narrow narrow, {int? nearMessageId}) {
7070
fragment.write('${element.operator}/');
7171

7272
switch (element) {
73+
case ApiNarrowMentions():
74+
fragment.write(element.operand.toString());
7375
case ApiNarrowStream():
7476
final streamId = element.operand;
7577
final name = store.streams[streamId]?.name ?? 'unknown';

lib/model/message_list.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ class MessageListView with ChangeNotifier, _MessageSequence {
357357
bool _messageVisible(Message message) {
358358
switch (narrow) {
359359
case CombinedFeedNarrow():
360+
case MentionsNarrow():
360361
return switch (message) {
361362
StreamMessage() =>
362363
store.isTopicVisible(message.streamId, message.topic),
@@ -380,6 +381,7 @@ class MessageListView with ChangeNotifier, _MessageSequence {
380381
bool get _allMessagesVisible {
381382
switch (narrow) {
382383
case CombinedFeedNarrow():
384+
case MentionsNarrow():
383385
case StreamNarrow():
384386
return false;
385387

lib/model/narrow.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,32 @@ class CombinedFeedNarrow extends Narrow {
6565
int get hashCode => 'CombinedFeedNarrow'.hashCode;
6666
}
6767

68+
class MentionsNarrow extends Narrow {
69+
const MentionsNarrow();
70+
71+
@override
72+
bool containsMessage(Message message) {
73+
return message.flags.any((flag) =>
74+
flag == MessageFlag.mentioned
75+
|| flag == MessageFlag.wildcardMentioned
76+
|| flag == MessageFlag.channelWildcardMentioned
77+
|| flag == MessageFlag.topicWildcardMentioned);
78+
}
79+
80+
@override
81+
ApiNarrow apiEncode() => [ApiNarrowMentions()];
82+
83+
@override
84+
bool operator ==(Object other) {
85+
if (other is! MentionsNarrow) return false;
86+
// Conceptually there's only one value of this type.
87+
return true;
88+
}
89+
90+
@override
91+
int get hashCode => 'MentionedNarrow'.hashCode;
92+
}
93+
6894
class StreamNarrow extends Narrow {
6995
const StreamNarrow(this.streamId);
7096

lib/model/unreads.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ class Unreads extends ChangeNotifier {
144144
return c;
145145
}
146146

147+
int countInMentionedNarrow() {
148+
return mentions.length;
149+
}
150+
147151
/// The "strict" unread count for this stream,
148152
/// using [StreamStore.isTopicVisible].
149153
///
@@ -197,6 +201,8 @@ class Unreads extends ChangeNotifier {
197201
switch (narrow) {
198202
case CombinedFeedNarrow():
199203
return countInCombinedFeedNarrow();
204+
case MentionsNarrow():
205+
return countInMentionedNarrow();
200206
case StreamNarrow():
201207
return countInStreamNarrow(narrow.streamId);
202208
case TopicNarrow():
@@ -222,6 +228,8 @@ class Unreads extends ChangeNotifier {
222228
if (
223229
message.flags.contains(MessageFlag.mentioned)
224230
|| message.flags.contains(MessageFlag.wildcardMentioned)
231+
|| message.flags.contains(MessageFlag.channelWildcardMentioned)
232+
|| message.flags.contains(MessageFlag.topicWildcardMentioned)
225233
) {
226234
mentions.add(message.id);
227235
}
@@ -308,6 +316,8 @@ class Unreads extends ChangeNotifier {
308316

309317
case MessageFlag.mentioned:
310318
case MessageFlag.wildcardMentioned:
319+
case MessageFlag.channelWildcardMentioned:
320+
case MessageFlag.topicWildcardMentioned:
311321
// Empirically, we don't seem to get these events when a message is edited
312322
// to add/remove an @-mention, even though @-mention state is represented
313323
// as flags. Instead, we just get the [UpdateMessageEvent], and that

lib/widgets/app.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,12 @@ class HomePage extends StatelessWidget {
276276
narrow: const CombinedFeedNarrow())),
277277
child: Text(zulipLocalizations.combinedFeedPageTitle)),
278278
const SizedBox(height: 16),
279+
ElevatedButton(
280+
onPressed: () => Navigator.push(context,
281+
MessageListPage.buildRoute(context: context,
282+
narrow: const MentionsNarrow())),
283+
child: Text(zulipLocalizations.mentionsPageTitle)),
284+
const SizedBox(height: 16),
279285
ElevatedButton(
280286
onPressed: () => Navigator.push(context,
281287
InboxPage.buildRoute(context: context)),

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: 12 additions & 2 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):
@@ -149,6 +150,8 @@ class MessageListAppBarTitle extends StatelessWidget {
149150
switch (narrow) {
150151
case CombinedFeedNarrow():
151152
return Text(zulipLocalizations.combinedFeedPageTitle);
153+
case MentionsNarrow():
154+
return Text(zulipLocalizations.mentionsPageTitle);
152155

153156
case StreamNarrow(:var streamId):
154157
final store = PerAccountStoreWidget.of(context);
@@ -340,7 +343,7 @@ class _MessageListState extends State<MessageList> with PerAccountStoreAwareStat
340343
return _buildItem(data, i);
341344
}));
342345

343-
if (widget.narrow is CombinedFeedNarrow) {
346+
if (widget.narrow is CombinedFeedNarrow || widget.narrow is MentionsNarrow) {
344347
// TODO(#311) If we have a bottom nav, it will pad the bottom
345348
// inset, and this shouldn't be necessary
346349
sliver = SliverSafeArea(sliver: sliver);
@@ -521,7 +524,7 @@ class RecipientHeader extends StatelessWidget {
521524
final message = this.message;
522525
return switch (message) {
523526
StreamMessage() => StreamMessageRecipientHeader(message: message,
524-
showStream: narrow is CombinedFeedNarrow),
527+
showStream: narrow is CombinedFeedNarrow || narrow is MentionsNarrow),
525528
DmMessage() => DmRecipientHeader(message: message),
526529
};
527530
}
@@ -1097,6 +1100,13 @@ Future<void> _legacyMarkNarrowAsRead(BuildContext context, Narrow narrow) async
10971100
switch (narrow) {
10981101
case CombinedFeedNarrow():
10991102
await markAllAsRead(connection);
1103+
case MentionsNarrow():
1104+
final unreadMentions = store.unreads.mentions.toList();
1105+
if (unreadMentions.isEmpty) return;
1106+
await updateMessageFlags(connection,
1107+
messages: unreadMentions,
1108+
op: UpdateMessageFlagsOp.add,
1109+
flag: MessageFlag.read);
11001110
case StreamNarrow(:final streamId):
11011111
await markStreamAsRead(connection, streamId: streamId);
11021112
case TopicNarrow(:final streamId, :final topic):

test/model/message_list_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,7 @@ void checkInvariants(MessageListView model) {
936936
case StreamNarrow():
937937
check(model.store.isTopicVisibleInStream(message.streamId, message.topic))
938938
.isTrue();
939+
case MentionsNarrow():
939940
case TopicNarrow():
940941
case DmNarrow():
941942
}

test/model/unreads_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,8 @@ void main() {
545545
MessageFlag.unknown => true,
546546
MessageFlag.mentioned => false,
547547
MessageFlag.wildcardMentioned => false,
548+
MessageFlag.channelWildcardMentioned => false,
549+
MessageFlag.topicWildcardMentioned => false,
548550
MessageFlag.read => false,
549551
});
550552

0 commit comments

Comments
 (0)