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
2 changes: 2 additions & 0 deletions lib/api/model/events.dart
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,8 @@ class ChannelUpdateEvent extends ChannelEvent {
return value as bool;
case ChannelPropertyName.messageRetentionDays:
return value as int?;
case ChannelPropertyName.topicsPolicy:
return TopicsPolicy.fromApiValue(value as String);
case ChannelPropertyName.channelPostPolicy:
return ChannelPostPolicy.fromApiValue(value as int);
case ChannelPropertyName.folderId:
Expand Down
1 change: 1 addition & 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.

15 changes: 15 additions & 0 deletions lib/api/model/initial_snapshot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ class InitialSnapshot {
/// Search for "realm_wildcard_mention_policy" in https://zulip.com/api/register-queue.
final RealmWildcardMentionPolicy realmWildcardMentionPolicy;

@JsonKey(unknownEnumValue: RealmTopicsPolicy.unknown)
final RealmTopicsPolicy? realmTopicsPolicy; // TODO(server-11)

final bool realmMandatoryTopics;

final String realmName;
Expand Down Expand Up @@ -183,6 +186,7 @@ class InitialSnapshot {
required this.realmCanDeleteOwnMessageGroup,
required this.realmDeleteOwnMessagePolicy,
required this.realmWildcardMentionPolicy,
required this.realmTopicsPolicy,
required this.realmMandatoryTopics,
required this.realmName,
required this.realmWaitingPeriodThreshold,
Expand Down Expand Up @@ -238,6 +242,17 @@ enum RealmDeleteOwnMessagePolicy {
int toJson() => apiValue;
}

/// A value of [InitialSnapshot.realmTopicsPolicy].
///
/// For docs, search for "realm_topics_policy"
/// in <https://zulip.com/api/register-queue#response>.
@JsonEnum(fieldRename: FieldRename.snake)
enum RealmTopicsPolicy {
allowEmptyTopic,
disableEmptyTopic,
unknown;
}

/// An item in `realm_default_external_accounts`.
///
/// For docs, search for "realm_default_external_accounts:"
Expand Down
12 changes: 12 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.

25 changes: 25 additions & 0 deletions lib/api/model/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,9 @@ class ZulipStream {
bool isWebPublic; // present since 2.1, according to /api/changelog
bool historyPublicToSubscribers;
int? messageRetentionDays;
@JsonKey(defaultValue: TopicsPolicy.inherit, // TODO(server-11) remove default value
unknownEnumValue: TopicsPolicy.unknown)
TopicsPolicy topicsPolicy;
@JsonKey(name: 'stream_post_policy')
ChannelPostPolicy? channelPostPolicy; // TODO(server-10) remove
// final bool isAnnouncementOnly; // deprecated for `channelPostPolicy`; ignore
Expand All @@ -684,6 +687,7 @@ class ZulipStream {
required this.isWebPublic,
required this.historyPublicToSubscribers,
required this.messageRetentionDays,
required this.topicsPolicy,
required this.channelPostPolicy,
required this.folderId,
required this.canAddSubscribersGroup,
Expand All @@ -708,6 +712,7 @@ class ZulipStream {
isWebPublic: subscription.isWebPublic,
historyPublicToSubscribers: subscription.historyPublicToSubscribers,
messageRetentionDays: subscription.messageRetentionDays,
topicsPolicy: subscription.topicsPolicy,
channelPostPolicy: subscription.channelPostPolicy,
folderId: subscription.folderId,
canAddSubscribersGroup: subscription.canAddSubscribersGroup,
Expand Down Expand Up @@ -744,6 +749,7 @@ enum ChannelPropertyName {
// isWebPublic is updated via its own [ChannelUpdateEvent] field
// historyPublicToSubscribers is updated via its own [ChannelUpdateEvent] field
messageRetentionDays,
topicsPolicy,
@JsonValue('stream_post_policy')
channelPostPolicy,
folderId,
Expand All @@ -765,6 +771,24 @@ enum ChannelPropertyName {
.map((key, value) => MapEntry(value, key));
}

/// A value of [ZulipStream.topicsPolicy].
///
/// For docs, search for "topics_policy"
/// in <https://zulip.com/api/get-stream-by-id>.
@JsonEnum(fieldRename: FieldRename.snake)
enum TopicsPolicy {
inherit,
allowEmptyTopic,
disableEmptyTopic,
emptyTopicOnly,
unknown;

static TopicsPolicy fromApiValue(String value) => _byApiValue[value] ?? unknown;

static final _byApiValue = _$TopicsPolicyEnumMap
.map((key, value) => MapEntry(value, key));
}

/// Policy for which users can post to the stream.
///
/// For docs, search for "stream_post_policy"
Expand Down Expand Up @@ -830,6 +854,7 @@ class Subscription extends ZulipStream {
required super.isWebPublic,
required super.historyPublicToSubscribers,
required super.messageRetentionDays,
required super.topicsPolicy,
required super.channelPostPolicy,
required super.folderId,
required super.canAddSubscribersGroup,
Expand Down
25 changes: 25 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.

2 changes: 2 additions & 0 deletions lib/model/channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,8 @@ class ChannelStoreImpl extends HasUserStore with ChannelStore {
stream.inviteOnly = event.value as bool;
case ChannelPropertyName.messageRetentionDays:
stream.messageRetentionDays = event.value as int?;
case ChannelPropertyName.topicsPolicy:
stream.topicsPolicy = event.value as TopicsPolicy;
case ChannelPropertyName.channelPostPolicy:
stream.channelPostPolicy = event.value as ChannelPostPolicy;
case ChannelPropertyName.folderId:
Expand Down
6 changes: 6 additions & 0 deletions lib/model/realm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ mixin RealmStore on PerAccountStoreBase, UserGroupStore {
GroupSettingValue? get realmCanDeleteAnyMessageGroup; // TODO(server-10)
GroupSettingValue? get realmCanDeleteOwnMessageGroup; // TODO(server-10)
bool get realmEnableReadReceipts;
RealmTopicsPolicy? get realmTopicsPolicy; // TODO(server-11)
bool get realmMandatoryTopics;
int get maxFileUploadSizeMib;
int? get realmMessageContentDeleteLimitSeconds;
Expand Down Expand Up @@ -174,6 +175,8 @@ mixin ProxyRealmStore on RealmStore {
@override
bool get realmEnableReadReceipts => realmStore.realmEnableReadReceipts;
@override
RealmTopicsPolicy? get realmTopicsPolicy => realmStore.realmTopicsPolicy;
@override
bool get realmMandatoryTopics => realmStore.realmMandatoryTopics;
@override
int get maxFileUploadSizeMib => realmStore.maxFileUploadSizeMib;
Expand Down Expand Up @@ -233,6 +236,7 @@ class RealmStoreImpl extends HasUserGroupStore with RealmStore {
realmAllowMessageEditing = initialSnapshot.realmAllowMessageEditing,
realmCanDeleteAnyMessageGroup = initialSnapshot.realmCanDeleteAnyMessageGroup,
realmCanDeleteOwnMessageGroup = initialSnapshot.realmCanDeleteOwnMessageGroup,
realmTopicsPolicy = initialSnapshot.realmTopicsPolicy,
realmMandatoryTopics = initialSnapshot.realmMandatoryTopics,
maxFileUploadSizeMib = initialSnapshot.maxFileUploadSizeMib,
realmMessageContentDeleteLimitSeconds = initialSnapshot.realmMessageContentDeleteLimitSeconds,
Expand Down Expand Up @@ -383,6 +387,8 @@ class RealmStoreImpl extends HasUserGroupStore with RealmStore {
@override
final bool realmEnableReadReceipts;
@override
final RealmTopicsPolicy? realmTopicsPolicy;
@override
final bool realmMandatoryTopics;
@override
final int maxFileUploadSizeMib;
Expand Down
27 changes: 19 additions & 8 deletions lib/widgets/compose_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1435,7 +1435,7 @@ abstract class _ComposeBoxBody extends StatelessWidget {

ComposeBoxController get controller;

Widget? buildTopicInput();
Widget? buildTopicInput(BuildContext context);
Widget buildContentInput();
bool getComposeButtonsEnabled(BuildContext context);
Widget? buildSendButton();
Expand Down Expand Up @@ -1471,7 +1471,7 @@ abstract class _ComposeBoxBody extends StatelessWidget {
_AttachFromCameraButton(controller: controller, enabled: composeButtonsEnabled),
];

final topicInput = buildTopicInput();
final topicInput = buildTopicInput(context);
final sendButton = buildSendButton();
return Column(children: [
Padding(
Expand Down Expand Up @@ -1509,10 +1509,21 @@ class _StreamComposeBoxBody extends _ComposeBoxBody {
@override
final StreamComposeBoxController controller;

@override Widget buildTopicInput() => _TopicInput(
streamId: narrow.streamId,
controller: controller,
);
@override
Widget? buildTopicInput(BuildContext context) {
final store = PerAccountStoreWidget.of(context);
final stream = store.streams[narrow.streamId];
final topicsPolicy = stream?.topicsPolicy;

if (topicsPolicy == TopicsPolicy.emptyTopicOnly) {
return null;
}

return _TopicInput(
streamId: narrow.streamId,
controller: controller,
);
}
Copy link
Member

Choose a reason for hiding this comment

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

I did a quick manual test and noticed that ComposeBoxController.requestFocusIfUnfocused doesn't work correctly with this implementation. So when selecting the general-chat-only channel from Share-to-Zulip page, the content box doesn't get focused automatically and presumably the non-existent topic box is being focused instead.

Copy link
Member

Choose a reason for hiding this comment

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

I am not sure what the correct implementation here would be. @gnprice @chrisbobbe Should this type of channel use the FixedDestinationComposeBoxController/_FixedDestinationComposeBoxBody directly?


@override Widget buildContentInput() => _StreamContentInput(
narrow: narrow,
Expand All @@ -1537,7 +1548,7 @@ class _FixedDestinationComposeBoxBody extends _ComposeBoxBody {
@override
final FixedDestinationComposeBoxController controller;

@override Widget? buildTopicInput() => null;
@override Widget? buildTopicInput(BuildContext context) => null;

@override Widget buildContentInput() => _FixedDestinationContentInput(
narrow: narrow,
Expand All @@ -1562,7 +1573,7 @@ class _EditMessageComposeBoxBody extends _ComposeBoxBody {
@override
final EditMessageComposeBoxController controller;

@override Widget? buildTopicInput() => null;
@override Widget? buildTopicInput(BuildContext context) => null;

@override Widget buildContentInput() => _EditMessageContentInput(
narrow: narrow,
Expand Down
7 changes: 7 additions & 0 deletions test/example_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ ZulipStream stream({
bool? isWebPublic,
bool? historyPublicToSubscribers,
int? messageRetentionDays,
TopicsPolicy? topicsPolicy,
ChannelPostPolicy? channelPostPolicy,
int? folderId,
GroupSettingValue? canAddSubscribersGroup,
Expand Down Expand Up @@ -496,6 +497,7 @@ ZulipStream stream({
isWebPublic: isWebPublic ?? false,
historyPublicToSubscribers: historyPublicToSubscribers ?? true,
messageRetentionDays: messageRetentionDays,
topicsPolicy: topicsPolicy ?? TopicsPolicy.inherit,
channelPostPolicy: channelPostPolicy ?? ChannelPostPolicy.any,
folderId: folderId,
canAddSubscribersGroup: canAddSubscribersGroup ?? GroupSettingValueNamed(nobodyGroup.id),
Expand Down Expand Up @@ -541,6 +543,7 @@ Subscription subscription(
isWebPublic: stream.isWebPublic,
historyPublicToSubscribers: stream.historyPublicToSubscribers,
messageRetentionDays: stream.messageRetentionDays,
topicsPolicy: stream.topicsPolicy,
channelPostPolicy: stream.channelPostPolicy,
folderId: stream.folderId,
canAddSubscribersGroup: stream.canAddSubscribersGroup,
Expand Down Expand Up @@ -1261,6 +1264,8 @@ ChannelUpdateEvent channelUpdateEvent(
assert(value is bool);
case ChannelPropertyName.messageRetentionDays:
assert(value is int?);
case ChannelPropertyName.topicsPolicy:
assert(value is TopicsPolicy);
case ChannelPropertyName.channelPostPolicy:
assert(value is ChannelPostPolicy);
case ChannelPropertyName.folderId:
Expand Down Expand Up @@ -1335,6 +1340,7 @@ InitialSnapshot initialSnapshot({
GroupSettingValue? realmCanDeleteOwnMessageGroup,
RealmDeleteOwnMessagePolicy? realmDeleteOwnMessagePolicy,
RealmWildcardMentionPolicy? realmWildcardMentionPolicy,
RealmTopicsPolicy? realmTopicsPolicy,
bool? realmMandatoryTopics,
String? realmName,
int? realmWaitingPeriodThreshold,
Expand Down Expand Up @@ -1399,6 +1405,7 @@ InitialSnapshot initialSnapshot({
realmCanDeleteOwnMessageGroup: realmCanDeleteOwnMessageGroup,
realmDeleteOwnMessagePolicy: realmDeleteOwnMessagePolicy,
realmWildcardMentionPolicy: realmWildcardMentionPolicy ?? RealmWildcardMentionPolicy.everyone,
realmTopicsPolicy: realmTopicsPolicy ?? RealmTopicsPolicy.unknown,
realmMandatoryTopics: realmMandatoryTopics ?? true,
realmName: realmName ?? 'Example Zulip organization',
realmWaitingPeriodThreshold: realmWaitingPeriodThreshold ?? 0,
Expand Down
Loading