feat: redesign dashboard with Fluent KPI tiles, connection strip, and devices column
- 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>
This commit is contained in:
@@ -42,11 +42,169 @@
|
||||
<Setter Property="Margin" Value="2,4"/>
|
||||
</Style>
|
||||
|
||||
<!-- Relay toggle button style -->
|
||||
<Style x:Key="RelayButton" TargetType="Button">
|
||||
<!-- Relay toggle button style — inherits WPF-UI Button appearance -->
|
||||
<Style x:Key="RelayButton" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Padding" Value="6,3"/>
|
||||
<Setter Property="Margin" Value="3,2"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
</Style>
|
||||
|
||||
<!--
|
||||
Base style for state-indicating toggle buttons (on/off with colour feedback).
|
||||
Uses a custom ControlTemplate so that TemplateBinding Background is honoured
|
||||
in ALL states — including IsChecked=True. Derived styles add IsChecked triggers
|
||||
with a custom Background colour (green, amber, blue, etc.) and those colours are
|
||||
guaranteed to propagate, unlike WPF-UI's own ToggleButton template which has an
|
||||
internal IsChecked trigger that would override a simple BasedOn + Background setter.
|
||||
Hover/pressed feedback is applied via a transparent overlay so it works on any
|
||||
background colour without conflicting with the checked state.
|
||||
-->
|
||||
<Style x:Key="FluentStateToggle" TargetType="ToggleButton">
|
||||
<Setter Property="OverridesDefaultStyle" Value="True"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}"/>
|
||||
<Setter Property="Padding" Value="8,4"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ControlStrokeColorDefaultBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ToggleButton">
|
||||
<Grid>
|
||||
<Border x:Name="Root"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="4"
|
||||
SnapsToDevicePixels="True"/>
|
||||
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}"/>
|
||||
<!-- Transparent overlay — darkens on hover/pressed over any background colour -->
|
||||
<Border x:Name="HoverOverlay" CornerRadius="4" Background="Transparent"
|
||||
IsHitTestVisible="False"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="HoverOverlay" Property="Background" Value="#18000000"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="HoverOverlay" Property="Background" Value="#30000000"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" Value="0.4"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
<!-- ── Dashboard KPI tile styles ─────────────────────────────────────── -->
|
||||
<Style x:Key="KpiTile" TargetType="Border">
|
||||
<Setter Property="Background" Value="{DynamicResource CardBackgroundFillColorDefaultBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource CardStrokeColorDefaultBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
<Setter Property="Padding" Value="16"/>
|
||||
<Setter Property="Margin" Value="6"/>
|
||||
<Setter Property="MinHeight" Value="140"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="KpiHeaderText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}"/>
|
||||
<Setter Property="Margin" Value="0,0,0,4"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="KpiValueText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}"/>
|
||||
<Setter Property="FontSize" Value="52"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}"/>
|
||||
<Setter Property="TextAlignment" Value="Left"/>
|
||||
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="KpiUnitText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorTertiaryBrush}"/>
|
||||
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
||||
<Setter Property="Margin" Value="6,0,0,6"/>
|
||||
</Style>
|
||||
|
||||
<!-- Connection strip chip -->
|
||||
<Style x:Key="ConnChip" TargetType="Border">
|
||||
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ControlStrokeColorDefaultBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="14"/>
|
||||
<Setter Property="Padding" Value="14,6"/>
|
||||
<Setter Property="Margin" Value="0,0,8,0"/>
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
</Style>
|
||||
|
||||
<!-- Status dot (10 px ellipse; Fill overridden by DataTrigger for state colour) -->
|
||||
<Style x:Key="StatusDot" TargetType="Ellipse">
|
||||
<Setter Property="Width" Value="10"/>
|
||||
<Setter Property="Height" Value="10"/>
|
||||
<Setter Property="Fill" Value="{DynamicResource SystemFillColorNeutralBrush}"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="6,0,4,0"/>
|
||||
</Style>
|
||||
|
||||
<!-- ── Device row button — hover tint indicates intent (connect=blue, disconnect=red) -->
|
||||
<Style x:Key="DeviceRow" TargetType="Button">
|
||||
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Padding" Value="10,6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,4"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="Bd"
|
||||
Background="{TemplateBinding Background}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
CornerRadius="6">
|
||||
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<!-- Hover + disconnected → accent blue (will connect) -->
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsMouseOver}" Value="True"/>
|
||||
<Condition Binding="{Binding IsConnected}" Value="False"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource AccentFillColorSecondaryBrush}"/>
|
||||
</MultiDataTrigger>
|
||||
<!-- Hover + connected → critical red (will disconnect) -->
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsMouseOver}" Value="True"/>
|
||||
<Condition Binding="{Binding IsConnected}" Value="True"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource SystemFillColorCriticalBackgroundBrush}"/>
|
||||
</MultiDataTrigger>
|
||||
<!-- Disabled → muted (bench placeholder) -->
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Bd" Property="Opacity" Value="0.5"/>
|
||||
<Setter Property="Cursor" Value="Arrow"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
Reference in New Issue
Block a user