Files
HC_APTBS/Views/Pages/PumpPage.xaml
LucianoDev 0280a2fad1 feat: page-based navigation shell + Tests page wizard
Replace the monolithic MainWindow with a SelectedPage-driven shell
(Dashboard / Pump / Bench / Tests / Results / Settings). The Tests
page gets the Plan -> Preconditions -> Running -> Done wizard from
ui-structure.md \u00a74, backed by a 7-item precondition gate and
shared sub-views (PhaseCardView / TestSectionView / GraphicIndicatorView)
extracted from the now-deleted monolithic TestPanelView.

New VMs / views:
- Tests wizard: TestPreconditions, PhaseCard, GraphicIndicator,
  TestSection, TestPlan, TestRunning, TestDone
- Dashboard panels: DashboardConnection, DashboardReadings,
  DashboardAlarms, InterlockBanner, ResultHistory
- Pump / bench panels: PumpIdentificationPanel, PumpLiveData,
  UnlockPanel, BenchDriveControl, BenchReadings, RelayBank,
  TemperatureControl, DtcList, AuthGate
- Dialogs: generic ConfirmDialog, UserManageDialog, UserPromptDialog

Supporting changes:
- IsOilPumpOn exposed on MainViewModel for precondition evaluation
- RequiresAuth added to TestDefinition (XML round-trip)
- BipStatusDefinition + CompletedTestRun models
- ~35 new Test.* localization keys (en + es)
- Settings moved from modal dialog to full page
- Pause / Retry / Skip stubs in TestRunningView; full spec in
  docs/gap-test-running-controls.md for follow-up implementation
- docs/ui-structure.md captures the wizard design

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-18 13:11:34 +02:00

289 lines
16 KiB
XML

