diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index a94430da19..2edbc28678 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -13,6 +13,7 @@ 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 } @@ -205,6 +206,20 @@ class ChatDetailsController extends State { void hoverEditNameIcon(bool hovering) => setState(() => showEditNameIcon = !showEditNameIcon); + Future setVisibility(matrix.Visibility visibility) async { + if (roomId == null) return; + await showFutureLoadingDialog( + context: context, + future: () async { + await Matrix.of(context).client.setRoomVisibilityOnDirectory( + roomId!, + visibility: visibility, + ); + }, + ); + if (mounted) setState(() {}); + } + @override void initState() { super.initState(); diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index 72441e450e..6040279b7b 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -9,6 +9,7 @@ import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_det import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_invitation_buttons.dart'; import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; import 'package:fluffychat/pangea/utils/lock_room.dart'; +import 'package:fluffychat/pangea/widgets/chat/visibility_toggle.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; @@ -340,6 +341,14 @@ class ChatDetailsView extends StatelessWidget { '/rooms/${room.id}/details/permissions', ), ), + // #Pangea + if (room.isRoomAdmin) + VisibilityToggle( + room: room, + setVisibility: controller.setVisibility, + iconColor: iconColor, + ), + // Pangea# Divider(color: theme.dividerColor), // #Pangea if (room.canInvite && diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 41bce1e9ae..4053bbb01a 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -8,6 +8,7 @@ import 'package:fluffychat/pages/chat_list/chat_list_item.dart'; import 'package:fluffychat/pages/chat_list/search_title.dart'; import 'package:fluffychat/pangea/constants/pangea_room_types.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/widgets/chat/add_room_dialog.dart'; import 'package:fluffychat/utils/adaptive_bottom_sheet.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/utils/stream_extension.dart'; @@ -331,43 +332,51 @@ class _SpaceViewState extends State { ); if (roomType == null) return; - final names = await showTextInputDialog( + // #Pangea + final RoomResponse? response = await showDialog( context: context, - title: roomType == AddRoomType.subspace - ? L10n.of(context)!.createNewSpace - // #Pangea - // : L10n.of(context)!.createGroup, - : L10n.of(context)!.createChat, - // Pangea# - textFields: [ - DialogTextField( - hintText: roomType == AddRoomType.subspace - ? L10n.of(context)!.spaceName - // #Pangea - // : L10n.of(context)!.groupName, - : L10n.of(context)!.chatName, - // Pangea# - minLines: 1, - maxLines: 1, - maxLength: 64, - validator: (text) { - if (text == null || text.isEmpty) { - return L10n.of(context)!.pleaseChoose; - } - return null; - }, - ), - DialogTextField( - hintText: L10n.of(context)!.chatDescription, - minLines: 4, - maxLines: 8, - maxLength: 255, - ), - ], - okLabel: L10n.of(context)!.create, - cancelLabel: L10n.of(context)!.cancel, + builder: (context) { + return AddRoomDialog( + roomType: roomType, + ); + }, ); - if (names == null) return; + if (response == null) return; + + // final names = await showTextInputDialog( + // context: context, + // title: roomType == AddRoomType.subspace + // ? L10n.of(context)!.createNewSpace + // : L10n.of(context)!.createGroup, + // : L10n.of(context)!.createChat, + // textFields: [ + // DialogTextField( + // hintText: roomType == AddRoomType.subspace + // ? L10n.of(context)!.spaceName + // L10n.of(context)!.groupName, + // : L10n.of(context)!.chatName, + // minLines: 1, + // maxLines: 1, + // maxLength: 64, + // validator: (text) { + // if (text == null || text.isEmpty) { + // return L10n.of(context)!.pleaseChoose; + // } + // return null; + // }, + // ), + // DialogTextField( + // hintText: L10n.of(context)!.chatDescription, + // minLines: 4, + // maxLines: 8, + // maxLength: 255, + // ), + // ], + // okLabel: L10n.of(context)!.create, + // cancelLabel: L10n.of(context)!.cancel, + // ); + // if (names == null) return; + // Pangea# final client = Matrix.of(context).client; final result = await showFutureLoadingDialog( context: context, @@ -378,33 +387,46 @@ class _SpaceViewState extends State { if (roomType == AddRoomType.subspace) { 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, + // #Pangea + // name: names.first, + // topic: names.last.isEmpty ? null : names.last, + // visibility: activeSpace.joinRules == JoinRules.public + // ? sdk.Visibility.public + // : sdk.Visibility.private, + name: response.roomName, + topic: response.roomDescription, + visibility: response.visibility, + // Pangea# ); } else { roomId = await client.createGroupChat( - groupName: names.first, // #Pangea + // groupName: names.first, // preset: activeSpace.joinRules == JoinRules.public // ? CreateRoomPreset.publicChat // : CreateRoomPreset.privateChat, + // visibility: activeSpace.joinRules == JoinRules.public + // ? sdk.Visibility.public + // : sdk.Visibility.private, + // initialState: names.length > 1 && names.last.isNotEmpty + // ? [ + // StateEvent( + // type: EventTypes.RoomTopic, + // content: {'topic': names.last}, + // ), + // ] + // : null, + groupName: response.roomName, preset: CreateRoomPreset.publicChat, - // Pangea# - visibility: activeSpace.joinRules == JoinRules.public - ? sdk.Visibility.public - : sdk.Visibility.private, - initialState: names.length > 1 && names.last.isNotEmpty + visibility: response.visibility, + initialState: response.roomDescription.isNotEmpty ? [ StateEvent( type: EventTypes.RoomTopic, - content: {'topic': names.last}, + content: {'topic': response.roomDescription}, ), ] : null, - // #Pangea enableEncryption: false, // Pangea# ); diff --git a/lib/pangea/widgets/chat/add_room_dialog.dart b/lib/pangea/widgets/chat/add_room_dialog.dart new file mode 100644 index 0000000000..d166cf0d70 --- /dev/null +++ b/lib/pangea/widgets/chat/add_room_dialog.dart @@ -0,0 +1,156 @@ +import 'package:fluffychat/pages/chat_list/space_view.dart'; +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; + +class AddRoomDialog extends StatefulWidget { + final AddRoomType? roomType; + + const AddRoomDialog({ + required this.roomType, + super.key, + }); + + @override + AddRoomDialogState createState() => AddRoomDialogState(); +} + +class AddRoomDialogState extends State { + final _formKey = GlobalKey(); + final TextEditingController _roomNameController = TextEditingController(); + final TextEditingController _roomDescriptionController = + TextEditingController(); + + matrix.Visibility visibility = matrix.Visibility.public; + + Future setVisibility(matrix.Visibility newVisibility) async { + setState(() => visibility = newVisibility); + } + + @override + void dispose() { + _roomNameController.dispose(); + _roomDescriptionController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Dialog( + child: Form( + key: _formKey, + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 400, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.all(20), + child: Column( + children: [ + Text( + style: Theme.of(context).textTheme.headlineSmall, + widget.roomType == AddRoomType.subspace + ? L10n.of(context)!.createNewSpace + : L10n.of(context)!.createChat, + ), + const SizedBox(height: 20), + TextFormField( + controller: _roomNameController, + decoration: InputDecoration( + hintText: widget.roomType == AddRoomType.subspace + ? L10n.of(context)!.spaceName + : L10n.of(context)!.chatName, + ), + minLines: 1, + maxLines: 1, + maxLength: 64, + validator: (text) { + if (text == null || text.isEmpty) { + return L10n.of(context)!.pleaseChoose; + } + return null; + }, + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), + ), + const SizedBox(height: 20), + TextFormField( + controller: _roomDescriptionController, + decoration: InputDecoration( + hintText: L10n.of(context)!.chatDescription, + ), + minLines: 4, + maxLines: 8, + maxLength: 255, + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), + ), + ], + ), + ), + VisibilityToggle( + setVisibility: setVisibility, + spaceMode: widget.roomType == AddRoomType.subspace, + visibility: visibility, + ), + Padding( + padding: const EdgeInsets.all(20), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(null); + }, + child: Text(L10n.of(context)!.cancel), + ), + const SizedBox(width: 20), + TextButton( + onPressed: () async { + final isValid = _formKey.currentState!.validate(); + if (!isValid) return; + + Navigator.of(context).pop( + RoomResponse( + roomName: _roomNameController.text, + roomDescription: _roomDescriptionController.text, + visibility: visibility, + ), + ); + }, + child: Text(L10n.of(context)!.confirm), + ), + ], + ), + ), + ], + ), + ), + ), + ); + } +} + +class RoomResponse { + final String roomName; + final String roomDescription; + final matrix.Visibility visibility; + + RoomResponse({ + required this.roomName, + required this.roomDescription, + required this.visibility, + }); + + Map toJson() { + return { + 'roomName': roomName, + 'roomDescripion': roomDescription, + 'visibility': visibility, + }; + } +} diff --git a/lib/pangea/widgets/chat/visibility_toggle.dart b/lib/pangea/widgets/chat/visibility_toggle.dart new file mode 100644 index 0000000000..5380e3b7a0 --- /dev/null +++ b/lib/pangea/widgets/chat/visibility_toggle.dart @@ -0,0 +1,59 @@ +import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/widgets/matrix.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 VisibilityToggle extends StatelessWidget { + final Room? room; + final Color? iconColor; + final Future Function(matrix.Visibility) setVisibility; + final bool spaceMode; + final matrix.Visibility visibility; + + const VisibilityToggle({ + required this.setVisibility, + this.room, + this.iconColor, + this.spaceMode = false, + this.visibility = matrix.Visibility.private, + super.key, + }); + + @override + Widget build(BuildContext context) { + return 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)!.spaceIsPublic + : L10n.of(context)!.groupIsPublic, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + secondary: CircleAvatar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + 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, + ), + ); + }, + ); + } +}