- Decentralized Room Registry pattern - Each room registers itself with central registry - Dynamic navigation tabs and settings dropdown - New Media Room and Parlor feature folders - Permission-based room filtering support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
114 lines
3.1 KiB
Dart
114 lines
3.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
/// Defines a room in the application.
|
|
///
|
|
/// Each feature/room registers itself with metadata for navigation,
|
|
/// routing, and permission-based access control.
|
|
class RoomDefinition {
|
|
const RoomDefinition({
|
|
required this.id,
|
|
required this.label,
|
|
required this.icon,
|
|
required this.selectedIcon,
|
|
required this.defaultRoute,
|
|
required this.routes,
|
|
this.requiredPermissions = const [],
|
|
});
|
|
|
|
/// Unique identifier used in preferences (e.g., 'front-hall', 'control-room').
|
|
final String id;
|
|
|
|
/// Display label for UI.
|
|
final String label;
|
|
|
|
/// Icon when not selected.
|
|
final IconData icon;
|
|
|
|
/// Icon when selected.
|
|
final IconData selectedIcon;
|
|
|
|
/// Default route path when room is selected.
|
|
final String defaultRoute;
|
|
|
|
/// All routes this room provides to go_router.
|
|
final List<RouteBase> Function() routes;
|
|
|
|
/// Permissions required to access this room (empty = accessible to all).
|
|
/// User must have ALL listed permissions.
|
|
final List<String> requiredPermissions;
|
|
}
|
|
|
|
/// Central registry of all rooms in the application.
|
|
///
|
|
/// Each room's router.dart file registers itself here.
|
|
/// UI components query this registry to build navigation.
|
|
class RoomRegistry {
|
|
RoomRegistry._();
|
|
|
|
static final RoomRegistry instance = RoomRegistry._();
|
|
|
|
final List<RoomDefinition> _rooms = [];
|
|
|
|
/// Register a room. Called by each room's router.dart.
|
|
void register(RoomDefinition room) {
|
|
// Avoid duplicate registration
|
|
if (!_rooms.any((r) => r.id == room.id)) {
|
|
_rooms.add(room);
|
|
}
|
|
}
|
|
|
|
/// Get all registered rooms.
|
|
List<RoomDefinition> get all => List.unmodifiable(_rooms);
|
|
|
|
/// Get rooms filtered by user permissions.
|
|
///
|
|
/// [userPermissions] is the set of permissions the user has.
|
|
/// Returns rooms where the user has ALL required permissions.
|
|
List<RoomDefinition> accessibleTo(Set<String> userPermissions) {
|
|
return _rooms.where((room) {
|
|
if (room.requiredPermissions.isEmpty) return true;
|
|
return room.requiredPermissions.every(userPermissions.contains);
|
|
}).toList();
|
|
}
|
|
|
|
/// Get a room by its ID.
|
|
RoomDefinition? byId(String id) {
|
|
try {
|
|
return _rooms.firstWhere((r) => r.id == id);
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Get the index of a room by its ID.
|
|
int indexOfId(String id) {
|
|
return _rooms.indexWhere((r) => r.id == id);
|
|
}
|
|
|
|
/// Get the index of a room by route path.
|
|
int indexOfRoute(String path) {
|
|
// Find room whose defaultRoute matches or whose routes start with path
|
|
for (var i = 0; i < _rooms.length; i++) {
|
|
final room = _rooms[i];
|
|
if (path == room.defaultRoute || path.startsWith('/${room.id}')) {
|
|
return i;
|
|
}
|
|
}
|
|
return 0; // Default to first room
|
|
}
|
|
|
|
/// Get all routes from all registered rooms.
|
|
List<RouteBase> allRoutes() {
|
|
return _rooms.expand((room) => room.routes()).toList();
|
|
}
|
|
|
|
/// Clear registry (useful for testing).
|
|
void clear() {
|
|
_rooms.clear();
|
|
}
|
|
}
|
|
|
|
/// Global registry instance.
|
|
final roomRegistry = RoomRegistry.instance;
|