diff --git a/lib/src/data/settings.dart b/lib/src/data/settings.dart index da32c6488c..7771b3795f 100644 --- a/lib/src/data/settings.dart +++ b/lib/src/data/settings.dart @@ -1,3 +1,5 @@ +import "package:flutter/material.dart"; + import "socket.dart"; /// A collection of functions for parsing [Settings]. @@ -197,6 +199,16 @@ enum SplitMode { const SplitMode(this.humanName); } +/// Helpful methods on [ThemeMode]s. +extension ThemeModeUtils on ThemeMode { + /// A human-friendly name for this mode. + String get humanName => switch (this) { + ThemeMode.system => "Match system", + ThemeMode.light => "Light theme", + ThemeMode.dark => "Dark theme", + }; +} + /// Settings related to the dashboard itself, not the rover. class DashboardSettings { /// How the Dashboard should split when only two views are present. @@ -215,24 +227,30 @@ class DashboardSettings { /// This does not affect how many frames are sent by the rover per second. final int maxFps; + /// The theme of the Dashboard. + final ThemeMode themeMode; + /// A const constructor. const DashboardSettings({ required this.splitMode, required this.mapBlockSize, required this.maxFps, + required this.themeMode, }); /// Parses Dashboard settings from JSON. DashboardSettings.fromJson(Json? json) : splitMode = SplitMode.values[json?["splitMode"] ?? SplitMode.horizontal.index], mapBlockSize = json?["mapBlockSize"] ?? 1.0, - maxFps = (json?["maxFps"] ?? 60) as int; + maxFps = (json?["maxFps"] ?? 60) as int, + themeMode = ThemeMode.values.byName(json?["theme"] ?? ThemeMode.system.name); /// Serializes these settings to JSON. Json toJson() => { "splitMode": splitMode.index, "mapBlockSize": mapBlockSize, "maxFps": maxFps, + "theme": themeMode.name, }; } diff --git a/lib/src/models/view/builders/settings_builder.dart b/lib/src/models/view/builders/settings_builder.dart index 46ea2b98c3..91e451cab5 100644 --- a/lib/src/models/view/builders/settings_builder.dart +++ b/lib/src/models/view/builders/settings_builder.dart @@ -1,3 +1,4 @@ +import "package:flutter/material.dart"; import "package:rover_dashboard/data.dart"; import "package:rover_dashboard/models.dart"; @@ -181,11 +182,15 @@ class DashboardSettingsBuilder extends ValueBuilder { /// How the Dashboard should split when only two views are present. SplitMode splitMode; + /// The theme of the Dashboard. See [DashboardSettings.themeMode]. + ThemeMode themeMode; + /// Modifies the given [DashboardSettings]. DashboardSettingsBuilder(DashboardSettings initial) : fps = NumberBuilder(initial.maxFps), blockSize = NumberBuilder(initial.mapBlockSize), - splitMode = initial.splitMode; + splitMode = initial.splitMode, + themeMode = initial.themeMode; @override bool get isValid => fps.isValid && blockSize.isValid; @@ -195,6 +200,7 @@ class DashboardSettingsBuilder extends ValueBuilder { maxFps: fps.value, mapBlockSize: blockSize.value, splitMode: splitMode, + themeMode: themeMode, ); /// Updates the [splitMode] when a new one is selected. @@ -203,6 +209,13 @@ class DashboardSettingsBuilder extends ValueBuilder { splitMode = mode; notifyListeners(); } + + /// Updates the [themeMode]. + void updateThemeMode(ThemeMode? input) { + if (input == null) return; + themeMode = input; + notifyListeners(); + } } /// A [ValueBuilder] that modifies an [EasterEggsSettings]. diff --git a/lib/src/pages/settings.dart b/lib/src/pages/settings.dart index a97f55e3eb..b57202a1d6 100644 --- a/lib/src/pages/settings.dart +++ b/lib/src/pages/settings.dart @@ -142,6 +142,25 @@ class SettingsPage extends ReactiveWidget { ], ), ],), + Row(children: [ + const SizedBox( + width: 200, + child: ListTile( + title: Text("Theme mode"), + ), + ), + const Spacer(), + DropdownMenu( + initialSelection: model.dashboard.themeMode, + onSelected: model.dashboard.updateThemeMode, + dropdownMenuEntries: [ + for (final value in ThemeMode.values) DropdownMenuEntry( + value: value, + label: value.humanName, + ), + ], + ), + ],), ], ), const Divider(),