- Replace LCD-style readings with a 3×2 KPI tile grid (Fluent card surfaces, 52pt values) - Add persistent top connection strip with horizontal chips + pump name badge - Add elapsed test timer (DispatcherTimer, mm:ss) to Test Summary card - Restyle Test Summary and Active Alarms with Fluent brushes/iconography - Add Devices column (CAN / K-Line / Bench tiles) between KPI grid and test/alarms - Enumerates attached PCAN USB channels via PCAN_ATTACHED_CHANNELS API - Enumerates FTDI K-Line adapters via existing FtdiInterface helpers - Click to connect/disconnect; confirmation dialog when session active or test running - Hover tint: blue = will connect, red = will disconnect; Bench row is read-only stub - Extend ICanService with SelectedChannel + EnumerateAttachedChannels() - Expose IKwpService.ConnectedPort for active session device tracking - Add DeviceRow button style with MultiDataTrigger hover colour logic - Add 30+ new localization keys (ES + EN) for KPI labels, devices, confirmations Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
214 lines
11 KiB
XML
214 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>
|
|
<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>
|
|
</DockPanel>
|
|
</ui:FluentWindow>
|