allow users to set room's searchability and public/private status seperatly, ensure public/private status determines which rooms show in space hierarchy (#1090)

This commit is contained in:
ggurdin 2024-11-21 16:10:33 -05:00 committed by GitHub
parent 7c5c28162e
commit 561359008c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 138 additions and 43 deletions

View file

@ -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"
}

View file

@ -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<ChatDetails> {
void hoverEditNameIcon(bool hovering) =>
setState(() => showEditNameIcon = !showEditNameIcon);
Future<void> setVisibility(matrix.Visibility visibility) async {
Future<void> 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<void> toggleMute() async {

View file

@ -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),

View file

@ -386,18 +386,27 @@ class _SpaceViewState extends State<SpaceView> {
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<SpaceView> {
// ]
// : null,
groupName: response.roomName,
preset: CreateRoomPreset.publicChat,
preset: response.joinRules == sdk.JoinRules.public
? CreateRoomPreset.publicChat
: CreateRoomPreset.privateChat,
visibility: response.visibility,
initialState: response.roomDescription.isNotEmpty
? [

View file

@ -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

View file

@ -28,6 +28,9 @@ class NewSpaceController extends State<NewSpace> {
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<NewSpace> {
});
}
// #Pangea
void setSpaceCanBeFound(bool b) => setState(() => spaceCanBeFound = b);
// Pangea#
void setPublicGroup(bool b) => setState(() => publicGroup = b);
// #Pangea
List<StateEvent> initialState(String joinCode) {
List<StateEvent> initialState(String joinCode, bool publicGroup) {
return [
StateEvent(
type: EventTypes.RoomPowerLevels,
@ -70,8 +77,9 @@ class NewSpaceController extends State<NewSpace> {
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<NewSpace> {
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<NewSpace> {
powerLevelContentOverride: {'events_default': 100},
initialState: [
// #Pangea
...initialState(joinCode),
...initialState(joinCode, publicGroup),
// Pangea#
if (avatar != null)
sdk.StateEvent(

View file

@ -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(

View file

@ -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),

View file

@ -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<AddRoomDialog> {
TextEditingController();
matrix.Visibility visibility = matrix.Visibility.public;
JoinRules joinRules = JoinRules.public;
Future<void> setVisibility(matrix.Visibility newVisibility) async {
Future<void> _setJoinRules(JoinRules newJoinRules) async {
setState(() => joinRules = newJoinRules);
}
Future<void> _setVisibility(matrix.Visibility newVisibility) async {
setState(() => visibility = newVisibility);
}
@ -93,9 +99,11 @@ class AddRoomDialogState extends State<AddRoomDialog> {
),
),
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<AddRoomDialog> {
RoomResponse(
roomName: _roomNameController.text,
roomDescription: _roomDescriptionController.text,
joinRules: joinRules,
visibility: visibility,
),
);
@ -138,11 +147,13 @@ class AddRoomDialogState extends State<AddRoomDialog> {
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,
};
}

View file

@ -9,26 +9,35 @@ class VisibilityToggle extends StatelessWidget {
final Room? room;
final Color? iconColor;
final Future<void> Function(matrix.Visibility) setVisibility;
final Future<void> 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,
),
);
},
),
);
},
],
);
}
}