Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions lib/api/model/events.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ sealed class Event {
case 'peer_remove': return SubscriptionPeerRemoveEvent.fromJson(json);
default: return UnexpectedEvent.fromJson(json);
}
case 'channel_folder':
switch (json['op'] as String) {
case 'add': return ChannelFolderAddEvent.fromJson(json);
case 'reorder': return ChannelFolderReorderEvent.fromJson(json);
case 'update': return ChannelFolderUpdateEvent.fromJson(json);
default: return UnexpectedEvent.fromJson(json);
}
// case 'muted_topics': … // TODO(#422) we ignore this feature on older servers
case 'user_status': return UserStatusEvent.fromJson(json);
case 'user_topic': return UserTopicEvent.fromJson(json);
Expand Down Expand Up @@ -677,6 +684,8 @@ class ChannelUpdateEvent extends ChannelEvent {
return value as int?;
case ChannelPropertyName.channelPostPolicy:
return ChannelPostPolicy.fromApiValue(value as int);
case ChannelPropertyName.folderId:
return value as int?;
case ChannelPropertyName.canAddSubscribersGroup:
case ChannelPropertyName.canDeleteAnyMessageGroup:
case ChannelPropertyName.canDeleteOwnMessageGroup:
Expand Down Expand Up @@ -881,6 +890,103 @@ class SubscriptionPeerRemoveEvent extends SubscriptionEvent {
Map<String, dynamic> toJson() => _$SubscriptionPeerRemoveEventToJson(this);
}

/// A Zulip event of type `channel_folder`.
///
/// The corresponding API docs are in several places for
/// different values of `op`; see subclasses.
sealed class ChannelFolderEvent extends Event {
@override
@JsonKey(includeToJson: true)
String get type => 'channel_folder';

String get op;

ChannelFolderEvent({required super.id});
}

/// A [ChannelFolderEvent] with op `add`:
/// https://zulip.com/api/get-events#channel_folder-add
@JsonSerializable(fieldRename: FieldRename.snake)
class ChannelFolderAddEvent extends ChannelFolderEvent {
@override
@JsonKey(includeToJson: true)
String get op => 'add';

final ChannelFolder channelFolder;

ChannelFolderAddEvent({required super.id, required this.channelFolder});

factory ChannelFolderAddEvent.fromJson(Map<String, dynamic> json) =>
_$ChannelFolderAddEventFromJson(json);

@override
Map<String, dynamic> toJson() => _$ChannelFolderAddEventToJson(this);
}

/// A [ChannelFolderEvent] with op `update`:
/// https://zulip.com/api/get-events#channel_folder-update
@JsonSerializable(fieldRename: FieldRename.snake)
class ChannelFolderUpdateEvent extends ChannelFolderEvent {
@override
@JsonKey(includeToJson: true)
String get op => 'update';

final int channelFolderId;
final ChannelFolderChange data;

ChannelFolderUpdateEvent({
required super.id,
required this.channelFolderId,
required this.data,
});

factory ChannelFolderUpdateEvent.fromJson(Map<String, dynamic> json) =>
_$ChannelFolderUpdateEventFromJson(json);

@override
Map<String, dynamic> toJson() => _$ChannelFolderUpdateEventToJson(this);
}

/// Details of a channel-folder change, as in [ChannelFolderUpdateEvent.data].
@JsonSerializable(fieldRename: FieldRename.snake)
class ChannelFolderChange {
final String? name;
final String? description;
final String? renderedDescription;
final bool? isArchived;

ChannelFolderChange({
required this.name,
required this.description,
required this.renderedDescription,
required this.isArchived,
});

factory ChannelFolderChange.fromJson(Map<String, dynamic> json) =>
_$ChannelFolderChangeFromJson(json);

Map<String, dynamic> toJson() => _$ChannelFolderChangeToJson(this);
}

/// A [ChannelFolderEvent] with op `update`:
/// https://zulip.com/api/get-events#channel_folder-update
@JsonSerializable(fieldRename: FieldRename.snake)
class ChannelFolderReorderEvent extends ChannelFolderEvent {
@override
@JsonKey(includeToJson: true)
String get op => 'reorder';

final List<int> order;

ChannelFolderReorderEvent({required super.id, required this.order});

factory ChannelFolderReorderEvent.fromJson(Map<String, dynamic> json) =>
_$ChannelFolderReorderEventFromJson(json);

@override
Map<String, dynamic> toJson() => _$ChannelFolderReorderEventToJson(this);
}

/// A Zulip event of type `user_status`: https://zulip.com/api/get-events#user_status
@JsonSerializable(fieldRename: FieldRename.snake, createToJson: false)
class UserStatusEvent extends Event {
Expand Down
72 changes: 72 additions & 0 deletions lib/api/model/events.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions lib/api/model/initial_snapshot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class InitialSnapshot {

final UnreadMessagesSnapshot unreadMsgs;

final List<ChannelFolder>? channelFolders;
Comment on lines 57 to +59
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: docs have these in opposite order

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO(server-11), right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: commit-message prefixes, similar to #1869 (comment) ; the current revision has

63b5b83 initial_snapshot: Add channelFolders
36e7c96 model: Add ZulipStream.folderId
3da70bc api: Add channel_folder event
3ff64be store: Add channelFolders
84604e0 channel: Add ChannelStore.compareChannelFolders

and I think the first three should all say "api:".


final List<ZulipStream> streams;

// In register-queue, the name of this field is the singular "user_status",
Expand Down Expand Up @@ -166,6 +168,7 @@ class InitialSnapshot {
required this.recentPrivateConversations,
required this.savedSnippets,
required this.subscriptions,
required this.channelFolders,
required this.unreadMsgs,
required this.streams,
required this.userStatuses,
Expand Down
4 changes: 4 additions & 0 deletions lib/api/model/initial_snapshot.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions lib/api/model/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,8 @@ class ZulipStream {
int? messageRetentionDays;
@JsonKey(name: 'stream_post_policy')
ChannelPostPolicy? channelPostPolicy; // TODO(server-10) remove
// TODO(server-11) delete TODO but keep optional, for channels not in folders
int? folderId;
Comment on lines +653 to +654
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is equivalent to not having a TODO, right? That seems simpler 🙂

// final bool isAnnouncementOnly; // deprecated for `channelPostPolicy`; ignore
Comment on lines 652 to 655
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this stanza is all various kinds of permission settings; let's pull this field out separately, earlier.

(We already have this class's fields in a different order from the docs in order to be more logical, in particular grouping description with renderedDescription.)


GroupSettingValue? canAddSubscribersGroup; // TODO(server-10)
Expand All @@ -674,6 +676,7 @@ class ZulipStream {
required this.historyPublicToSubscribers,
required this.messageRetentionDays,
required this.channelPostPolicy,
required this.folderId,
required this.canAddSubscribersGroup,
required this.canDeleteAnyMessageGroup,
required this.canDeleteOwnMessageGroup,
Expand All @@ -697,6 +700,7 @@ class ZulipStream {
historyPublicToSubscribers: subscription.historyPublicToSubscribers,
messageRetentionDays: subscription.messageRetentionDays,
channelPostPolicy: subscription.channelPostPolicy,
folderId: subscription.folderId,
canAddSubscribersGroup: subscription.canAddSubscribersGroup,
canDeleteAnyMessageGroup: subscription.canDeleteAnyMessageGroup,
canDeleteOwnMessageGroup: subscription.canDeleteOwnMessageGroup,
Expand Down Expand Up @@ -733,6 +737,7 @@ enum ChannelPropertyName {
messageRetentionDays,
@JsonValue('stream_post_policy')
channelPostPolicy,
folderId,
canAddSubscribersGroup,
canDeleteAnyMessageGroup,
canDeleteOwnMessageGroup,
Expand Down Expand Up @@ -818,6 +823,7 @@ class Subscription extends ZulipStream {
required super.historyPublicToSubscribers,
required super.messageRetentionDays,
required super.channelPostPolicy,
required super.folderId,
required super.canAddSubscribersGroup,
required super.canDeleteAnyMessageGroup,
required super.canDeleteOwnMessageGroup,
Expand All @@ -841,6 +847,38 @@ class Subscription extends ZulipStream {
Map<String, dynamic> toJson() => _$SubscriptionToJson(this);
}

/// As in `channel_folders` in the initial snapshot.
///
/// For docs, search for "channel_folders:"
/// in <https://zulip.com/api/register-queue>.
@JsonSerializable(fieldRename: FieldRename.snake)
class ChannelFolder {
final int id;
String name;
int? order; // TODO(server-11); added in a later FL than the rest
final int? dateCreated;
final int? creatorId;
String description;
String renderedDescription;
bool isArchived;

ChannelFolder({
required this.id,
required this.name,
required this.order,
required this.dateCreated,
required this.creatorId,
required this.description,
required this.renderedDescription,
required this.isArchived,
});

factory ChannelFolder.fromJson(Map<String, dynamic> json) =>
_$ChannelFolderFromJson(json);

Map<String, dynamic> toJson() => _$ChannelFolderToJson(this);
}

@JsonEnum(fieldRename: FieldRename.snake, valueField: "apiValue")
enum UserTopicVisibilityPolicy {
none(apiValue: 0),
Expand Down
29 changes: 29 additions & 0 deletions lib/api/model/model.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading