feat: developer tools page, auto-test orchestrator, BIP display, tests redesign
Bundles several feature streams that have been iterating on the working tree: - Developer Tools page (Debug-only via DEVELOPER_TOOLS symbol): hosts the identification card, manual KWP write + transaction log, ROM/EEPROM dump card with progress banner and completion message, persisted custom-commands library, persisted EEPROM passwords library. New service primitives: IKwpService.SendRawCustomAsync / ReadEepromAsync / ReadRomEepromAsync. Persistence mirrors the Clients XML pattern in two new files (custom_commands.xml, eeprom_passwords.xml). - Auto-test orchestrator (IAutoTestOrchestrator + AutoTestState): linear K-Line read -> unlock -> bench-on -> test sequence with snackbar UI and progress dialog VM, gated on dashboard alarms. - BIP-STATUS display: BipDisplayViewModel + BipDisplayView, RAM read at 0x0106 via IKwpService.ReadBipStatusAsync; status definitions in BipStatusDefinition. - Tests page redesign: TestSectionCard + PhaseTileView replacing the old TestPlanView/TestRunningView/TestDoneView/TestPreconditionsView/ TestSectionView controls and their VMs. - Pump command sliders: Fluent thick-track style with overhang thumb, click-anywhere-and-drag, mouse-wheel adjustment. - Window startup: app.manifest declares PerMonitorV2 DPI awareness, MainWindow installs a WM_GETMINMAXINFO hook in OnSourceInitialized and maximizes there (after the hook is in place) so the app fits the work area exactly on any display configuration. - Misc: PercentToPixelsConverter, seed_aliases.py one-shot pump-alias importer, tools/Import-BipStatus.ps1, kline_eeprom_spec.md and dump-functions reference docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,57 +1,11 @@
|
||||
<ResourceDictionary 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:conv="clr-namespace:HC_APTBS.Converters">
|
||||
|
||||
<!-- Shared converter: enum ↔ int for TabControl.SelectedIndex -->
|
||||
<conv:EnumToIntConverter x:Key="EnumToInt"/>
|
||||
|
||||
<!-- Nav rail ListBoxItem: 56px tall, left accent bar on selection -->
|
||||
<Style x:Key="NavItem" TargetType="ListBoxItem">
|
||||
<Setter Property="Height" Value="56"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalContentAlignment" 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="4"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border x:Name="Accent" Grid.Column="0" Background="Transparent"/>
|
||||
<ContentPresenter Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Margin="16,0,0,0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="Root" Property="Background" Value="#FF3A4050"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter TargetName="Root" Property="Background" Value="#FF404860"/>
|
||||
<Setter TargetName="Accent" Property="Background" Value="#FF2196F3"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Nav rail ListBox -->
|
||||
<Style x:Key="NavRail" TargetType="ListBox">
|
||||
<Setter Property="Background" Value="#FF2F3440"/>
|
||||
<Setter Property="Foreground" Value="#FFE6E6E6"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource NavItem}"/>
|
||||
</Style>
|
||||
|
||||
<!-- TabControl that hides its tab strip so the nav rail is the only selector -->
|
||||
<Style x:Key="HiddenTabsTabControl" TargetType="TabControl">
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
@@ -72,4 +26,122 @@
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!--
|
||||
Boxy nav item template: vertical icon-over-label tile inside a rounded
|
||||
card. Replaces WPF-UI's default horizontal row layout
|
||||
(LeftCompactNavigationViewItemTemplate) when assigned to
|
||||
NavigationView.ItemTemplate.
|
||||
|
||||
Mechanism: WPF-UI's NavigationView assigns each NavigationViewItem's
|
||||
Template programmatically via UpdateMenuItemsTemplate (in
|
||||
NavigationView.Base.cs). A direct property assignment beats any
|
||||
Style.Setter, so the only reliable way to override is to provide a
|
||||
keyed ControlTemplate and assign it to NavigationView.ItemTemplate
|
||||
from MainWindow.xaml.
|
||||
|
||||
Active = current page. Per user request, the active state is a muted
|
||||
grey instead of a bright accent fill, signalling "you are here / not a
|
||||
clickable destination right now". Hover and pressed states still
|
||||
layer a transparent darkening overlay on top.
|
||||
|
||||
Triggers on IsActive (WPF-UI's selected-state DP on
|
||||
NavigationViewItemBase), not IsSelected.
|
||||
-->
|
||||
<ControlTemplate x:Key="BoxyNavItemTemplate"
|
||||
TargetType="{x:Type ui:NavigationViewItem}">
|
||||
<!-- Asymmetric horizontal margin compensates for the 4px scrollbar
|
||||
gutter that WPF-UI's NavigationView reserves on the right
|
||||
(DynamicScrollViewer Padding="0,0,4,0"); this lands the visible
|
||||
item edges at 10px from both the left and right of the pane. -->
|
||||
<Grid Margin="6,3" MinHeight="80">
|
||||
<!-- Background lives in Border.Style (level-8 style setter), NOT
|
||||
as a local-value attribute (level 3), so the IsActive
|
||||
template trigger below (level 7) can actually override it.
|
||||
Setting Background="{DynamicResource ...}" as an attribute
|
||||
here would silently block the trigger — same precedence
|
||||
trap as Background="Transparent" on HoverOverlay. -->
|
||||
<Border x:Name="Root"
|
||||
CornerRadius="8"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
|
||||
SnapsToDevicePixels="True">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background"
|
||||
Value="{DynamicResource ControlFillColorDefaultBrush}"/>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
<Grid Margin="6">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!-- Icon: hosts the ui:SymbolIcon assigned via
|
||||
NavigationViewItem.Icon. TextElement inheritance
|
||||
propagates FontSize/Foreground into the SymbolIcon. -->
|
||||
<ContentControl x:Name="IconHost"
|
||||
Grid.Row="0"
|
||||
Content="{TemplateBinding Icon}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Focusable="False"
|
||||
IsTabStop="False"
|
||||
TextElement.FontSize="32"
|
||||
TextElement.Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
|
||||
<ContentPresenter x:Name="LabelHost"
|
||||
Grid.Row="1"
|
||||
Content="{TemplateBinding Content}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,4,0,0"
|
||||
TextBlock.FontFamily="{DynamicResource ContentControlThemeFontFamily}"
|
||||
TextBlock.FontSize="12"
|
||||
TextBlock.FontWeight="SemiBold"
|
||||
TextBlock.Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
|
||||
</Grid>
|
||||
<!-- Overlay darkens on hover/press/active without disturbing the
|
||||
Root background colour. Background is intentionally LEFT
|
||||
UNSET — assigning Background="Transparent" here would be a
|
||||
local value, which beats template-trigger setters in WPF
|
||||
property precedence and would silently block the
|
||||
IsMouseOver/IsPressed/IsActive triggers below from changing
|
||||
the colour. With Background unset, those triggers drive the
|
||||
overlay. -->
|
||||
<Border x:Name="HoverOverlay"
|
||||
CornerRadius="8"
|
||||
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>
|
||||
<!-- Active = current page: pressed-looking dark fill + muted
|
||||
foreground, signalling "you are here / not a destination"
|
||||
with a held-down feel.
|
||||
|
||||
IMPORTANT: we paint the dark fill onto Root directly with a
|
||||
translucent-BLACK brush (#30000000 ≈ 19% black) instead of
|
||||
going through HoverOverlay or a WPF-UI ControlFillColor*
|
||||
brush. WPF-UI's ControlFillColorSecondaryBrush is
|
||||
#80F9F9F9 (translucent WHITE) — over the white pane it
|
||||
doesn't actually darken anything. A translucent-black brush
|
||||
darkens reliably regardless of the parent colour and
|
||||
matches the IsPressed overlay strength. -->
|
||||
<Trigger Property="IsActive" Value="True">
|
||||
<Setter TargetName="Root" Property="Background" Value="#30000000"/>
|
||||
<Setter TargetName="IconHost" Property="TextElement.Foreground"
|
||||
Value="{DynamicResource TextFillColorSecondaryBrush}"/>
|
||||
<Setter TargetName="LabelHost" Property="TextBlock.Foreground"
|
||||
Value="{DynamicResource TextFillColorSecondaryBrush}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" Value="0.4"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
<sys:String x:Key="Dashboard.LastTestFail">Last test: FAIL</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.StartTest">Start Test</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.StartTest.Tip">Requires a selected pump and an open CAN connection.</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.AutoTest">Connect & Auto Test</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.AutoTest.Tip">Opens K-Line, reads the pump, unlocks if required, turns on the bench and starts the test in one step.</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.Stop">Stop</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.EmergencyStop">EMERGENCY STOP</sys:String>
|
||||
|
||||
@@ -71,6 +73,12 @@
|
||||
<sys:String x:Key="Dashboard.Devices.State.Failed">Error</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.None">No devices found</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.BenchRow">Bench controller</sys:String>
|
||||
<!-- CAN connect/disconnect snackbar -->
|
||||
<sys:String x:Key="Dashboard.Devices.Snackbar.Connecting">Connecting to CAN…</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.Snackbar.Disconnecting">Disconnecting CAN…</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.Snackbar.Connected">CAN connected</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.Snackbar.Disconnected">CAN disconnected</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.Snackbar.Failed">Operation failed</sys:String>
|
||||
<!-- Confirmation dialogs -->
|
||||
<sys:String x:Key="Devices.Confirm.Title">Confirm device change</sys:String>
|
||||
<sys:String x:Key="Devices.Confirm.Body.Active">The {0} session is active. Disconnect?</sys:String>
|
||||
@@ -180,6 +188,15 @@
|
||||
<sys:String x:Key="Pump.LiveData.Fbkw">FBKW</sys:String>
|
||||
<sys:String x:Key="Pump.LiveData.RpmChart">RPM trend</sys:String>
|
||||
<sys:String x:Key="Pump.Status.Active">Active</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Title">BIP-STATUS</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.RawLabel">BIP:</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.0000.9">BIP captured, no current fault</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.000F.9">No BIP within entire detection window</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.00F0.9">No BIP in detection window, MV off (o.k.)</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.0F00.9">No MV drive due to MAB</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.F00F.9">BIP captured, but deviation from characteristic curve too large</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.A00F.9">BIP captured, but too close to HLU switching point</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.000F.11">No BIP within entire detection window (Ford)</sys:String>
|
||||
<sys:String x:Key="Pump.Dfi.Title">Idling Calibration</sys:String>
|
||||
<sys:String x:Key="Pump.Dfi.Version">Version</sys:String>
|
||||
<sys:String x:Key="Pump.Dfi.Current">Current DFI</sys:String>
|
||||
@@ -299,16 +316,22 @@
|
||||
<sys:String x:Key="Test.Required">Required:</sys:String>
|
||||
<sys:String x:Key="Test.TestLabel">Test:</sys:String>
|
||||
<sys:String x:Key="Test.Critical">Critical</sys:String>
|
||||
<sys:String x:Key="Test.Plan.Title">Plan — select phases to run</sys:String>
|
||||
<sys:String x:Key="Test.Plan.Remaining">estimated</sys:String>
|
||||
<sys:String x:Key="Test.Plan.EnableAll">All phases</sys:String>
|
||||
<sys:String x:Key="Test.Plan.HoverHint">Hover a phase for required / send values</sys:String>
|
||||
<sys:String x:Key="Test.Plan.MetaCond">Cond</sys:String>
|
||||
<sys:String x:Key="Test.Plan.MetaMeas">Meas</sys:String>
|
||||
<sys:String x:Key="Test.Plan.MetaMps">M/s</sys:String>
|
||||
<sys:String x:Key="Test.Plan.NoIndicators">no measurements</sys:String>
|
||||
<sys:String x:Key="Test.Started">Test started...</sys:String>
|
||||
<sys:String x:Key="Test.Stopped">Test stopped.</sys:String>
|
||||
|
||||
<!-- ── Tests-page wizard ──────────────────────────────────────────────── -->
|
||||
<sys:String x:Key="Test.Wizard.Plan">1. Plan</sys:String>
|
||||
<sys:String x:Key="Test.Wizard.Preconditions">2. Preconditions</sys:String>
|
||||
<sys:String x:Key="Test.Wizard.Running">3. Running</sys:String>
|
||||
<sys:String x:Key="Test.Wizard.Done">4. Done</sys:String>
|
||||
<sys:String x:Key="Test.Wizard.Next">Next ▶</sys:String>
|
||||
<sys:String x:Key="Test.Wizard.Back">◀ Back</sys:String>
|
||||
<!-- ── Tests-page status bar ──────────────────────────────────────────── -->
|
||||
<sys:String x:Key="Test.Status.Ready">Ready to start</sys:String>
|
||||
<sys:String x:Key="Test.Status.NotReady">Not ready</sys:String>
|
||||
<sys:String x:Key="Test.Status.Running">Running</sys:String>
|
||||
<sys:String x:Key="Test.Status.NoPhases">Select at least one phase to start.</sys:String>
|
||||
|
||||
<!-- ── Preconditions checklist ────────────────────────────────────────── -->
|
||||
<sys:String x:Key="Test.Precheck.Title">Preconditions</sys:String>
|
||||
@@ -345,6 +368,7 @@
|
||||
<sys:String x:Key="Test.Done.Failed">FAILED</sys:String>
|
||||
<sys:String x:Key="Test.Done.ViewFullResults">View full results</sys:String>
|
||||
<sys:String x:Key="Test.Done.RunAgain">Run again</sys:String>
|
||||
<sys:String x:Key="Test.Done.ClearData">Clear test data</sys:String>
|
||||
|
||||
<!-- ── Abort confirmation ─────────────────────────────────────────────── -->
|
||||
<sys:String x:Key="Test.Abort.Title">Abort test?</sys:String>
|
||||
@@ -443,6 +467,7 @@
|
||||
<sys:String x:Key="Dialog.Unlock.Unlocked">UNLOCKED</sys:String>
|
||||
<sys:String x:Key="Dialog.Unlock.Failed">UNLOCK FAILED</sys:String>
|
||||
<sys:String x:Key="Dialog.Unlock.TypeLabel">Type {0}</sys:String>
|
||||
<sys:String x:Key="Dialog.Unlock.Retry">Retry unlock</sys:String>
|
||||
|
||||
<!-- ── Dialog: K-Line errors ────────────────────────────────────────── -->
|
||||
<sys:String x:Key="Dialog.KlineErrors.Title">K-Line Fault Codes</sys:String>
|
||||
@@ -470,6 +495,7 @@
|
||||
<sys:String x:Key="Dialog.Settings.ToleranceUp">UP tolerance extension:</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.TolerancePfp">PFP tolerance extension:</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.IgnoreTin">Ignore T-in by default</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.AutoTestSkipsOilPumpConfirm">Skip oil-pump confirmation during Auto Test (operator accepts leak-check responsibility up front)</sys:String>
|
||||
|
||||
<sys:String x:Key="Dialog.Settings.PidP">Proportional (P):</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.PidI">Integral (I):</sys:String>
|
||||
@@ -502,6 +528,7 @@
|
||||
<sys:String x:Key="Dialog.Settings.RefreshPumpParams">Pump params (ms):</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.BlinkInterval">Blink interval (ms):</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.FlasherInterval">Flasher interval (ms):</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.RpmChartUpdateHz">RPM chart rate (Hz):</sys:String>
|
||||
|
||||
<sys:String x:Key="Dialog.Settings.UsersHeader">Users</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.ManageUsers">Manage Users...</sys:String>
|
||||
@@ -526,6 +553,35 @@
|
||||
<sys:String x:Key="Dialog.UserManage.Error.LastUserTitle">Cannot Remove</sys:String>
|
||||
<sys:String x:Key="Dialog.UserManage.Error.LastUser">Cannot remove the last remaining user.</sys:String>
|
||||
|
||||
<!-- ── Auto Test (Dashboard snackbar) ───────────────────────────────── -->
|
||||
<sys:String x:Key="AutoTest.TypeLabel">Auto Test</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Preflight">Running pre-flight checks…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Connecting">Connecting K-Line…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Reading">Reading pump identification…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Unlocking">Unlocking pump…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.UnlockingWithDetail">Unlocking pump — {0}</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.BenchOn">Turning on bench…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.OilPump">Starting oil pump…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.TestStart">Starting test procedure…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Running">Test running…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.RunningWithPhase">Test running — {0}</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Completed">Auto Test completed.</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Aborted">Aborted — {0}</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.UserCancelled">Cancelled by operator</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.PreflightDenied">Pre-flight conditions not met</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.KLineConnectFailed">Failed to open K-Line session</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.KLineLost">K-Line session lost</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.ReadFailed">Failed to read pump identification</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.PumpNotRecognized">Pump ID not recognised</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.UnlockFailed">Immobilizer unlock failed</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.BenchCanLost">Bench CAN bus lost</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.PumpCanLost">Pump ECU CAN lost</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.AlarmTriggered">Critical alarm triggered</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.OilPumpNotConfirmed">Oil-pump confirmation cancelled by operator</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.TestInterrupted">Test interrupted</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.TestFailed">Test failed</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.Unexpected">Unexpected error</sys:String>
|
||||
|
||||
<!-- ── Error messages ───────────────────────────────────────────────── -->
|
||||
<sys:String x:Key="Error.ReportGeneration">Failed to generate report:\n{0}</sys:String>
|
||||
<sys:String x:Key="Error.ReportTitle">Report Error</sys:String>
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
<sys:String x:Key="Dashboard.LastTestFail">Última prueba: FALLIDA</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.StartTest">Iniciar prueba</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.StartTest.Tip">Requiere una bomba seleccionada y conexión CAN abierta.</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.AutoTest">Conectar y probar</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.AutoTest.Tip">Abre K-Line, lee la bomba, desbloquea si procede, enciende el banco y comienza la prueba en un solo paso.</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.Stop">Detener</sys:String>
|
||||
<sys:String x:Key="Dashboard.Action.EmergencyStop">PARADA DE EMERGENCIA</sys:String>
|
||||
|
||||
@@ -71,6 +73,12 @@
|
||||
<sys:String x:Key="Dashboard.Devices.State.Failed">Error</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.None">Sin dispositivos</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.BenchRow">Controlador del banco</sys:String>
|
||||
<!-- CAN connect/disconnect snackbar -->
|
||||
<sys:String x:Key="Dashboard.Devices.Snackbar.Connecting">Conectando con CAN…</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.Snackbar.Disconnecting">Desconectando CAN…</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.Snackbar.Connected">CAN conectado</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.Snackbar.Disconnected">CAN desconectado</sys:String>
|
||||
<sys:String x:Key="Dashboard.Devices.Snackbar.Failed">Operación fallida</sys:String>
|
||||
<!-- Confirmation dialogs -->
|
||||
<sys:String x:Key="Devices.Confirm.Title">Confirmar cambio de dispositivo</sys:String>
|
||||
<sys:String x:Key="Devices.Confirm.Body.Active">La sesión {0} está activa. ¿Desea desconectar?</sys:String>
|
||||
@@ -180,6 +188,15 @@
|
||||
<sys:String x:Key="Pump.LiveData.Fbkw">FBKW</sys:String>
|
||||
<sys:String x:Key="Pump.LiveData.RpmChart">Tendencia RPM</sys:String>
|
||||
<sys:String x:Key="Pump.Status.Active">Activo</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Title">BIP-STATUS</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.RawLabel">BIP:</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.0000.9">BIP detectado, sin fallo actual</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.000F.9">Sin BIP en todo el período de detección</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.00F0.9">Sin BIP en período de detección, MV desactivada (o.k.)</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.0F00.9">Sin excitación de MV por MAB</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.F00F.9">BIP detectado, pero desviación excesiva respecto a la curva característica</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.A00F.9">BIP detectado, pero demasiado cerca del punto de conmutación HLU</sys:String>
|
||||
<sys:String x:Key="Pump.Bip.Desc.000F.11">Sin BIP en todo el período de detección (Ford)</sys:String>
|
||||
<sys:String x:Key="Pump.Dfi.Title">Calibración Ralentí</sys:String>
|
||||
<sys:String x:Key="Pump.Dfi.Version">Versión</sys:String>
|
||||
<sys:String x:Key="Pump.Dfi.Current">DFI Actual</sys:String>
|
||||
@@ -299,16 +316,22 @@
|
||||
<sys:String x:Key="Test.Required">Requerido:</sys:String>
|
||||
<sys:String x:Key="Test.TestLabel">Test:</sys:String>
|
||||
<sys:String x:Key="Test.Critical">Crítico</sys:String>
|
||||
<sys:String x:Key="Test.Plan.Title">Plan — selecciona las fases a ejecutar</sys:String>
|
||||
<sys:String x:Key="Test.Plan.Remaining">estimado</sys:String>
|
||||
<sys:String x:Key="Test.Plan.EnableAll">Todas las fases</sys:String>
|
||||
<sys:String x:Key="Test.Plan.HoverHint">Pasa el cursor sobre una fase para ver valores</sys:String>
|
||||
<sys:String x:Key="Test.Plan.MetaCond">Cond</sys:String>
|
||||
<sys:String x:Key="Test.Plan.MetaMeas">Med</sys:String>
|
||||
<sys:String x:Key="Test.Plan.MetaMps">M/s</sys:String>
|
||||
<sys:String x:Key="Test.Plan.NoIndicators">sin mediciones</sys:String>
|
||||
<sys:String x:Key="Test.Started">Test iniciado...</sys:String>
|
||||
<sys:String x:Key="Test.Stopped">Test detenido.</sys:String>
|
||||
|
||||
<!-- ── Asistente de la página de tests ────────────────────────────────── -->
|
||||
<sys:String x:Key="Test.Wizard.Plan">1. Planificar</sys:String>
|
||||
<sys:String x:Key="Test.Wizard.Preconditions">2. Precondiciones</sys:String>
|
||||
<sys:String x:Key="Test.Wizard.Running">3. En ejecución</sys:String>
|
||||
<sys:String x:Key="Test.Wizard.Done">4. Finalizado</sys:String>
|
||||
<sys:String x:Key="Test.Wizard.Next">Siguiente ▶</sys:String>
|
||||
<sys:String x:Key="Test.Wizard.Back">◀ Atrás</sys:String>
|
||||
<!-- ── Barra de estado de la página de tests ──────────────────────────── -->
|
||||
<sys:String x:Key="Test.Status.Ready">Listo para comenzar</sys:String>
|
||||
<sys:String x:Key="Test.Status.NotReady">No listo</sys:String>
|
||||
<sys:String x:Key="Test.Status.Running">Ejecutando</sys:String>
|
||||
<sys:String x:Key="Test.Status.NoPhases">Selecciona al menos una fase para comenzar.</sys:String>
|
||||
|
||||
<!-- ── Checklist de precondiciones ────────────────────────────────────── -->
|
||||
<sys:String x:Key="Test.Precheck.Title">Precondiciones</sys:String>
|
||||
@@ -345,6 +368,7 @@
|
||||
<sys:String x:Key="Test.Done.Failed">FALLIDO</sys:String>
|
||||
<sys:String x:Key="Test.Done.ViewFullResults">Ver resultados completos</sys:String>
|
||||
<sys:String x:Key="Test.Done.RunAgain">Ejecutar de nuevo</sys:String>
|
||||
<sys:String x:Key="Test.Done.ClearData">Borrar resultados</sys:String>
|
||||
|
||||
<!-- ── Confirmación de aborto ─────────────────────────────────────────── -->
|
||||
<sys:String x:Key="Test.Abort.Title">¿Abortar el test?</sys:String>
|
||||
@@ -443,6 +467,7 @@
|
||||
<sys:String x:Key="Dialog.Unlock.Unlocked">DESBLOQUEADO</sys:String>
|
||||
<sys:String x:Key="Dialog.Unlock.Failed">DESBLOQUEO FALLIDO</sys:String>
|
||||
<sys:String x:Key="Dialog.Unlock.TypeLabel">Tipo {0}</sys:String>
|
||||
<sys:String x:Key="Dialog.Unlock.Retry">Reintentar desbloqueo</sys:String>
|
||||
|
||||
<!-- ── Dialog: K-Line errors ────────────────────────────────────────── -->
|
||||
<sys:String x:Key="Dialog.KlineErrors.Title">Códigos de Falla K-Line</sys:String>
|
||||
@@ -470,6 +495,7 @@
|
||||
<sys:String x:Key="Dialog.Settings.ToleranceUp">Extensión tolerancia UP:</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.TolerancePfp">Extensión tolerancia PFP:</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.IgnoreTin">Ignorar T-in por defecto</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.AutoTestSkipsOilPumpConfirm">Omitir confirmación de bomba de aceite en Auto Test (el operario asume la comprobación de fugas)</sys:String>
|
||||
|
||||
<sys:String x:Key="Dialog.Settings.PidP">Proporcional (P):</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.PidI">Integral (I):</sys:String>
|
||||
@@ -502,6 +528,7 @@
|
||||
<sys:String x:Key="Dialog.Settings.RefreshPumpParams">Parámetros bomba (ms):</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.BlinkInterval">Intervalo parpadeo (ms):</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.FlasherInterval">Intervalo flasher (ms):</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.RpmChartUpdateHz">Tasa gráfico RPM (Hz):</sys:String>
|
||||
|
||||
<sys:String x:Key="Dialog.Settings.UsersHeader">Usuarios</sys:String>
|
||||
<sys:String x:Key="Dialog.Settings.ManageUsers">Administrar Usuarios...</sys:String>
|
||||
@@ -526,6 +553,35 @@
|
||||
<sys:String x:Key="Dialog.UserManage.Error.LastUserTitle">No Se Puede Eliminar</sys:String>
|
||||
<sys:String x:Key="Dialog.UserManage.Error.LastUser">No se puede eliminar el último usuario restante.</sys:String>
|
||||
|
||||
<!-- ── Auto Test (snackbar del panel) ───────────────────────────────── -->
|
||||
<sys:String x:Key="AutoTest.TypeLabel">Auto Test</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Preflight">Comprobaciones previas…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Connecting">Conectando K-Line…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Reading">Leyendo identificación de bomba…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Unlocking">Desbloqueando bomba…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.UnlockingWithDetail">Desbloqueando bomba — {0}</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.BenchOn">Encendiendo banco…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.OilPump">Arrancando bomba de aceite…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.TestStart">Iniciando procedimiento de prueba…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Running">Prueba en curso…</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.RunningWithPhase">Prueba en curso — {0}</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Completed">Auto Test completado.</sys:String>
|
||||
<sys:String x:Key="AutoTest.State.Aborted">Abortado — {0}</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.UserCancelled">Cancelado por el operario</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.PreflightDenied">No se cumplen las condiciones previas</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.KLineConnectFailed">No se pudo abrir la sesión K-Line</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.KLineLost">Sesión K-Line perdida</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.ReadFailed">Fallo al leer la identificación de la bomba</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.PumpNotRecognized">ID de bomba no reconocida</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.UnlockFailed">Fallo en el desbloqueo del inmovilizador</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.BenchCanLost">Bus CAN del banco perdido</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.PumpCanLost">CAN de la ECU perdido</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.AlarmTriggered">Alarma crítica disparada</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.OilPumpNotConfirmed">Confirmación de bomba de aceite cancelada por el operador</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.TestInterrupted">Prueba interrumpida</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.TestFailed">Prueba fallida</sys:String>
|
||||
<sys:String x:Key="AutoTest.Failure.Unexpected">Error inesperado</sys:String>
|
||||
|
||||
<!-- ── Error messages ───────────────────────────────────────────────── -->
|
||||
<sys:String x:Key="Error.ReportGeneration">Error al generar informe:\n{0}</sys:String>
|
||||
<sys:String x:Key="Error.ReportTitle">Error de Informe</sys:String>
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
<Setter Property="Padding" Value="16"/>
|
||||
<Setter Property="Margin" Value="6"/>
|
||||
<Setter Property="Margin" Value="4"/>
|
||||
<Setter Property="MinHeight" Value="140"/>
|
||||
</Style>
|
||||
|
||||
@@ -211,6 +211,34 @@
|
||||
<Setter Property="Height" Value="30"/>
|
||||
</Style>
|
||||
|
||||
<!-- ── Tests page: meta pill (Tacond / Tmeas / M·s⁻¹ chips in section header) ── -->
|
||||
<Style x:Key="TestMetaPill" TargetType="Border">
|
||||
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ControlStrokeColorDefaultBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="9"/>
|
||||
<Setter Property="Padding" Value="7,2"/>
|
||||
<Setter Property="Margin" Value="0,0,4,0"/>
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="TestMetaPillText" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="10"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<!-- ── Tests page: phase tile (compact card inside a TestSectionCard) ── -->
|
||||
<Style x:Key="PhaseTile" TargetType="Border">
|
||||
<Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ControlStrokeColorDefaultBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="6"/>
|
||||
<Setter Property="Padding" Value="6"/>
|
||||
<Setter Property="Margin" Value="3"/>
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
</Style>
|
||||
|
||||
<!-- Snackbar bottom-overlay shell -->
|
||||
<Style x:Key="SnackbarShell" TargetType="Border">
|
||||
<Setter Property="Background" Value="{DynamicResource CardBackgroundFillColorDefaultBrush}"/>
|
||||
@@ -272,4 +300,120 @@
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!--
|
||||
Fluent-style vertical slider with a thick pill-shaped track.
|
||||
- Track background fills the entire slider width (Width set on the Slider element).
|
||||
- Lower (decrease) portion is filled with the accent brush; upper portion is the
|
||||
unfilled rail in ControlStrongFillColorDefaultBrush.
|
||||
- Thumb is a horizontal Fluent-style pill with subtle border.
|
||||
Designed for Orientation="Vertical" only.
|
||||
-->
|
||||
<Style x:Key="FluentThickVerticalSlider" TargetType="Slider">
|
||||
<Setter Property="Focusable" Value="False"/>
|
||||
<!-- Intentionally NOT setting IsMoveToPointEnabled. The built-in implementation
|
||||
marks the preview event handled, which would suppress the code-behind
|
||||
handler that drives our click-anywhere-and-drag gesture. -->
|
||||
<Setter Property="MinWidth" Value="20"/>
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Slider">
|
||||
<!-- Background="Transparent" makes the Slider itself the click target,
|
||||
so the code-behind's PreviewMouseLeftButtonDown can capture and drive
|
||||
the value. Track repeat buttons are hit-test invisible to prevent
|
||||
ButtonBase's class handler from stealing mouse capture. -->
|
||||
<Grid HorizontalAlignment="Stretch" Background="Transparent" ClipToBounds="False">
|
||||
<!-- Unfilled rail. Pinned to a fixed cross-axis width and centered
|
||||
so the Slider can be widened to host an overhanging Thumb
|
||||
without growing the visible track. -->
|
||||
<Border CornerRadius="6"
|
||||
Background="{DynamicResource ControlStrongFillColorDefaultBrush}"
|
||||
Opacity="0.35"
|
||||
Width="32"
|
||||
HorizontalAlignment="Center"
|
||||
IsHitTestVisible="False"
|
||||
SnapsToDevicePixels="True"/>
|
||||
<!-- Track + thumb. Orientation/direction must mirror the templated
|
||||
Slider so Track.ValueFromPoint computes against the vertical axis. -->
|
||||
<Track x:Name="PART_Track"
|
||||
Orientation="{TemplateBinding Orientation}"
|
||||
IsDirectionReversed="{TemplateBinding IsDirectionReversed}">
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton Command="Slider.DecreaseLarge"
|
||||
IsTabStop="False" Focusable="False"
|
||||
IsHitTestVisible="False">
|
||||
<RepeatButton.Template>
|
||||
<ControlTemplate TargetType="RepeatButton">
|
||||
<!-- Filled portion pinned to the rail width so it
|
||||
stays inside the visible track regardless of how
|
||||
wide the Slider/Thumb are set. -->
|
||||
<Border CornerRadius="0,0,6,6"
|
||||
Background="{DynamicResource AccentFillColorDefaultBrush}"
|
||||
Width="32"
|
||||
HorizontalAlignment="Center"
|
||||
SnapsToDevicePixels="True"/>
|
||||
</ControlTemplate>
|
||||
</RepeatButton.Template>
|
||||
</RepeatButton>
|
||||
</Track.DecreaseRepeatButton>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton Command="Slider.IncreaseLarge"
|
||||
IsTabStop="False" Focusable="False"
|
||||
IsHitTestVisible="False">
|
||||
<RepeatButton.Template>
|
||||
<ControlTemplate TargetType="RepeatButton">
|
||||
<Border Background="Transparent"/>
|
||||
</ControlTemplate>
|
||||
</RepeatButton.Template>
|
||||
</RepeatButton>
|
||||
</Track.IncreaseRepeatButton>
|
||||
<Track.Thumb>
|
||||
<Thumb x:Name="ThumbPill" ClipToBounds="False">
|
||||
<Thumb.Template>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
<Grid ClipToBounds="False">
|
||||
<!-- Outer pill: white fill with subtle gray border.
|
||||
Width is fixed and centered so the pill can
|
||||
overhang the rail without being clipped. -->
|
||||
<Border x:Name="ThumbOuter"
|
||||
Height="20"
|
||||
Width="52"
|
||||
CornerRadius="8"
|
||||
Background="{DynamicResource ControlSolidFillColorDefaultBrush}"
|
||||
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
HorizontalAlignment="Center"
|
||||
SnapsToDevicePixels="True"/>
|
||||
<!-- Inner accent dot -->
|
||||
<Border x:Name="ThumbInner"
|
||||
Width="44" Height="12"
|
||||
CornerRadius="8"
|
||||
Background="{DynamicResource AccentFillColorDefaultBrush}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
SnapsToDevicePixels="True"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<!-- Press-color feedback only; thumb size stays constant. -->
|
||||
<Trigger Property="IsDragging" Value="True">
|
||||
<Setter TargetName="ThumbInner" Property="Background"
|
||||
Value="{DynamicResource AccentFillColorSecondaryBrush}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Thumb.Template>
|
||||
</Thumb>
|
||||
</Track.Thumb>
|
||||
</Track>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" Value="0.4"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
Reference in New Issue
Block a user