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,132 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.DfiCalibrationCard"
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"
mc:Ignorable="d"
d:DesignHeight="260" d:DesignWidth="260">
<!-- DataContext = DfiManageViewModel (via {Binding DfiViewModel}) -->
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</UserControl.Resources>
<Border Style="{StaticResource PumpCard}">
<DockPanel LastChildFill="True">
<!-- ── Card header ───────────────────────────────────────────── -->
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,12">
<ui:SymbolIcon DockPanel.Dock="Left" Symbol="Gauge24" FontSize="16"
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
Margin="0,0,8,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Pump.Dfi.Title}"
Style="{StaticResource PumpCardHeader}" Margin="0"/>
</DockPanel>
<!-- ── Version selector row ──────────────────────────────────── -->
<Grid DockPanel.Dock="Top" Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{DynamicResource Pump.Dfi.Version}"
Style="{StaticResource PumpCommandLabel}"
VerticalAlignment="Center" Margin="0,0,8,0"/>
<ComboBox Grid.Column="1"
SelectedIndex="{Binding VersionIndex}"
Height="28">
<ComboBoxItem Content="V1"/>
<ComboBoxItem Content="V2"/>
<ComboBoxItem Content="V3"/>
<ComboBoxItem Content="V4"/>
</ComboBox>
<CheckBox Grid.Column="2"
IsChecked="{Binding IsAutoMode}"
Content="{DynamicResource Dfi.Auto}"
FontSize="12"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
VerticalAlignment="Center" Margin="8,0,0,0"/>
</Grid>
<!-- ── Current DFI readout ───────────────────────────────────── -->
<Border DockPanel.Dock="Top"
Background="{DynamicResource ControlFillColorSecondaryBrush}"
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
BorderThickness="1" CornerRadius="6" Padding="12,8"
Margin="0,0,0,12">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{DynamicResource Pump.Dfi.Current}"
FontSize="11"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
VerticalAlignment="Center"/>
<TextBlock Grid.Column="1"
Text="{Binding CurrentDfi, StringFormat=F2, Mode=OneWay}"
FontFamily="Consolas" FontSize="22" FontWeight="SemiBold"
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
VerticalAlignment="Center"/>
</Grid>
</Border>
<!-- ── Busy indicator ─────────────────────────────────────────── -->
<ProgressBar DockPanel.Dock="Top"
Value="{Binding ProgressPercent, Mode=OneWay}"
Minimum="0" Maximum="100" Height="3"
Margin="0,0,0,6"
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVis}}"/>
<!-- ── DFI slider ─────────────────────────────────────────────── -->
<Grid DockPanel.Dock="Top" Margin="0,0,0,8">
<Slider Value="{Binding SliderRaw}"
Minimum="-145" Maximum="145"
TickFrequency="5" SmallChange="5" LargeChange="5"
IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Margin="0,0,0,4" VerticalAlignment="Center"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="-1.45"
HorizontalAlignment="Left" VerticalAlignment="Bottom"
FontSize="10" Foreground="{DynamicResource TextFillColorTertiaryBrush}"/>
<TextBlock Grid.Column="1"
Text="{Binding SliderDfiValue, StringFormat=F2, Mode=OneWay}"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
FontFamily="Consolas" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"/>
<TextBlock Grid.Column="2" Text="+1.45"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
FontSize="10" Foreground="{DynamicResource TextFillColorTertiaryBrush}"/>
</Grid>
</Grid>
<!-- ── Read / Write buttons ──────────────────────────────────── -->
<Grid DockPanel.Dock="Bottom" Margin="0,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="8"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ui:Button Grid.Column="0"
Content="{DynamicResource Dfi.Read}"
Command="{Binding ReadDfiCommand}"
Appearance="Secondary"
FontWeight="Bold" Height="32"/>
<ui:Button Grid.Column="2"
Content="{DynamicResource Dfi.Write}"
Command="{Binding WriteDfiCommand}"
Appearance="Primary"
FontWeight="Bold" Height="32"/>
</Grid>
</DockPanel>
</Border>
</UserControl>

View File

@@ -0,0 +1,9 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
public partial class DfiCalibrationCard : UserControl
{
public DfiCalibrationCard() => InitializeComponent();
}
}

View File

@@ -1,115 +0,0 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.DfiManageView"
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"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="460" MaxHeight="150">
<UserControl.Resources>
<Style x:Key="LcdGreen" TargetType="Border">
<Setter Property="BorderThickness" Value="3"/>
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="DarkSlateGray" Offset="0"/>
<GradientStop Color="LawnGreen" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="LawnGreen" Offset="0"/>
<GradientStop Color="#57B000" Offset="1.5"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid Margin="16,8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="75"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="144" MinWidth="60"/>
<ColumnDefinition MinWidth="200"/>
</Grid.ColumnDefinitions>
<!-- LEFT: version picker + read/write buttons -->
<ComboBox Margin="4" VerticalAlignment="Bottom"
SelectedIndex="{Binding VersionIndex}">
<ComboBoxItem Content="V1"/>
<ComboBoxItem Content="V2"/>
<ComboBoxItem Content="V3"/>
<ComboBoxItem Content="V4"/>
</ComboBox>
<Grid Grid.Row="1" Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="4"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="{DynamicResource Dfi.Read}"
Command="{Binding ReadDfiCommand}"
FontSize="12" FontWeight="Bold" Padding="4"/>
<Button Grid.Column="2" Content="{DynamicResource Dfi.Write}"
Command="{Binding WriteDfiCommand}"
FontSize="12" FontWeight="Bold" Padding="4"/>
</Grid>
<!-- TOP RIGHT: DFI value LCD + auto checkbox -->
<Grid Grid.Row="0" Grid.Column="1" Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="200"/>
<ColumnDefinition MinWidth="100"/>
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="1" Style="{StaticResource LcdGreen}" Margin="0,0,12,0" >
<Grid Grid.Row="1" >
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{DynamicResource Dfi.Label}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="Black" FontSize="18" FontFamily="Consolas"/>
<TextBlock Text="{Binding CurrentDfi, StringFormat=F2, Mode=OneWay}"
Grid.Column="1"
HorizontalAlignment="Center" VerticalAlignment="Center"
FontSize="26" FontWeight="Bold" Foreground="Black"/>
</Grid>
</Border>
<Border Grid.ColumnSpan="1" BorderThickness="1" BorderBrush="Black" Margin="0,0,12,0" SnapsToDevicePixels="True"/>
</Grid>
<!-- AUTO checkbox — sits outside the column pair; placed in Column=1 outside normal layout -->
<CheckBox IsChecked="{Binding IsAutoMode}"
Content="{DynamicResource Dfi.Auto}"
Grid.Row="0" Grid.Column="1"
Height="Auto"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,10,0"
Foreground="Black" FontSize="20"/>
<!-- BOTTOM RIGHT: slider with range labels + current value -->
<Grid Grid.Row="1" Grid.Column="1">
<Slider Value="{Binding SliderRaw}"
Minimum="-145" Maximum="145"
TickFrequency="5" SmallChange="5" LargeChange="5"
IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Margin="10,0" VerticalAlignment="Center"
Foreground="Black"/>
<TextBlock Text="-1.45" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10,0,0,0" Foreground="DimGray"/>
<TextBlock Text="+1.45" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,10,0" Foreground="DimGray"/>
<TextBlock Text="{Binding SliderDfiValue, StringFormat=F2, Mode=OneWay}"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Margin="0,0,0,4" FontSize="20" Foreground="Black"/>
</Grid>
</Grid>
</UserControl>

