diff --git a/lib/pages/chat_access_settings/chat_access_settings_controller.dart b/lib/pages/chat_access_settings/chat_access_settings_controller.dart index 471c07d92..9c3a48b86 100644 --- a/lib/pages/chat_access_settings/chat_access_settings_controller.dart +++ b/lib/pages/chat_access_settings/chat_access_settings_controller.dart @@ -5,7 +5,7 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/chat_settings/pages/pangea_chat_access_settings.dart'; -import 'package:fluffychat/pangea/spaces/utils/client_spaces_extension.dart'; +import 'package:fluffychat/pangea/extensions/join_rule_extension.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; @@ -70,8 +70,7 @@ class ChatAccessSettingsController extends State { try { // #Pangea // await room.setJoinRules(newJoinRules); - await room.client.pangeaSetJoinRules( - room.id, + await room.pangeaSetJoinRules( newJoinRules.toString().replaceAll('JoinRules.', ''), ); // Pangea# diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 826f87a4e..26aece57d 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -15,11 +15,10 @@ import 'package:fluffychat/pangea/chat_settings/models/bot_options_model.dart'; import 'package:fluffychat/pangea/chat_settings/pages/pangea_chat_details.dart'; import 'package:fluffychat/pangea/chat_settings/utils/download_chat.dart'; import 'package:fluffychat/pangea/chat_settings/utils/download_file.dart'; -import 'package:fluffychat/pangea/common/constants/model_keys.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart'; +import 'package:fluffychat/pangea/extensions/join_rule_extension.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; -import 'package:fluffychat/pangea/spaces/utils/space_code.dart'; import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; @@ -339,7 +338,6 @@ class ChatDetailsController extends State { future: () async { final activeSpace = client.getRoomById(roomId!)!; await activeSpace.postLoad(); - final accessCode = await SpaceCodeUtil.generateSpaceCode(client); final resp = await client.createRoom( name: names, @@ -347,18 +345,14 @@ class ChatDetailsController extends State { creationContent: {'type': 'm.space'}, initialState: [ RoomDefaults.defaultSpacePowerLevels(client.userID!), - StateEvent( - type: EventTypes.RoomJoinRules, - content: { - 'join_rule': 'knock_restricted', - 'allow': [ - { - "type": "m.room_membership", - "room_id": roomId!, - } - ], - ModelKey.accessCode: accessCode, - }, + await client.pangeaJoinRules( + 'knock_restricted', + allow: [ + { + "type": "m.room_membership", + "room_id": roomId!, + } + ], ), ], ); diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index fe4782b37..30dfe7a16 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -23,8 +23,8 @@ import 'package:fluffychat/pangea/chat_settings/utils/delete_room.dart'; import 'package:fluffychat/pangea/chat_settings/widgets/delete_space_dialog.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart'; +import 'package:fluffychat/pangea/extensions/join_rule_extension.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; -import 'package:fluffychat/pangea/spaces/utils/client_spaces_extension.dart'; import 'package:fluffychat/pangea/subscription/widgets/subscription_snackbar.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; @@ -1057,7 +1057,7 @@ class ChatListController extends State ); // #Pangea try { - await space.client.setSpaceChildAccess(room.id); + await space.setSpaceChildAccess(); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( @@ -1077,7 +1077,7 @@ class ChatListController extends State }, ); try { - await room.client.resetSpaceChildAccess(room.id); + await room.resetSpaceChildAccess(); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 395804047..37755b8de 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -12,6 +12,7 @@ import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart'; import 'package:fluffychat/pangea/chat/constants/default_power_level.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart'; +import 'package:fluffychat/pangea/extensions/join_rule_extension.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; import 'package:fluffychat/pangea/spaces/utils/client_spaces_extension.dart'; import 'package:fluffychat/utils/file_selector.dart'; @@ -142,19 +143,21 @@ class NewGroupController extends State { RoomDefaults.defaultPowerLevels( Matrix.of(context).client.userID!, ), - if (widget.spaceId != null) - StateEvent( - type: EventTypes.RoomJoinRules, - content: { - 'join_rule': 'knock_restricted', - 'allow': [ - { - "type": "m.room_membership", - "room_id": widget.spaceId, - } - ], - }, - ), + await Matrix.of(context).client.pangeaJoinRules( + widget.spaceId != null + ? 'knock_restricted' + : JoinRules.public + .toString() + .replaceAll('JoinRules.', ''), + allow: widget.spaceId != null + ? [ + { + "type": "m.room_membership", + "room_id": widget.spaceId, + } + ] + : null, + ), // Pangea# ], // #Pangea diff --git a/lib/pangea/chat_settings/pages/pangea_invitation_selection.dart b/lib/pangea/chat_settings/pages/pangea_invitation_selection.dart index 1edb9003c..39b7f1160 100644 --- a/lib/pangea/chat_settings/pages/pangea_invitation_selection.dart +++ b/lib/pangea/chat_settings/pages/pangea_invitation_selection.dart @@ -9,6 +9,9 @@ import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/bot/utils/bot_name.dart'; import 'package:fluffychat/pangea/chat_settings/pages/pangea_invitation_selection_view.dart'; import 'package:fluffychat/pangea/common/config/environment.dart'; +import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/extensions/join_rule_extension.dart'; +import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -131,6 +134,8 @@ class PangeaInvitationSelectionController controller.addListener(() { setState(() {}); }); + + _addJoinCode(); } String filterLabel(InvitationFilter filter) { @@ -321,6 +326,22 @@ class PangeaInvitationSelectionController ); } + Future _addJoinCode() async { + if (_room == null || _room!.classCode != null) return; + if (!_room!.canChangeStateEvent(EventTypes.RoomJoinRules)) return; + + try { + await _room!.addJoinCode(); + if (mounted) setState(() {}); + } catch (e, s) { + ErrorHandler.logError( + e: e, + s: s, + data: {'roomId': _room!.id}, + ); + } + } + Future searchUser(BuildContext context, String text) async { coolDown?.cancel(); if (text.isEmpty) { diff --git a/lib/pangea/chat_settings/pages/pangea_invitation_selection_view.dart b/lib/pangea/chat_settings/pages/pangea_invitation_selection_view.dart index f4abaea00..08c93ab14 100644 --- a/lib/pangea/chat_settings/pages/pangea_invitation_selection_view.dart +++ b/lib/pangea/chat_settings/pages/pangea_invitation_selection_view.dart @@ -262,7 +262,7 @@ class PangeaInvitationSelectionView extends StatelessWidget { Row( spacing: 12.0, children: [ - if (room.isSpace && room.classCode != null) + if (room.classCode != null) Expanded( child: PopupMenuButton( borderRadius: BorderRadius.circular(32.0), @@ -342,7 +342,7 @@ class PangeaInvitationSelectionView extends StatelessWidget { ], ), ), - room.isSpace && room.classCode != null + room.classCode != null ? doneButton : Expanded(child: doneButton), ], diff --git a/lib/pangea/extensions/join_rule_extension.dart b/lib/pangea/extensions/join_rule_extension.dart new file mode 100644 index 000000000..1033cfabb --- /dev/null +++ b/lib/pangea/extensions/join_rule_extension.dart @@ -0,0 +1,110 @@ +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/pangea/common/constants/model_keys.dart'; +import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/spaces/utils/space_code.dart'; + +extension JoinRuleExtension on Client { + Future pangeaJoinRules( + String joinRule, { + List>? allow, + }) async { + String? joinCode; + try { + joinCode = await SpaceCodeUtil.generateSpaceCode(this); + } catch (e, s) { + ErrorHandler.logError( + e: e, + s: s, + data: { + 'joinRule': joinRule, + }, + ); + } + + return StateEvent( + type: EventTypes.RoomJoinRules, + content: { + ModelKey.joinRule: joinRule, + if (joinCode != null) ModelKey.accessCode: joinCode, + if (allow != null) 'allow': allow, + }, + ); + } +} + +extension JoinRuleExtensionOnRoom on Room { + Future addJoinCode() async { + if (!canChangeStateEvent(EventTypes.RoomJoinRules)) { + throw Exception('Cannot change join rules for this room'); + } + + final currentJoinRules = getState(EventTypes.RoomJoinRules)?.content ?? {}; + if (currentJoinRules[ModelKey.accessCode] != null) return; + + final joinCode = await SpaceCodeUtil.generateSpaceCode(client); + currentJoinRules[ModelKey.accessCode] = joinCode; + + await client.setRoomStateWithKey( + id, + EventTypes.RoomJoinRules, + '', + currentJoinRules, + ); + } + + /// Keep the room's current join rule state event content (except for what's intentionally replaced) + /// since space's access codes were stored there. Don't want to accidentally remove them. + Future pangeaSetJoinRules( + String joinRule, { + List>? allow, + }) async { + final currentJoinRule = getState( + EventTypes.RoomJoinRules, + )?.content ?? + {}; + + if (currentJoinRule[ModelKey.joinRule] == joinRule && + (currentJoinRule['allow'] == allow)) { + return; // No change needed + } + + currentJoinRule[ModelKey.joinRule] = joinRule; + currentJoinRule['allow'] = allow; + + await client.setRoomStateWithKey( + id, + EventTypes.RoomJoinRules, + '', + currentJoinRule, + ); + } + + Future setSpaceChildAccess() async { + await pangeaSetJoinRules( + 'knock_restricted', + allow: [ + { + "type": "m.room_membership", + "room_id": id, + } + ], + ); + + await client.setRoomVisibilityOnDirectory( + id, + visibility: Visibility.private, + ); + } + + Future resetSpaceChildAccess() async { + await pangeaSetJoinRules( + JoinRules.knock.toString().replaceAll('JoinRules.', ''), + ); + + await client.setRoomVisibilityOnDirectory( + id, + visibility: Visibility.private, + ); + } +} diff --git a/lib/pangea/extensions/room_space_settings_extension.dart b/lib/pangea/extensions/room_space_settings_extension.dart index 333539d6b..47dea0d74 100644 --- a/lib/pangea/extensions/room_space_settings_extension.dart +++ b/lib/pangea/extensions/room_space_settings_extension.dart @@ -2,7 +2,6 @@ part of "pangea_room_extension.dart"; extension SpaceRoomExtension on Room { String? get classCode { - if (!isSpace) return null; final roomJoinRules = getState(EventTypes.RoomJoinRules, ""); if (roomJoinRules != null) { final accessCode = roomJoinRules.content.tryGet(ModelKey.accessCode); diff --git a/lib/pangea/spaces/utils/client_spaces_extension.dart b/lib/pangea/spaces/utils/client_spaces_extension.dart index e94efd224..fb0a2f5db 100644 --- a/lib/pangea/spaces/utils/client_spaces_extension.dart +++ b/lib/pangea/spaces/utils/client_spaces_extension.dart @@ -5,11 +5,10 @@ import 'package:http/http.dart' as http; import 'package:matrix/matrix.dart'; import 'package:fluffychat/pangea/chat/constants/default_power_level.dart'; -import 'package:fluffychat/pangea/common/constants/model_keys.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/extensions/join_rule_extension.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; import 'package:fluffychat/pangea/spaces/constants/space_constants.dart'; -import 'package:fluffychat/pangea/spaces/utils/space_code.dart'; extension SpacesClientExtension on Client { Future createPangeaSpace({ @@ -21,17 +20,15 @@ extension SpacesClientExtension on Client { Uint8List? avatar, Uri? avatarUrl, }) async { - final joinCode = await SpaceCodeUtil.generateSpaceCode(this); final roomId = await createRoom( creationContent: {'type': RoomCreationTypes.mSpace}, visibility: visibility, name: name.trim(), powerLevelContentOverride: {'events_default': 100}, initialState: [ - ..._spaceInitialState( - userID!, - joinCode, - joinRules: joinRules, + RoomDefaults.defaultSpacePowerLevels(userID!), + await pangeaJoinRules( + joinRules.toString().replaceAll('JoinRules.', ''), ), if (avatar != null) StateEvent( @@ -123,17 +120,14 @@ extension SpacesClientExtension on Client { content: {'url': introChatUploadURL.toString()}, ), RoomDefaults.defaultPowerLevels(userID!), - StateEvent( - type: EventTypes.RoomJoinRules, - content: { - 'join_rule': 'knock_restricted', - 'allow': [ - { - "type": "m.room_membership", - "room_id": space.id, - } - ], - }, + await pangeaJoinRules( + 'knock_restricted', + allow: [ + { + "type": "m.room_membership", + "room_id": space.id, + } + ], ), ], ); @@ -151,17 +145,14 @@ extension SpacesClientExtension on Client { content: {'url': announcementsChatUploadURL.toString()}, ), RoomDefaults.restrictedPowerLevels(userID!), - StateEvent( - type: EventTypes.RoomJoinRules, - content: { - 'join_rule': 'knock_restricted', - 'allow': [ - { - "type": "m.room_membership", - "room_id": space.id, - } - ], - }, + await pangeaJoinRules( + 'knock_restricted', + allow: [ + { + "type": "m.room_membership", + "room_id": space.id, + } + ], ), ], ); @@ -195,86 +186,4 @@ extension SpacesClientExtension on Client { addAnnouncementsChatFuture, ]); } - - List _spaceInitialState( - String userID, - String joinCode, { - required JoinRules joinRules, - }) { - return [ - RoomDefaults.defaultSpacePowerLevels(userID), - StateEvent( - type: EventTypes.RoomJoinRules, - content: { - ModelKey.joinRule: joinRules.toString().replaceAll('JoinRules.', ''), - ModelKey.accessCode: joinCode, - }, - ), - ]; - } - - /// Keep the room's current join rule state event content (except for what's intentionally replaced) - /// since space's access codes were stored there. Don't want to accidentally remove them. - Future pangeaSetJoinRules( - String roomId, - String joinRule, { - List>? allow, - }) async { - final room = getRoomById(roomId); - if (room == null) { - throw Exception('Room not found for user ID: $userID'); - } - - final currentJoinRule = room - .getState( - EventTypes.RoomJoinRules, - ) - ?.content ?? - {}; - - if (currentJoinRule[ModelKey.joinRule] == joinRule && - (currentJoinRule['allow'] == allow)) { - return; // No change needed - } - - currentJoinRule[ModelKey.joinRule] = joinRule; - currentJoinRule['allow'] = allow; - - await setRoomStateWithKey( - roomId, - EventTypes.RoomJoinRules, - '', - currentJoinRule, - ); - } - - Future setSpaceChildAccess(String roomId) async { - await pangeaSetJoinRules( - roomId, - 'knock_restricted', - allow: [ - { - "type": "m.room_membership", - "room_id": id, - } - ], - ); - - await setRoomVisibilityOnDirectory( - roomId, - visibility: Visibility.private, - ); - } - - Future resetSpaceChildAccess(String roomId) async { - await pangeaSetJoinRules( - roomId, - JoinRules.knock.toString().replaceAll('JoinRules.', ''), - ); - - await setRoomVisibilityOnDirectory( - roomId, - visibility: Visibility.private, - ); - } }