feat(ui): PowerUse-Einstellungen nach Settings -> Ausfuehrung verschieben

Schalter, Zeitfenster und Handoff-Prozent lagen im Usage-Monitor und mussten
in SettingsModalViewModel nur load->save durchgeschleift werden, damit ein
Settings-Speichern sie nicht zurueckwirft. Jetzt gehoeren sie dem General-Tab,
der Monitor ist wieder nur Anzeige + Threshold-Drag, und "Jetzt aktualisieren"
sitzt als Icon in der Titelleiste (neuer ModalShell.HeaderActions-Slot).
This commit is contained in:
mika kuns
2026-09-07 08:17:37 +02:00
parent c7392e085f
commit 7c7c33d677
21 changed files with 179 additions and 213 deletions
@@ -252,8 +252,8 @@
<TextBlock Text="{loc:Tr settings.general.autoContinueOnUsageLimitHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
<!-- PowerUse itself is toggled on the usage monitor; only its handoff budget is
typed here, because it also applies to a normal (interactive) handler run. -->
<!-- Outside the PowerUse section below on purpose: the handoff budget also bounds
a normal (interactive) handler run. -->
<StackPanel Spacing="4">
<TextBlock Classes="eyebrow" Text="{loc:Tr settings.general.listHandlerMaxHandoffs}"/>
<NumericUpDown Value="{Binding General.ListHandlerMaxHandoffs, Mode=TwoWay, Converter={StaticResource KeepLastNumber}}"
@@ -264,6 +264,34 @@
</StackPanel>
</StackPanel>
<!-- PowerUse: a master switch plus its time window. Never sufficient on its own —
the run's list must also allow PowerUse in its list settings. -->
<StackPanel Spacing="4">
<TextBlock Classes="field-label" Text="{loc:Tr settings.general.powerUseHeading}"/>
<CheckBox IsChecked="{Binding General.PowerUseEnabled, Mode=TwoWay}"
Content="{loc:Tr settings.general.powerUse}"/>
<TextBlock Text="{loc:Tr settings.general.powerUseHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
<StackPanel Orientation="Horizontal" Spacing="8" Margin="0,6,0,0">
<TextBlock Classes="eyebrow" VerticalAlignment="Center"
Text="{loc:Tr settings.general.powerUseWindow}"/>
<TextBox Width="70" FontSize="12" Padding="6,2"
Watermark="{loc:Tr settings.general.powerUseWindowPlaceholder}"
Text="{Binding General.PowerUseWindowStart, Mode=TwoWay}"/>
<TextBlock Classes="meta" VerticalAlignment="Center" Text="–"/>
<TextBox Width="70" FontSize="12" Padding="6,2"
Watermark="{loc:Tr settings.general.powerUseWindowPlaceholder}"
Text="{Binding General.PowerUseWindowEnd, Mode=TwoWay}"/>
<TextBlock Classes="eyebrow" VerticalAlignment="Center" Margin="12,0,0,0"
Text="{loc:Tr settings.general.powerUseHandoffPct}"/>
<NumericUpDown Width="80" FontSize="12" Padding="6,2" ShowButtonSpinner="False"
Minimum="50" Maximum="99" Increment="1" FormatString="0"
Value="{Binding General.PowerUseHandoffPct, Mode=TwoWay, Converter={StaticResource KeepLastNumber}}"/>
</StackPanel>
<TextBlock Text="{loc:Tr settings.general.powerUseWindowHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
<!-- Throttle stages live on the usage-monitor gauges (drag + spinner per stage);
echoed read-only here so they aren't invisible on the tab that owns the gate. -->
<StackPanel Spacing="4">
@@ -19,6 +19,18 @@
</Window.KeyBindings>
<ctl:ModalShell Title="{loc:Tr modals.usageMonitor.title}" CloseCommand="{Binding CloseCommand}">
<!-- Refresh sits in the titlebar: the worker polls on a slow cadence to avoid the endpoint's
429s, so this is the way to get a number now — but it doesn't earn a row in the body. -->
<ctl:ModalShell.HeaderActions>
<StackPanel Orientation="Horizontal" Spacing="6">
<Ellipse Classes="spinner" Width="12" Height="12" VerticalAlignment="Center"
IsVisible="{Binding IsRefreshing}"/>
<Button Classes="icon-btn" Content="⟳" FontSize="{DynamicResource FontSizeBody}"
Command="{Binding RefreshCommand}"
IsEnabled="{Binding !IsRefreshing}"
ToolTip.Tip="{loc:Tr modals.usageMonitor.refreshHint}"/>
</StackPanel>
</ctl:ModalShell.HeaderActions>
<DockPanel>
<!-- Stale / gate bands -->
@@ -47,18 +59,6 @@
</Border>
</StackPanel>
<!-- Refresh: the worker polls on a slow cadence to avoid the endpoint's 429s -->
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Spacing="8"
Margin="20,12,20,0" VerticalAlignment="Center">
<Button Classes="btn" Content="{loc:Tr modals.usageMonitor.refresh}"
Command="{Binding RefreshCommand}"
IsEnabled="{Binding !IsRefreshing}"/>
<Ellipse Classes="spinner" Width="14" Height="14" VerticalAlignment="Center"
IsVisible="{Binding IsRefreshing}"/>
<TextBlock Classes="meta" VerticalAlignment="Center"
Text="{loc:Tr modals.usageMonitor.refreshHint}"/>
</StackPanel>
<!-- Gauges -->
<ItemsControl DockPanel.Dock="Top" Margin="20,12,20,0" ItemsSource="{Binding GaugeRows}">
<ItemsControl.ItemsPanel>
@@ -134,42 +134,6 @@
Text="{loc:Tr modals.usageMonitor.noGauges}"
IsVisible="{Binding !GaugeRows.Count}"/>
<!-- PowerUse: sits under the gauges on purpose — "spend the rest of the window" is a
decision made while looking at how much window is left. Saves immediately on toggle. -->
<Border DockPanel.Dock="Top" Margin="20,12,20,0" Padding="12,10"
Background="{DynamicResource DeepBrush}" BorderBrush="{DynamicResource LineBrush}"
BorderThickness="1" CornerRadius="6">
<StackPanel Spacing="4">
<CheckBox IsChecked="{Binding PowerUseEnabled, Mode=TwoWay}"
Content="{loc:Tr modals.usageMonitor.powerUse}"/>
<TextBlock Classes="meta" TextWrapping="Wrap"
Text="{loc:Tr modals.usageMonitor.powerUseHint}"/>
<!-- Window + handoff threshold. Same commit-on-blur/Enter discipline as the gauge
legend boxes: a hub write per keystroke would be one save per typed digit. -->
<StackPanel Orientation="Horizontal" Spacing="8" Margin="0,6,0,0">
<TextBlock Classes="meta" VerticalAlignment="Center"
Text="{loc:Tr modals.usageMonitor.powerUseWindow}"/>
<TextBox Width="70" FontSize="12" Padding="6,2"
Watermark="{loc:Tr modals.usageMonitor.powerUseWindowPlaceholder}"
Text="{Binding PowerUseWindowStart, Mode=TwoWay}"
LostFocus="OnPowerUseBoxCommit" KeyDown="OnPowerUseBoxKeyDown"/>
<TextBlock Classes="meta" VerticalAlignment="Center" Text="–"/>
<TextBox Width="70" FontSize="12" Padding="6,2"
Watermark="{loc:Tr modals.usageMonitor.powerUseWindowPlaceholder}"
Text="{Binding PowerUseWindowEnd, Mode=TwoWay}"
LostFocus="OnPowerUseBoxCommit" KeyDown="OnPowerUseBoxKeyDown"/>
<TextBlock Classes="meta" VerticalAlignment="Center" Margin="12,0,0,0"
Text="{loc:Tr modals.usageMonitor.powerUseHandoffPct}"/>
<NumericUpDown Width="80" FontSize="12" Padding="6,2" ShowButtonSpinner="False"
Minimum="50" Maximum="99" Increment="1" FormatString="0"
Value="{Binding PowerUseHandoffPct, Mode=TwoWay, Converter={StaticResource KeepLastNumber}}"
LostFocus="OnPowerUseBoxCommit" KeyDown="OnPowerUseBoxKeyDown"/>
</StackPanel>
<TextBlock Classes="meta" TextWrapping="Wrap" Opacity="0.75"
Text="{loc:Tr modals.usageMonitor.powerUseWindowHint}"/>
</StackPanel>
</Border>
<!-- Period picker -->
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Spacing="8" Margin="20,12,20,0">
<TextBlock Classes="meta" Text="{loc:Tr modals.usageMonitor.period}" VerticalAlignment="Center"/>
@@ -33,19 +33,4 @@ public partial class UsageMonitorModalView : Window
OnStageBoxCommit(sender, e);
e.Handled = true;
}
/// <summary>Persists the PowerUse window / handoff threshold on blur — a save per keystroke
/// would be one hub round-trip per typed digit.</summary>
private void OnPowerUseBoxCommit(object? sender, RoutedEventArgs e)
{
if (DataContext is not UsageMonitorModalViewModel vm) return;
if (vm.SavePowerUseCommand.CanExecute(null)) vm.SavePowerUseCommand.Execute(null);
}
private void OnPowerUseBoxKeyDown(object? sender, KeyEventArgs e)
{
if (e.Key != Key.Enter) return;
OnPowerUseBoxCommit(sender, e);
e.Handled = true;
}
}