feat(ground-suite): add theme selector

This commit is contained in:
Onur Özkan committed 2026-08-10 16:04:07 +03:00
1 parent eb6a343983
commit c67d553076
6 files changed
+66 -3

No files matched your search

+5 -3
View File
@@ -1,19 +1,21 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'app_shell.dart';
import 'theme.dart';
import 'theme_mode_controller.dart';
class GroundSuiteApp extends StatelessWidget {
class GroundSuiteApp extends ConsumerWidget {
const GroundSuiteApp({super.key});
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp(
title: 'Ground Suite',
debugShowCheckedModeBanner: false,
theme: groundSuiteLightTheme(),
darkTheme: groundSuiteDarkTheme(),
themeMode: ThemeMode.system,
themeMode: ref.watch(themeModeProvider),
home: const AppShell(),
);
}
+29
View File
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'theme_mode_controller.dart';
import '../features/diagnostics/presentation/diagnostics_page.dart';
import '../features/observability/presentation/observability_controller.dart';
import '../features/overview/presentation/overview_page.dart';
@@ -220,6 +221,7 @@ class _ConnectionBar extends StatelessWidget {
_StatusChip(label: state.status.label),
Text(peer),
Text(frameTime),
const _ThemeMenu(),
],
),
),
@@ -229,6 +231,27 @@ class _ConnectionBar extends StatelessWidget {
}
}
class _ThemeMenu extends ConsumerWidget {
const _ThemeMenu();
@override
Widget build(BuildContext context, WidgetRef ref) {
final mode = ref.watch(themeModeProvider);
return PopupMenuButton<ThemeMode>(
tooltip: 'Choose theme',
initialValue: mode,
onSelected: ref.read(themeModeProvider.notifier).select,
icon: Icon(_iconFor(mode)),
itemBuilder: (context) => const [
PopupMenuItem(value: ThemeMode.system, child: Text('System default')),
PopupMenuItem(value: ThemeMode.light, child: Text('Light')),
PopupMenuItem(value: ThemeMode.dark, child: Text('Dark')),
],
);
}
}
class _CriticalAnnouncement extends StatelessWidget {
const _CriticalAnnouncement({required this.message});
@@ -257,3 +280,9 @@ class _StatusChip extends StatelessWidget {
}
String _formatTimestamp(DateTime value) => value.toIso8601String();
IconData _iconFor(ThemeMode mode) => switch (mode) {
ThemeMode.system => Icons.brightness_auto_outlined,
ThemeMode.light => Icons.light_mode_outlined,
ThemeMode.dark => Icons.dark_mode_outlined,
};
@@ -0,0 +1,17 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final themeModeProvider = NotifierProvider<ThemeModeController, ThemeMode>(
ThemeModeController.new,
);
/// Holds the local display preference for the current application session.
///
/// It intentionally starts at the system preference. Persisting an operator's
/// visual preference can be added later without coupling it to vehicle state.
class ThemeModeController extends Notifier<ThemeMode> {
@override
ThemeMode build() => ThemeMode.system;
void select(ThemeMode mode) => state = mode;
}