View File

@@ -1,10 +0,0 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>Code-behind for DfiManageView — no logic; all behaviour is in the ViewModel.</summary>
public partial class DfiManageView : UserControl
{
public DfiManageView() => InitializeComponent();
}
}

View File

@@ -0,0 +1,102 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.DtcCard"
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"
mc:Ignorable="d"
d:DesignHeight="280" d:DesignWidth="320">
<!-- DataContext = DtcListViewModel (via {Binding DtcList}) -->
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</UserControl.Resources>
<Border Style="{StaticResource PumpCard}">
<DockPanel LastChildFill="True">
<!-- ── Card header ───────────────────────────────────────────── -->
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,10">
<ui:SymbolIcon DockPanel.Dock="Left" Symbol="Warning24" FontSize="16"
Foreground="{DynamicResource SystemFillColorCautionBrush}"
Margin="0,0,8,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Pump.Dtcs.Title}"
Style="{StaticResource PumpCardHeader}" Margin="0"/>
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal"
VerticalAlignment="Center" HorizontalAlignment="Right">
<ui:Button Content="{DynamicResource Dtc.Read}"
Command="{Binding ReadCommand}"
Appearance="Secondary"
Height="28" Margin="0,0,6,0"/>
<ui:Button Content="{DynamicResource Dtc.Clear}"
Command="{Binding ClearCommand}"
Appearance="Secondary"
Height="28"/>
</StackPanel>
</DockPanel>
<!-- ── Busy indicator ─────────────────────────────────────────── -->
<ProgressBar DockPanel.Dock="Top"
IsIndeterminate="True" Height="3" Margin="0,0,0,6"
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVis}}"/>
<!-- ── Status text ─────────────────────────────────────────────── -->
<TextBlock DockPanel.Dock="Top"
Text="{Binding StatusText}"
FontSize="11"
Foreground="{DynamicResource TextFillColorTertiaryBrush}"
Margin="0,0,0,6"/>
<!-- ── "No faults" success pill ───────────────────────────────── -->
<Border DockPanel.Dock="Top"
Background="{DynamicResource SystemFillColorSuccessBackgroundBrush}"
BorderBrush="{DynamicResource SystemFillColorSuccessBrush}"
BorderThickness="1" CornerRadius="6" Padding="10,6"
HorizontalAlignment="Left" Margin="0,0,0,4"
Visibility="{Binding IsClear, Converter={StaticResource BoolToVis}}">
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon Symbol="CheckmarkCircle24" FontSize="14"
Foreground="{DynamicResource SystemFillColorSuccessBrush}"
Margin="0,0,6,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Dtc.NoFaults}"
FontSize="12" FontWeight="SemiBold"
Foreground="{DynamicResource SystemFillColorSuccessBrush}"
VerticalAlignment="Center"/>
</StackPanel>
</Border>
<!-- ── DTC rows ───────────────────────────────────────────────── -->
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Codes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="{DynamicResource SystemFillColorCautionBackgroundBrush}"
BorderBrush="{DynamicResource SystemFillColorCautionBrush}"
BorderThickness="0,0,0,1" CornerRadius="4"
Padding="8,6" Margin="0,2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Code}"
FontFamily="Consolas" FontWeight="Bold"
FontSize="12"
Foreground="{DynamicResource SystemFillColorCriticalBrush}"
VerticalAlignment="Center"/>
<TextBlock Grid.Column="1"
Text="{Binding Description}"
FontSize="12"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
TextWrapping="Wrap"
VerticalAlignment="Center"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DockPanel>
</Border>
</UserControl>

View File

@@ -0,0 +1,9 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
public partial class DtcCard : UserControl
{
public DtcCard() => InitializeComponent();
}
}

View File

@@ -1,94 +0,0 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.DtcListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="360" d:DesignWidth="700">
<!--
Pump page §3.b DTC list. DataContext = DtcListViewModel.
Moves the fault-code surface out of the one-shot KlineErrorsDialog
into a proper sub-section with read / clear actions and a row list.
-->
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</UserControl.Resources>
<Border Background="#FAFAFA" BorderBrush="#DDD" BorderThickness="1"
CornerRadius="4" Padding="12" Margin="6">
<DockPanel>
<!-- ── Header row: title + actions ─────────────────────────── -->
<Grid DockPanel.Dock="Top" Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{DynamicResource PumpSub.Dtcs}"
FontSize="15" FontWeight="SemiBold" Foreground="#333"
VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Button Content="{DynamicResource Dtc.Read}"
Command="{Binding ReadCommand}"
MinWidth="90" Height="28" Margin="0,0,6,0"
FontWeight="Bold"/>
<Button Content="{DynamicResource Dtc.Clear}"
Command="{Binding ClearCommand}"
MinWidth="90" Height="28"/>
</StackPanel>
</Grid>
<!-- ── Status line ─────────────────────────────────────────── -->
<TextBlock DockPanel.Dock="Top"
Text="{Binding StatusText}"
Foreground="#666" FontSize="11" Margin="0,0,0,6"/>
<!-- ── Busy indicator ──────────────────────────────────────── -->
<ProgressBar DockPanel.Dock="Top"
IsIndeterminate="True" Height="3" Margin="0,0,0,6"
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVis}}"/>
<!-- ── "No faults" banner ──────────────────────────────────── -->
<Border DockPanel.Dock="Top"
Background="#26C200" CornerRadius="3" Padding="10,6"
HorizontalAlignment="Left"
Visibility="{Binding IsClear, Converter={StaticResource BoolToVis}}">
<TextBlock Text="{DynamicResource Dtc.NoFaults}"
Foreground="White" FontWeight="Bold" FontSize="12"/>
</Border>
<!-- ── DTC rows ────────────────────────────────────────────── -->
<ListBox ItemsSource="{Binding Codes}"
BorderThickness="0" Background="Transparent">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="0"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Background="#FDECEA" BorderBrush="#D62828"
BorderThickness="0,0,0,1" Padding="8,6" Margin="0,2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Code}"
FontFamily="Consolas" FontWeight="Bold"
FontSize="13" Foreground="#B22222"
VerticalAlignment="Center"/>
<TextBlock Grid.Column="1"
Text="{Binding Description}"
FontSize="12" Foreground="#333"
TextWrapping="Wrap"
VerticalAlignment="Center"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Border>
</UserControl>

View File

