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/room.dart";
class RoomChatController extends AsyncNotifier<IList<Event>> {
class RoomChatController extends AsyncNotifier<IList<Event>?> {
final String roomId;
RoomChatController(this.roomId);
@override
Future<IList<Event>> build() async {
Future<IList<Event>?> build() async {
final client = ref.watch(ClientController.provider.notifier);
final room = ref.watch(
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));
await ref.read(RoomsController.provider.notifier).addState(roomId, state);
@ -214,7 +216,7 @@ class RoomChatController extends AsyncNotifier<IList<Event>> {
}
static final provider = AsyncNotifierProvider.family
.autoDispose<RoomChatController, IList<Event>, String>(
.autoDispose<RoomChatController, IList<Event>?, String>(
RoomChatController.new,
);
}

View file

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

View file

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

View file

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