Dunkelmodus mit Umschalter in der Fensterleiste

Farbschema hell / dunkel / dem System folgen, umschaltbar per Klick, Stand wird in
server_settings.xml gemerkt (ServerSettings.Theme). Der Editor zeigt die Einstellung
automatisch als Auswahlfeld - kein Zusatzcode, weil sie ein Enum ist.

- App.axaml: 18 Farb-Token je Variante (Flaechen, Rahmen, Texte, Bedeutungsfarben,
  Zeilenfaerbung, Trading-Umschalter, Chat-Rollen). Die Standard-Steuerelemente stellt
  das FluentTheme selbst um.
- 22 fest verdrahtete Farben in 11 XAML-Dateien auf DynamicResource umgestellt - die
  wechseln damit von selbst mit.
- Umschalter (Sonne/Mond) sitzt in der gemeinsamen Fensterleiste, also auf JEDEM Fenster.

Der eigentliche Knackpunkt waren die Farben, die im Code gesetzt werden - die folgen dem
Thema NICHT von selbst:
- TradeRowPalette liefert jetzt Eigenschaften statt static readonly, loest also bei jedem
  Zugriff neu auf. Im Dunkeln gedaempfte Toene statt der hellen Pastelltoene, die dort
  blenden und den Text unlesbar machen wuerden.
- ChatEntry speichert die ROLLE statt eines fertigen Brush - dadurch stimmt der Verlauf
  nach dem Umschalten ohne Neuaufbau der Liste.
- Launcher-Umschalter, Dashboard-KPI und die Grid-Zeilenfarben zeichnen sich ueber
  ThemeManager.ThemeChanged neu.
- Das Terminal bleibt in beiden Schemata dunkel (Konsolen sind konventionell dunkel).

Nebenbei die Anzeige-Kultur gepinnt (stand ohnehin auf der Linux-Liste): auf Linux richtet
sie sich sonst nach LANG/LC_ALL, das unter systemd oft nicht gesetzt ist - dann faellt .NET
auf Invariant zurueck und aus '1.234,56 USDC' wird '1,234.56 USDC'. Maschinen-I/O laeuft
davon unabhaengig weiter invariant.

Smoke-UI prueft jetzt zusaetzlich, dass ALLE 18 Farben in BEIDEN Varianten aufloesen -
ein vertippter Ressourcenschluessel wuerde sonst still grau werden.