@@ -1,16 +0,0 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>
/// Pump page §3.b DTC list view. DataContext is
/// <c>DtcListViewModel</c>.
/// </summary>
public partial class DtcListView : UserControl
{
public DtcListView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,231 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.PumpCommandsCard"
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"
mc:Ignorable="d"
d:DesignHeight="460" d:DesignWidth="260"
IsEnabled="{Binding IsEnabled}">
<!-- DataContext = PumpControlViewModel (via {Binding PumpControl}) -->
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
<Style x:Key="SettingsTextBox" TargetType="TextBox">
<Setter Property="Width" Value="44"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="FontSize" Value="13"/>
</Style>
<Style x:Key="SettingsLabel" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Margin" Value="0,2,0,0"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</UserControl.Resources>
<Border Style="{StaticResource PumpCard}">
<DockPanel LastChildFill="True">
<!-- ── Card header ───────────────────────────────────────────── -->
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,12">
<ui:SymbolIcon DockPanel.Dock="Left" Symbol="ArrowTrendingLines24" FontSize="16"
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
Margin="0,0,8,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Pump.Commands.Title}"
Style="{StaticResource PumpCardHeader}" Margin="0"/>
</DockPanel>
<!-- ── Slider columns ────────────────────────────────────────── -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<!-- PreIn: collapses when not applicable -->
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- ── FBKW ────────────────────────────────────────────── -->
<StackPanel Grid.Column="0" HorizontalAlignment="Center">
<!-- Settings toggle -->
<ToggleButton x:Name="FbkwToggle"
Width="28" Height="22"
HorizontalAlignment="Center"
Background="Transparent" BorderBrush="Transparent"
Content="..." FontWeight="Bold" FontSize="13"
ToolTip="{DynamicResource PumpCtrl.MinStepMax}"/>
<!-- Max label -->
<TextBlock Text="{Binding FbkwMax, StringFormat=F1}"
Style="{StaticResource PumpCommandLabel}"
Margin="0,4,0,2"/>
<!-- Vertical slider -->
<Slider Orientation="Vertical"
Minimum="{Binding FbkwMin}" Maximum="{Binding FbkwMax}"
Value="{Binding FbkwValue}"
TickFrequency="{Binding FbkwStep}"
TickPlacement="TopLeft"
IsSnapToTickEnabled="True"
AutoToolTipPrecision="2"
Height="240" Width="32"
HorizontalAlignment="Center"
Focusable="False"/>
<!-- Min label -->
<TextBlock Text="{Binding FbkwMin, StringFormat=F1}"
Style="{StaticResource PumpCommandLabel}"
Margin="0,2,0,6"/>
<!-- Editable value box -->
<TextBox Text="{Binding FbkwValue, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}"
Style="{StaticResource PumpCommandValue}"/>
<!-- Parameter name -->
<TextBlock Text="{DynamicResource Pump.Commands.Fbkw}"
Style="{StaticResource PumpCommandLabel}"
Margin="0,6,0,0"/>
<!-- Settings popup -->
<Popup IsOpen="{Binding IsChecked, ElementName=FbkwToggle}"
StaysOpen="False" Placement="Bottom" AllowsTransparency="True">
<Border Background="#BB000000" Padding="8,6" CornerRadius="3">
<UniformGrid Columns="3" Width="180">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding FbkwMin, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Min}" Style="{StaticResource SettingsLabel}"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding FbkwStep, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Step}" Style="{StaticResource SettingsLabel}"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding FbkwMax, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Max}" Style="{StaticResource SettingsLabel}"/>
</StackPanel>
</UniformGrid>
</Border>
</Popup>
</StackPanel>
<!-- ── ME ──────────────────────────────────────────────── -->
<StackPanel Grid.Column="1" HorizontalAlignment="Center">
<ToggleButton x:Name="MeToggle"
Width="28" Height="22"
HorizontalAlignment="Center"
Background="Transparent" BorderBrush="Transparent"
Content="..." FontWeight="Bold" FontSize="13"
ToolTip="{DynamicResource PumpCtrl.MinStepMax}"/>
<TextBlock Text="{Binding MeMax, StringFormat=F1}"
Style="{StaticResource PumpCommandLabel}"
Margin="0,4,0,2"/>
<Slider Orientation="Vertical"
Minimum="{Binding MeMin}" Maximum="{Binding MeMax}"
Value="{Binding MeValue}"
TickFrequency="{Binding MeStep}"
TickPlacement="TopLeft"
IsSnapToTickEnabled="False"
AutoToolTipPrecision="2"
Height="240" Width="32"
HorizontalAlignment="Center"
Focusable="False"/>
<TextBlock Text="{Binding MeMin, StringFormat=F1}"
Style="{StaticResource PumpCommandLabel}"
Margin="0,2,0,6"/>
<TextBox Text="{Binding MeValue, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}"
Style="{StaticResource PumpCommandValue}"/>
<TextBlock Text="{DynamicResource Pump.Commands.Me}"
Style="{StaticResource PumpCommandLabel}"
Margin="0,6,0,0"/>
<Popup IsOpen="{Binding IsChecked, ElementName=MeToggle}"
StaysOpen="False" Placement="Bottom" AllowsTransparency="True">
<Border Background="#BB000000" Padding="8,6" CornerRadius="3">
<UniformGrid Columns="3" Width="180">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding MeMin, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Min}" Style="{StaticResource SettingsLabel}"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding MeStep, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Step}" Style="{StaticResource SettingsLabel}"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding MeMax, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Max}" Style="{StaticResource SettingsLabel}"/>
</StackPanel>
</UniformGrid>
</Border>
</Popup>
</StackPanel>
<!-- ── PreIn (conditional) ─────────────────────────────── -->
<StackPanel Grid.Column="2" HorizontalAlignment="Center"
Visibility="{Binding IsPreInVisible, Converter={StaticResource BoolToVis}}">
<ToggleButton x:Name="PreInToggle"
Width="28" Height="22"
HorizontalAlignment="Center"
Background="Transparent" BorderBrush="Transparent"
Content="..." FontWeight="Bold" FontSize="13"
ToolTip="{DynamicResource PumpCtrl.MinStepMax}"/>
<TextBlock Text="{Binding PreInMax, StringFormat=F1}"
Style="{StaticResource PumpCommandLabel}"
Margin="0,4,0,2"/>
<Slider Orientation="Vertical"
Minimum="{Binding PreInMin}" Maximum="{Binding PreInMax}"
Value="{Binding PreInValue}"
TickFrequency="{Binding PreInStep}"
TickPlacement="TopLeft"
IsSnapToTickEnabled="True"
AutoToolTipPrecision="2"
Height="240" Width="32"
HorizontalAlignment="Center"
Focusable="False"/>
<TextBlock Text="{Binding PreInMin, StringFormat=F1}"
Style="{StaticResource PumpCommandLabel}"
Margin="0,2,0,6"/>
<TextBox Text="{Binding PreInValue, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}"
Style="{StaticResource PumpCommandValue}"/>
<TextBlock Text="{DynamicResource Pump.Commands.PreIn}"
Style="{StaticResource PumpCommandLabel}"
Margin="0,6,0,0"/>
<Popup IsOpen="{Binding IsChecked, ElementName=PreInToggle}"
StaysOpen="False" Placement="Bottom" AllowsTransparency="True">
<Border Background="#BB000000" Padding="8,6" CornerRadius="3">
<UniformGrid Columns="3" Width="180">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding PreInMin, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Min}" Style="{StaticResource SettingsLabel}"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding PreInStep, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Step}" Style="{StaticResource SettingsLabel}"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding PreInMax, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Max}" Style="{StaticResource SettingsLabel}"/>
</StackPanel>
</UniformGrid>
</Border>
</Popup>
</StackPanel>
</Grid>
</DockPanel>
</Border>
</UserControl>

View File

@@ -0,0 +1,9 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
public partial class PumpCommandsCard : UserControl
{
public PumpCommandsCard() => InitializeComponent();
}
}

View File

