Split MainWindowViewModel into feature view-models - #80
Merged
Merged
Conversation
IsRendering and RenderProgress were never set outside a test, so the loading overlay always read "Loading..." with an indeterminate bar. The overlay now says so directly, which keeps the dead state from being carried into the view-model split.
The first step of splitting MainWindowViewModel by feature. ErrorOverlayViewModel owns the notice that covers the video area (title, details, dismissability, the first-run empty state, and the FFmpeg download prompt), and every feature reports through the one instance the main window owns. The overlay-visibility logic that combines errors with loading and selection state stays on the main view-model.
AboutViewModel owns what the About and help page shows: this build's version and runtime, and the result of the update check. Opening and closing the page stays on the main view-model, since the window and keyboard handling drive it.
CameraViewsViewModel owns which camera is enlarged (or the grid), the selector strip built from the cameras a clip actually recorded, the event-camera mapping, and which camera an export of the current view uses. The window now listens to it directly to re-parent its Flyleaf hosts, and the main view-model only tells it when the selected clip changes.
PlaybackViewModel owns the player: loading the selected clip, transport commands, the seek gesture and scrubbing, the event marker, chunk seams and gap ticks, the now-playing badge, and speed. Siblings reach the player only through a small surface (the playlist, a raw stop, the open clip and its media source), and the player reports clip changes back through an event instead of writing the list selection itself. IsLoading used to be one flag written by the clip scan, the FFmpeg download, and clip loading, which never overlap. The main view-model now computes it from the three, while CanSeek and the transport gates read only the playback part, which is the only part that was ever set whenever they could be true.
ClipLibraryViewModel owns the clip list: scanning dashcam folders, search with its debounce, the selected clip, and the per-clip context menu actions (open folder, copy, delete, show on map). The main view-model reacts to the selection (camera tiles, trim, loading the clip) and feeds clip changes from the player back into it.
TrimViewModel owns the trim panel's in/out marks and both exports (the marked range and "Save event clip"). It follows the player on its own: its commands re-check whenever seeking becomes possible or impossible, and the marks are dropped when the player rebuilds the clip's media, since they no longer point at the same footage. This finishes the split. MainWindowViewModel is down from about 1,900 lines to about 430 and now only composes the feature view-models and owns what spans them: startup, the overlay over the video area, the About page toggle, the FFmpeg prompt, and keyboard shortcuts.
Three connections now cross view-model boundaries and had no direct test: - The player reports clip changes back to the list, so Next moves the list selection. - The loading overlay follows the clip scan, not only clip loading, now that IsLoading combines the scan, the FFmpeg download, and playback. - The trim marks are dropped when recovery rebuilds a clip's media, now that TrimViewModel follows PlaybackViewModel itself. Each test was checked to fail with its wiring removed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
MainWindowViewModelwas about 1,900 lines owning every feature. It's now a roughly 430-line shell that composes one view-model per feature and owns only what spans them. One commit per extraction, so merge without squashing to keep them.ErrorOverlayViewModelAboutViewModelCameraViewsViewModelPlaybackViewModelClipLibraryViewModelTrimViewModelMainWindowViewModelThe new view-models live in
SentryDeck/ViewModels/. The window binds to them through the shell (Playback.CanSeek,Library.SelectedClip, and so on), and the code-behind talks toCamerasandPlaybackdirectly.Behavior
No intended behavior change. Two internal changes are worth reviewing:
IsLoadingwas one flag written by the clip scan, the FFmpeg download, and clip loading, which never overlap. The shell now computes it from the three.PlaybackViewModel.CurrentClipChangedinstead of writing the selection itself.The unused render-progress state (
IsRendering/RenderProgress, never set outside a test) is removed first, so it isn't carried into the split.How this was checked
mainwere identical. After every commit the diff againstmainwas 0 lines with 0 binding errors.mainwithin run-to-run noise.Found along the way (not changed here)
CanStopisIsPlaying || IsLoading).