Add room preview dialog

Closes #79
This commit is contained in:
Henry Hiles 2026-09-29 13:55:17 -04:00
commit 281bab0202
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
9 changed files with 230 additions and 204 deletions

View file

@ -1,16 +1,111 @@
import "package:collection/collection.dart";
import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:material_ui/material_ui.dart";
import "package:flutter_hooks/flutter_hooks.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:nexus/controllers/client.dart";
import "package:nexus/controllers/key.dart";
import "package:nexus/controllers/spaces.dart";
import "package:nexus/controllers/room_summary.dart";
import "package:nexus/helpers/extensions/better_when.dart";
import "package:nexus/helpers/extensions/focus_room.dart";
import "package:nexus/helpers/extensions/link_to_mention.dart";
import "package:nexus/widgets/room_summary_dialog.dart";
import "package:nexus/main.dart";
class const JoinDialog(final WidgetRef ref, {super.key}) extends HookWidget {
@override
Widget build(BuildContext context) {
final roomAlias = useTextEditingController();
Future<void> onJoin() async {
Navigator.of(context).pop();
final roomIdOrAlias = roomAlias.text.mention ?? roomAlias.text;
final IList<String> via = .new(
Uri.tryParse(roomAlias.text.replaceAll("/#", ""))
?.queryParametersAll["via"] ??
[],
);
showDialog(
context: context,
builder: (context) => ref
.watch(
RoomSummaryController.provider(
.new(roomIdOrAlias: roomIdOrAlias, via: via),
),
)
.betterWhen(
data: (summary) => RoomSummaryDialog(
summary,
extraActions: .new([
TextButton(
onPressed: () async {
// Capture everything before the dialog closes.
final container = ProviderScope.containerOf(context);
final scaffoldMessenger = ScaffoldMessenger.of(context);
final colors = Theme.of(context).colorScheme;
Navigator.of(context).pop();
final snackbar = scaffoldMessenger.showSnackBar(
.new(
content: Text("Joining room $roomIdOrAlias."),
duration: Duration(days: 999),
),
);
try {
final id = await container
.read(ClientController.provider.notifier)
.joinRoom(
.new(roomIdOrAlias: roomIdOrAlias, via: via),
);
snackbar.close();
scaffoldMessenger.showSnackBar(
.new(
content: Text(
"Room $roomIdOrAlias successfully joined.",
),
action: .new(
label: "Open",
onPressed: () =>
container.focusRoom(id).onError(showError),
),
),
);
} catch (error) {
snackbar.close();
scaffoldMessenger.showSnackBar(
.new(
backgroundColor: colors.errorContainer,
content: Text(
error.toString(),
style: .new(color: colors.onErrorContainer),
),
),
);
}
},
child: Text("Join"),
),
]),
),
loading: () => Dialog(
child: Row(
mainAxisAlignment: .center,
mainAxisSize: .min,
children: [
Padding(
padding: .all(24),
child: CircularProgressIndicator(),
),
],
),
),
),
);
}
return AlertDialog(
title: Text("Join a Room"),
content: Column(
@ -21,111 +116,14 @@ class const JoinDialog(final WidgetRef ref, {super.key}) extends HookWidget {
SizedBox(height: 12),
TextField(
controller: roomAlias,
decoration: .new(hintText: "#room:server"),
decoration: .new(hintText: "#room:server.name"),
onEditingComplete: onJoin,
),
],
),
actions: [
TextButton(onPressed: Navigator.of(context).pop, child: Text("Cancel")),
TextButton(
onPressed: () async {
Navigator.of(context).pop();
if (context.mounted) {
final roomIdOrAlias = roomAlias.text.mention ?? roomAlias.text;
final scaffoldMessenger = ScaffoldMessenger.of(context);
final snackbar = scaffoldMessenger.showSnackBar(
.new(
content: Text("Joining room $roomIdOrAlias."),
duration: Duration(days: 999),
),
);
try {
final id = await ref
.watch(ClientController.provider.notifier)
.joinRoom(
.new(
roomIdOrAlias: roomIdOrAlias,
via: .new(
Uri.tryParse(roomAlias.text.replaceAll("/#", ""))
?.queryParametersAll["via"] ??
[],
),
),
);
snackbar.close();
scaffoldMessenger.showSnackBar(
.new(
content: Text("Room $roomIdOrAlias successfully joined."),
action: .new(
label: "Open",
onPressed: () async {
final spaces = ref.watch(SpacesController.provider);
final space = spaces.firstWhereOrNull(
(space) => space.id == id,
);
await ref
.watch(
KeyController.provider(KeyController.spaceKey)
.notifier,
)
.set(
space?.id ??
spaces
.firstWhere(
(space) =>
space.children.any(
(child) =>
child.metadata?.id == id,
) ||
space.subSpaces.any(
(child) =>
child.room.metadata?.id == id,
),
)
.id,
);
if (space == null) {
await ref
.watch(
KeyController.provider(KeyController.roomKey)
.notifier,
)
.set(id);
}
},
),
),
);
} catch (error) {
snackbar.close();
if (context.mounted) {
scaffoldMessenger.showSnackBar(
.new(
backgroundColor: Theme.of(context)
.colorScheme
.errorContainer,
content: Text(
error.toString(),
style: .new(
color: Theme.of(context).colorScheme.onErrorContainer,
),
),
),
);
}
}
}
},
child: Text("Join"),
),
TextButton(onPressed: onJoin, child: Text("Join")),
],
);
}