@@ -1,194 +0,0 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.PumpControlView"
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"
mc:Ignorable="d"
d:DesignHeight="260" d:DesignWidth="440"
IsEnabled="{Binding IsEnabled}">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
<!-- Shared style for the settings popup min/max/step text boxes -->
<Style x:Key="SettingsTextBox" TargetType="TextBox">
<Setter Property="Width" Value="40"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!-- Label inside settings popup -->
<Style x:Key="SettingsLabel" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Margin" Value="0,2,0,0"/>
</Style>
</UserControl.Resources>
<StackPanel>
<!-- ═══ FBKW — Advance Control ═══════════════════════════════════════ -->
<Grid Margin="6,6,6,2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{DynamicResource PumpCtrl.Fbkw}" HorizontalAlignment="Center"
FontSize="13" Foreground="Black" Margin="0,0,0,2"/>
<DockPanel Grid.Row="1" Margin="4,0,4,2">
<!-- Settings button -->
<ToggleButton x:Name="FbkwSettingsToggle" DockPanel.Dock="Left"
Width="28" Height="28" Margin="0,0,4,0"
Background="Transparent" BorderBrush="Transparent"
Content="..." FontWeight="Bold" FontSize="14"
ToolTip="{DynamicResource PumpCtrl.MinStepMax}"/>
<!-- Numeric text box -->
<TextBox DockPanel.Dock="Right" Width="50" Height="28" Margin="4,0,0,0"
TextAlignment="Center" VerticalContentAlignment="Center"
FontWeight="Bold" FontSize="13"
Text="{Binding FbkwValue, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}"/>
<!-- Slider -->
<Slider Minimum="{Binding FbkwMin}" Maximum="{Binding FbkwMax}"
Value="{Binding FbkwValue}" TickFrequency="{Binding FbkwStep}"
TickPlacement="BottomRight" AutoToolTipPrecision="2"
IsSnapToTickEnabled="True" VerticalAlignment="Center"
Focusable="False" Foreground="Black"/>
</DockPanel>
<!-- Settings popup -->
<Popup IsOpen="{Binding IsChecked, ElementName=FbkwSettingsToggle}"
StaysOpen="False" Placement="Bottom" AllowsTransparency="True"
HorizontalOffset="30">
<Border Background="#BB000000" Padding="8,6" CornerRadius="3">
<UniformGrid Columns="3" Width="180">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding FbkwMin, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Min}" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding FbkwStep, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Step}" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding FbkwMax, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Max}" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
</UniformGrid>
</Border>
</Popup>
</Grid>
<!-- ═══ ME — Quantity Control ════════════════════════════════════════ -->
<Grid Margin="6,4,6,2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{DynamicResource PumpCtrl.Me}" HorizontalAlignment="Center"
FontSize="13" Foreground="Black" Margin="0,0,0,2"/>
<DockPanel Grid.Row="1" Margin="4,0,4,2">
<ToggleButton x:Name="MeSettingsToggle" DockPanel.Dock="Left"
Width="28" Height="28" Margin="0,0,4,0"
Background="Transparent" BorderBrush="Transparent"
Content="..." FontWeight="Bold" FontSize="14"
ToolTip="{DynamicResource PumpCtrl.MinStepMax}"/>
<TextBox DockPanel.Dock="Right" Width="50" Height="28" Margin="4,0,0,0"
TextAlignment="Center" VerticalContentAlignment="Center"
FontWeight="Bold" FontSize="13"
Text="{Binding MeValue, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}"/>
<Slider Minimum="{Binding MeMin}" Maximum="{Binding MeMax}"
Value="{Binding MeValue}" TickFrequency="{Binding MeStep}"
TickPlacement="BottomRight" AutoToolTipPrecision="2"
IsSnapToTickEnabled="False" VerticalAlignment="Center"
Focusable="False" Foreground="Black"/>
</DockPanel>
<Popup IsOpen="{Binding IsChecked, ElementName=MeSettingsToggle}"
StaysOpen="False" Placement="Bottom" AllowsTransparency="True"
HorizontalOffset="30">
<Border Background="#BB000000" Padding="8,6" CornerRadius="3">
<UniformGrid Columns="3" Width="180">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding MeMin, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Min}" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding MeStep, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Step}" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding MeMax, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Max}" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
</UniformGrid>
</Border>
</Popup>
</Grid>
<!-- ═══ PreIn — Pre-injection Quantity ═══════════════════════════════ -->
<Grid Margin="6,4,6,2"
Visibility="{Binding IsPreInVisible, Converter={StaticResource BoolToVis}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{DynamicResource PumpCtrl.PreInj}" HorizontalAlignment="Center"
FontSize="13" Foreground="Black" Margin="0,0,0,2"/>
<DockPanel Grid.Row="1" Margin="4,0,4,2">
<ToggleButton x:Name="PreInSettingsToggle" DockPanel.Dock="Left"
Width="28" Height="28" Margin="0,0,4,0"
Background="Transparent" BorderBrush="Transparent"
Content="..." FontWeight="Bold" FontSize="14"
ToolTip="{DynamicResource PumpCtrl.MinStepMax}"/>
<TextBox DockPanel.Dock="Right" Width="50" Height="28" Margin="4,0,0,0"
TextAlignment="Center" VerticalContentAlignment="Center"
FontWeight="Bold" FontSize="13"
Text="{Binding PreInValue, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}"/>
<Slider Minimum="{Binding PreInMin}" Maximum="{Binding PreInMax}"
Value="{Binding PreInValue}" TickFrequency="{Binding PreInStep}"
TickPlacement="BottomRight" AutoToolTipPrecision="2"
IsSnapToTickEnabled="True" VerticalAlignment="Center"
Focusable="False" Foreground="Black"/>
</DockPanel>
<Popup IsOpen="{Binding IsChecked, ElementName=PreInSettingsToggle}"
StaysOpen="False" Placement="Bottom" AllowsTransparency="True"
HorizontalOffset="30">
<Border Background="#BB000000" Padding="8,6" CornerRadius="3">
<UniformGrid Columns="3" Width="180">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding PreInMin, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Min}" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding PreInStep, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Step}" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding PreInMax, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="{DynamicResource PumpCtrl.Max}" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
</UniformGrid>
</Border>
</Popup>
</Grid>
</StackPanel>
</UserControl>

View File

@@ -1,15 +0,0 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>
/// Manual pump control sliders (FBKW, ME, PreIn) with configurable min/max/step popups.
/// </summary>
public partial class PumpControlView : UserControl
{
public PumpControlView()
{
InitializeComponent();
}
}
}

View File

