Watch
1
0
Fork
You've already forked nexus
0
forked from Nexus/nexus

add support for creating rooms

Fixes #81
This commit is contained in:
Henry Hiles 2026-10-15 19:49:04 -04:00
commit ed84410039
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
13 changed files with 540 additions and 66 deletions

View file

@ -0,0 +1,149 @@
import "package:flutter_hooks/flutter_hooks.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:material_ui/material_ui.dart";
import "package:nexus/controllers/client_state.dart";
import "package:nexus/helpers/extensions/create_room.dart";
import "package:nexus/helpers/extensions/get_localpart.dart";
import "package:nexus/widgets/sheet_layout.dart";
class const CreateRoomSheet({super.key}) extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final serverName = ref
.watch(ClientStateController.provider)
?.userId
?.serverName;
final nameController = useTextEditingController();
final topicController = useTextEditingController();
final aliasController = useTextEditingController();
final name = useValueListenable(nameController).text.trim();
final isPublic = useState(false);
final isPublished = useState(false);
final isEncrypted = useState(false);
final isSpace = useState(false);
void submit() {
if (name.isEmpty) return;
final topic = topicController.text.trim();
final alias = aliasController.text.trim();
context.createRoom(
.new(
name: name,
topic: topic.isEmpty ? null : topic,
roomAliasName: isPublic.value && alias.isNotEmpty ? alias : null,
visibility: isPublic.value && isPublished.value ? .public : .private,
preset: isPublic.value ? .publicChat : .privateChat,
initialState: isEncrypted.value && !isSpace.value
? .new([.encryption])
: const .empty(),
creationContent: isSpace.value ? .new({"type": "m.space"}) : null,
),
name: name,
);
Navigator.of(context).pop();
}
AnimatedSize animated({
required bool visible,
required Widget child,
double gap = 12,
}) => AnimatedSize(
duration: Durations.medium2,
curve: Curves.easeInOut,
alignment: .topCenter,
child: visible
? Padding(
padding: .only(top: gap),
child: child,
)
: const SizedBox(width: .infinity),
);
return SheetLayout(
title: Text("Create a ${isSpace.value ? "Space" : "Room"}"),
actions: [
TextButton(
onPressed: Navigator.of(context).pop,
child: const Text("Cancel"),
),
TextButton(
onPressed: name.isEmpty ? null : submit,
child: const Text("Create"),
),
],
children: [
TextField(
controller: nameController,
autofocus: true,
textCapitalization: .sentences,
onSubmitted: (_) => submit(),
decoration: const .new(labelText: "Name"),
),
TextField(
controller: topicController,
textCapitalization: .sentences,
decoration: const .new(labelText: "Topic (optional)"),
),
Column(
children: [
SwitchListTile(
secondary: const Icon(Icons.public),
title: const Text("Public"),
subtitle: const Text("Anyone can join"),
value: isPublic.value,
onChanged: (value) {
isPublic.value = value;
if (value) isEncrypted.value = false;
},
),
animated(
visible: isPublic.value,
child: TextField(
controller: aliasController,
decoration: .new(
labelText: "Canonical alias (optional)",
prefixText: "# ",
suffixText: serverName == null ? null : ":$serverName",
hintText: "my-room",
),
),
),
animated(
visible: isPublic.value,
child: SwitchListTile(
secondary: const Icon(Icons.travel_explore),
title: const Text("Publish to room directory"),
subtitle: const Text("List it in your homeserver's directory"),
value: isPublished.value,
onChanged: (value) => isPublished.value = value,
),
),
],
),
Column(
children: [
SwitchListTile(
secondary: const Icon(Icons.workspaces),
title: const Text("Space"),
subtitle: const Text("A group of rooms"),
value: isSpace.value,
onChanged: (value) => isSpace.value = value,
),
animated(
visible: !isSpace.value,
child: SwitchListTile(
secondary: const Icon(Icons.lock),
title: const Text("Encrypted"),
subtitle: const Text("Can't be turned off later"),
value: isEncrypted.value,
onChanged: (value) => isEncrypted.value = value,
),
),
],
),
],
);
}
}