From 5939a1dc5b9700331f676a6950b6f6fdfbc6257a Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Fri, 27 Jun 2025 21:52:57 +0800 Subject: [PATCH] :sparkles: Can make the chat and realm public --- assets/i18n/en-US.json | 69 +-------------- lib/models/chat.dart | 1 + lib/models/chat.freezed.dart | 27 +++--- lib/models/chat.g.dart | 2 + lib/route.dart | 8 +- lib/screens/account/relationship.dart | 1 + lib/screens/chat/chat.dart | 43 ++++++--- lib/screens/chat/room_detail.dart | 2 +- lib/screens/realm/realms.dart | 121 +++++++++++++++----------- 9 files changed, 128 insertions(+), 146 deletions(-) diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index 9bc0476..8361aea 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -89,33 +89,14 @@ "authFactorInAppNotifyDescription": "A one-time code sent via in-app notification.", "authFactorPin": "Pin Code", "authFactorPinDescription": "It consists of 6 digits. It cannot be used to log in. When performing some dangerous operations, the system will ask you to enter this PIN for confirmation.", - "realms": "Realms", - "createRealm": "Create a Realm", - "createRealmHint": "Meet friends with same interests, build communities, and more.", - "editRealm": "Edit Realm", - "deleteRealm": "Delete Realm", - "deleteRealmHint": "Are you sure to delete this realm? This will also deleted all the channels, publishers, and posts under this realm.", "explore": "Explore", "exploreFilterSubscriptions": "Subscriptions", "exploreFilterFriends": "Friends", "discover": "Discover", - "discoverRealms": "Discover Realms", - "joinRealm": "Join Realm", "account": "Account", "name": "Name", "slug": "Slug", "slugHint": "The slug will be used in the URL to access this resource, it should be unique and URL safe.", - "createChatRoom": "Create a Room", - "editChatRoom": "Edit Room", - "deleteChatRoom": "Delete Room", - "deleteChatRoomHint": "Are you sure to delete this room? This action cannot be undone.", - "chat": "Chat", - "chatTabAll": "All", - "chatTabDirect": "Direct Messages", - "chatTabGroup": "Group Chats", - "chatMessageHint": "Message in {}", - "chatDirectMessageHint": "Message to {}", - "directMessage": "Direct Message", "loading": "Loading...", "descriptionNone": "No description yet.", "invites": "Invites", @@ -250,7 +231,6 @@ "uploadingProgress": "Uploading {} of {}", "uploadAll": "Upload All", "stickerCopyPlaceholder": "Copy Placeholder", - "realmSelection": "Select a Realm", "individual": "Individual", "firstPostBadgeName": "First Post", "firstPostBadgeDescription": "Created your first post on Solar Network", @@ -306,10 +286,6 @@ "levelingProgressExperience": "{} EXP", "levelingProgressLevel": "Level {}", "fileUploadingProgress": "Uploading file #{}: {}%", - "removeChatMember": "Remove Chat Room Member", - "removeChatMemberHint": "Are you sure to remove this member from the room?", - "removeRealmMember": "Remove Realm Member", - "removeRealmMemberHint": "Are you sure to remove this member from the realm?", "memberRole": "Member Role", "memberRoleHint": "Greater number has higher permission.", "memberRoleEdit": "Edit role for @{}", @@ -317,10 +293,6 @@ "openLinkConfirmDescription": "You're going to leave the Solar Network and open the link ({}) in your browser. It is not related to Solar Network. Beware of phishing and scams.", "brokenLink": "Unable open link {}... It might be broken or missing uri parts...", "copyToClipboard": "Copy to clipboard", - "leaveChatRoom": "Leave Chat Room", - "leaveChatRoomHint": "Are you sure to leave this chat room?", - "leaveRealm": "Leave Realm", - "leaveRealmHint": "Are you sure to leave this realm?", "walletNotFound": "Wallet not found", "walletCreateHint": "You don't have a wallet yet. Create one to start using the Solar Network eWallet.", "walletCreate": "Create a Wallet", @@ -332,12 +304,6 @@ "settingsBackgroundImageClear": "Clear Background Image", "settingsBackgroundGenerateColor": "Generate color scheme from Bacground Image", "messageNone": "No content to display", - "unreadMessages": { - "one": "{} unread message", - "other": "{} unread messages" - }, - "chatBreakNone": "None", - "settingsRealmCompactView": "Compact Realm View", "settingsMixedFeed": "Mixed Feed", "settingsAutoTranslate": "Auto Translate", "settingsHideBottomNav": "Hide Bottom Navigation", @@ -380,7 +346,6 @@ "postVisibilityUnlisted": "Unlisted", "postVisibilityPrivate": "Private", "postTruncated": "Content truncated, tap to view full post", - "copyMessage": "Copy Message", "authFactor": "Authentication Factor", "authFactorDelete": "Delete the Factor", "authFactorDeleteHint": "Are you sure you want to delete this authentication factor? This action cannot be undone.", @@ -413,10 +378,6 @@ "authDeviceLabelHint": "Enter a name for this device", "authDeviceSwipeEditHint": "Swipe left to edit label", "authDeviceSwipeLogoutHint": "Swipe right to logout device", - "typingHint": { - "one": "{} is typing...", - "other": "{} are typing..." - }, "settingsAppearance": "Appearance", "settingsServer": "Server", "settingsBehavior": "Behavior", @@ -478,21 +439,6 @@ "contactMethodSetPrimary": "Set as Primary", "contactMethodSetPrimaryHint": "Set this contact method as your primary contact method for account recovery and notifications", "contactMethodDeleteHint": "Are you sure to delete this contact method? This action cannot be undone.", - "chatNotifyLevel": "Notify Level", - "chatNotifyLevelDescription": "Decide how many notifications you will receive.", - "chatNotifyLevelAll": "All", - "chatNotifyLevelMention": "Mentions", - "chatNotifyLevelNone": "None", - "chatNotifyLevelUpdated": "The notify level has been updated to {}.", - "chatBreak": "Take a Break", - "chatBreakDescription": "Set a time, before that time, your notification level will be metions only, to take a break of the current topic they're talking about.", - "chatBreakClear": "Clear the break time", - "chatBreakHour": "{} break", - "chatBreakDay": "{} day break", - "chatBreakSet": "Break set for {}", - "chatBreakCleared": "Chat break has been cleared.", - "chatBreakCustom": "Custom duration", - "chatBreakEnterMinutes": "Enter minutes", "firstName": "First Name", "middleName": "Middle Name", "lastName": "Last Name", @@ -574,29 +520,17 @@ "quickActions": "Quick Actions", "post": "Post", "copy": "Copy", - "sendToChat": "Send to Chat", "failedToShareToPost": "Failed to share to post: {}", "shareToChatComingSoon": "Share to chat functionality coming soon", - "failedToShareToChat": "Failed to share to chat: {}", - "shareToSpecificChatComingSoon": "Share to {} coming soon", - "directChat": "Direct Chat", "systemShareComingSoon": "System share functionality coming soon", "failedToShareToSystem": "Failed to share to system: {}", "failedToCopy": "Failed to copy: {}", - "noChatRoomsAvailable": "No chat rooms available", - "failedToLoadChats": "Failed to load chats", "contentToShare": "Content to share:", - "unknownChat": "Unknown Chat", - "addAdditionalMessage": "Add additional message...", "uploadingFiles": "Uploading files...", - "sharedSuccessfully": "Shared successfully!", "shareSuccess": "Shared successfully!", - "shareToSpecificChatSuccess": "Shared to {} successfully!", "wouldYouLikeToGoToChat": "Would you like to go to the chat?", "no": "No", "yes": "Yes", - "navigateToChat": "Navigate to Chat", - "wouldYouLikeToNavigateToChat": "Would you like to navigate to the chat?", "abuseReport": "Report", "abuseReportTitle": "Report Content", "abuseReportDescription": "Help us keep the community safe by reporting inappropriate content or behavior.", @@ -622,6 +556,5 @@ "tags": "Tags", "tagsHint": "Enter tags, separated by commas", "categories": "Categories", - "categoriesHint": "Enter categories, separated by commas", - "joinRealmSuccess": "Successfully joined realm!" + "categoriesHint": "Enter categories, separated by commas" } diff --git a/lib/models/chat.dart b/lib/models/chat.dart index 4a3faa2..3b55b6b 100644 --- a/lib/models/chat.dart +++ b/lib/models/chat.dart @@ -14,6 +14,7 @@ sealed class SnChatRoom with _$SnChatRoom { required String? description, required int type, required bool isPublic, + required bool isCommunity, required SnCloudFile? picture, required SnCloudFile? background, required String? realmId, diff --git a/lib/models/chat.freezed.dart b/lib/models/chat.freezed.dart index 86597ae..966ca0c 100644 --- a/lib/models/chat.freezed.dart +++ b/lib/models/chat.freezed.dart @@ -16,7 +16,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$SnChatRoom { - String get id; String? get name; String? get description; int get type; bool get isPublic; SnCloudFile? get picture; SnCloudFile? get background; String? get realmId; SnRealm? get realm; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; List? get members; + String get id; String? get name; String? get description; int get type; bool get isPublic; bool get isCommunity; SnCloudFile? get picture; SnCloudFile? get background; String? get realmId; SnRealm? get realm; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; List? get members; /// Create a copy of SnChatRoom /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -29,16 +29,16 @@ $SnChatRoomCopyWith get copyWith => _$SnChatRoomCopyWithImpl Object.hash(runtimeType,id,name,description,type,isPublic,picture,background,realmId,realm,createdAt,updatedAt,deletedAt,const DeepCollectionEquality().hash(members)); +int get hashCode => Object.hash(runtimeType,id,name,description,type,isPublic,isCommunity,picture,background,realmId,realm,createdAt,updatedAt,deletedAt,const DeepCollectionEquality().hash(members)); @override String toString() { - return 'SnChatRoom(id: $id, name: $name, description: $description, type: $type, isPublic: $isPublic, picture: $picture, background: $background, realmId: $realmId, realm: $realm, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, members: $members)'; + return 'SnChatRoom(id: $id, name: $name, description: $description, type: $type, isPublic: $isPublic, isCommunity: $isCommunity, picture: $picture, background: $background, realmId: $realmId, realm: $realm, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, members: $members)'; } @@ -49,7 +49,7 @@ abstract mixin class $SnChatRoomCopyWith<$Res> { factory $SnChatRoomCopyWith(SnChatRoom value, $Res Function(SnChatRoom) _then) = _$SnChatRoomCopyWithImpl; @useResult $Res call({ - String id, String? name, String? description, int type, bool isPublic, SnCloudFile? picture, SnCloudFile? background, String? realmId, SnRealm? realm, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List? members + String id, String? name, String? description, int type, bool isPublic, bool isCommunity, SnCloudFile? picture, SnCloudFile? background, String? realmId, SnRealm? realm, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List? members }); @@ -66,13 +66,14 @@ class _$SnChatRoomCopyWithImpl<$Res> /// Create a copy of SnChatRoom /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = freezed,Object? description = freezed,Object? type = null,Object? isPublic = null,Object? picture = freezed,Object? background = freezed,Object? realmId = freezed,Object? realm = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? members = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = freezed,Object? description = freezed,Object? type = null,Object? isPublic = null,Object? isCommunity = null,Object? picture = freezed,Object? background = freezed,Object? realmId = freezed,Object? realm = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? members = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable as int,isPublic: null == isPublic ? _self.isPublic : isPublic // ignore: cast_nullable_to_non_nullable +as bool,isCommunity: null == isCommunity ? _self.isCommunity : isCommunity // ignore: cast_nullable_to_non_nullable as bool,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable as SnCloudFile?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable @@ -128,7 +129,7 @@ $SnRealmCopyWith<$Res>? get realm { @JsonSerializable() class _SnChatRoom implements SnChatRoom { - const _SnChatRoom({required this.id, required this.name, required this.description, required this.type, required this.isPublic, required this.picture, required this.background, required this.realmId, required this.realm, required this.createdAt, required this.updatedAt, required this.deletedAt, required final List? members}): _members = members; + const _SnChatRoom({required this.id, required this.name, required this.description, required this.type, required this.isPublic, required this.isCommunity, required this.picture, required this.background, required this.realmId, required this.realm, required this.createdAt, required this.updatedAt, required this.deletedAt, required final List? members}): _members = members; factory _SnChatRoom.fromJson(Map json) => _$SnChatRoomFromJson(json); @override final String id; @@ -136,6 +137,7 @@ class _SnChatRoom implements SnChatRoom { @override final String? description; @override final int type; @override final bool isPublic; +@override final bool isCommunity; @override final SnCloudFile? picture; @override final SnCloudFile? background; @override final String? realmId; @@ -166,16 +168,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnChatRoom&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.type, type) || other.type == type)&&(identical(other.isPublic, isPublic) || other.isPublic == isPublic)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&const DeepCollectionEquality().equals(other._members, _members)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnChatRoom&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.type, type) || other.type == type)&&(identical(other.isPublic, isPublic) || other.isPublic == isPublic)&&(identical(other.isCommunity, isCommunity) || other.isCommunity == isCommunity)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&const DeepCollectionEquality().equals(other._members, _members)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,name,description,type,isPublic,picture,background,realmId,realm,createdAt,updatedAt,deletedAt,const DeepCollectionEquality().hash(_members)); +int get hashCode => Object.hash(runtimeType,id,name,description,type,isPublic,isCommunity,picture,background,realmId,realm,createdAt,updatedAt,deletedAt,const DeepCollectionEquality().hash(_members)); @override String toString() { - return 'SnChatRoom(id: $id, name: $name, description: $description, type: $type, isPublic: $isPublic, picture: $picture, background: $background, realmId: $realmId, realm: $realm, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, members: $members)'; + return 'SnChatRoom(id: $id, name: $name, description: $description, type: $type, isPublic: $isPublic, isCommunity: $isCommunity, picture: $picture, background: $background, realmId: $realmId, realm: $realm, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, members: $members)'; } @@ -186,7 +188,7 @@ abstract mixin class _$SnChatRoomCopyWith<$Res> implements $SnChatRoomCopyWith<$ factory _$SnChatRoomCopyWith(_SnChatRoom value, $Res Function(_SnChatRoom) _then) = __$SnChatRoomCopyWithImpl; @override @useResult $Res call({ - String id, String? name, String? description, int type, bool isPublic, SnCloudFile? picture, SnCloudFile? background, String? realmId, SnRealm? realm, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List? members + String id, String? name, String? description, int type, bool isPublic, bool isCommunity, SnCloudFile? picture, SnCloudFile? background, String? realmId, SnRealm? realm, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List? members }); @@ -203,13 +205,14 @@ class __$SnChatRoomCopyWithImpl<$Res> /// Create a copy of SnChatRoom /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = freezed,Object? description = freezed,Object? type = null,Object? isPublic = null,Object? picture = freezed,Object? background = freezed,Object? realmId = freezed,Object? realm = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? members = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = freezed,Object? description = freezed,Object? type = null,Object? isPublic = null,Object? isCommunity = null,Object? picture = freezed,Object? background = freezed,Object? realmId = freezed,Object? realm = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? members = freezed,}) { return _then(_SnChatRoom( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable as int,isPublic: null == isPublic ? _self.isPublic : isPublic // ignore: cast_nullable_to_non_nullable +as bool,isCommunity: null == isCommunity ? _self.isCommunity : isCommunity // ignore: cast_nullable_to_non_nullable as bool,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable as SnCloudFile?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable diff --git a/lib/models/chat.g.dart b/lib/models/chat.g.dart index b55befd..b5e3134 100644 --- a/lib/models/chat.g.dart +++ b/lib/models/chat.g.dart @@ -12,6 +12,7 @@ _SnChatRoom _$SnChatRoomFromJson(Map json) => _SnChatRoom( description: json['description'] as String?, type: (json['type'] as num).toInt(), isPublic: json['is_public'] as bool, + isCommunity: json['is_community'] as bool, picture: json['picture'] == null ? null @@ -44,6 +45,7 @@ Map _$SnChatRoomToJson(_SnChatRoom instance) => 'description': instance.description, 'type': instance.type, 'is_public': instance.isPublic, + 'is_community': instance.isCommunity, 'picture': instance.picture?.toJson(), 'background': instance.background?.toJson(), 'realm_id': instance.realmId, diff --git a/lib/route.dart b/lib/route.dart index dc831ea..6abd41d 100644 --- a/lib/route.dart +++ b/lib/route.dart @@ -200,6 +200,10 @@ final routerProvider = Provider((ref) { path: '/chat', builder: (context, state) => const ChatListScreen(), routes: [ + GoRoute( + path: 'new', + builder: (context, state) => const NewChatScreen(), + ), GoRoute( path: ':id', builder: (context, state) { @@ -207,10 +211,6 @@ final routerProvider = Provider((ref) { return ChatRoomScreen(id: id); }, ), - GoRoute( - path: 'new', - builder: (context, state) => const NewChatScreen(), - ), GoRoute( path: ':id/edit', builder: (context, state) { diff --git a/lib/screens/account/relationship.dart b/lib/screens/account/relationship.dart index d077827..02dbf9a 100644 --- a/lib/screens/account/relationship.dart +++ b/lib/screens/account/relationship.dart @@ -215,6 +215,7 @@ class RelationshipScreen extends HookConsumerWidget { Future addFriend() async { final result = await showModalBottomSheet( context: context, + useRootNavigator: true, builder: (context) => AccountPickerSheet(), ); if (result == null) return; diff --git a/lib/screens/chat/chat.dart b/lib/screens/chat/chat.dart index 1f9262d..b7cf628 100644 --- a/lib/screens/chat/chat.dart +++ b/lib/screens/chat/chat.dart @@ -186,7 +186,7 @@ class ChatShellScreen extends HookConsumerWidget { child: Row( children: [ Flexible(flex: 2, child: ChatListScreen(isAside: true)), - VerticalDivider(width: 1), + const VerticalDivider(width: 1), Flexible(flex: 4, child: child), ], ), @@ -227,7 +227,8 @@ class ChatListScreen extends HookConsumerWidget { Future createDirectMessage() async { final result = await showModalBottomSheet( context: context, - builder: (context) => AccountPickerSheet(), + useRootNavigator: true, + builder: (context) => const AccountPickerSheet(), ); if (result == null) return; final client = ref.read(apiClientProvider); @@ -242,7 +243,7 @@ class ChatListScreen extends HookConsumerWidget { return AppScaffold( extendBody: false, // Prevent conflicts with tabs navigation appBar: AppBar( - title: Text('chat').tr(), + title: const Text('chat').tr(), bottom: TabBar( controller: tabController, tabs: [ @@ -296,7 +297,7 @@ class ChatListScreen extends HookConsumerWidget { showModalBottomSheet( isScrollControlled: true, context: context, - builder: (context) => _ChatInvitesSheet(), + builder: (context) => const _ChatInvitesSheet(), ); }, ), @@ -307,13 +308,14 @@ class ChatListScreen extends HookConsumerWidget { onPressed: () { showModalBottomSheet( context: context, + useRootNavigator: true, builder: (context) => Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ ListTile( - title: Text('createChatRoom').tr(), + title: const Text('createChatRoom').tr(), leading: const Icon(Symbols.add), onTap: () { Navigator.pop(context); @@ -325,7 +327,7 @@ class ChatListScreen extends HookConsumerWidget { }, ), ListTile( - title: Text('createDirectMessage').tr(), + title: const Text('createDirectMessage').tr(), leading: const Icon(Symbols.person), onTap: () { Navigator.pop(context); @@ -450,7 +452,7 @@ class NewChatScreen extends StatelessWidget { @override Widget build(BuildContext context) { - return EditChatScreen(); + return const EditChatScreen(); } } @@ -468,6 +470,8 @@ class EditChatScreen extends HookConsumerWidget { final descriptionController = useTextEditingController(); final picture = useState(null); final background = useState(null); + final isPublic = useState(true); + final isCommunity = useState(false); final chat = ref.watch(chatroomProvider(id)); @@ -480,12 +484,14 @@ class EditChatScreen extends HookConsumerWidget { descriptionController.text = chat.value!.description ?? ''; picture.value = chat.value!.picture; background.value = chat.value!.background; + isPublic.value = chat.value!.isPublic; + isCommunity.value = chat.value!.isCommunity; currentRealm.value = joinedRealms.value?.firstWhereOrNull( (realm) => realm.id == chat.value!.realmId, ); } return; - }, [chat]); + }, [chat, joinedRealms]); void setPicture(String position) async { showLoadingModal(context); @@ -503,9 +509,9 @@ class EditChatScreen extends HookConsumerWidget { image: result, allowedAspectRatios: [ if (position == 'background') - CropAspectRatio(height: 7, width: 16) + const CropAspectRatio(height: 7, width: 16) else - CropAspectRatio(height: 1, width: 1), + const CropAspectRatio(height: 1, width: 1), ], ); if (result == null) { @@ -562,6 +568,8 @@ class EditChatScreen extends HookConsumerWidget { 'background_id': background.value?.id, 'picture_id': picture.value?.id, 'realm_id': currentRealm.value?.id, + 'is_public': isPublic.value, + 'is_community': isCommunity.value, }, options: Options(method: id == null ? 'POST' : 'PATCH'), ); @@ -654,6 +662,19 @@ class EditChatScreen extends HookConsumerWidget { (_) => FocusManager.instance.primaryFocus?.unfocus(), ), const SizedBox(height: 16), + CheckboxListTile( + title: const Text('isPublic').tr(), + subtitle: const Text('isPublicHint').tr(), + value: isPublic.value, + onChanged: (value) => isPublic.value = value ?? false, + ), + CheckboxListTile( + title: const Text('isCommunity').tr(), + subtitle: const Text('isCommunityHint').tr(), + value: isCommunity.value, + onChanged: (value) => isCommunity.value = value ?? false, + ), + const SizedBox(height: 16), Align( alignment: Alignment.centerRight, child: TextButton.icon( @@ -754,7 +775,7 @@ class _ChatInvitesSheet extends HookConsumerWidget { ), if (invite.chatRoom!.type == 1) Badge( - label: Text('directMessage').tr(), + label: const Text('directMessage').tr(), backgroundColor: Theme.of(context).colorScheme.primary, textColor: diff --git a/lib/screens/chat/room_detail.dart b/lib/screens/chat/room_detail.dart index 7c812f5..cbd0e1b 100644 --- a/lib/screens/chat/room_detail.dart +++ b/lib/screens/chat/room_detail.dart @@ -584,8 +584,8 @@ class _ChatMemberListSheet extends HookConsumerWidget { Future invitePerson() async { final result = await showModalBottomSheet( - isScrollControlled: true, context: context, + useRootNavigator: true, builder: (context) => const AccountPickerSheet(), ); if (result == null) return; diff --git a/lib/screens/realm/realms.dart b/lib/screens/realm/realms.dart index 146369d..412b692 100644 --- a/lib/screens/realm/realms.dart +++ b/lib/screens/realm/realms.dart @@ -70,7 +70,7 @@ class RealmListScreen extends HookConsumerWidget { showModalBottomSheet( context: context, isScrollControlled: true, - builder: (_) => _RealmInviteSheet(), + builder: (_) => const _RealmInviteSheet(), ); }, ), @@ -78,7 +78,7 @@ class RealmListScreen extends HookConsumerWidget { ], ), floatingActionButton: FloatingActionButton( - heroTag: Key("realms-page-fab"), + heroTag: const Key("realms-page-fab"), child: const Icon(Symbols.add), onPressed: () { context.push('/realms/new').then((value) { @@ -110,7 +110,7 @@ class RealmListScreen extends HookConsumerWidget { onTap: () { context.push('/realms/${value[item].slug}'); }, - contentPadding: EdgeInsets.only( + contentPadding: const EdgeInsets.only( left: 16, right: 14, top: 8, @@ -162,6 +162,8 @@ class EditRealmScreen extends HookConsumerWidget { final picture = useState(null); final background = useState(null); + final isPublic = useState(true); + final isCommunity = useState(false); final slugController = useTextEditingController(); final nameController = useTextEditingController(); @@ -178,6 +180,8 @@ class EditRealmScreen extends HookConsumerWidget { slugController.text = realm.value!.slug; nameController.text = realm.value!.name; descriptionController.text = realm.value!.description; + isPublic.value = realm.value!.isPublic; + isCommunity.value = realm.value!.isCommunity; } return null; }, [realm]); @@ -198,9 +202,9 @@ class EditRealmScreen extends HookConsumerWidget { image: result, allowedAspectRatios: [ if (position == 'background') - CropAspectRatio(height: 7, width: 16) + const CropAspectRatio(height: 7, width: 16) else - CropAspectRatio(height: 1, width: 1), + const CropAspectRatio(height: 1, width: 1), ], ); if (result == null) { @@ -256,6 +260,8 @@ class EditRealmScreen extends HookConsumerWidget { 'description': descriptionController.text, 'background_id': background.value?.id, 'picture_id': picture.value?.id, + 'is_public': isPublic.value, + 'is_community': isCommunity.value, }, options: Options(method: slug == null ? 'POST' : 'PATCH'), ); @@ -288,9 +294,9 @@ class EditRealmScreen extends HookConsumerWidget { child: background.value != null ? CloudFileWidget( - item: background.value!, - fit: BoxFit.cover, - ) + item: background.value!, + fit: BoxFit.cover, + ) : const SizedBox.shrink(), ), onTap: () { @@ -318,7 +324,6 @@ class EditRealmScreen extends HookConsumerWidget { key: formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, - spacing: 16, children: [ TextFormField( controller: slugController, @@ -329,12 +334,14 @@ class EditRealmScreen extends HookConsumerWidget { onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), ), + const SizedBox(height: 16), TextFormField( controller: nameController, decoration: InputDecoration(labelText: 'name'.tr()), onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), ), + const SizedBox(height: 16), TextFormField( controller: descriptionController, decoration: InputDecoration(labelText: 'description'.tr()), @@ -343,6 +350,20 @@ class EditRealmScreen extends HookConsumerWidget { onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), ), + const SizedBox(height: 16), + CheckboxListTile( + title: const Text('isPublic').tr(), + subtitle: const Text('isPublicHint').tr(), + value: isPublic.value, + onChanged: (value) => isPublic.value = value ?? false, + ), + CheckboxListTile( + title: const Text('isCommunity').tr(), + subtitle: const Text('isCommunityHint').tr(), + value: isCommunity.value, + onChanged: (value) => isCommunity.value = value ?? false, + ), + const SizedBox(height: 16), Align( alignment: Alignment.centerRight, child: TextButton.icon( @@ -414,47 +435,47 @@ class _RealmInviteSheet extends HookConsumerWidget { (items) => items.isEmpty ? Center( - child: - Text( - 'invitesEmpty', - textAlign: TextAlign.center, - ).tr(), - ) + child: + Text( + 'invitesEmpty', + textAlign: TextAlign.center, + ).tr(), + ) : ListView.builder( - shrinkWrap: true, - itemCount: items.length, - itemBuilder: (context, index) { - final invite = items[index]; - return ListTile( - leading: ProfilePictureWidget( - fileId: invite.realm!.picture?.id, - fallbackIcon: Symbols.group, - ), - title: Text(invite.realm!.name), - subtitle: - Text( - invite.role >= 100 - ? 'permissionOwner' - : invite.role >= 50 - ? 'permissionModerator' - : 'permissionMember', - ).tr(), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Symbols.check), - onPressed: () => acceptInvite(invite), - ), - IconButton( - icon: const Icon(Symbols.close), - onPressed: () => declineInvite(invite), - ), - ], - ), - ); - }, - ), + shrinkWrap: true, + itemCount: items.length, + itemBuilder: (context, index) { + final invite = items[index]; + return ListTile( + leading: ProfilePictureWidget( + fileId: invite.realm!.picture?.id, + fallbackIcon: Symbols.group, + ), + title: Text(invite.realm!.name), + subtitle: + Text( + invite.role >= 100 + ? 'permissionOwner' + : invite.role >= 50 + ? 'permissionModerator' + : 'permissionMember', + ).tr(), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon(Symbols.check), + onPressed: () => acceptInvite(invite), + ), + IconButton( + icon: const Icon(Symbols.close), + onPressed: () => declineInvite(invite), + ), + ], + ), + ); + }, + ), loading: () => const Center(child: CircularProgressIndicator()), error: (error, _) => ResponseErrorWidget( @@ -464,4 +485,4 @@ class _RealmInviteSheet extends HookConsumerWidget { ), ); } -} +} \ No newline at end of file