@@ -1,97 +1,82 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.PumpIdentificationPanelView"
<UserControl x:Class="HC_APTBS.Views.UserControls.PumpIdentificationCard"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
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"
mc:Ignorable="d"
d:DesignHeight="360" d:DesignWidth="700">
<!--
Pump-page variant of PumpIdentificationView (spec §3.a Identification).
Reuses PumpIdentificationViewModel. Presents the ECU info panel
in a larger, two-column format suitable for the Pump page.
-->
d:DesignHeight="360" d:DesignWidth="320">
<!-- DataContext = PumpIdentificationViewModel (via {Binding Identification}) -->
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
<Style x:Key="IdLabel" TargetType="TextBlock">
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#555"/>
<Setter Property="Width" Value="110"/>
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}"/>
<Setter Property="Width" Value="88"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style x:Key="IdValue" TargetType="TextBlock">
<Setter Property="FontSize" Value="13"/>
<Setter Property="FontFamily" Value="Consolas"/>
<Setter Property="FontFamily" Value="Consolas"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
</Style>
</UserControl.Resources>
<Border Background="#FAFAFA" BorderBrush="#DDD" BorderThickness="1"
CornerRadius="4" Padding="12" Margin="6">
<StackPanel>
<Border Style="{StaticResource PumpCard}">
<DockPanel LastChildFill="True">
<!-- ── Section title ────────────────────────────────────────── -->
<TextBlock Text="{DynamicResource PumpSub.Identification}"
FontSize="15" FontWeight="SemiBold" Foreground="#333"
Margin="0,0,0,8"/>
<!-- ── Card header ───────────────────────────────────────────── -->
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,12">
<ui:SymbolIcon DockPanel.Dock="Left" Symbol="Server24" FontSize="16"
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
Margin="0,0,8,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Pump.Identification.Title}"
Style="{StaticResource PumpCardHeader}"/>
</DockPanel>
<!-- ── Pump selector row ────────────────────────────────────── -->
<Grid Margin="0,0,0,10">
<!-- ── Action row: Read + Disconnect + progress ──────────────── -->
<Grid DockPanel.Dock="Top" Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{DynamicResource PumpId.Label}"
VerticalAlignment="Center" FontSize="13"/>
<ComboBox Grid.Column="1"
ItemsSource="{Binding PumpIds}"
SelectedItem="{Binding SelectedPumpId}"
FontSize="18" Margin="0,0,12,0"
VerticalContentAlignment="Center"/>
<TextBlock Grid.Column="2"
Text="{Binding CurrentPump.Model}"
FontSize="13" Foreground="#888"
VerticalAlignment="Center"/>
</Grid>
<!-- ── Action row: Read + Disconnect + progress ─────────────── -->
<Grid Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="8"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Content="{DynamicResource PumpId.ReadKLine}"
Command="{Binding ReadKlineCommand}"
MinWidth="130" Height="34" FontWeight="Bold"
Margin="0,0,8,0"/>
<Button Grid.Column="1"
Content="{DynamicResource PumpId.Disconnect}"
Command="{Binding DisconnectKLineCommand}"
MinWidth="110" Height="34"
Margin="0,0,12,0"/>
<StackPanel Grid.Column="2"
Orientation="Vertical"
VerticalAlignment="Center"
Visibility="{Binding IsReading, Converter={StaticResource BoolToVis}}">
<TextBlock Text="{Binding ProgressMessage}"
FontSize="11" Foreground="#666"
TextTrimming="CharacterEllipsis"/>
<ProgressBar Value="{Binding ProgressPercent, Mode=OneWay}"
Minimum="0" Maximum="100" Height="8" Margin="0,2,0,0"/>
</StackPanel>
<ui:Button Grid.Column="0"
Content="{DynamicResource PumpId.ReadKLine}"
Command="{Binding ReadKlineCommand}"
Appearance="Primary"
FontWeight="Bold" Height="32"/>
<ui:Button Grid.Column="2"
Content="{DynamicResource PumpId.Disconnect}"
Command="{Binding DisconnectKLineCommand}"
Appearance="Secondary"
Height="32"/>
</Grid>
<!-- ── Two-column ECU info grid ─────────────────────────────── -->
<!-- ── Inline progress (visible while reading) ───────────────── -->
<StackPanel DockPanel.Dock="Top"
Margin="0,0,0,8"
Visibility="{Binding IsReading, Converter={StaticResource BoolToVis}}">
<TextBlock Text="{Binding ProgressMessage}"
FontSize="11"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
TextTrimming="CharacterEllipsis"
Margin="0,0,0,3"/>
<ProgressBar Value="{Binding ProgressPercent, Mode=OneWay}"
Minimum="0" Maximum="100" Height="4"/>
</StackPanel>
<!-- ── ECU info: two columns ─────────────────────────────────── -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="8"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
@@ -139,14 +124,18 @@
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2">
<TextBlock Text="{DynamicResource PumpId.Errors}" Style="{StaticResource IdLabel}"/>
<TextBlock Text="{Binding KlineErrors}" Style="{StaticResource IdValue}" Foreground="DarkRed"/>
<TextBlock Text="{Binding KlineErrors}" Style="{StaticResource IdValue}"
Foreground="{DynamicResource SystemFillColorCriticalBrush}"/>
</StackPanel>
</StackPanel>
</Grid>
<!-- ── Connection error footer (auto-collapses) ─────────────── -->
<Border Background="#FDECEA" BorderBrush="#D62828" BorderThickness="1"
CornerRadius="3" Padding="8,4" Margin="0,10,0,0">
<!-- ── Connection error footer ──────────────────────────────── -->
<Border DockPanel.Dock="Bottom"
Background="{DynamicResource SystemFillColorCriticalBackgroundBrush}"
BorderBrush="{DynamicResource SystemFillColorCriticalBrush}"
BorderThickness="1" CornerRadius="4"
Padding="8,4" Margin="0,10,0,0">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
@@ -157,9 +146,11 @@
</Style>
</Border.Style>
<TextBlock Text="{Binding KlineConnectError}"
FontSize="12" FontFamily="Consolas" Foreground="#B22222"
FontSize="11" FontFamily="Consolas"
Foreground="{DynamicResource SystemFillColorCriticalBrush}"
TextWrapping="Wrap"/>
</Border>
</StackPanel>
</DockPanel>
</Border>
</UserControl>

View File

@@ -0,0 +1,9 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
public partial class PumpIdentificationCard : UserControl
{
public PumpIdentificationCard() => InitializeComponent();
}
}

View File

