Something already sitting where Documents/N1MM Logger+ should go — a file, or a link to somewhere that is not there — threw out of Directory.CreateDirectory before the program had a window, so the operator got a stack trace and nothing else. CreateFolders answers with what stopped it, and the program shows it in a window naming the path and stops there. NONEMM_HOME moves the whole lot somewhere else, for a station that keeps its files off the Documents folder. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoGtneMQaz4M9w7Kk49AVD
85 lines
3.3 KiB
C#
85 lines
3.3 KiB
C#
using Avalonia;
|
|
using Avalonia.Controls.ApplicationLifetimes;
|
|
using Avalonia.Markup.Xaml;
|
|
using Avalonia.Media;
|
|
using Nonemm.App.Configuration;
|
|
using Nonemm.App.Theming;
|
|
using Nonemm.App.Windows;
|
|
|
|
namespace Nonemm.App;
|
|
|
|
public partial class App : Application
|
|
{
|
|
public override void Initialize() => AvaloniaXamlLoader.Load(this);
|
|
|
|
public override void OnFrameworkInitializationCompleted()
|
|
{
|
|
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
|
{
|
|
UserPaths paths = UserPaths.Default();
|
|
if (paths.CreateFolders() is { } problem)
|
|
{
|
|
desktop.MainWindow = new StartupProblemWindow(problem, paths.Root);
|
|
base.OnFrameworkInitializationCompleted();
|
|
return;
|
|
}
|
|
Settings settings = Settings.Load(paths.SettingsFile);
|
|
Themes.Use(settings.Theme);
|
|
Themes.Changed += (_, _) => ApplyTheme();
|
|
ApplyTheme();
|
|
AppSession session = new(paths, settings);
|
|
desktop.MainWindow = new EntryWindow(session);
|
|
desktop.ShutdownRequested += (_, _) => session.Dispose();
|
|
}
|
|
base.OnFrameworkInitializationCompleted();
|
|
}
|
|
|
|
/// The window chrome follows the theme through these resources; everything
|
|
/// that draws a station or a spot asks `Themes.Current` as it paints.
|
|
private void ApplyTheme()
|
|
{
|
|
Theme theme = Themes.Current;
|
|
RequestedThemeVariant = theme.Variant;
|
|
Set("FormBackground", theme.FormBackground);
|
|
Set("FormForeground", theme.FormForeground);
|
|
Set("FieldBackground", theme.FieldBackground);
|
|
Set("FieldForeground", theme.FieldForeground);
|
|
// the keys the Fluent controls read, so a text box and a button take
|
|
// the theme's colours in every state rather than only where a style of
|
|
// ours reaches them
|
|
foreach (string key in new[]
|
|
{
|
|
"TextControlBackground", "TextControlBackgroundPointerOver",
|
|
"TextControlBackgroundFocused", "TextControlBackgroundDisabled",
|
|
"ComboBoxBackground", "ComboBoxBackgroundPointerOver", "ComboBoxBackgroundPressed",
|
|
"DataGridRowBackgroundBrush",
|
|
})
|
|
{
|
|
Set(key, theme.FieldBackground);
|
|
}
|
|
foreach (string key in new[]
|
|
{
|
|
"TextControlForeground", "TextControlForegroundPointerOver",
|
|
"TextControlForegroundFocused", "ComboBoxForeground", "ButtonForeground",
|
|
"ButtonForegroundPointerOver", "ButtonForegroundPressed",
|
|
})
|
|
{
|
|
Set(key, theme.FieldForeground);
|
|
}
|
|
Set("ButtonBackground", theme.ButtonBackground);
|
|
Set("ButtonBackgroundPointerOver", Lighter(theme.ButtonBackground));
|
|
Set("ButtonBackgroundPressed", Darker(theme.ButtonBackground));
|
|
}
|
|
|
|
private void Set(string key, Color colour) => Resources[key] = new SolidColorBrush(colour);
|
|
|
|
private static Color Lighter(Color colour) => Shifted(colour, 12);
|
|
|
|
private static Color Darker(Color colour) => Shifted(colour, -18);
|
|
|
|
private static Color Shifted(Color colour, int by) => Color.FromRgb(
|
|
(byte)Math.Clamp(colour.R + by, 0, 255),
|
|
(byte)Math.Clamp(colour.G + by, 0, 255),
|
|
(byte)Math.Clamp(colour.B + by, 0, 255));
|
|
}
|