Skip to content

feat: unified Logged Data pane + dark theme sweep#494

Merged
tylerkron merged 9 commits intomainfrom
claude/distracted-tesla-5641c6
Apr 19, 2026
Merged

feat: unified Logged Data pane + dark theme sweep#494
tylerkron merged 9 commits intomainfrom
claude/distracted-tesla-5641c6

Conversation

@tylerkron
Copy link
Copy Markdown
Contributor

Summary

Continues the design-philosophy redesign across the app, focused on the Logged Data and Device Logs surfaces plus the OxyPlot rendering stack.

  • Logged Data pane rewritten from scratch to match the prototype pattern used by the Channels, Devices, and Settings drawers (sessions list, session header with inline controls, empty-state gating, single row of chrome).
  • OxyPlot dark theme — new `Helpers/OxyPlotDarkTheme.cs` mirrors the design tokens (Surface, BorderDim, TextSecondary, Accent, etc.) and is applied to the live `PlotLogger`, the `DatabaseLogger` session plot, and the minimap (dim overlay + accent selection rect).
  • Plot chrome consolidation — zoom / reset / save-PNG buttons moved out of the plot area into the session header strip as a horizontal pill row, with an Arrow*Vertical swap for the Y-zoom icons and a divider between zoom and reset/save.
  • Device Logs tab themed to match: kickered DEVICE selector, dark ComboBox (custom template because MahApps Light.Blue forces a white toggle), SurfaceRaised connection-status pill with a status-color dot, dark ListView/GridView with Consolas filename, FORMAT chip, per-row IMPORT pill, and two guarded empty states (NO FILES vs USB REQUIRED) behind a MultiDataTrigger so the empty ListView never shows through.
  • Bug fixes picked up along the way: `OxyColorToBrushConverter` was declared only in `MainWindow.xaml` and couldn't be resolved from inside a `ContentPresenter` DataTemplate, causing a `XamlParseException` when clicking a logging session — promoted to `App.xaml` so it's reachable from every scope.
  • Cleanup: removed `LoggedSessionFlyout.xaml/.cs` (dead after the drawer rewrite) and the unused `StringRightConverter`.

Test plan

  • Open the Logged Data pane with no sessions — verify single empty state, no overlap
  • Open with sessions, click one — plot loads without `XamlParseException`
  • Zoom X/Y from the header strip; reset-zoom restores view; save exports a PNG
  • Minimap drag/dim renders with the dark palette (accent selection rect, translucent black dim)
  • Device Logs tab: WiFi device shows USB REQUIRED, USB device with empty SD shows NO FILES, USB device with files shows the list; refresh/import/per-row import all work
  • Dark ComboBox opens over `SurfaceRaised` popup, keyboard-focus border goes Accent, hover border goes BorderBright
  • Full regression pass across other panes (Channels, Devices, Settings drawer) to confirm no style bleed

🤖 Generated with Claude Code

