Skip to content

Commit 3e56f1d

Browse files
committed
user_topics: Treat invalid visibility_policy values as null
Previously, UserTopicVisibilityPolicy included an .unknown value to represent unexpected server values. This change removes that value and instead invalid or missing visibility_policy values deserialize as null. Did the same for UserTopicItem.visibilityPolicy, so unknown/missing values in the initial snapshot user_topics data are represented as null.handleUserTopicEvent- For events with visibilityPolicy == null, removed any existing entry for that topic and dropped the per‑stream map if it becomes empty.Tests added Fixes #1074
1 parent 89f6663 commit 3e56f1d

18 files changed

+217
-80
lines changed

lib/api/model/events.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,8 @@ class UserTopicEvent extends Event {
10511051
final int streamId;
10521052
final TopicName topicName;
10531053
final int lastUpdated;
1054-
final UserTopicVisibilityPolicy visibilityPolicy;
1054+
@JsonKey(unknownEnumValue: JsonKey.nullForUndefinedEnumValue)
1055+
final UserTopicVisibilityPolicy? visibilityPolicy;
10551056

10561057
UserTopicEvent({
10571058
required super.id,

lib/api/model/events.g.dart

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

lib/api/model/initial_snapshot.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,8 @@ class UserTopicItem {
370370
final int streamId;
371371
final TopicName topicName;
372372
final int lastUpdated;
373-
@JsonKey(unknownEnumValue: UserTopicVisibilityPolicy.unknown)
374-
final UserTopicVisibilityPolicy visibilityPolicy;
373+
@JsonKey(unknownEnumValue: JsonKey.nullForUndefinedEnumValue)
374+
final UserTopicVisibilityPolicy? visibilityPolicy;
375375

376376
UserTopicItem({
377377
required this.streamId,

lib/api/model/initial_snapshot.g.dart

Lines changed: 2 additions & 3 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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -899,8 +899,8 @@ enum UserTopicVisibilityPolicy {
899899
none(apiValue: 0),
900900
muted(apiValue: 1),
901901
unmuted(apiValue: 2), // TODO(server-7) newly added
902-
followed(apiValue: 3), // TODO(server-8) newly added
903-
unknown(apiValue: null); // TODO(#1074) remove this
902+
followed(apiValue: 3); // TODO(server-8) newly added
903+
//Removed unknown (#1074)
904904

905905
const UserTopicVisibilityPolicy({required this.apiValue});
906906

lib/api/route/channels.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ Future<void> updateUserTopic(ApiConnection connection, {
119119
required TopicName topic,
120120
required UserTopicVisibilityPolicy visibilityPolicy,
121121
}) {
122-
assert(visibilityPolicy != UserTopicVisibilityPolicy.unknown);
123122
assert(connection.zulipFeatureLevel! >= 170);
124123
return connection.post('updateUserTopic', (_) {}, 'user_topics', {
125124
'stream_id': streamId,

lib/model/channel.dart

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ mixin ChannelStore on UserStore {
4545
/// All the channel folders, including archived ones, indexed by ID.
4646
Map<int, ChannelFolder> get channelFolders;
4747

48+
static bool _warnInvalidVisibilityPolicy(
49+
UserTopicVisibilityPolicy? visibilityPolicy
50+
) {
51+
if (visibilityPolicy == null) {
52+
// Not a value we expect. Keep it out of our data structures. // TODO(log)
53+
return true;
54+
}
55+
return false;
56+
}
57+
4858
static int compareChannelsByName(ZulipStream a, ZulipStream b) {
4959
// A user gave feedback wanting zulip-flutter to match web in putting
5060
// emoji-prefixed channels first; see #1202.
@@ -118,9 +128,14 @@ mixin ChannelStore on UserStore {
118128
UserTopicVisibilityEffect willChangeIfTopicVisibleInStream(UserTopicEvent event) {
119129
final streamId = event.streamId;
120130
final topic = event.topicName;
131+
final UserTopicVisibilityPolicy? visibilityPolicy = event.visibilityPolicy;
132+
if (ChannelStore._warnInvalidVisibilityPolicy(visibilityPolicy)) {
133+
return UserTopicVisibilityEffect.none;
134+
}
135+
final UserTopicVisibilityPolicy policy = visibilityPolicy!;
121136
return UserTopicVisibilityEffect._fromBeforeAfter(
122137
_isTopicVisibleInStream(topicVisibilityPolicy(streamId, topic)),
123-
_isTopicVisibleInStream(event.visibilityPolicy));
138+
_isTopicVisibleInStream(policy));
124139
}
125140

126141
static bool _isTopicVisibleInStream(UserTopicVisibilityPolicy policy) {
@@ -132,9 +147,6 @@ mixin ChannelStore on UserStore {
132147
case UserTopicVisibilityPolicy.unmuted:
133148
case UserTopicVisibilityPolicy.followed:
134149
return true;
135-
case UserTopicVisibilityPolicy.unknown:
136-
assert(false);
137-
return true;
138150
}
139151
}
140152

@@ -155,9 +167,14 @@ mixin ChannelStore on UserStore {
155167
UserTopicVisibilityEffect willChangeIfTopicVisible(UserTopicEvent event) {
156168
final streamId = event.streamId;
157169
final topic = event.topicName;
170+
final UserTopicVisibilityPolicy? visibilityPolicy = event.visibilityPolicy;
171+
if (ChannelStore._warnInvalidVisibilityPolicy(visibilityPolicy)) {
172+
return UserTopicVisibilityEffect.none;
173+
}
174+
final UserTopicVisibilityPolicy policy = visibilityPolicy!;
158175
return UserTopicVisibilityEffect._fromBeforeAfter(
159176
_isTopicVisible(streamId, topicVisibilityPolicy(streamId, topic)),
160-
_isTopicVisible(streamId, event.visibilityPolicy));
177+
_isTopicVisible(streamId, policy));
161178
}
162179

163180
bool _isTopicVisible(int streamId, UserTopicVisibilityPolicy policy) {
@@ -173,9 +190,6 @@ mixin ChannelStore on UserStore {
173190
case UserTopicVisibilityPolicy.unmuted:
174191
case UserTopicVisibilityPolicy.followed:
175192
return true;
176-
case UserTopicVisibilityPolicy.unknown:
177-
assert(false);
178-
return true;
179193
}
180194
}
181195

@@ -332,12 +346,13 @@ class ChannelStoreImpl extends HasUserStore with ChannelStore {
332346

333347
final topicVisibility = <int, TopicKeyedMap<UserTopicVisibilityPolicy>>{};
334348
for (final item in initialSnapshot.userTopics) {
335-
if (_warnInvalidVisibilityPolicy(item.visibilityPolicy)) {
336-
// Not a value we expect. Keep it out of our data structures. // TODO(log)
349+
final UserTopicVisibilityPolicy? visibilityPolicy = item.visibilityPolicy;
350+
if (ChannelStore._warnInvalidVisibilityPolicy(visibilityPolicy)) {
337351
continue;
338352
}
353+
final UserTopicVisibilityPolicy policy = visibilityPolicy!;
339354
final forStream = topicVisibility.putIfAbsent(item.streamId, () => makeTopicKeyedMap());
340-
forStream[item.topicName] = item.visibilityPolicy;
355+
forStream[item.topicName] = policy;
341356
}
342357

343358
return ChannelStoreImpl._(
@@ -378,13 +393,6 @@ class ChannelStoreImpl extends HasUserStore with ChannelStore {
378393
return topicVisibility[streamId]?[topic] ?? UserTopicVisibilityPolicy.none;
379394
}
380395

381-
static bool _warnInvalidVisibilityPolicy(UserTopicVisibilityPolicy visibilityPolicy) {
382-
if (visibilityPolicy == UserTopicVisibilityPolicy.unknown) {
383-
// Not a value we expect. Keep it out of our data structures. // TODO(log)
384-
return true;
385-
}
386-
return false;
387-
}
388396

389397
void handleChannelEvent(ChannelEvent event) {
390398
switch (event) {
@@ -558,13 +566,18 @@ class ChannelStoreImpl extends HasUserStore with ChannelStore {
558566
}
559567

560568
void handleUserTopicEvent(UserTopicEvent event) {
561-
UserTopicVisibilityPolicy visibilityPolicy = event.visibilityPolicy;
562-
if (_warnInvalidVisibilityPolicy(visibilityPolicy)) {
563-
visibilityPolicy = UserTopicVisibilityPolicy.none;
569+
final UserTopicVisibilityPolicy? visibilityPolicy = event.visibilityPolicy;
570+
if (ChannelStore._warnInvalidVisibilityPolicy(visibilityPolicy)) {
571+
final forStream = topicVisibility[event.streamId];
572+
if (forStream == null) return;
573+
forStream.remove(event.topicName);
574+
if (forStream.isEmpty) {
575+
topicVisibility.remove(event.streamId);
576+
}
577+
return;
564578
}
565-
if (visibilityPolicy == UserTopicVisibilityPolicy.none) {
566-
// This is the "zero value" for this type, which our data structure
567-
// represents by leaving the topic out entirely.
579+
final UserTopicVisibilityPolicy policy = visibilityPolicy!;
580+
if (policy == UserTopicVisibilityPolicy.none) {
568581
final forStream = topicVisibility[event.streamId];
569582
if (forStream == null) return;
570583
forStream.remove(event.topicName);
@@ -573,7 +586,7 @@ class ChannelStoreImpl extends HasUserStore with ChannelStore {
573586
}
574587
} else {
575588
final forStream = topicVisibility.putIfAbsent(event.streamId, () => makeTopicKeyedMap());
576-
forStream[event.topicName] = visibilityPolicy;
589+
forStream[event.topicName] = policy;
577590
}
578591
}
579592
}

lib/widgets/action_sheet.dart

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -725,10 +725,6 @@ void showTopicActionSheet(BuildContext context, {
725725
if (supportsFollowingTopics) {
726726
visibilityOptions.add(UserTopicVisibilityPolicy.none);
727727
}
728-
case UserTopicVisibilityPolicy.unknown:
729-
// TODO(#1074): This should be unreachable as we keep `unknown` out of
730-
// our data structures.
731-
assert(false);
732728
}
733729
} else {
734730
// Channel is muted.
@@ -750,10 +746,6 @@ void showTopicActionSheet(BuildContext context, {
750746
if (supportsFollowingTopics) {
751747
visibilityOptions.add(UserTopicVisibilityPolicy.none);
752748
}
753-
case UserTopicVisibilityPolicy.unknown:
754-
// TODO(#1074): This should be unreachable as we keep `unknown` out of
755-
// our data structures.
756-
assert(false);
757749
}
758750
}
759751
}
@@ -824,11 +816,6 @@ class UserTopicUpdateButton extends ActionSheetMenuItemButton {
824816
return ZulipIcons.unmute;
825817
case UserTopicVisibilityPolicy.followed:
826818
return ZulipIcons.follow;
827-
case UserTopicVisibilityPolicy.unknown:
828-
// TODO(#1074): This should be unreachable as we keep `unknown` out of
829-
// our data structures.
830-
assert(false);
831-
return ZulipIcons.inherit;
832819
}
833820
}
834821

@@ -855,11 +842,6 @@ class UserTopicUpdateButton extends ActionSheetMenuItemButton {
855842
assert(false);
856843
return '';
857844

858-
case (_, UserTopicVisibilityPolicy.unknown):
859-
// This case is unreachable (or should be) because we keep `unknown` out
860-
// of our data structures. We plan to remove the `unknown` case in #1074.
861-
assert(false);
862-
return '';
863845
}
864846
}
865847

@@ -885,11 +867,6 @@ class UserTopicUpdateButton extends ActionSheetMenuItemButton {
885867
assert(false);
886868
return '';
887869

888-
case (_, UserTopicVisibilityPolicy.unknown):
889-
// This case is unreachable (or should be) because we keep `unknown` out
890-
// of our data structures. We plan to remove the `unknown` case in #1074.
891-
assert(false);
892-
return '';
893870
}
894871
}
895872

lib/widgets/icons.dart

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,5 @@ IconData? iconDataForTopicVisibilityPolicy(UserTopicVisibilityPolicy policy) {
226226
return ZulipIcons.follow;
227227
case UserTopicVisibilityPolicy.none:
228228
return null;
229-
case UserTopicVisibilityPolicy.unknown:
230-
// This case is unreachable (or should be) because we keep `unknown` out
231-
// of our data structures. We plan to remove the `unknown` case in #1074.
232-
assert(false);
233-
return null;
234229
}
235230
}

lib/widgets/topic_list.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,6 @@ class _TopicItem extends StatelessWidget {
247247
case UserTopicVisibilityPolicy.unmuted:
248248
case UserTopicVisibilityPolicy.followed:
249249
opacity = 1;
250-
case UserTopicVisibilityPolicy.unknown:
251-
assert(false);
252-
opacity = 1;
253250
}
254251

255252
final visibilityIcon = iconDataForTopicVisibilityPolicy(visibilityPolicy);

0 commit comments

Comments
 (0)