Verifiziert: Solution baut, 450 Tests gruen, --smoke-ui gruen (10 Fenster + Editor +
beide Farbschemata), App startet im gespeicherten Schema, Linux-Publish laeuft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-08-06 22:41:25 +02:00
co-authored by Claude Opus 5
parent 669676ac60
commit 487ea4466d
23 changed files with 350 additions and 60 deletions
+88 -12
View File
@@ -1,7 +1,78 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="PolyTrader.App.Avalonia.App"
RequestedThemeVariant="Light">
x:Class="PolyTrader.App.Avalonia.App">
<!--
Farbschema. RequestedThemeVariant wird NICHT hier festgelegt, sondern beim Start vom
ThemeManager aus den Server-Settings gesetzt (hell / dunkel / dem System folgen).
Alle projekteigenen Farben stehen als Token in beiden Varianten. Im XAML werden sie über
DynamicResource gebunden – dadurch wechseln sie beim Umschalten von selbst. Nur wenige
Stellen setzen Farben im Code (Grid-Zeilen, Umschalter); die holen sie über
ThemeManager.Brush(...) und zeichnen sich bei ThemeChanged neu.
-->
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<!-- Flächen und Rahmen -->
<SolidColorBrush x:Key="AppSurfaceBrush" Color="#FAFAFA" />
<SolidColorBrush x:Key="AppSurfaceAltBrush" Color="#F3F3F3" />
<SolidColorBrush x:Key="AppCardBrush" Color="#F5F5F5" />
<SolidColorBrush x:Key="AppBorderBrush" Color="#DDDDDD" />
<!-- Texte -->
<SolidColorBrush x:Key="AppMutedTextBrush" Color="#777777" />
<SolidColorBrush x:Key="AppCaptionTextBrush" Color="#666666" />
<SolidColorBrush x:Key="AppReadOnlyTextBrush" Color="#444444" />
<!-- Bedeutungsfarben -->
<SolidColorBrush x:Key="AppPositiveBrush" Color="#2E7D32" />
<SolidColorBrush x:Key="AppNegativeBrush" Color="#C62828" />
<SolidColorBrush x:Key="AppWarningBrush" Color="#996600" />
<!-- Zeilenfärbung der Trade-Listen (Pastell auf hellem Grund) -->
<SolidColorBrush x:Key="AppTradeLossBrush" Color="#F5C8C8" />
<SolidColorBrush x:Key="AppTradeSmallWinBrush" Color="#D4F0D4" />
<SolidColorBrush x:Key="AppTradeBigWinBrush" Color="#8CD68C" />
<!-- Trading-Umschalter im Launcher -->
<SolidColorBrush x:Key="AppToggleActiveBrush" Color="#90EE90" />
<SolidColorBrush x:Key="AppToggleSellOnlyBrush" Color="#FFA500" />
<SolidColorBrush x:Key="AppToggleInactiveBrush" Color="#CD5C5C" />
<!-- Supervisor-Analyseverlauf -->
<SolidColorBrush x:Key="AppChatUserBrush" Color="#4682B4" />
<SolidColorBrush x:Key="AppChatAgentBrush" Color="#2E8B57" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<!-- Flächen und Rahmen -->
<SolidColorBrush x:Key="AppSurfaceBrush" Color="#2B2B2B" />
<SolidColorBrush x:Key="AppSurfaceAltBrush" Color="#333333" />
<SolidColorBrush x:Key="AppCardBrush" Color="#2F2F2F" />
<SolidColorBrush x:Key="AppBorderBrush" Color="#484848" />
<!-- Texte: heller, aber nicht reinweiß – sonst flimmert es auf Dunkel -->
<SolidColorBrush x:Key="AppMutedTextBrush" Color="#9A9A9A" />
<SolidColorBrush x:Key="AppCaptionTextBrush" Color="#AAAAAA" />
<SolidColorBrush x:Key="AppReadOnlyTextBrush" Color="#CFCFCF" />
<!-- Bedeutungsfarben: gleiche Aussage, aufgehellt für Kontrast auf Dunkel -->
<SolidColorBrush x:Key="AppPositiveBrush" Color="#81C784" />
<SolidColorBrush x:Key="AppNegativeBrush" Color="#EF5350" />
<SolidColorBrush x:Key="AppWarningBrush" Color="#FFB74D" />
<!-- Zeilenfärbung: gedämpft statt pastell – die hellen Töne würden auf Dunkel
blenden und den Text unlesbar machen. Reihenfolge der Aussage bleibt. -->
<SolidColorBrush x:Key="AppTradeLossBrush" Color="#4E2A2A" />
<SolidColorBrush x:Key="AppTradeSmallWinBrush" Color="#2C3F2C" />
<SolidColorBrush x:Key="AppTradeBigWinBrush" Color="#3D6B3D" />
<!-- Trading-Umschalter -->
<SolidColorBrush x:Key="AppToggleActiveBrush" Color="#3F7A3F" />
<SolidColorBrush x:Key="AppToggleSellOnlyBrush" Color="#A76B1F" />
<SolidColorBrush x:Key="AppToggleInactiveBrush" Color="#8E3B3B" />
<!-- Supervisor-Analyseverlauf -->
<SolidColorBrush x:Key="AppChatUserBrush" Color="#7FB3D8" />
<SolidColorBrush x:Key="AppChatAgentBrush" Color="#68B68A" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>
<Application.Styles>
<FluentTheme />
@@ -18,11 +89,11 @@
<Setter Property="FontSize" Value="12" />
</Style>
<!-- KPI-Kachel: entspricht den zweizeiligen Labels der WinForms-Oberflaeche
<!-- KPI-Kachel: entspricht den zweizeiligen Labels der WinForms-Oberfläche
("<Titel> \n <Wert>"), siehe docs/UI-SPEZIFIKATION-WinForms.md. -->
<Style Selector="Border.kpi">
<Setter Property="Background" Value="#F5F5F5" />
<Setter Property="BorderBrush" Value="#DDDDDD" />
<Setter Property="Background" Value="{DynamicResource AppCardBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource AppBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="4" />
<Setter Property="Padding" Value="12,8" />
@@ -31,17 +102,17 @@
</Style>
<Style Selector="Border.kpi > StackPanel > TextBlock.caption">
<Setter Property="FontSize" Value="11" />
<Setter Property="Foreground" Value="#666666" />
<Setter Property="Foreground" Value="{DynamicResource AppCaptionTextBrush}" />
</Style>
<Style Selector="Border.kpi > StackPanel > TextBlock.value">
<Setter Property="FontSize" Value="18" />
<Setter Property="FontWeight" Value="SemiBold" />
</Style>
<!-- Werkzeugleiste oben in jedem Fenster (Ersatz fuer ToolStrip). -->
<!-- Werkzeugleiste oben in jedem Fenster (Ersatz für ToolStrip). -->
<Style Selector="Border.toolbar">
<Setter Property="Background" Value="#FAFAFA" />
<Setter Property="BorderBrush" Value="#DDDDDD" />
<Setter Property="Background" Value="{DynamicResource AppSurfaceBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource AppBorderBrush}" />
<Setter Property="BorderThickness" Value="0,0,0,1" />
<Setter Property="Padding" Value="6,4" />
</Style>
@@ -50,13 +121,18 @@
<Setter Property="Padding" Value="10,4" />
</Style>
<!-- Statusleiste unten (Ersatz fuer StatusStrip). -->
<!-- Statusleiste unten (Ersatz für StatusStrip). -->
<Style Selector="Border.statusbar">
<Setter Property="Background" Value="#FAFAFA" />
<Setter Property="BorderBrush" Value="#DDDDDD" />
<Setter Property="Background" Value="{DynamicResource AppSurfaceBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource AppBorderBrush}" />
<Setter Property="BorderThickness" Value="0,1,0,0" />
<Setter Property="Padding" Value="8,4" />
</Style>
<!-- Gedämpfte Hinweistexte (Statuszeilen, Erklärungen unter Feldern). -->
<Style Selector="TextBlock.muted">
<Setter Property="Foreground" Value="{DynamicResource AppMutedTextBrush}" />
</Style>
</Application.Styles>
</Application>