better handle when room is null

This commit is contained in:
Henry Hiles 2026-06-05 18:33:16 -04:00
commit 02b7892fb0
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
4 changed files with 42 additions and 37 deletions

View file

@ -14,18 +14,20 @@ import "package:nexus/models/relation_type.dart";
import "package:nexus/models/requests/send_message_request.dart"; import "package:nexus/models/requests/send_message_request.dart";
import "package:nexus/models/room.dart"; import "package:nexus/models/room.dart";
class RoomChatController extends AsyncNotifier<IList<Event>> { class RoomChatController extends AsyncNotifier<IList<Event>?> {
final String roomId; final String roomId;
RoomChatController(this.roomId); RoomChatController(this.roomId);
@override @override
Future<IList<Event>> build() async { Future<IList<Event>?> build() async {
final client = ref.watch(ClientController.provider.notifier); final client = ref.watch(ClientController.provider.notifier);
final room = ref.watch( final room = ref.watch(
RoomsController.provider.select((rooms) => rooms[roomId]), RoomsController.provider.select((rooms) => rooms[roomId]),
); );
if (!room!.hasFetchedState) { if (room == null) return null;
if (!room.hasFetchedState) {
final state = await client.getRoomState(.new(roomId: roomId)); final state = await client.getRoomState(.new(roomId: roomId));
await ref.read(RoomsController.provider.notifier).addState(roomId, state); await ref.read(RoomsController.provider.notifier).addState(roomId, state);
@ -214,7 +216,7 @@ class RoomChatController extends AsyncNotifier<IList<Event>> {
} }
static final provider = AsyncNotifierProvider.family static final provider = AsyncNotifierProvider.family
.autoDispose<RoomChatController, IList<Event>, String>( .autoDispose<RoomChatController, IList<Event>?, String>(
RoomChatController.new, RoomChatController.new,
); );
} }

View file

@ -1,4 +1,3 @@
import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:nexus/controllers/rooms_controller.dart"; import "package:nexus/controllers/rooms_controller.dart";
@ -93,13 +92,15 @@ class RoomAppbar extends ConsumerWidget implements PreferredSizeWidget {
), ),
), ),
), ),
leading: isDesktop && room != null leading: isDesktop
? AvatarOrHash( ? room == null
room.metadata?.avatar, ? null
room.metadata?.name ?? "Unnamed Room", : AvatarOrHash(
height: 24, room.metadata?.avatar,
fallback: Icon(Icons.numbers), room.metadata?.name ?? "Unnamed Room",
) height: 24,
fallback: Icon(Icons.numbers),
)
: DrawerButton(onPressed: () => onOpenDrawer(context)), : DrawerButton(onPressed: () => onOpenDrawer(context)),
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
title: room == null title: room == null
@ -123,19 +124,21 @@ class RoomAppbar extends ConsumerWidget implements PreferredSizeWidget {
), ),
], ],
), ),
actions: [ actions: room == null
IconButton( ? .new()
onPressed: null, : .new([
icon: Icon(Icons.push_pin), IconButton(
tooltip: "Open pinned messages", onPressed: null,
), icon: Icon(Icons.push_pin),
IconButton( tooltip: "Open pinned messages",
onPressed: () => onOpenMemberList?.call(context), ),
tooltip: "Open member list", IconButton(
icon: Icon(Icons.people), onPressed: () => onOpenMemberList?.call(context),
), tooltip: "Open member list",
if (room != null) RoomMenu(room), icon: Icon(Icons.people),
].toIList(), ),
RoomMenu(room),
]),
); );
} }
} }

View file

@ -50,6 +50,12 @@ class RoomChat extends HookConsumerWidget {
final userId = ref.watch(ClientStateController.provider)?.userId; final userId = ref.watch(ClientStateController.provider)?.userId;
final theme = Theme.of(context); final theme = Theme.of(context);
final nothing = Center(
child: Text(
"Nothing to see here...",
style: theme.textTheme.headlineMedium,
),
);
if (userId == null || this.roomId == null) { if (userId == null || this.roomId == null) {
return Scaffold( return Scaffold(
appBar: RoomAppbar( appBar: RoomAppbar(
@ -58,12 +64,7 @@ class RoomChat extends HookConsumerWidget {
onOpenDrawer: (_) => Scaffold.of(context).openDrawer(), onOpenDrawer: (_) => Scaffold.of(context).openDrawer(),
onOpenMemberList: null, onOpenMemberList: null,
), ),
body: Center( body: nothing,
child: Text(
"Nothing to see here...",
style: theme.textTheme.headlineMedium,
),
),
); );
} }
@ -81,7 +82,7 @@ class RoomChat extends HookConsumerWidget {
final topEventBeforeLoad = useState<String?>(null); final topEventBeforeLoad = useState<String?>(null);
Future<void> loadOlder() async { Future<void> loadOlder() async {
if (controllerData case AsyncData(:final value)) { if (controllerData case AsyncData(:final value?)) {
topEventBeforeLoad.value = value.firstOrNull?.eventId; topEventBeforeLoad.value = value.firstOrNull?.eventId;
await notifier.loadOlder(); await notifier.loadOlder();
} }
@ -105,7 +106,7 @@ class RoomChat extends HookConsumerWidget {
useEffect(() { useEffect(() {
if (controllerData case AsyncData( if (controllerData case AsyncData(
:final value, :final value?,
) when scrollController.hasClients) { ) when scrollController.hasClients) {
if (topEventBeforeLoad.value != null) { if (topEventBeforeLoad.value != null) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
@ -401,7 +402,7 @@ class RoomChat extends HookConsumerWidget {
child: Padding( child: Padding(
padding: .symmetric(horizontal: 12), padding: .symmetric(horizontal: 12),
child: switch (controllerData) { child: switch (controllerData) {
AsyncData(:final value) || AsyncData(:final value?) ||
AsyncLoading(:final value?) => CustomScrollView( AsyncLoading(:final value?) => CustomScrollView(
controller: scrollController, controller: scrollController,
slivers: [ slivers: [
@ -467,6 +468,7 @@ class RoomChat extends HookConsumerWidget {
), ),
], ],
), ),
AsyncData() => nothing,
AsyncLoading() => Loading(), AsyncLoading() => Loading(),
AsyncError(:final error, :final stackTrace) => AsyncError(:final error, :final stackTrace) =>
ErrorDialog(error, stackTrace), ErrorDialog(error, stackTrace),

View file

@ -39,9 +39,7 @@ class Sidebar extends HookConsumerWidget {
(room) => room.metadata?.id == selectedRoomId, (room) => room.metadata?.id == selectedRoomId,
); );
final selectedRoomIndex = indexOfSelectedRoom == -1 final selectedRoomIndex = indexOfSelectedRoom == -1
? selectedSpace.children.isEmpty ? null
? null
: 0
: indexOfSelectedRoom; : indexOfSelectedRoom;
return Drawer( return Drawer(