@@ -1,17 +0,0 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>
/// Larger page-scoped variant of <see cref="PumpIdentificationView"/> used by the
/// Pump page §3.a Identification sub-section. DataContext is
/// <c>PumpIdentificationViewModel</c>.
/// </summary>
public partial class PumpIdentificationPanelView : UserControl
{
public PumpIdentificationPanelView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,175 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.PumpLiveDataCard"
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:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
xmlns:uc="clr-namespace:HC_APTBS.Views.UserControls"
mc:Ignorable="d"
d:DesignHeight="700" d:DesignWidth="500">
<!--
DataContext = PumpPageViewModel.
Live values accessed via Root.PumpRpm / Root.PumpTemp / Root.PumpMe / Root.PumpFbkw / Root.PumpTein.
Status words accessed via StatusDisplay1 and StatusDisplay2 (both StatusDisplayViewModel).
RPM chart via RpmChart (SingleFlowChartViewModel).
-->
<Border Style="{StaticResource PumpCard}">
<DockPanel LastChildFill="True">
<!-- ── Card header ───────────────────────────────────────────── -->
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,12">
<ui:SymbolIcon DockPanel.Dock="Left" Symbol="PulseSquare24" FontSize="16"
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
Margin="0,0,8,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Pump.LiveData.Title}"
Style="{StaticResource PumpCardHeader}" Margin="0"/>
</DockPanel>
<!-- ── Status displays (docked bottom so chart gets the middle) ── -->
<StackPanel DockPanel.Dock="Bottom" Margin="0,8,0,0">
<uc:StatusDisplayView DataContext="{Binding StatusDisplay1}" Margin="0,0,0,8"/>
<uc:StatusDisplayView DataContext="{Binding StatusDisplay2}"/>
</StackPanel>
<!-- ── RPM chart (docked bottom of the upper area) ──────────── -->
<Border DockPanel.Dock="Bottom"
Background="{DynamicResource ControlFillColorSecondaryBrush}"
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
BorderThickness="1" CornerRadius="6"
Padding="4,4" Margin="0,8,0,0">
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Top"
Text="{DynamicResource Pump.LiveData.RpmChart}"
FontSize="11"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Margin="4,0,0,2"/>
<lvc:CartesianChart Height="110"
Series="{Binding RpmChart.Series}"
XAxes="{Binding RpmChart.XAxes}"
YAxes="{Binding RpmChart.YAxes}"
TooltipPosition="Hidden"
AnimationsSpeed="00:00:00"/>
</DockPanel>
</Border>
<!-- ── KPI tiles (top portion, fills remaining space) ────────── -->
<UniformGrid Rows="1" Columns="5">
<!-- RPM -->
<Border Style="{StaticResource KpiTile}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon Symbol="Gauge24" FontSize="14"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Margin="0,0,4,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Pump.LiveData.RPM}"
Style="{StaticResource KpiHeaderText}" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Bottom">
<TextBlock Text="{Binding Root.PumpRpm, StringFormat=F0}"
Style="{StaticResource KpiValueText}" FontSize="32"/>
<TextBlock Text="{DynamicResource Pump.UnitRpm}"
Style="{StaticResource KpiUnitText}"/>
</StackPanel>
</Grid>
</Border>
<!-- T-hyb -->
<Border Style="{StaticResource KpiTile}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon Symbol="Temperature24" FontSize="14"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Margin="0,0,4,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Pump.LiveData.THyb}"
Style="{StaticResource KpiHeaderText}" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Bottom">
<TextBlock Text="{Binding Root.PumpTemp, StringFormat=F1}"
Style="{StaticResource KpiValueText}" FontSize="32"/>
<TextBlock Text="{DynamicResource Pump.UnitCelsius}"
Style="{StaticResource KpiUnitText}"/>
</StackPanel>
</Grid>
</Border>
<!-- T-ein -->
<Border Style="{StaticResource KpiTile}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon Symbol="Timer24" FontSize="14"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Margin="0,0,4,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Pump.LiveData.TEin}"
Style="{StaticResource KpiHeaderText}" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Bottom">
<TextBlock Text="{Binding Root.PumpTein, StringFormat=F0}"
Style="{StaticResource KpiValueText}" FontSize="32"/>
<TextBlock Text="{DynamicResource Pump.UnitUs}"
Style="{StaticResource KpiUnitText}"/>
</StackPanel>
</Grid>
</Border>
<!-- ME -->
<Border Style="{StaticResource KpiTile}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon Symbol="ArrowTrendingLines24" FontSize="14"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Margin="0,0,4,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Pump.LiveData.Me}"
Style="{StaticResource KpiHeaderText}" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Bottom">
<TextBlock Text="{Binding Root.PumpMe, StringFormat=F2}"
Style="{StaticResource KpiValueText}" FontSize="32"/>
</StackPanel>
</Grid>
</Border>
<!-- FBKW -->
<Border Style="{StaticResource KpiTile}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon Symbol="ArrowTrendingLines24" FontSize="14"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Margin="0,0,4,0" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource Pump.LiveData.Fbkw}"
Style="{StaticResource KpiHeaderText}" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Bottom">
<TextBlock Text="{Binding Root.PumpFbkw, StringFormat=F2}"
Style="{StaticResource KpiValueText}" FontSize="32"/>
</StackPanel>
</Grid>
</Border>
</UniformGrid>
</DockPanel>
</Border>
</UserControl>

View File

@@ -0,0 +1,9 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
public partial class PumpLiveDataCard : UserControl
{
public PumpLiveDataCard() => InitializeComponent();
}
}

View File

@@ -1,130 +0,0 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.PumpLiveDataView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uc="clr-namespace:HC_APTBS.Views.UserControls"
mc:Ignorable="d"
d:DesignHeight="380" d:DesignWidth="700">
<!--
Pump page §3.c Live Data. DataContext = PumpPageViewModel so the view
can reach the MainViewModel-owned live readings via {Binding Root.X}
and the two StatusDisplay VMs.
-->
<Border Background="#FAFAFA" BorderBrush="#DDD" BorderThickness="1"
CornerRadius="4" Padding="12" Margin="6">
<StackPanel>
<!-- ── Section title ─────────────────────────────────────────── -->
<TextBlock Text="{DynamicResource PumpSub.LiveData}"
FontSize="15" FontWeight="SemiBold" Foreground="#333"
Margin="0,0,0,8"/>
<!-- ── LCD-style readings block ──────────────────────────────── -->
<Border Style="{StaticResource LcdBlue}" Padding="10,6">
<Grid Height="110">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90"/>
<ColumnDefinition/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<!-- Left column: T-hyb / RPM / T-ein -->
<TextBlock Text="{DynamicResource Pump.THyb}"
VerticalAlignment="Center" Foreground="#EBEBFF" FontSize="13"/>
<TextBlock Text="{DynamicResource Pump.Rpm}"
Grid.Row="1" VerticalAlignment="Center" Foreground="#EBEBFF" FontSize="13"/>
<TextBlock Text="{DynamicResource Pump.TEin}"
Grid.Row="2" VerticalAlignment="Center" Foreground="#EBEBFF" FontSize="13"/>
<TextBlock Text="{Binding Root.PumpTemp, StringFormat=F2}"
Grid.Column="1"
HorizontalAlignment="Right" VerticalAlignment="Center"
Foreground="#EBEBFF" FontSize="22" FontWeight="Bold" FontFamily="Consolas"/>
<TextBlock Text="{Binding Root.PumpRpm, StringFormat=F0}"
Grid.Column="1" Grid.Row="1"
HorizontalAlignment="Right" VerticalAlignment="Center"
Foreground="#EBEBFF" FontSize="22" FontWeight="Bold" FontFamily="Consolas"/>
<TextBlock Text="{Binding Root.PumpTein, StringFormat=F0}"
Grid.Column="1" Grid.Row="2"
HorizontalAlignment="Right" VerticalAlignment="Center"
Foreground="#EBEBFF" FontSize="22" FontWeight="Bold" FontFamily="Consolas"/>
<TextBlock Text="°C" Grid.Column="2"
VerticalAlignment="Center" Foreground="#EBEBFF" FontSize="12" Margin="4,0"/>
<TextBlock Text="{DynamicResource Pump.UnitRpm}"
Grid.Column="2" Grid.Row="1"
VerticalAlignment="Center" Foreground="#EBEBFF" FontSize="12" Margin="4,0"/>
<TextBlock Text="µs" Grid.Column="2" Grid.Row="2"
VerticalAlignment="Center" Foreground="#EBEBFF" FontSize="12" Margin="4,0"/>
<!-- Right column: ME / FBKW -->
<TextBlock Text="{DynamicResource Bench.PumpMe}"
Grid.Column="4" VerticalAlignment="Center" Foreground="#EBEBFF" FontSize="13"/>
<TextBlock Text="{DynamicResource Bench.PumpFbkw}"
Grid.Column="4" Grid.Row="1"
VerticalAlignment="Center" Foreground="#EBEBFF" FontSize="13"/>
<TextBlock Text="{Binding Root.PumpMe, StringFormat=F2}"
Grid.Column="5"
HorizontalAlignment="Right" VerticalAlignment="Center"
Foreground="#EBEBFF" FontSize="22" FontWeight="Bold" FontFamily="Consolas"/>
<TextBlock Text="{Binding Root.PumpFbkw, StringFormat=F2}"
Grid.Column="5" Grid.Row="1"
HorizontalAlignment="Right" VerticalAlignment="Center"
Foreground="#EBEBFF" FontSize="22" FontWeight="Bold" FontFamily="Consolas"/>
</Grid>
</Border>
<!-- ── Status displays (Status word + Empf3) ─────────────────── -->
<StackPanel Margin="0,8,0,0">
<uc:StatusDisplayView DataContext="{Binding StatusDisplay1}"/>
<uc:StatusDisplayView DataContext="{Binding StatusDisplay2}" Margin="0,4,0,0"/>
</StackPanel>
<!-- ── Engineering expander (raw values) ─────────────────────── -->
<Expander Header="{DynamicResource PumpLive.Engineering}"
IsExpanded="False" Margin="0,10,0,0" FontSize="12">
<Border Background="#1E1E1E" Padding="10,6" CornerRadius="2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock Foreground="#9CDCFE" FontFamily="Consolas" FontSize="11">
<Run Text="PumpRpm = "/><Run Text="{Binding Root.PumpRpm, StringFormat=F2, Mode=OneWay}"/>
</TextBlock>
<TextBlock Foreground="#9CDCFE" FontFamily="Consolas" FontSize="11">
<Run Text="PumpTemp = "/><Run Text="{Binding Root.PumpTemp, StringFormat=F2, Mode=OneWay}"/>
</TextBlock>
<TextBlock Foreground="#9CDCFE" FontFamily="Consolas" FontSize="11">
<Run Text="PumpMe = "/><Run Text="{Binding Root.PumpMe, StringFormat=F3, Mode=OneWay}"/>
</TextBlock>
</StackPanel>
<StackPanel Grid.Column="1">
<TextBlock Foreground="#9CDCFE" FontFamily="Consolas" FontSize="11">
<Run Text="PumpFbkw = "/><Run Text="{Binding Root.PumpFbkw, StringFormat=F3, Mode=OneWay}"/>
</TextBlock>
<TextBlock Foreground="#9CDCFE" FontFamily="Consolas" FontSize="11">
<Run Text="PumpTein = "/><Run Text="{Binding Root.PumpTein, StringFormat=F0, Mode=OneWay}"/>
</TextBlock>
<TextBlock Foreground="#9CDCFE" FontFamily="Consolas" FontSize="11">
<Run Text="KLineState = "/><Run Text="{Binding Root.KLineState, Mode=OneWay}"/>
</TextBlock>
</StackPanel>
</Grid>
</Border>
</Expander>
</StackPanel>
</Border>
</UserControl>

