Files
HC_APTBS/MainWindow.xaml
LucianoDev 70be693116 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>
2026-04-20 14:03:47 +02:00

221 lines
11 KiB
XML

<ui:FluentWindow x:Class="HC_APTBS.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:HC_APTBS.ViewModels"
xmlns:uc="clr-namespace:HC_APTBS.Views.UserControls"
xmlns:pages="clr-namespace:HC_APTBS.Views.Pages"
xmlns:models="clr-namespace:HC_APTBS.Models"
mc:Ignorable="d"
Title="{DynamicResource App.Title}"
Height="1080" Width="1920"
WindowState="Maximized"
WindowStartupLocation="CenterScreen"
FontFamily="Ebrima"
Closing="OnWindowClosing">
<DockPanel>
<!-- ── WPF-UI custom title bar (replaces OS chrome) ──────────────────── -->
<ui:TitleBar DockPanel.Dock="Top"
Title="{DynamicResource App.Title}"
ShowMaximize="True"
ShowMinimize="True"/>
<!-- ── Persistent app header: pump identification + connection state ──── -->
<Border DockPanel.Dock="Top" Background="Transparent"
BorderBrush="#999" BorderThickness="0,0,0,1" Visibility="Collapsed">
<Grid Margin="4,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Pump selector + K-Line ECU info -->
<uc:PumpIdentificationView DataContext="{Binding PumpIdentification}"/>
<!-- Connection indicators + CAN connect/disconnect -->
<StackPanel Grid.Column="1" Orientation="Horizontal"
VerticalAlignment="Center" Margin="8,0,0,0">
<TextBlock Text="{DynamicResource Status.Label}" VerticalAlignment="Center"
FontSize="10" Margin="0,0,6,0"/>
<Border Width="54" Margin="2,0">
<Border.Style>
<Style TargetType="Border" BasedOn="{StaticResource ConnIndicator}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsCanConnected}" Value="True">
<Setter Property="Background" Value="#26C200"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="{DynamicResource Status.Can}" HorizontalAlignment="Center"
FontSize="10" Padding="2"/>
</Border>
<Border Width="54" Margin="2,0">
<Border.Style>
<Style TargetType="Border" BasedOn="{StaticResource ConnIndicator}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsBenchConnected}" Value="True">
<Setter Property="Background" Value="#26C200"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="{DynamicResource Status.Bench}" HorizontalAlignment="Center"
FontSize="10" Padding="2"/>
</Border>
<Border Width="54" Margin="2,0">
<Border.Style>
<Style TargetType="Border" BasedOn="{StaticResource ConnIndicator}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsPumpConnected}" Value="True">
<Setter Property="Background" Value="#26C200"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="{DynamicResource Status.Pump}" HorizontalAlignment="Center"
FontSize="10" Padding="2"/>
</Border>
<Border Width="54" Margin="2,0,8,0">
<Border.Style>
<Style TargetType="Border" BasedOn="{StaticResource ConnIndicator}">
<Style.Triggers>
<DataTrigger Binding="{Binding KLineState}" Value="{x:Static models:KLineConnectionState.Connected}">
<Setter Property="Background" Value="#26C200"/>
</DataTrigger>
<DataTrigger Binding="{Binding KLineState}" Value="{x:Static models:KLineConnectionState.Failed}">
<Setter Property="Background" Value="#FF3333"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="{DynamicResource Status.KLine}" HorizontalAlignment="Center"
FontSize="10" Padding="2"/>
</Border>
<Button Content="{DynamicResource Bench.ConnectCan}" Width="110" Margin="4,0,4,0"
Command="{Binding ConnectCanCommand}"/>
<Button Content="{DynamicResource Bench.DisconnectCan}" Width="120"
Command="{Binding DisconnectCanCommand}"
IsEnabled="{Binding IsCanConnected}"/>
</StackPanel>
</Grid>
</Border>
<!-- ── Status bar ─────────────────────────────────────────────────── -->
<StatusBar DockPanel.Dock="Bottom" Height="24" Background="#FFD0D0D0">
<StatusBarItem>
<TextBlock Text="{Binding CanStatusText}" Margin="4,0"/>
</StatusBarItem>
<Separator/>
<StatusBarItem>
<TextBlock Text="{Binding VerboseStatus}" Margin="4,0"/>
</StatusBarItem>
</StatusBar>
<!-- ── Main content: left navigation rail + hidden-tab page host ──── -->
<Grid>
<!-- Inner grid: nav rail (col 0) + page host (col 1) -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--
Nav rail column: primary pages at top, Settings pinned at bottom
with a divider. Both ListBoxes bind to SelectedPage; WPF auto-
deselects a ListBox whose SelectedValue is not among its items,
so clicking Settings clears the top highlight and vice versa.
-->
<Grid Grid.Column="0" Background="#FF2F3440">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Grid.Row="0"
Style="{StaticResource NavRail}"
SelectedValuePath="Tag"
SelectedValue="{Binding SelectedPage, Mode=TwoWay}">
<ListBoxItem Tag="{x:Static vm:AppPage.Dashboard}">
<TextBlock Text="{DynamicResource Nav.Dashboard}"
Foreground="#FFE6E6E6" FontSize="14"/>
</ListBoxItem>
<ListBoxItem Tag="{x:Static vm:AppPage.Bench}">
<TextBlock Text="{DynamicResource Nav.Bench}"
Foreground="#FFE6E6E6" FontSize="14"/>
</ListBoxItem>
<ListBoxItem Tag="{x:Static vm:AppPage.Pump}">
<TextBlock Text="{DynamicResource Nav.Pump}"
Foreground="#FFE6E6E6" FontSize="14"/>
</ListBoxItem>
<ListBoxItem Tag="{x:Static vm:AppPage.Tests}">
<TextBlock Text="{DynamicResource Nav.Tests}"
Foreground="#FFE6E6E6" FontSize="14"/>
</ListBoxItem>
<ListBoxItem Tag="{x:Static vm:AppPage.Results}">
<TextBlock Text="{DynamicResource Nav.Results}"
Foreground="#FFE6E6E6" FontSize="14"/>
</ListBoxItem>
</ListBox>
<Border Grid.Row="1" Height="1" Background="#FF555C6B"
Margin="12,4,12,4"/>
<ListBox Grid.Row="2"
Style="{StaticResource NavRail}"
SelectedValuePath="Tag"
SelectedValue="{Binding SelectedPage, Mode=TwoWay}">
<ListBoxItem Tag="{x:Static vm:AppPage.Settings}">
<TextBlock Text="{DynamicResource Nav.Settings}"
Foreground="#FFE6E6E6" FontSize="14"/>
</ListBoxItem>
</ListBox>
</Grid>
<!--
TabItem order must match AppPage enum values:
Bench=0, Pump=1, Tests=2, Dashboard=3, Settings=4, Results=5.
Nav rail order above is UX-driven (Dashboard first) via Tag binding.
-->
<TabControl Grid.Column="1"
Style="{StaticResource HiddenTabsTabControl}"
SelectedIndex="{Binding SelectedPage, Converter={StaticResource EnumToInt}}">
<TabItem>
<pages:BenchPage DataContext="{Binding BenchPage}"/>
</TabItem>
<TabItem>
<pages:PumpPage DataContext="{Binding PumpPage}"/>
</TabItem>
<TabItem>
<pages:TestsPage DataContext="{Binding TestsPage}"/>
</TabItem>
<TabItem>
<pages:DashboardPage DataContext="{Binding DashboardPage}"/>
</TabItem>
<TabItem>
<pages:SettingsPage DataContext="{Binding SettingsPage}"/>
</TabItem>
<TabItem>
<pages:ResultsPage DataContext="{Binding ResultsPage}"/>
</TabItem>
</TabControl>
</Grid>
<uc:UnlockSnackbarView DataContext="{Binding CurrentUnlockVm}"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Margin="0,0,0,8"/>
</Grid>
</DockPanel>
</ui:FluentWindow>