diff --git a/lib/controllers/selected_room.dart b/lib/controllers/selected_room.dart index f59232c..075fcdd 100644 --- a/lib/controllers/selected_room.dart +++ b/lib/controllers/selected_room.dart @@ -17,7 +17,9 @@ class SelectedRoomController extends Notifier { (space) => space?.allChildRooms .map((room) => room.metadata?.id) .nonNulls - .toIList(), + .toIList() + // Real spaces have a timeline of their own + .addAll([?space.room?.metadata?.id]), ), ); if (roomIds == null) return roomId; diff --git a/lib/helpers/extensions/room_destinations.dart b/lib/helpers/extensions/room_destinations.dart index 59bb3d2..3628d05 100644 --- a/lib/helpers/extensions/room_destinations.dart +++ b/lib/helpers/extensions/room_destinations.dart @@ -4,20 +4,28 @@ import "package:navigation_rail_m3e/navigation_rail_m3e.dart"; import "package:nexus/models/room.dart"; import "package:nexus/widgets/avatar_or_hash.dart"; +extension RoomDestination on Room { + NavigationRailM3EDestination toDestination({ + required bool isDm, + String? label, + Widget? icon, + }) => NavigationRailM3EDestination( + label: label ?? metadata?.name ?? "Unnamed Room", + badgeCount: switch (metadata?.unreadNotifications) { + 0 || null => metadata?.unreadMessages == 0 ? null : 0, + int unread => unread, + }, + icon: + icon ?? + AvatarOrHash( + metadata?.avatar, + metadata?.name ?? "Unnamed Room", + fallback: isDm ? null : const Icon(Icons.numbers), + ), + ); +} + extension RoomDestinations on IList { List toDestinations({required bool isDm}) => - map( - (room) => NavigationRailM3EDestination( - label: room.metadata?.name ?? "Unnamed Room", - badgeCount: switch (room.metadata?.unreadNotifications) { - 0 || null => room.metadata?.unreadMessages == 0 ? null : 0, - int unread => unread, - }, - icon: AvatarOrHash( - room.metadata?.avatar, - room.metadata?.name ?? "Unnamed Room", - fallback: isDm ? null : const Icon(Icons.numbers), - ), - ), - ).toList(); + map((room) => room.toDestination(isDm: isDm)).toList(); } diff --git a/lib/widgets/room_list.dart b/lib/widgets/room_list.dart index f8d366e..c43d103 100644 --- a/lib/widgets/room_list.dart +++ b/lib/widgets/room_list.dart @@ -1,5 +1,6 @@ import "dart:math"; +import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:material_ui/material_ui.dart"; import "package:m3e_design/m3e_design.dart"; @@ -222,6 +223,9 @@ class const RoomsPane({super.key}) extends ConsumerWidget { final selectedSpace = ref.watch(SelectedSpaceController.provider)!; final isDm = selectedSpace.id == "dms"; final spaceMetadata = selectedSpace.room?.metadata; + // In the order the rail shows them, with the space's own timeline first + final destinationIds = IList([?spaceMetadata?.id]) + .addAll(selectedSpace.allChildRooms.map((room) => room.metadata?.id)); return Scaffold( backgroundColor: Colors.transparent, @@ -287,13 +291,19 @@ class const RoomsPane({super.key}) extends ConsumerWidget { scrollable: true, background: Colors.transparent, type: .alwaysExpand, - selectedIndex: max( - 0, - selectedSpace.allChildRooms.indexWhere( - (room) => room.metadata?.id == selectedRoomId, - ), - ), + selectedIndex: max(0, destinationIds.indexOf(selectedRoomId)), sections: [ + if (selectedSpace.room case final room? + when spaceMetadata != null) + .new( + destinations: [ + room.toDestination( + isDm: isDm, + label: "Space timeline", + icon: const Icon(Icons.forum), + ), + ], + ), .new( header: selectedSpace.room == null ? null @@ -339,7 +349,7 @@ class const RoomsPane({super.key}) extends ConsumerWidget { KeyController.provider(KeyController.roomKey) .notifier, ) - .set(selectedSpace.allChildRooms[value].metadata?.id); + .set(destinationIds[value]); if (Navigator.of(context).canPop()) { Navigator.of(context).pop(); }