Split Settings into model, serializer, paths and store

698 lines did all of it at once. The mutable CaptureFromUi callback becomes an
ISettingsCapture the settings view implements.
This commit is contained in:
maj00r
2026-09-04 21:13:06 +02:00
parent 8e5fe01104
commit 3c502f630d
30 changed files with 1371 additions and 779 deletions

View File

@@ -4,7 +4,7 @@ using Avalonia.Controls.Primitives;
using Avalonia.Layout;
using Avalonia.Media;
using StarterNG.Infrastructure;
using SettingsModel = StarterNG.Classes.Settings;
using StarterNG.Application;
namespace StarterNG.Views;
@@ -156,7 +156,7 @@ public sealed class AdvancedSettingsWindow : Window
private void Load()
{
var s = SettingsModel.Instance;
var s = AppServices.Current.Settings;
_compressTex.IsChecked = s.CompressTextures;
_mipmaps.IsChecked = s.ScreenMipmaps;
_scaleSpeculars.IsChecked = s.ScaleSpeculars;
@@ -172,7 +172,7 @@ public sealed class AdvancedSettingsWindow : Window
private void Store()
{
var s = SettingsModel.Instance;
var s = AppServices.Current.Settings;
s.CompressTextures = _compressTex.IsChecked == true;
s.ScreenMipmaps = _mipmaps.IsChecked == true;
s.ScaleSpeculars = _scaleSpeculars.IsChecked == true;

View File

@@ -91,7 +91,7 @@ public partial class Depot : UserControl
Dispatcher.UIThread.Post(() =>
{
hideArchivalCheck.IsChecked = StarterNG.Classes.Settings.Instance.HideArchivalVehicles;
hideArchivalCheck.IsChecked = AppServices.Current.Settings.HideArchivalVehicles;
_browser.InitClassComboTemplates();
_browser.PopulateCategoryCombo();
PopulateSceneryConsists();
@@ -232,8 +232,8 @@ public partial class Depot : UserControl
private void ConsistFilter_OnChanged(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (_suppress) return;
StarterNG.Classes.Settings.Instance.ShowAiVehicles = depotShowAiCheck.IsChecked == true;
StarterNG.Classes.Settings.Instance.DrivableOnly = depotDrivableOnlyCheck.IsChecked == true;
AppServices.Current.Settings.ShowAiVehicles = depotShowAiCheck.IsChecked == true;
AppServices.Current.Settings.DrivableOnly = depotDrivableOnlyCheck.IsChecked == true;
PopulateSceneryConsists();
}
@@ -242,8 +242,8 @@ public partial class Depot : UserControl
_suppress = true;
sceneryConsistList.Items.Clear();
depotShowAiCheck.IsChecked = StarterNG.Classes.Settings.Instance.ShowAiVehicles;
depotDrivableOnlyCheck.IsChecked = StarterNG.Classes.Settings.Instance.DrivableOnly;
depotShowAiCheck.IsChecked = AppServices.Current.Settings.ShowAiVehicles;
depotDrivableOnlyCheck.IsChecked = AppServices.Current.Settings.DrivableOnly;
_listScenery = AppServices.Current.State.CurrentScenery ?? _sceneries.FirstOrDefault();
sceneryConsistsTab.Header = App.Loc["SceneryConsists"];
@@ -252,8 +252,8 @@ public partial class Depot : UserControl
if (_listScenery != null)
{
bool showAi = StarterNG.Classes.Settings.Instance.ShowAiVehicles;
bool drivableOnly = StarterNG.Classes.Settings.Instance.DrivableOnly;
bool showAi = AppServices.Current.Settings.ShowAiVehicles;
bool drivableOnly = AppServices.Current.Settings.DrivableOnly;
foreach (var trainset in _listScenery.Trainsets)
{

View File

@@ -16,6 +16,7 @@ using StarterNG.Classes;
using StarterNG.Domain;
using StarterNG.Domain.Sceneries;
using StarterNG.Domain.Vehicles;
using StarterNG.Application;
namespace StarterNG.Views;
@@ -35,7 +36,7 @@ public sealed class VehicleBrowser
public void SyncHideArchival()
{
bool hideArchival = Classes.Settings.Instance.HideArchivalVehicles;
bool hideArchival = AppServices.Current.Settings.HideArchivalVehicles;
if (hideArchivalCheck.IsChecked == hideArchival)
return;
@@ -246,7 +247,7 @@ public sealed class VehicleBrowser
_db.Textures
.Where(t => category == null || category(VehicleInfo.CategoryOf(t)))
.Where(t => !_db.IsSetFollower(t))
.Where(t => !StarterNG.Classes.Settings.Instance.HideArchivalVehicles || !t.ResolvedArchived)
.Where(t => !AppServices.Current.Settings.HideArchivalVehicles || !t.ResolvedArchived)
.Select(VehicleInfo.ClassOf)
.Where(s => !string.IsNullOrEmpty(s))
.Distinct(StringComparer.OrdinalIgnoreCase)
@@ -469,7 +470,7 @@ public sealed class VehicleBrowser
if (_db.IsSetFollower(t))
return false;
if (StarterNG.Classes.Settings.Instance.HideArchivalVehicles && t.ResolvedArchived)
if (AppServices.Current.Settings.HideArchivalVehicles && t.ResolvedArchived)
return false;
if (hasSearch && !Matches(t, search))
@@ -515,8 +516,8 @@ public sealed class VehicleBrowser
public void HideArchivalCheck_OnChanged(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (_suppress) return;
StarterNG.Classes.Settings.Instance.HideArchivalVehicles = hideArchivalCheck.IsChecked ?? true;
StarterNG.Classes.Settings.Instance.Save();
AppServices.Current.Settings.HideArchivalVehicles = hideArchivalCheck.IsChecked ?? true;
AppServices.Current.SettingsStore.Save();
Rebuild();
}

View File

@@ -1,4 +1,5 @@
using Avalonia.Media;
using StarterNG.Application;
namespace StarterNG.Views;
@@ -14,5 +15,5 @@ public static class VehicleCardStyle
public static readonly IBrush Placeholder = new SolidColorBrush(Color.Parse("#22808080"));
public static int ThumbHeight =>
Classes.Settings.Instance.LargeThumbnails ? 68 : 34;
AppServices.Current.Settings.LargeThumbnails ? 68 : 34;
}

View File

@@ -41,7 +41,7 @@ public partial class Scenarios : UserControl
Sceneries = AppServices.Current.Library.Sceneries;
_loadingFilters = true;
archivalSwitch.IsChecked = !StarterNG.Classes.Settings.Instance.ShowArchivalSceneries;
archivalSwitch.IsChecked = !AppServices.Current.Settings.ShowArchivalSceneries;
_loadingFilters = false;
BuildSceneryTree();
@@ -75,7 +75,7 @@ public partial class Scenarios : UserControl
if (scenery.Archival && !showArchival)
continue;
bool expand = StarterNG.Classes.Settings.Instance.AutoExpandSceneryTree;
bool expand = AppServices.Current.Settings.AutoExpandSceneryTree;
AppServices.Current.SceneryTexts.LoadFor(scenery, App.Loc.CurrentLangCode);
string label = scenery.DisplayName;
@@ -123,7 +123,7 @@ public partial class Scenarios : UserControl
private void RestoreLastScenery()
{
string last = StarterNG.Classes.Settings.Instance.LastScenery;
string last = AppServices.Current.Settings.LastScenery;
string want = Path.GetFileNameWithoutExtension(last);
TreeViewItem? MatchLeaf(TreeViewItem node)
@@ -193,10 +193,10 @@ public partial class Scenarios : UserControl
{
string name = scenery.DisplayName;
if (string.Equals(StarterNG.Classes.Settings.Instance.LastScenery, name, StringComparison.OrdinalIgnoreCase))
if (string.Equals(AppServices.Current.Settings.LastScenery, name, StringComparison.OrdinalIgnoreCase))
return;
StarterNG.Classes.Settings.Instance.LastScenery = name;
StarterNG.Classes.Settings.Instance.Save();
AppServices.Current.Settings.LastScenery = name;
AppServices.Current.SettingsStore.Save();
}
private static string TrainsetListLabel(Trainset trainset) =>
@@ -215,8 +215,8 @@ public partial class Scenarios : UserControl
{
vehicleList.Items.Clear();
bool showAi = StarterNG.Classes.Settings.Instance.ShowAiVehicles;
bool drivableOnly = StarterNG.Classes.Settings.Instance.DrivableOnly;
bool showAi = AppServices.Current.Settings.ShowAiVehicles;
bool drivableOnly = AppServices.Current.Settings.DrivableOnly;
for (int i = 0; i < scn.Trainsets.Count; i++)
{
@@ -250,8 +250,8 @@ public partial class Scenarios : UserControl
{
if (_loadingFilters) return;
StarterNG.Classes.Settings.Instance.ShowArchivalSceneries = archivalSwitch.IsChecked != true;
StarterNG.Classes.Settings.Instance.Save();
AppServices.Current.Settings.ShowArchivalSceneries = archivalSwitch.IsChecked != true;
AppServices.Current.SettingsStore.Save();
BuildSceneryTree();
RestoreLastScenery();
@@ -405,7 +405,7 @@ public partial class Scenarios : UserControl
BuildSceneryTree();
if (!string.IsNullOrEmpty(selected))
{
StarterNG.Classes.Settings.Instance.LastScenery =
AppServices.Current.Settings.LastScenery =
Path.GetFileNameWithoutExtension(selected);
RestoreLastScenery();
}
@@ -428,7 +428,7 @@ public partial class Scenarios : UserControl
BuildSceneryTree();
if (!string.IsNullOrEmpty(selected))
{
StarterNG.Classes.Settings.Instance.LastScenery =
AppServices.Current.Settings.LastScenery =
Path.GetFileNameWithoutExtension(selected);
}
RestoreLastScenery();
@@ -895,7 +895,7 @@ public partial class Scenarios : UserControl
string miniName = db.MiniForSkin(train.SkinFile) ?? train.SkinFile;
if (!AppServices.Current.MiniTextures.Has(miniName) && AppServices.Current.MiniTextures.Has(train.SkinFile))
miniName = train.SkinFile;
int thumbH = StarterNG.Classes.Settings.Instance.LargeThumbnails ? 64 : 32;
int thumbH = AppServices.Current.Settings.LargeThumbnails ? 64 : 32;
var bmp = LoadMini(miniName, thumbH);
Control visual = bmp is not null

View File

@@ -19,10 +19,12 @@ using StarterNG.Infrastructure;
using StarterNG.Services;
using KeyBinding = StarterNG.Classes.KeyBinding;
using StarterNG.Domain.Settings;
using StarterNG.Application;
namespace StarterNG.Views;
public partial class Settings : UserControl
public partial class Settings : UserControl, ISettingsCapture
{
private bool _loading;
@@ -33,14 +35,14 @@ public partial class Settings : UserControl
public event Action? ThumbnailSizeChanged;
/// <summary>Thumbnail size the other tabs were last drawn at.</summary>
private bool _drawnThumbs = StarterNG.Classes.Settings.Instance.LargeThumbnails;
private bool _drawnThumbs = AppServices.Current.Settings.LargeThumbnails;
public Settings()
{
InitializeComponent();
SettingsPathText.Text = StarterNG.Classes.Settings.Instance.LoadedFrom;
ToolTip.SetTip(SettingsPathText, StarterNG.Classes.Settings.Instance.LoadedFrom);
SettingsPathText.Text = AppServices.Current.SettingsStore.LoadedFrom;
ToolTip.SetTip(SettingsPathText, AppServices.Current.SettingsStore.LoadedFrom);
this.AttachedToVisualTree += (_, _) =>
{
@@ -60,7 +62,7 @@ public partial class Settings : UserControl
FeedbackCb.SelectionChanged += FeedbackCb_OnSelectionChanged;
FpsLimitEnableCb.IsCheckedChanged += (_, _) => FpsLimitSlider.IsEnabled = IsChecked(FpsLimitEnableCb);
StarterNG.Classes.Settings.Instance.CaptureFromUi = ReadFromUi;
AppServices.Current.SettingsStore.RegisterCapture(this);
PopulateProfileCombo();
ApplyToUi();
@@ -111,7 +113,7 @@ public partial class Settings : UserControl
return;
string path = SettingsProfileStore.PathFor(name);
if (!File.Exists(path)) return;
StarterNG.Classes.Settings.Instance.LoadFrom(path);
AppServices.Current.SettingsStore.LoadFrom(path);
ApplyToUi();
RedrawThumbnailsIfNeeded();
}
@@ -129,8 +131,8 @@ public partial class Settings : UserControl
void Commit()
{
if (string.IsNullOrWhiteSpace(nameBox.Text)) return;
ReadFromUi();
StarterNG.Classes.Settings.Instance.SaveTo(SettingsProfileStore.PathFor(nameBox.Text));
CaptureInto(AppServices.Current.Settings);
AppServices.Current.SettingsStore.SaveTo(SettingsProfileStore.PathFor(nameBox.Text));
PopulateProfileCombo();
int idx = FindComboIndexByContent(ProfileCb, nameBox.Text.Trim());
if (idx >= 0) ProfileCb.SelectedIndex = idx;
@@ -147,7 +149,7 @@ public partial class Settings : UserControl
string? current = (SelectExeCb.SelectedItem as ComboBoxItem)?.Content?.ToString();
SelectExeCb.Items.Clear();
SelectExeCb.Items.Add(new ComboBoxItem { Content = App.Loc["SelectEXEAuto"] });
foreach (string exe in StarterNG.Classes.Settings.ListCandidateExecutables())
foreach (string exe in AppServices.Current.Executables.ListCandidates())
SelectExeCb.Items.Add(new ComboBoxItem { Content = exe });
if (current is not null)
{
@@ -160,7 +162,7 @@ public partial class Settings : UserControl
private void ApplyToUi()
{
var s = StarterNG.Classes.Settings.Instance;
var s = AppServices.Current.Settings;
_loading = true;
try
{
@@ -268,9 +270,12 @@ public partial class Settings : UserControl
UpdateQualityCaptions();
}
private void ReadFromUi()
/// <summary>
/// Writes the pending edits on this screen into the settings, so a save from
/// anywhere in the application picks them up.
/// </summary>
public void CaptureInto(SimulatorSettings s)
{
var s = StarterNG.Classes.Settings.Instance;
s.Language = (ChangeLanguageCb.SelectedItem as ComboBoxItem)?.Content?.ToString()
?? App.Loc.CurrentLanguage;
@@ -297,8 +302,8 @@ public partial class Settings : UserControl
s.BufferScalePercent = (int)bufferScale.Value;
s.MaxTextureSize = 1 << (int)textureResolutionSlider.Value;
s.MaxCabTextureSize = 1 << (int)cabTextureResolutionSlider.Value;
s.TextureFiltering = StarterNG.Classes.Settings.AnisotropySteps[
Clamp((int)TexFilteringSlider.Value - 1, 0, StarterNG.Classes.Settings.AnisotropySteps.Length - 1)];
s.TextureFiltering = SimulatorSettings.AnisotropySteps[
Clamp((int)TexFilteringSlider.Value - 1, 0, SimulatorSettings.AnisotropySteps.Length - 1)];
s.Multisampling = Clamp((int)MultisamplingSlider.Value - 1, 0, 3);
s.DynamicLights = (int)DynamicLightsSlider.Value;
s.DrawRangeFactor = RenderRangeSlider.Value;
@@ -363,8 +368,8 @@ public partial class Settings : UserControl
private void SaveButton_OnClick(object? sender, RoutedEventArgs e)
{
ReadFromUi();
StarterNG.Classes.Settings.Instance.Save();
CaptureInto(AppServices.Current.Settings);
AppServices.Current.SettingsStore.Save();
KeyboardConfig.Instance.Save();
RedrawThumbnailsIfNeeded();
_dirty = false;
@@ -375,7 +380,7 @@ public partial class Settings : UserControl
private void RedrawThumbnailsIfNeeded()
{
bool large = StarterNG.Classes.Settings.Instance.LargeThumbnails;
bool large = AppServices.Current.Settings.LargeThumbnails;
if (large == _drawnThumbs)
return;
@@ -385,7 +390,7 @@ public partial class Settings : UserControl
private void ResetButton_OnClick(object? sender, RoutedEventArgs e)
{
StarterNG.Classes.Settings.Instance.Load();
AppServices.Current.SettingsStore.Load();
ApplyToUi();
RedrawThumbnailsIfNeeded();
CancelCapture();
@@ -413,7 +418,7 @@ public partial class Settings : UserControl
ResolutionCb.SelectedItem = added;
}
private void ReadResolution(Classes.Settings s)
private void ReadResolution(SimulatorSettings s)
{
var text = (ResolutionCb.SelectedItem as ComboBoxItem)?.Content?.ToString();
if (string.IsNullOrEmpty(text))
@@ -688,7 +693,7 @@ public partial class Settings : UserControl
private static int AnisotropyToSlider(int anisotropy)
{
var steps = StarterNG.Classes.Settings.AnisotropySteps;
var steps = SimulatorSettings.AnisotropySteps;
for (int i = 0; i < steps.Length; i++)
if (steps[i] == anisotropy)
return i + 1;

View File

@@ -2,7 +2,7 @@ using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Layout;
using Avalonia.Media;
using SettingsModel = StarterNG.Classes.Settings;
using StarterNG.Application;
namespace StarterNG.Views;
@@ -99,7 +99,7 @@ public sealed class UartWindow : Window
private void Load()
{
var s = SettingsModel.Instance;
var s = AppServices.Current.Settings;
_enabled.IsChecked = s.UartEnabled;
_port.Text = s.UartPort;
_tune.Text = s.UartTune;
@@ -114,7 +114,7 @@ public sealed class UartWindow : Window
private void Store()
{
var s = SettingsModel.Instance;
var s = AppServices.Current.Settings;
s.UartEnabled = _enabled.IsChecked == true;
s.UartPort = _port.Text ?? "";
s.UartTune = _tune.Text ?? "";