Skip to content

Extract MainWindowViewModel from MainWindow#34

Merged
danielchalmers merged 2 commits into
mainfrom
claude/upbeat-bohr-be1d07
Jun 18, 2026
Merged

Extract MainWindowViewModel from MainWindow#34
danielchalmers merged 2 commits into
mainfrom
claude/upbeat-bohr-be1d07

Conversation

@danielchalmers

Copy link
Copy Markdown
Owner

What

Splits the 996-line MainWindow god-object into a dedicated MainWindowViewModel plus a thin view shell, then adds unit tests for the extracted logic.

Before

MainWindow.xaml.cs (996 lines) was simultaneously the Window, the view-model ([INotifyPropertyChanged] + DataContext = this), the playback orchestrator, the update checker, the FFmpeg prompt host, the clip loader, the keyboard handler, and the shell-action host. None of that logic was unit-testable, because you can't instantiate a WPF Window in a test.

After

  • MainWindowViewModel.cs (new) — all observable state, computed properties, commands, clip loading, playback orchestration, update checks, FFmpeg prompts, the error-overlay state machine, and keyboard handling.
  • MainWindow.xaml.cs (996 → 227 lines) — only genuine view concerns: window lifecycle/shutdown, the Flyleaf host-layout engine (reparents named controls), seek-slider input plumbing, search-box focus, and hyperlink navigation.
  • MainWindow.xaml — only the design-time d:DataContext type changed.

Seams used to keep them decoupled

  • The view injects a Func<VideoPlayerController> factory closing over the named FlyleafHost controls, so the VM owns the controller without referencing any control.
  • The VM raises SearchBoxFocusRequested; the view handles focus.
  • The view reacts to SelectedCameraView changes to drive host layout.

Tests

Adds MainWindowViewModelTests (27 new cases) covering logic that previously had zero coverage: camera-view selection, about toggle, the overlay/visibility state machine, play/stop enablement, loading/render text, the update badge, the search-focus keyboard shortcut, and error dismissal.

Full suite: 81 passing (was 54).

Behavior

No intended runtime change. Verified locally: builds clean, all tests pass, and a startup smoke-run produces the identical initialization sequence (init → FFmpeg check → prompt). Manually confirmed working by the maintainer.

Notes / follow-ups

  • FilteredClips filtering, seek math, and the clip→auto-play path need a small DI seam or a pumped dispatcher to test cleanly — deferred.
  • This unblocks further slicing (ClipBrowser / Playback / Updates / About sub-models) and is step 1 of the agreed reorg plan.

@danielchalmers danielchalmers merged commit d870834 into main Jun 18, 2026
1 check passed
@danielchalmers danielchalmers deleted the claude/upbeat-bohr-be1d07 branch June 18, 2026 17:35
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