<UserControl x:Class="HC_APTBS.Views.Pages.PumpPage"
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"
xmlns:vm="clr-namespace:HC_APTBS.ViewModels.Pages"
mc:Ignorable="d"
d:DesignHeight="780" d:DesignWidth="1100">
<!--
Pump page — ECU diagnostics and control.
DataContext = PumpPageViewModel.
Layout:
- Banner row: K-Line session banner + "no pump selected" banner
- Sub-nav (left): Identification / DTCs / LiveData / Adaptation / Unlock
- Sub-page content (right): selected sub-section via hidden tabs
-->
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
<!-- Sub-nav item: narrower than the main rail, same accent pattern -->
<Style x:Key="SubNavItem" TargetType="ListBoxItem">
<Setter Property="Height" Value="44"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="Root" Background="Transparent">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="Accent" Grid.Column="0" Background="Transparent"/>
<ContentPresenter Grid.Column="1"
VerticalAlignment="Center"
Margin="12,0,6,0"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Root" Property="Background" Value="#ECECEC"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Root" Property="Background" Value="#E4EEF7"/>
<Setter TargetName="Accent" Property="Background" Value="#2196F3"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.35"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="SubNavText" TargetType="TextBlock">
<Setter Property="FontSize" Value="13"/>
<Setter Property="Foreground" Value="#333"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- banners -->
<RowDefinition Height="*"/> <!-- body -->
</Grid.RowDefinitions>
<!-- ══════════════════════════════════════════════════════════════
Banners: K-Line session + no pump selected
══════════════════════════════════════════════════════════════ -->
<StackPanel Grid.Row="0">
<!-- K-Line session banner (closed / failed) -->
<Border Padding="10,6">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#FFF3CD"/>
<Setter Property="BorderBrush" Value="#FFC107"/>
<Setter Property="BorderThickness" Value="0,0,0,1"/>
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsKLineSessionOpen}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsKLineSessionFailed}" Value="True">
<Setter Property="Background" Value="#FDECEA"/>
<Setter Property="BorderBrush" Value="#D62828"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock FontSize="12" TextWrapping="Wrap">
<Run Text="●" FontSize="14"/>
<Run Text=" "/>
<Run Text="{DynamicResource Pump.KLineClosed}"/>
</TextBlock>
</Border>
<!-- No pump selected banner (BoolToVis has no Invert support, so use a DataTrigger style) -->
<Border Background="#E3F2FD" BorderBrush="#2196F3" BorderThickness="0,0,0,1"
Padding="10,6">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsPumpSelected}" Value="False">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="{DynamicResource Pump.NoPumpSelected}"
FontSize="12" Foreground="#0D47A1"/>
</Border>
</StackPanel>
<!-- ══════════════════════════════════════════════════════════════
Body: sub-nav + sub-page content
══════════════════════════════════════════════════════════════ -->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- ── Sub-nav rail ───────────────────────────────────────── -->
<Border Grid.Column="0" Background="#F7F7F7"
BorderBrush="#DDD" BorderThickness="0,0,1,0">
<ListBox SelectedValuePath="Tag" BorderThickness="0"
Background="Transparent"
ItemContainerStyle="{StaticResource SubNavItem}"
SelectedValue="{Binding SelectedSubPage, Mode=TwoWay}">
<ListBoxItem Tag="{x:Static vm:PumpSubPage.Identification}">
<TextBlock Text="{DynamicResource PumpSub.Identification}"
Style="{StaticResource SubNavText}"/>
</ListBoxItem>
<ListBoxItem Tag="{x:Static vm:PumpSubPage.Dtcs}"
IsEnabled="{Binding IsPumpSelected}">
<TextBlock Text="{DynamicResource PumpSub.Dtcs}"
Style="{StaticResource SubNavText}"/>
</ListBoxItem>
<ListBoxItem Tag="{x:Static vm:PumpSubPage.LiveData}"
IsEnabled="{Binding IsPumpSelected}">
<TextBlock Text="{DynamicResource PumpSub.LiveData}"
Style="{StaticResource SubNavText}"/>
</ListBoxItem>
<ListBoxItem Tag="{x:Static vm:PumpSubPage.Adaptation}"
IsEnabled="{Binding IsPumpSelected}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource PumpSub.Adaptation}"
Style="{StaticResource SubNavText}"/>
<TextBlock Text=" 🔒" FontSize="11"
VerticalAlignment="Center">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding DataContext.AdaptationAuth.IsAuthenticated,
RelativeSource={RelativeSource AncestorType=UserControl}}"
Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</ListBoxItem>
<ListBoxItem Tag="{x:Static vm:PumpSubPage.Unlock}">
<ListBoxItem.Style>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource SubNavItem}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsUnlockApplicable}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBoxItem.Style>
<TextBlock Text="{DynamicResource PumpSub.Unlock}"
Style="{StaticResource SubNavText}"/>
</ListBoxItem>
</ListBox>
</Border>
<!-- ── Sub-page content ───────────────────────────────────── -->
<TabControl Grid.Column="1"
Style="{StaticResource HiddenTabsTabControl}"
SelectedIndex="{Binding SelectedSubPage, Converter={StaticResource EnumToInt}}">
<!-- 3a Identification -->
<TabItem>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<uc:PumpIdentificationPanelView
DataContext="{Binding Identification}"/>
</ScrollViewer>
</TabItem>
<!-- 3b DTCs -->
<TabItem>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<uc:DtcListView DataContext="{Binding DtcList}"/>
</ScrollViewer>
</TabItem>
<!-- 3c Live Data — DataContext stays as PumpPageViewModel so
the view can reach Root.PumpXxx and StatusDisplay1/2. -->
<TabItem>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<uc:PumpLiveDataView/>
</ScrollViewer>
</TabItem>
<!-- 3d Adaptation (auth-gated) -->
<TabItem>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<uc:AuthGateView DataContext="{Binding AdaptationAuth}">
<uc:AuthGateView.GatedContent>
<Border Background="#FAFAFA" BorderBrush="#DDD"
BorderThickness="1" CornerRadius="4"
Padding="12" Margin="6">
<StackPanel>
<TextBlock Text="{DynamicResource PumpSub.Adaptation}"
FontSize="15" FontWeight="SemiBold"
Foreground="#333" Margin="0,0,0,8"/>
<uc:DfiManageView DataContext="{Binding DataContext.DfiViewModel,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
<Separator Margin="0,10"/>
<uc:PumpControlView DataContext="{Binding DataContext.PumpControl,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
</StackPanel>
</Border>
</uc:AuthGateView.GatedContent>
</uc:AuthGateView>
</ScrollViewer>
</TabItem>
<!-- 3e Unlock -->
<TabItem>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid>
<!-- "No active unlock" placeholder — visible when UnlockVm is null -->
<Border Background="#F5F5F5" BorderBrush="#CCC"
BorderThickness="1" CornerRadius="4"
Padding="20" Margin="6"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding UnlockVm}" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="{DynamicResource Pump.NoUnlockActive}"
FontSize="13" Foreground="#666"/>
</Border>
<!-- Active unlock panel — visible when UnlockVm is non-null.
DataContext binds to UnlockVm so `{Binding}` inside the
style evaluates to the VM instance (or null). -->
<uc:UnlockPanelView DataContext="{Binding UnlockVm}">
<uc:UnlockPanelView.Style>
<Style TargetType="uc:UnlockPanelView">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</uc:UnlockPanelView.Style>
</uc:UnlockPanelView>
</Grid>
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>
</Grid>
</UserControl>