View File

@@ -1,17 +0,0 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>
/// Pump page §3.c Live Data view: pump CAN readings, status-word displays,
/// and a collapsible engineering panel. DataContext is
/// <c>PumpPageViewModel</c> (reaches MainViewModel via <c>Root</c>).
/// </summary>
public partial class PumpLiveDataView : UserControl
{
public PumpLiveDataView()
{
InitializeComponent();
}
}
}

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>

View File

@@ -0,0 +1,9 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
public partial class PumpTopStripView : UserControl
{
public PumpTopStripView() => InitializeComponent();
}
}

View File

@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:conv="clr-namespace:HC_APTBS.Converters"
mc:Ignorable="d"
d:DesignHeight="70" d:DesignWidth="375">
d:DesignHeight="90" d:DesignWidth="340">
<UserControl.Resources>
<conv:HexColorToBrushConverter x:Key="HexToBrush"/>
@@ -13,45 +13,70 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Title -->
<TextBlock Text="{Binding Title}"
HorizontalAlignment="Center" VerticalAlignment="Center"
FontSize="14" FontWeight="SemiBold" Foreground="Black"/>
<!-- Header: title (left) + "Active: n/16" chip (right) -->
<DockPanel Margin="0,0,0,6">
<Border DockPanel.Dock="Right"
Background="{DynamicResource ControlFillColorSecondaryBrush}"
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
BorderThickness="1" CornerRadius="10" Padding="8,2">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Pump.Status.Active}"
FontSize="11" FontFamily="{DynamicResource ContentControlThemeFontFamily}"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Margin="0,0,3,0"/>
<TextBlock Text=": " FontSize="11"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"/>
<TextBlock Text="{Binding ActiveCount}"
FontSize="11" FontWeight="SemiBold"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
<TextBlock Text="/16" FontSize="11"
Foreground="{DynamicResource TextFillColorTertiaryBrush}"/>
</StackPanel>
</Border>
<TextBlock Text="{Binding Title}"
FontSize="12" FontWeight="SemiBold"
FontFamily="{DynamicResource ContentControlThemeFontFamily}"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
VerticalAlignment="Center"/>
</DockPanel>
<!-- 16-bit indicator row -->
<ItemsControl Grid.Row="1"
ItemsSource="{Binding Bits}"
Margin="10,0,10,6">
<!-- 2×8 grid of rounded bit tiles -->
<ItemsControl Grid.Row="1" ItemsSource="{Binding Bits}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
<UniformGrid Rows="2" Columns="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- Each bit: coloured dot + bit-number label -->
<Grid Margin="1,0">
<Grid.RowDefinitions>
<RowDefinition Height="3*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Rectangle Fill="{Binding Color, Converter={StaticResource HexToBrush}}"
Stroke="#5D5D5D" StrokeThickness="1"
Width="16" Height="10"
<Border Margin="2" CornerRadius="4"
BorderThickness="1"
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
MinWidth="28" MinHeight="28"
Background="{Binding Color, Converter={StaticResource HexToBrush}}"
ToolTip="{Binding Description}"
ToolTipService.InitialShowDelay="150"
ToolTipService.ShowDuration="30000"
SnapsToDevicePixels="True">
<TextBlock Text="{Binding Index}"
HorizontalAlignment="Center" VerticalAlignment="Center"
ToolTip="{Binding Description}"
ToolTipService.InitialShowDelay="150"
ToolTipService.ShowDuration="30000"
SnapsToDevicePixels="True"/>
<TextBlock Grid.Row="1" FontSize="12"
Text="{Binding Index}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="DimGray"/>
</Grid>
FontSize="11" FontWeight="SemiBold">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter Property="Foreground" Value="#FFFFFF"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

View File