tylerkron and others added 7 commits April 18, 2026 15:02
Redesigns the Logged Data page to match the dark, tile-based language
established by the Channels and Devices panes. Session list becomes an
inline dark list with accent stripe for selection; plot area carries
session header/minimap/legend; APP LOGS / DEVICE LOGS switches from
legacy tabs to a segmented toggle. Session settings open in an inline
drawer rather than the old flyout. Removes the now-unreferenced
LoggedSessionFlyout in keeping with "replace rather than skin."

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The converter was defined only in MainWindow.xaml Resources, which is
not visible from DataTemplates realized inside the new Logged Data
pane's ContentPresenter. Clicking a session triggered a XamlParseException
when the legend item template tried to resolve the brush. Move the
converter to App.xaml so it is globally available.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The logged-data plot and minimap (and the live-graph plot) were still
rendering with OxyPlot's default light colors — a bright white panel
in the middle of a dark app, directly violating principle #2 and
fragmenting the visual system. Add an OxyPlotDarkTheme helper that
mirrors the DesignTokens palette (Surface, BorderDim, TextSecondary,
Accent) and apply it in DatabaseLogger and PlotLogger. The minimap's
dim overlay flips from light-gray to translucent black, and its
selection rectangle adopts the accent color so the selected viewport
reads as the active region rather than a cutout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Save-image and zoom buttons previously floated over the plot,
overlapping the rightmost axis ticks and sitting on top of the data.
Moved them into the right side of the session header strip so the
plot area shows data only (principle #1) and all plot chrome lives
in one row (principle #8). Swapped the Y-zoom magnifier icons for
vertical expand/collapse arrows so X-zoom and Y-zoom read as
different axes at a glance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrites DeviceLogsView to match the design philosophy used across the
Channels, Devices, Settings, and Logged Data surfaces. Adds local pill
button, dark ComboBox, and dark ListView/GridView styles; replaces the
old light ComboBox + white buttons with a kickered device selector and
pill/accent actions; introduces two dedicated empty states (NO FILES and
USB REQUIRED); wraps the connection status in a SurfaceRaised pill with
a status-color dot; and gates the ListView behind a MultiDataTrigger so
it only shows when a USB device has at least one file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Defined as a global resource in MainWindow.xaml but never referenced by
any binding. Orphaned after the drawer and flyout redesigns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@tylerkron tylerkron requested a review from a team as a code owner April 19, 2026 03:37
@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Redesign Logged Data pane with dark theme and unified UI patterns

✨ Enhancement 🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Redesigned Logged Data pane with dark theme matching design system
• Applied OxyPlot dark theme to plots, minimap, and live graph rendering
• Consolidated plot controls into header strip with zoom/reset/save buttons
• Refactored Device Logs tab with dark ComboBox, styled list, and empty states
• Fixed XamlParseException by promoting OxyColorToBrushConverter to App.xaml
• Removed unused StringRightConverter and legacy LoggedSessionFlyout
Diagram
flowchart LR
  A["Old Logged Data<br/>Light theme<br/>Legacy layout"] -->|Redesign| B["New LoggedDataPanePrototype<br/>Dark theme<br/>Prototype pattern"]
  C["OxyPlot<br/>Default colors"] -->|Apply| D["OxyPlotDarkTheme<br/>Design tokens<br/>Surface/Accent/Border"]
  D -->|Theme| E["PlotLogger<br/>DatabaseLogger<br/>Minimap"]
  F["MainWindow.xaml<br/>OxyColorToBrushConverter"] -->|Promote| G["App.xaml<br/>Global scope"]
  H["DeviceLogsView<br/>Basic styling"] -->|Enhance| I["Dark ComboBox<br/>Styled ListView<br/>Empty states"]
Loading

Grey Divider

File Changes

1. Daqifi.Desktop/Helpers/OxyPlotDarkTheme.cs ✨ Enhancement +48/-0

New dark theme helper for OxyPlot models

Daqifi.Desktop/Helpers/OxyPlotDarkTheme.cs


2. Daqifi.Desktop/Loggers/DatabaseLogger.cs ✨ Enhancement +10/-4

Apply dark theme to plot and minimap

Daqifi.Desktop/Loggers/DatabaseLogger.cs


3. Daqifi.Desktop/Loggers/PlotLogger.cs ✨ Enhancement +6/-0

Apply dark theme to live graph plot

Daqifi.Desktop/Loggers/PlotLogger.cs


View more (8)
4. Daqifi.Desktop/View/Prototype/LoggedDataPanePrototype.xaml.cs ✨ Enhancement +6/-6

Rename and refactor session settings handler

Daqifi.Desktop/View/Prototype/LoggedDataPanePrototype.xaml.cs


5. Daqifi.Desktop/ViewModels/DaqifiViewModel.cs ✨ Enhancement +8/-0

Add HasLoggingSessions property and close command

Daqifi.Desktop/ViewModels/DaqifiViewModel.cs


6. Daqifi.Desktop/App.xaml 🐞 Bug fix +1/-0

Promote OxyColorToBrushConverter to global scope

Daqifi.Desktop/App.xaml


7. Daqifi.Desktop/MainWindow.xaml ✨ Enhancement +7/-547

Replace Logged Data content with prototype, remove legacy styles

Daqifi.Desktop/MainWindow.xaml


8. Daqifi.Desktop/View/DeviceLogsView.xaml ✨ Enhancement +375/-82

Redesign with dark theme, styled controls, and empty states

Daqifi.Desktop/View/DeviceLogsView.xaml


9. Daqifi.Desktop/View/Prototype/LoggedDataPanePrototype.xaml ✨ Enhancement +1008/-0

Complete redesign of Logged Data pane with dark theme

Daqifi.Desktop/View/Prototype/LoggedDataPanePrototype.xaml


10. Daqifi.Desktop/Converters/StringRightConverter.cs Miscellaneous +0/-30

Remove unused string converter

Daqifi.Desktop/Converters/StringRightConverter.cs


11. Daqifi.Desktop/View/Flyouts/LoggedSessionFlyout.xaml Miscellaneous +0/-25

Remove legacy session settings flyout

Daqifi.Desktop/View/Flyouts/LoggedSessionFlyout.xaml


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented Apr 19, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Remediation recommended

1. Empty session name persisted🐞 Bug ≡ Correctness
Description
LoggedDataPanePrototype.OnSessionNameChanged persists the raw TextBox text to both the in-memory
LoggingSession and the database even when it’s empty/whitespace. Because LoggingSession.Name renders
whitespace as a computed default ("Session {ID}"), the UI can display a non-empty name while the DB
stores an empty string, making renames appear inconsistent after reload.
Code

Daqifi.Desktop/View/Prototype/LoggedDataPanePrototype.xaml.cs[R30-33]

+    private async void OnSessionNameChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
    {
        if ((DataContext as DaqifiViewModel)?.SelectedLoggingSession is not LoggingSession session ||
            sender is not System.Windows.Controls.TextBox textBox)
Evidence
The rename handler saves newName = textBox.Text directly onto the entity and into the DB. The
LoggingSession.Name getter masks empty/whitespace _name values by returning a generated default
string, so persisting an empty string creates a mismatch between what’s stored and what’s shown.

Daqifi.Desktop/View/Prototype/LoggedDataPanePrototype.xaml.cs[30-57]
Daqifi.Desktop/Loggers/LoggingSession.cs[43-47]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`OnSessionNameChanged` writes `textBox.Text` verbatim into `LoggingSession.Name` and `Sessions.Name`. Because `LoggingSession.Name` *renders* whitespace as a computed default (`"Session {ID}"`), persisting whitespace/empty values can cause the UI to show a default name while the DB stores an empty string.

## Issue Context
This is a debounced rename flow; users may briefly clear the textbox (or type spaces) while editing.

## Fix Focus Areas
- Daqifi.Desktop/View/Prototype/LoggedDataPanePrototype.xaml.cs[30-74]
- Daqifi.Desktop/Loggers/LoggingSession.cs[43-47]

## Suggested fix
- Trim the input and treat empty/whitespace as `null` (or don’t persist changes when blank).
- Persist the same normalized value that the UI will display (e.g., store `null` and let the getter generate, or store the generated default string explicitly), so DB and UI are consistent.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

tylerkron and others added 2 commits April 18, 2026 22:03
…la-5641c6

# Conflicts:
#	Daqifi.Desktop/MainWindow.xaml
The session name textbox persists textBox.Text verbatim, but
LoggingSession.Name's getter renders whitespace as "Session {ID}".
Clearing the textbox therefore writes "" to the DB while the UI shows
the computed default, so the two disagree on reload.

Trim the input and persist null when blank. The getter then produces
the same "Session {ID}" for both in-memory and reloaded state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@tylerkron
Copy link
Copy Markdown
Contributor Author

@qodo-code-review regarding the Empty session name persisted finding — fixed in 496ee3b.

OnSessionNameChanged now trims textBox.Text and persists null when the trimmed result is empty, so LoggingSession.Name's getter renders the same "Session {ID}" default whether the session was just edited blank or reloaded from the DB. DB and UI now agree.

@github-actions
Copy link
Copy Markdown

📊 Code Coverage Report

Summary

Summary
Generated on: 4/19/2026 - 4:08:56 AM
Coverage date: 4/19/2026 - 4:08:23 AM - 4/19/2026 - 4:08:52 AM
Parser: MultiReport (4x Cobertura)
Assemblies: 3
Classes: 118
Files: 145
Line coverage: 17.8% (1507 of 8439)
Covered lines: 1507
Uncovered lines: 6932
Coverable lines: 8439
Total lines: 25492
Branch coverage: 18.9% (521 of 2752)
Covered branches: 521
Total branches: 2752
Method coverage: Feature is only available for sponsors

Coverage

DAQiFi - 17.6%
Name Line Branch
DAQiFi 17.6% 18.9%
Daqifi.Desktop.App 5.4% 0%
Daqifi.Desktop.Channel.AbstractChannel 40.9% 27.7%
Daqifi.Desktop.Channel.AnalogChannel 58.7% 25%
Daqifi.Desktop.Channel.Channel 11.5% 0%
Daqifi.Desktop.Channel.ChannelColorManager 100% 100%
Daqifi.Desktop.Channel.DataSample 91.6%
Daqifi.Desktop.Channel.DigitalChannel 65.2% 25%
Daqifi.Desktop.Commands.CompositeCommand 0% 0%
Daqifi.Desktop.Commands.HostCommands 0%
Daqifi.Desktop.Commands.WeakEventHandlerManager 0% 0%
Daqifi.Desktop.Configuration.FirewallConfiguration 90.6% 66.6%
Daqifi.Desktop.Configuration.WindowsFirewallWrapper 64% 68.4%
Daqifi.Desktop.ConnectionManager 42.4% 39.2%
Daqifi.Desktop.Converters.BoolToActiveStatusConverter 0% 0%
Daqifi.Desktop.Converters.BoolToConnectionStatusConverter 0% 0%
Daqifi.Desktop.Converters.BoolToStatusColorConverter 0% 0%
Daqifi.Desktop.Converters.BrushColorMatchConverter 0% 0%
Daqifi.Desktop.Converters.ConnectionTypeToColorConverter 0% 0%
Daqifi.Desktop.Converters.ConnectionTypeToUsbConverter 0% 0%
Daqifi.Desktop.Converters.InvertedBoolToVisibilityConverter 0% 0%
Daqifi.Desktop.Converters.ListToStringConverter 0% 0%
Daqifi.Desktop.Converters.NotNullToVisibilityConverter 0% 0%
Daqifi.Desktop.Converters.OxyColorToBrushConverter 0% 0%
Daqifi.Desktop.Device.AbstractStreamingDevice 42.9% 38.6%
Daqifi.Desktop.Device.DeviceMessage 0%
Daqifi.Desktop.Device.Firmware.BootloaderSessionStreamingDeviceAdapter 0% 0%
Daqifi.Desktop.Device.Firmware.WifiPromptDelayProcessRunner 0% 0%
Daqifi.Desktop.Device.NativeMethods 100%
Daqifi.Desktop.Device.SerialDevice.SerialStreamingDevice 27.6% 30.8%
Daqifi.Desktop.Device.WiFiDevice.DaqifiStreamingDevice 40.9% 39.4%
Daqifi.Desktop.DialogService.DialogService 0% 0%
Daqifi.Desktop.DialogService.ServiceLocator 0% 0%
Daqifi.Desktop.DiskSpace.DiskSpaceCheckResult 100%
Daqifi.Desktop.DiskSpace.DiskSpaceEventArgs 100%
Daqifi.Desktop.DiskSpace.DiskSpaceMonitor 88.2% 86.6%
Daqifi.Desktop.DuplicateDeviceCheckResult 100%
Daqifi.Desktop.Exporter.OptimizedLoggingSessionExporter 66.5% 62.7%
Daqifi.Desktop.Exporter.SampleData 100%
Daqifi.Desktop.Helpers.BooleanConverter`1 0% 0%
Daqifi.Desktop.Helpers.BooleanToInverseBoolConverter 0% 0%
Daqifi.Desktop.Helpers.BooleanToVisibilityConverter 0%
Daqifi.Desktop.Helpers.EnumDescriptionConverter 100% 100%
Daqifi.Desktop.Helpers.IntToVisibilityConverter 0% 0%
Daqifi.Desktop.Helpers.MinMaxDownsampler 98.6% 97.9%
Daqifi.Desktop.Helpers.MyMultiValueConverter 0%
Daqifi.Desktop.Helpers.NaturalSortHelper 100% 100%
Daqifi.Desktop.Helpers.OxyPlotDarkTheme 0%
Daqifi.Desktop.Helpers.VersionHelper 98.2% 66.2%
Daqifi.Desktop.Logger.DatabaseLogger 0% 0%
Daqifi.Desktop.Logger.DatabaseMigrator 0% 0%
Daqifi.Desktop.Logger.DeviceLegendGroup 100% 100%
Daqifi.Desktop.Logger.LoggedSeriesLegendItem 0% 0%
Daqifi.Desktop.Logger.LoggingContext 100%
Daqifi.Desktop.Logger.LoggingContextDesignTimeFactory 0%
Daqifi.Desktop.Logger.LoggingManager 0% 0%
Daqifi.Desktop.Logger.LoggingSession 16% 5%
Daqifi.Desktop.Logger.PlotLogger 0% 0%
Daqifi.Desktop.Logger.SessionDeviceMetadata 80%
Daqifi.Desktop.Logger.SummaryLogger 0% 0%
Daqifi.Desktop.Logger.TimestampGapDetector 95% 83.3%
Daqifi.Desktop.Loggers.ImportOptions 0%
Daqifi.Desktop.Loggers.ImportProgress 0% 0%
Daqifi.Desktop.Loggers.SdCardSessionImporter 0% 0%
Daqifi.Desktop.MainWindow 0% 0%
Daqifi.Desktop.Migrations.AddSamplesSessionTimeIndex 0%
Daqifi.Desktop.Migrations.AddSessionDeviceMetadata 0%
Daqifi.Desktop.Migrations.AddSessionSampleCount 0%
Daqifi.Desktop.Migrations.InitialSQLiteMigration 0%
Daqifi.Desktop.Migrations.LoggingContextModelSnapshot 0%
Daqifi.Desktop.Models.AddProfileModel 0%
Daqifi.Desktop.Models.DaqifiSettings 80.5% 83.3%
Daqifi.Desktop.Models.DebugDataCollection 6.6% 0%
Daqifi.Desktop.Models.DebugDataModel 0% 0%
Daqifi.Desktop.Models.Notifications 0%
Daqifi.Desktop.Models.SdCardFile 0% 0%
Daqifi.Desktop.Services.WindowsPrincipalAdminChecker 0%
Daqifi.Desktop.Services.WpfMessageBoxService 0%
Daqifi.Desktop.UpdateVersion.VersionNotification 0% 0%
Daqifi.Desktop.View.ConnectionDialog 0% 0%
Daqifi.Desktop.View.DebugWindow 0% 0%
Daqifi.Desktop.View.DeviceLogsView 0% 0%
Daqifi.Desktop.View.DuplicateDeviceDialog 0% 0%
Daqifi.Desktop.View.ErrorDialog 0% 0%
Daqifi.Desktop.View.ExportDialog 0% 0%
Daqifi.Desktop.View.FirmwareDialog 0% 0%
Daqifi.Desktop.View.Flyouts.FirmwareFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.LiveGraphFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.NotificationsFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.SummaryFlyout 0% 0%
Daqifi.Desktop.View.MigrationStatusWindow 0% 0%
Daqifi.Desktop.View.MinimapInteractionController 0% 0%
Daqifi.Desktop.View.ProfilesPane 0% 0%
Daqifi.Desktop.View.Prototype.ChannelsPanePrototype 0% 0%
Daqifi.Desktop.View.Prototype.DevicesPanePrototype 0% 0%
Daqifi.Desktop.View.Prototype.LoggedDataPanePrototype 0% 0%
Daqifi.Desktop.View.SuccessDialog 0% 0%
Daqifi.Desktop.ViewModels.ChannelsPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.ChannelTileViewModel 0% 0%
Daqifi.Desktop.ViewModels.ConnectionDialogViewModel 37.3% 39.1%
Daqifi.Desktop.ViewModels.DaqifiViewModel 17.5% 11%
Daqifi.Desktop.ViewModels.DeviceLogsViewModel 0% 0%
Daqifi.Desktop.ViewModels.DevicesPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.DeviceTileViewModel 0% 0%
Daqifi.Desktop.ViewModels.DuplicateDeviceDialogViewModel 0%
Daqifi.Desktop.ViewModels.ErrorDialogViewModel 0%
Daqifi.Desktop.ViewModels.ExportDialogViewModel 0% 0%
Daqifi.Desktop.ViewModels.FirmwareDialogViewModel 0% 0%
Daqifi.Desktop.ViewModels.NewProfileChannelItem 0%
Daqifi.Desktop.ViewModels.NewProfileDeviceItem 0% 0%
Daqifi.Desktop.ViewModels.ProfilesPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.SettingsViewModel 0% 0%
Daqifi.Desktop.ViewModels.SuccessDialogViewModel 85.7%
Daqifi.Desktop.WindowViewModelMapping.IWindowViewModelMappingsContract 0%
Daqifi.Desktop.WindowViewModelMapping.WindowViewModelMappings 0%
Sentry.Generated.BuildPropertyInitializer 100%
Daqifi.Desktop.Common - 30.8%
Name Line Branch
Daqifi.Desktop.Common 30.8% 16.6%
Daqifi.Desktop.Common.Loggers.AppLogger 33.7% 16.6%
Daqifi.Desktop.Common.Loggers.NoOpLogger 0%
Daqifi.Desktop.IO - 100%
Name Line Branch
Daqifi.Desktop.IO 100% ****
Daqifi.Desktop.IO.Messages.MessageEventArgs`1 100%

Coverage report generated by ReportGeneratorView full report in build artifacts

@tylerkron tylerkron merged commit 9107d7c into main Apr 19, 2026
2 checks passed
@tylerkron tylerkron deleted the claude/distracted-tesla-5641c6 branch April 19, 2026 04:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant