Add a setting (off by default) for showing all rooms in home

Fixes #107

@LogN review
This commit is contained in:
Henry Hiles 2026-10-03 01:15:11 -04:00
commit 3875c3a14a
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
5 changed files with 52 additions and 9 deletions

View file

@ -93,6 +93,23 @@ class SettingsSectionsController
: null, : null,
), ),
), ),
.new(
title: "All Rooms In Home",
description: "Show all rooms in home, instead of just ones that aren't in spaces",
icon: Icons.home,
builder: (title, description, icon) => SwitchListTile(
title: Text(title),
subtitle: Text(description),
secondary: Icon(icon),
value: settings.showAllInHome,
onChanged: Platform.isLinux
? (value) => ref
.watch(SettingsController.provider.notifier)
.set(settings.copyWith(showAllInHome: value))
.onError(showError)
: null,
),
),
]), ]),
), ),
]), ]),

View file

@ -4,15 +4,16 @@ import "package:material_ui/material_ui.dart";
import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/account_data.dart"; import "package:nexus/controllers/account_data.dart";
import "package:nexus/controllers/rooms.dart"; import "package:nexus/controllers/rooms.dart";
import "package:nexus/controllers/settings.dart";
import "package:nexus/controllers/top_level_spaces.dart"; import "package:nexus/controllers/top_level_spaces.dart";
import "package:nexus/controllers/space_edges.dart"; import "package:nexus/controllers/space_edges.dart";
import "package:nexus/models/room.dart"; import "package:nexus/models/room.dart";
import "package:nexus/models/space.dart"; import "package:nexus/models/space.dart";
import "package:nexus/models/subspace.dart"; import "package:nexus/models/subspace.dart";
class SpacesController extends Notifier<IList<Space>> { class SpacesController extends AsyncNotifier<IList<Space>> {
@override @override
IList<Space> build() { Future<IList<Space>> build() async {
final rooms = ref.watch(RoomsController.provider); final rooms = ref.watch(RoomsController.provider);
final topLevelSpaceIds = ref.watch(TopLevelSpacesController.provider); final topLevelSpaceIds = ref.watch(TopLevelSpacesController.provider);
final spaceEdges = ref.watch(SpaceEdgesController.provider); final spaceEdges = ref.watch(SpaceEdgesController.provider);
@ -77,10 +78,10 @@ class SpacesController extends Notifier<IList<Space>> {
final spaces = topLevelSpaceIds.map(buildSpace).toIList(); final spaces = topLevelSpaceIds.map(buildSpace).toIList();
final usedRoomIds = { final usedRooms = {
for (final space in spaces) ...[ for (final space in spaces) ...[
...space.children.map((r) => r.metadata?.id), ...space.children,
...space.subSpaces.expand((s) => s.children.map((r) => r.metadata?.id)), ...space.subSpaces.expand((s) => s.children),
], ],
}.nonNulls.toISet(); }.nonNulls.toISet();
@ -89,7 +90,9 @@ class SpacesController extends Notifier<IList<Space>> {
final otherRooms = rooms.entries final otherRooms = rooms.entries
.where( .where(
(e) => (e) =>
!usedRoomIds.contains(e.key) && !usedRooms
.map((element) => element.metadata?.id)
.contains(e.key) &&
!topLevelSpaceIds.contains(e.key) && !topLevelSpaceIds.contains(e.key) &&
!childrenById.containsKey(e.key), !childrenById.containsKey(e.key),
) )
@ -97,6 +100,15 @@ class SpacesController extends Notifier<IList<Space>> {
.toIList(); .toIList();
final homeRooms = otherRooms final homeRooms = otherRooms
.addAll(
await ref.watch(
SettingsController.provider.selectAsync(
(data) => data.showAllInHome,
),
)
? usedRooms
: .empty(),
)
.where((r) => !directMessages.contains(r.metadata?.id)) .where((r) => !directMessages.contains(r.metadata?.id))
.toIList(); .toIList();
@ -143,7 +155,7 @@ class SpacesController extends Notifier<IList<Space>> {
.toIList(); .toIList();
} }
static final provider = NotifierProvider<SpacesController, IList<Space>>( static final provider = AsyncNotifierProvider<SpacesController, IList<Space>>(
SpacesController.new, SpacesController.new,
); );
} }

View file

@ -7,7 +7,7 @@ import "package:nexus/models/space.dart";
extension FocusRoom on MutationTarget { extension FocusRoom on MutationTarget {
Future<bool> focusRoom(String roomId, [int? eventRowId]) async { Future<bool> focusRoom(String roomId, [int? eventRowId]) async {
final spaces = container.read(SpacesController.provider); final spaces = await container.read(SpacesController.provider.future);
if (spaces.firstWhereOrNull((space) => space.id == roomId) case Space _?) { if (spaces.firstWhereOrNull((space) => space.id == roomId) case Space _?) {
await container await container

View file

@ -10,6 +10,7 @@ class const Settings({
final ThemeMode theme = ThemeMode.system, final ThemeMode theme = ThemeMode.system,
final bool useDynamicTheming = true, final bool useDynamicTheming = true,
final bool linuxMobileMode = false, final bool linuxMobileMode = false,
final bool showAllInHome = false,
}) with _$Settings { }) with _$Settings {
Map<String, Object?> toJson() => _$SettingsToJson(this); Map<String, Object?> toJson() => _$SettingsToJson(this);

View file

@ -4,6 +4,7 @@ import "package:navigation_rail_m3e/navigation_rail_m3e.dart";
import "package:nexus/models/nav_page.dart"; import "package:nexus/models/nav_page.dart";
import "package:nexus/widgets/avatar_or_hash.dart"; import "package:nexus/widgets/avatar_or_hash.dart";
import "package:nexus/widgets/divider_widget.dart"; import "package:nexus/widgets/divider_widget.dart";
import "package:nexus/widgets/error_dialog.dart";
import "package:nexus/widgets/pages/settings.dart"; import "package:nexus/widgets/pages/settings.dart";
import "package:nexus/widgets/join_dialog.dart"; import "package:nexus/widgets/join_dialog.dart";
import "package:nexus/widgets/room_menu.dart"; import "package:nexus/widgets/room_menu.dart";
@ -43,10 +44,22 @@ class const RoomList({super.key})
final selectedRoomId = ref.watch(selectedRoomController).requireValue; final selectedRoomId = ref.watch(selectedRoomController).requireValue;
final selectedRoomIdNotifier = ref.watch(selectedRoomController.notifier); final selectedRoomIdNotifier = ref.watch(selectedRoomController.notifier);
final spaces = ref.watch(SpacesController.provider); final spacesAsync = ref.watch(SpacesController.provider);
final spaces = spacesAsync.value;
if (spaces == null) {
return switch (spacesAsync) {
AsyncError(:final error, :final stackTrace) => ErrorDialog(
error,
stackTrace,
),
_ => const Center(child: CircularProgressIndicator()),
};
}
final indexOfSelected = spaces.indexWhere( final indexOfSelected = spaces.indexWhere(
(space) => space.id == selectedSpaceId, (space) => space.id == selectedSpaceId,
); );
final selectedIndex = indexOfSelected == -1 ? 0 : indexOfSelected; final selectedIndex = indexOfSelected == -1 ? 0 : indexOfSelected;
final selectedSpace = final selectedSpace =