Skip to content

Commit

Permalink
934 enrolling users automatically in several spaces (#975)
Browse files Browse the repository at this point in the history
* allow users to set visibility of rooms in add chat or subspace dialog and in room details

* only allow room admins to change visibility
  • Loading branch information
ggurdin authored Nov 13, 2024
1 parent 81d4823 commit af1561b
Show file tree
Hide file tree
Showing 5 changed files with 309 additions and 48 deletions.
15 changes: 15 additions & 0 deletions lib/pages/chat_details/chat_details.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -205,6 +206,20 @@ class ChatDetailsController extends State<ChatDetails> {
void hoverEditNameIcon(bool hovering) =>
setState(() => showEditNameIcon = !showEditNameIcon);

Future<void> 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();
Expand Down
9 changes: 9 additions & 0 deletions lib/pages/chat_details/chat_details_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 &&
Expand Down
118 changes: 70 additions & 48 deletions lib/pages/chat_list/space_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -331,43 +332,51 @@ class _SpaceViewState extends State<SpaceView> {
);
if (roomType == null) return;

final names = await showTextInputDialog(
// #Pangea
final RoomResponse? response = await showDialog<RoomResponse>(
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,
Expand All @@ -378,33 +387,46 @@ class _SpaceViewState extends State<SpaceView> {

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#
);
Expand Down
156 changes: 156 additions & 0 deletions lib/pangea/widgets/chat/add_room_dialog.dart
Original file line number Diff line number Diff line change
@@ -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<AddRoomDialog> {
final _formKey = GlobalKey<FormState>();
final TextEditingController _roomNameController = TextEditingController();
final TextEditingController _roomDescriptionController =
TextEditingController();

matrix.Visibility visibility = matrix.Visibility.public;

Future<void> 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<String, dynamic> toJson() {
return {
'roomName': roomName,
'roomDescripion': roomDescription,
'visibility': visibility,
};
}
}
Loading

0 comments on commit af1561b

Please sign in to comment.