feat: redesign Pump page with Fluent card layout, bottom snackbar, and RPM chart

- Replace sub-nav + HiddenTabsTabControl with 3-column Fluent card layout:
  PumpCommandsCard (vertical ME/FBKW/PreIn sliders) + DfiCalibrationCard /
  PumpLiveDataCard (KPI tiles + RPM rolling chart + redesigned status bytes) /
  PumpIdentificationCard + DtcCard
- Add PumpTopStripView: pump selector, model badge, CAN + K-Line chips
- Move immobilizer unlock to MainWindow bottom snackbar (UnlockSnackbarView):
  auto-close on success after 3 s, persist on failure with manual Dismiss
- Redesign StatusDisplayView to 2×8 rounded 28px tiles with bit index + tooltip
- Add NullToVisibilityConverter; add SnackbarShell, PumpCard, and related styles
- Delete obsolete views: UnlockProgressDialog, UnlockPanelView,
  PumpIdentificationPanelView, PumpLiveDataView, DfiManageView,
  DtcListView, PumpControlView
- PumpPageViewModel: remove PumpSubPage enum, add RpmChart wired to Root.PumpRpm

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 14:03:47 +02:00
parent 197e9d1775
commit 70be693116
37 changed files with 1356 additions and 1317 deletions

View File

@@ -0,0 +1,162 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.PumpTopStripView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:models="clr-namespace:HC_APTBS.Models"
mc:Ignorable="d"
d:DesignHeight="52" d:DesignWidth="1100">
<!-- DataContext = PumpPageViewModel. Binds via Root.* and Identification.* -->
<Border Background="{DynamicResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{DynamicResource CardStrokeColorDefaultBrush}"
BorderThickness="1" CornerRadius="8"
Padding="14,10" Margin="0,0,0,8">
<DockPanel LastChildFill="False">
<!-- ── Right side: CAN chip + K-Line chip ────────────────────── -->
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" VerticalAlignment="Center">
<!-- CAN chip -->
<Border Style="{StaticResource ConnChip}">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<ui:SymbolIcon Symbol="PlugConnected24" FontSize="15"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Margin="0,0,6,0"/>
<TextBlock Text="{DynamicResource Pump.TopStrip.Can}" FontSize="12"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
VerticalAlignment="Center" Margin="0,0,10,0"/>
<Ellipse>
<Ellipse.Style>
<Style TargetType="Ellipse" BasedOn="{StaticResource StatusDot}">
<Style.Triggers>
<DataTrigger Binding="{Binding Root.IsCanConnected}" Value="True">
<Setter Property="Fill" Value="{DynamicResource SystemFillColorSuccessBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<TextBlock FontSize="11" FontWeight="SemiBold" VerticalAlignment="Center">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{DynamicResource Dashboard.StateOffline}"/>
<Setter Property="Foreground" Value="{DynamicResource TextFillColorTertiaryBrush}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Root.IsCanConnected}" Value="True">
<Setter Property="Text" Value="{DynamicResource Dashboard.StateOnline}"/>
<Setter Property="Foreground" Value="{DynamicResource SystemFillColorSuccessBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Border>
<!-- K-Line chip — 3-state: Connected / Closed / Failed -->
<Border Margin="0,0,0,0">
<Border.Style>
<Style TargetType="Border" BasedOn="{StaticResource ConnChip}">
<Style.Triggers>
<DataTrigger Binding="{Binding Root.KLineState}"
Value="{x:Static models:KLineConnectionState.Failed}">
<Setter Property="Background" Value="{DynamicResource SystemFillColorCautionBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource SystemFillColorCautionBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<ui:SymbolIcon Symbol="UsbPlug24" FontSize="15"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Margin="0,0,6,0"/>
<TextBlock Text="{DynamicResource Pump.TopStrip.KLine}" FontSize="12"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
VerticalAlignment="Center" Margin="0,0,10,0"/>
<Ellipse>
<Ellipse.Style>
<Style TargetType="Ellipse" BasedOn="{StaticResource StatusDot}">
<Style.Triggers>
<DataTrigger Binding="{Binding Root.KLineState}"
Value="{x:Static models:KLineConnectionState.Connected}">
<Setter Property="Fill" Value="{DynamicResource SystemFillColorSuccessBrush}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Root.KLineState}"
Value="{x:Static models:KLineConnectionState.Failed}">
<Setter Property="Fill" Value="{DynamicResource SystemFillColorCautionBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<TextBlock FontSize="11" FontWeight="SemiBold" VerticalAlignment="Center">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{DynamicResource Dashboard.StateClosed}"/>
<Setter Property="Foreground" Value="{DynamicResource TextFillColorTertiaryBrush}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Root.KLineState}"
Value="{x:Static models:KLineConnectionState.Connected}">
<Setter Property="Text" Value="{DynamicResource Dashboard.StateOpen}"/>
<Setter Property="Foreground" Value="{DynamicResource SystemFillColorSuccessBrush}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Root.KLineState}"
Value="{x:Static models:KLineConnectionState.Failed}">
<Setter Property="Text" Value="{DynamicResource Dashboard.StateFailed}"/>
<Setter Property="Foreground" Value="{DynamicResource SystemFillColorCautionBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Border>
</StackPanel>
<!-- ── Left side: Pump selector + Brand/Model label ─────────── -->
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal" VerticalAlignment="Center">
<!-- Pump ID label -->
<TextBlock Text="{DynamicResource PumpId.Label}"
FontSize="12"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
VerticalAlignment="Center" Margin="0,0,8,0"/>
<!-- Pump selector ComboBox -->
<ComboBox ItemsSource="{Binding Identification.PumpIds}"
SelectedItem="{Binding Identification.SelectedPumpId}"
MinWidth="200" FontSize="13" Height="32"
VerticalContentAlignment="Center"/>
<!-- Model / Brand badge -->
<Border Background="{DynamicResource ControlFillColorSecondaryBrush}"
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
BorderThickness="1" CornerRadius="10" Padding="10,4" Margin="10,0,0,0">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Pump.TopStrip.Brand}"
FontSize="11"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Margin="0,0,4,0"/>
<TextBlock FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource TextFillColorPrimaryBrush}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{Binding Identification.CurrentPump.Model}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Identification.CurrentPump}" Value="{x:Null}">
<Setter Property="Text" Value="{DynamicResource Pump.TopStrip.NoPump}"/>
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="Foreground" Value="{DynamicResource TextFillColorTertiaryBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Border>
</StackPanel>
</DockPanel>
</Border>
</UserControl>