From 561359008cc1c250f4f794bd62806e006fbcccdb Mon Sep 17 00:00:00 2001 From: ggurdin <46800240+ggurdin@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:10:33 -0500 Subject: [PATCH] allow users to set room's searchability and public/private status seperatly, ensure public/private status determines which rooms show in space hierarchy (#1090) --- assets/l10n/intl_en.arb | 4 +- lib/pages/chat_details/chat_details.dart | 19 ++++-- lib/pages/chat_details/chat_details_view.dart | 4 +- lib/pages/chat_list/space_view.dart | 31 ++++++--- lib/pages/new_group/new_group_view.dart | 5 +- lib/pages/new_space/new_space.dart | 22 ++++-- lib/pages/new_space/new_space_view.dart | 9 +++ .../chat_details/pangea_chat_details.dart | 4 +- lib/pangea/widgets/chat/add_room_dialog.dart | 16 ++++- .../widgets/chat/visibility_toggle.dart | 67 ++++++++++++++----- 10 files changed, 138 insertions(+), 43 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index f3e646016..6aa9e66b6 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -4517,5 +4517,7 @@ "spaceDescription": "Space description", "addSpaceDescription": "Add a space description", "notificationsOn": "Notifications on", - "notificationsOff": "Notifications off" + "notificationsOff": "Notifications off", + "spaceCanBeFoundViaSearch": "Space can be found via search", + "chatCanBeFoundViaSearch": "Chat can be found via search" } \ No newline at end of file diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 35763009a..126ec0826 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -12,7 +12,6 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:go_router/go_router.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:matrix/matrix.dart' as matrix; import 'package:matrix/matrix.dart'; enum AliasActions { copy, delete, setCanonical } @@ -207,18 +206,24 @@ class ChatDetailsController extends State { void hoverEditNameIcon(bool hovering) => setState(() => showEditNameIcon = !showEditNameIcon); - Future setVisibility(matrix.Visibility visibility) async { + Future setJoinRules(JoinRules joinRules) async { if (roomId == null) return; + final room = Matrix.of(context).client.getRoomById(roomId!); + if (room == null) return; + + final content = room.getState(EventTypes.RoomJoinRules)?.content ?? {}; + content['join_rule'] = joinRules.toString().replaceAll('JoinRules.', ''); await showFutureLoadingDialog( context: context, future: () async { - await Matrix.of(context).client.setRoomVisibilityOnDirectory( - roomId!, - visibility: visibility, - ); + await room.client.setRoomStateWithKey( + roomId!, + EventTypes.RoomJoinRules, + '', + content, + ); }, ); - if (mounted) setState(() {}); } Future toggleMute() async { diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index 9f05f959d..c521c3daa 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -342,8 +342,10 @@ class ChatDetailsView extends StatelessWidget { if (room.isRoomAdmin) VisibilityToggle( room: room, - setVisibility: controller.setVisibility, + setVisibility: (_) async {}, + setJoinRules: controller.setJoinRules, iconColor: iconColor, + showSearchToggle: false, ), // Pangea# Divider(color: theme.dividerColor), diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 2fced0f79..61509dcf0 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -386,18 +386,27 @@ class _SpaceViewState extends State { await activeSpace.postLoad(); if (roomType == AddRoomType.subspace) { - roomId = await client.createSpace( - // #Pangea - // name: names.first, - // topic: names.last.isEmpty ? null : names.last, - // visibility: activeSpace.joinRules == JoinRules.public - // ? sdk.Visibility.public - // : sdk.Visibility.private, + // #Pangea + // roomId = await client.createSpace( + // name: names.first, + // topic: names.last.isEmpty ? null : names.last, + // visibility: activeSpace.joinRules == JoinRules.public + // ? sdk.Visibility.public + // : sdk.Visibility.private, + // ); + roomId = await client.createRoom( + preset: response.joinRules == sdk.JoinRules.public + ? sdk.CreateRoomPreset.publicChat + : sdk.CreateRoomPreset.privateChat, + creationContent: {'type': RoomCreationTypes.mSpace}, + visibility: response.joinRules == sdk.JoinRules.public + ? response.visibility + : null, name: response.roomName, topic: response.roomDescription, - visibility: response.visibility, - // Pangea# + powerLevelContentOverride: {'events_default': 100}, ); + // Pangea# } else { roomId = await client.createGroupChat( // #Pangea @@ -417,7 +426,9 @@ class _SpaceViewState extends State { // ] // : null, groupName: response.roomName, - preset: CreateRoomPreset.publicChat, + preset: response.joinRules == sdk.JoinRules.public + ? CreateRoomPreset.publicChat + : CreateRoomPreset.privateChat, visibility: response.visibility, initialState: response.roomDescription.isNotEmpty ? [ diff --git a/lib/pages/new_group/new_group_view.dart b/lib/pages/new_group/new_group_view.dart index 7ea7f9de5..a28b801a6 100644 --- a/lib/pages/new_group/new_group_view.dart +++ b/lib/pages/new_group/new_group_view.dart @@ -84,7 +84,10 @@ class NewGroupView extends StatelessWidget { contentPadding: const EdgeInsets.symmetric(horizontal: 32), secondary: const Icon(Icons.search_outlined), - title: Text(L10n.of(context)!.groupCanBeFoundViaSearch), + // #Pangea + // title: Text(L10n.of(context)!.groupCanBeFoundViaSearch), + title: Text(L10n.of(context)!.chatCanBeFoundViaSearch), + // Pangea# value: controller.groupCanBeFound, onChanged: controller.loading ? null diff --git a/lib/pages/new_space/new_space.dart b/lib/pages/new_space/new_space.dart index 9264d0657..be598bea7 100644 --- a/lib/pages/new_space/new_space.dart +++ b/lib/pages/new_space/new_space.dart @@ -28,6 +28,9 @@ class NewSpaceController extends State { TextEditingController nameController = TextEditingController(); TextEditingController topicController = TextEditingController(); bool publicGroup = false; + // #Pangea + bool spaceCanBeFound = true; + // Pangea# bool loading = false; String? nameError; String? topicError; @@ -48,10 +51,14 @@ class NewSpaceController extends State { }); } + // #Pangea + void setSpaceCanBeFound(bool b) => setState(() => spaceCanBeFound = b); + // Pangea# + void setPublicGroup(bool b) => setState(() => publicGroup = b); // #Pangea - List initialState(String joinCode) { + List initialState(String joinCode, bool publicGroup) { return [ StateEvent( type: EventTypes.RoomPowerLevels, @@ -70,8 +77,9 @@ class NewSpaceController extends State { StateEvent( type: sdk.EventTypes.RoomJoinRules, content: { - ModelKey.joinRule: - sdk.JoinRules.knock.toString().replaceAll('JoinRules.', ''), + ModelKey.joinRule: publicGroup + ? sdk.JoinRules.public.toString().replaceAll('JoinRules.', '') + : sdk.JoinRules.invite.toString().replaceAll('JoinRules.', ''), ModelKey.accessCode: joinCode, }, ), @@ -104,8 +112,12 @@ class NewSpaceController extends State { preset: publicGroup ? sdk.CreateRoomPreset.publicChat : sdk.CreateRoomPreset.privateChat, + // #Pangea + visibility: publicGroup && spaceCanBeFound + ? sdk.Visibility.public + : sdk.Visibility.private, + // Pangea# creationContent: {'type': RoomCreationTypes.mSpace}, - visibility: publicGroup ? sdk.Visibility.public : null, roomAliasName: publicGroup ? nameController.text.trim().toLowerCase().replaceAll(' ', '_') : null, @@ -114,7 +126,7 @@ class NewSpaceController extends State { powerLevelContentOverride: {'events_default': 100}, initialState: [ // #Pangea - ...initialState(joinCode), + ...initialState(joinCode, publicGroup), // Pangea# if (avatar != null) sdk.StateEvent( diff --git a/lib/pages/new_space/new_space_view.dart b/lib/pages/new_space/new_space_view.dart index 3842231c8..5c9e69a1b 100644 --- a/lib/pages/new_space/new_space_view.dart +++ b/lib/pages/new_space/new_space_view.dart @@ -62,6 +62,15 @@ class NewSpaceView extends StatelessWidget { value: controller.publicGroup, onChanged: controller.setPublicGroup, ), + // #Pangea + if (controller.publicGroup) + SwitchListTile.adaptive( + contentPadding: const EdgeInsets.symmetric(horizontal: 32), + title: Text(L10n.of(context)!.spaceCanBeFoundViaSearch), + value: controller.spaceCanBeFound, + onChanged: controller.setSpaceCanBeFound, + ), + // Pangea# ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 32), trailing: const Padding( diff --git a/lib/pangea/pages/chat_details/pangea_chat_details.dart b/lib/pangea/pages/chat_details/pangea_chat_details.dart index 4685c4896..ccc9baed3 100644 --- a/lib/pangea/pages/chat_details/pangea_chat_details.dart +++ b/lib/pangea/pages/chat_details/pangea_chat_details.dart @@ -316,8 +316,10 @@ class PangeaChatDetailsView extends StatelessWidget { if (room.isRoomAdmin) VisibilityToggle( room: room, - setVisibility: controller.setVisibility, + setVisibility: (_) async {}, + setJoinRules: controller.setJoinRules, iconColor: iconColor, + showSearchToggle: false, ), if (room.isRoomAdmin) Divider(color: theme.dividerColor, height: 1), diff --git a/lib/pangea/widgets/chat/add_room_dialog.dart b/lib/pangea/widgets/chat/add_room_dialog.dart index d166cf0d7..42d8b4786 100644 --- a/lib/pangea/widgets/chat/add_room_dialog.dart +++ b/lib/pangea/widgets/chat/add_room_dialog.dart @@ -3,6 +3,7 @@ import 'package:fluffychat/pangea/widgets/chat/visibility_toggle.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart' as matrix; +import 'package:matrix/matrix.dart'; class AddRoomDialog extends StatefulWidget { final AddRoomType? roomType; @@ -23,8 +24,13 @@ class AddRoomDialogState extends State { TextEditingController(); matrix.Visibility visibility = matrix.Visibility.public; + JoinRules joinRules = JoinRules.public; - Future setVisibility(matrix.Visibility newVisibility) async { + Future _setJoinRules(JoinRules newJoinRules) async { + setState(() => joinRules = newJoinRules); + } + + Future _setVisibility(matrix.Visibility newVisibility) async { setState(() => visibility = newVisibility); } @@ -93,9 +99,11 @@ class AddRoomDialogState extends State { ), ), VisibilityToggle( - setVisibility: setVisibility, + setJoinRules: _setJoinRules, + setVisibility: _setVisibility, spaceMode: widget.roomType == AddRoomType.subspace, visibility: visibility, + joinRules: joinRules, ), Padding( padding: const EdgeInsets.all(20), @@ -118,6 +126,7 @@ class AddRoomDialogState extends State { RoomResponse( roomName: _roomNameController.text, roomDescription: _roomDescriptionController.text, + joinRules: joinRules, visibility: visibility, ), ); @@ -138,11 +147,13 @@ class AddRoomDialogState extends State { class RoomResponse { final String roomName; final String roomDescription; + final JoinRules joinRules; final matrix.Visibility visibility; RoomResponse({ required this.roomName, required this.roomDescription, + required this.joinRules, required this.visibility, }); @@ -150,6 +161,7 @@ class RoomResponse { return { 'roomName': roomName, 'roomDescripion': roomDescription, + 'joinRules': joinRules, 'visibility': visibility, }; } diff --git a/lib/pangea/widgets/chat/visibility_toggle.dart b/lib/pangea/widgets/chat/visibility_toggle.dart index 5380e3b7a..59ab2dce6 100644 --- a/lib/pangea/widgets/chat/visibility_toggle.dart +++ b/lib/pangea/widgets/chat/visibility_toggle.dart @@ -9,26 +9,35 @@ class VisibilityToggle extends StatelessWidget { final Room? room; final Color? iconColor; final Future Function(matrix.Visibility) setVisibility; + final Future Function(JoinRules) setJoinRules; final bool spaceMode; final matrix.Visibility visibility; + final JoinRules joinRules; + + final bool showSearchToggle; const VisibilityToggle({ required this.setVisibility, + required this.setJoinRules, this.room, this.iconColor, this.spaceMode = false, this.visibility = matrix.Visibility.private, + this.joinRules = JoinRules.invite, + this.showSearchToggle = true, super.key, }); + bool get _isPublic => room != null + ? room!.joinRules == matrix.JoinRules.public + : joinRules == matrix.JoinRules.public; + @override Widget build(BuildContext context) { - return FutureBuilder( - future: room != null - ? Matrix.of(context).client.getRoomVisibilityOnDirectory(room!.id) - : null, - builder: (context, snapshot) { - return SwitchListTile.adaptive( + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SwitchListTile.adaptive( activeColor: AppConfig.activeToggleColor, title: Text( room?.isSpace ?? spaceMode @@ -44,16 +53,44 @@ class VisibilityToggle extends StatelessWidget { foregroundColor: iconColor, child: const Icon(Icons.public_outlined), ), - value: room != null - ? snapshot.hasData - ? snapshot.data == matrix.Visibility.public - : false - : visibility == matrix.Visibility.public, - onChanged: (value) => setVisibility( - value ? matrix.Visibility.public : matrix.Visibility.private, + value: _isPublic, + onChanged: (value) => + setJoinRules(value ? JoinRules.public : JoinRules.invite), + ), + if (_isPublic && showSearchToggle) + FutureBuilder( + future: room != null + ? Matrix.of(context) + .client + .getRoomVisibilityOnDirectory(room!.id) + : null, + builder: (context, snapshot) { + return SwitchListTile.adaptive( + activeColor: AppConfig.activeToggleColor, + title: Text( + room?.isSpace ?? spaceMode + ? L10n.of(context)!.spaceCanBeFoundViaSearch + : L10n.of(context)!.chatCanBeFoundViaSearch, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + secondary: CircleAvatar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + foregroundColor: iconColor, + child: const Icon(Icons.search_outlined), + ), + value: room != null + ? room!.joinRules == matrix.JoinRules.public + : visibility == matrix.Visibility.public, + onChanged: (value) => setVisibility( + value ? matrix.Visibility.public : matrix.Visibility.private, + ), + ); + }, ), - ); - }, + ], ); } }