@@ -1,113 +0,0 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.UnlockPanelView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="380" d:DesignWidth="700">
<!--
Pump page §3.e Unlock inline view. DataContext = UnlockProgressViewModel
(exposed from MainViewModel.CurrentUnlockVm). Hidden by the parent when
the selected pump does not require unlock or the VM is null.
-->
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</UserControl.Resources>
<Border Background="#2B2929" BorderBrush="#111" BorderThickness="1"
CornerRadius="4" Padding="18" Margin="6">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- title -->
<RowDefinition Height="Auto"/> <!-- type label -->
<RowDefinition Height="210"/> <!-- ring -->
<RowDefinition Height="Auto"/> <!-- phase text -->
<RowDefinition Height="Auto"/> <!-- progress bar -->
<RowDefinition Height="Auto"/> <!-- result -->
<RowDefinition Height="Auto"/> <!-- buttons -->
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Text="{DynamicResource PumpSub.Unlock}"
FontSize="15" FontWeight="SemiBold" Foreground="#EEE"
HorizontalAlignment="Center" Margin="0,0,0,4"/>
<TextBlock Grid.Row="1"
Text="{Binding UnlockTypeLabel, Mode=OneWay}"
FontSize="13" Foreground="#AAA"
HorizontalAlignment="Center" Margin="0,0,0,6"/>
<!-- Progress ring -->
<Grid Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center">
<Ellipse Width="200" Height="200"
Stroke="#4D4D4D" StrokeThickness="10"
Fill="Transparent"/>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Dialog.Unlock.Progress}"
FontSize="12" Foreground="#888"
HorizontalAlignment="Center" Margin="0,0,0,4"/>
<TextBlock FontSize="60" FontFamily="Courier New"
Foreground="White" HorizontalAlignment="Center">
<TextBlock.Text>
<Binding Path="Progress" Mode="OneWay"
StringFormat="{}{0}%"/>
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{Binding ElapsedTime, Mode=OneWay}"
FontSize="16" FontFamily="Courier New"
Foreground="#CCC" HorizontalAlignment="Center"
Margin="0,2,0,0"/>
</StackPanel>
</Grid>
<TextBlock Grid.Row="3"
Text="{Binding PhaseText, Mode=OneWay}"
FontSize="16" Foreground="White"
HorizontalAlignment="Center" Margin="0,6"/>
<ProgressBar Grid.Row="4"
Value="{Binding Progress, Mode=OneWay}"
Minimum="0" Maximum="100"
Height="12" Margin="12,0"
Foreground="#00EC00" Background="#3D3D3D"/>
<TextBlock Grid.Row="5"
Text="{Binding ResultText, Mode=OneWay}"
FontSize="22" FontWeight="Bold"
HorizontalAlignment="Center" Margin="0,10,0,0"
Visibility="{Binding IsComplete, Converter={StaticResource BoolToVis}}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#FF5858"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSuccess}" Value="True">
<Setter Property="Foreground" Value="#00EC00"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<!-- Only the cancel button is exposed inline; the panel cannot be "closed" here -->
<StackPanel Grid.Row="6" Orientation="Horizontal"
HorizontalAlignment="Center" Margin="0,14,0,0">
<Button Content="{DynamicResource Common.Cancel}"
Command="{Binding CancelCommand}"
Width="110" Height="30"
Foreground="White" FontWeight="Bold">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="#FF5858"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="#4D4D4D"/>
<Setter Property="Foreground" Value="#888"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Grid>
</Border>
</UserControl>

View File

@@ -1,17 +0,0 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>
/// Inline unlock panel (Pump page §3.e). DataContext is the
/// shared <c>UnlockProgressViewModel</c> also driving the floating
/// progress dialog.
/// </summary>
public partial class UnlockPanelView : UserControl
{
public UnlockPanelView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,115 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.UnlockSnackbarView"
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"
mc:Ignorable="d"
d:DesignHeight="80" d:DesignWidth="700">
<!-- DataContext = UnlockProgressViewModel (may be null — NullToVis collapses the border) -->
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</UserControl.Resources>
<Border Visibility="{Binding Converter={StaticResource NullToVis}}"
Style="{StaticResource SnackbarShell}"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
MinWidth="560" MaxWidth="860">
<DockPanel LastChildFill="True" Margin="16,10">
<!-- ── Leading state icon ────────────────────────────────────── -->
<Grid DockPanel.Dock="Left" Width="30" Height="30" Margin="0,0,12,0">
<!-- In-progress spinner -->
<ui:ProgressRing IsIndeterminate="True" Width="24" Height="24">
<ui:ProgressRing.Style>
<Style TargetType="ui:ProgressRing">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsComplete}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ui:ProgressRing.Style>
</ui:ProgressRing>
<!-- Success check -->
<ui:SymbolIcon Symbol="CheckmarkCircle24" FontSize="24"
Foreground="{DynamicResource SystemFillColorSuccessBrush}">
<ui:SymbolIcon.Style>
<Style TargetType="ui:SymbolIcon">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSuccess}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ui:SymbolIcon.Style>
</ui:SymbolIcon>
<!-- Failure/cancel X -->
<ui:SymbolIcon Symbol="DismissCircle24" FontSize="24"
Foreground="{DynamicResource SystemFillColorCriticalBrush}">
<ui:SymbolIcon.Style>
<Style TargetType="ui:SymbolIcon">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsComplete}" Value="True"/>
<Condition Binding="{Binding IsSuccess}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Visible"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</ui:SymbolIcon.Style>
</ui:SymbolIcon>
</Grid>
<!-- ── Trailing buttons ───────────────────────────────────────── -->
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" VerticalAlignment="Center" Margin="12,0,0,0">
<TextBlock Text="{Binding Progress, StringFormat={}{0}%}"
FontFamily="Consolas" FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
VerticalAlignment="Center" Margin="0,0,12,0"/>
<ui:Button Content="{DynamicResource Common.Cancel}"
Command="{Binding CancelCommand}"
Appearance="Caution"
Visibility="{Binding IsCancellable, Converter={StaticResource BoolToVis}}"
Height="30" Padding="12,4"/>
<ui:Button Content="{DynamicResource Common.Dismiss}"
Click="OnDismissClick"
Appearance="Secondary"
Visibility="{Binding IsComplete, Converter={StaticResource BoolToVis}}"
Height="30" Padding="12,4"/>
</StackPanel>
<!-- ── Middle: type + phase + progress bar ────────────────────── -->
<StackPanel VerticalAlignment="Center">
<DockPanel>
<TextBlock DockPanel.Dock="Left"
Text="{Binding UnlockTypeLabel}"
FontWeight="SemiBold" FontSize="12"
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
VerticalAlignment="Center" Margin="0,0,8,0"/>
<TextBlock Text="{Binding PhaseText}"
FontSize="12"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
VerticalAlignment="Center"
TextTrimming="CharacterEllipsis"/>
</DockPanel>
<ProgressBar Value="{Binding Progress, Mode=OneWay}"
Minimum="0" Maximum="100" Height="3"
Margin="0,4,0,0"/>
</StackPanel>
</DockPanel>
</Border>
</UserControl>

View File

@@ -0,0 +1,54 @@
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using HC_APTBS.ViewModels.Dialogs;
namespace HC_APTBS.Views.UserControls
{
public partial class UnlockSnackbarView : UserControl
{
private DispatcherTimer? _autoHideTimer;
public UnlockSnackbarView()
{
InitializeComponent();
DataContextChanged += OnDataContextChanged;
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue is UnlockProgressViewModel oldVm)
oldVm.PropertyChanged -= OnVmPropertyChanged;
if (e.NewValue is UnlockProgressViewModel newVm)
newVm.PropertyChanged += OnVmPropertyChanged;
}
private void OnVmPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != nameof(UnlockProgressViewModel.IsSuccess)) return;
if (DataContext is not UnlockProgressViewModel vm) return;
if (vm.IsSuccess == true)
{
_autoHideTimer?.Stop();
_autoHideTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(3) };
_autoHideTimer.Tick += (_, _) =>
{
_autoHideTimer!.Stop();
if (vm.CloseCommand.CanExecute(null))
vm.CloseCommand.Execute(null);
};
_autoHideTimer.Start();
}
}
private void OnDismissClick(object sender, RoutedEventArgs e)
{
if (DataContext is UnlockProgressViewModel vm && vm.CloseCommand.CanExecute(null))
vm.CloseCommand.Execute(null);
}
}
}