You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While wrapping up architecture review P2 #3 (shared view-model extraction for the three detail view pairs), we noticed that apps/Mac/Views/SongDetailView.swift is 1,626 lines versus apps/iOS/Views/SongDetailView.swift at 887 lines. That's ~740 lines of asymmetry between two files that are supposed to render the same data.
The difference breaks down into two independent causes.
Cause 1: iOS extracts subviews into component files; Mac inlines everything
iOS keeps these subviews in their own files under apps/iOS/Components/:
File
Lines
RecordingsSection.swift
479
BackingTracksSection.swift
304
TranscriptionsSection.swift
186
TranscriptionRowView.swift
116
Total
1,085
Mac defines the same material inline at the bottom of SongDetailView.swift:
Type
Lines
RecordingCard
~215
FeaturedRecordingCard
~191
TranscriptionRow
~83
BackingTrackRow
~99
StreamingButtons
~58
Total
~646
Cause 2: Mac's main SongDetailView struct is itself ~290 lines bigger
Mac's struct has recording filtering + grouping logic that iOS delegates to its RecordingsSection component:
Plus the corresponding Mac-only filter UI state: selectedFilter, selectedVocalFilter, selectedInstrument.
These represent a Mac-only UX choice (decade grouping and artist consolidation) that iOS does not currently offer, so it is not purely "code in the wrong place" — but the asymmetry means a logic fix has to be made twice if iOS ever adopts the same grouping.
Proposed fix
Pure file moves first (low-risk): extract Mac's five inline subviews into apps/Mac/Components/ mirroring the iOS structure.
RecordingCard.swift
FeaturedRecordingCard.swift
TranscriptionRow.swift
BackingTrackRow.swift
StreamingButtons.swift
Expected result: Mac SongDetailView.swift drops to ~980 lines. No behavior change. Diff reviewable line-by-line.
Then share the filtering/grouping logic: move availableInstruments / filteredRecordings / groupedRecordings / groupByDecade / groupByArtistWithConsolidation into a shared utility (apps/Shared/Support/RecordingGrouping.swift, or methods on SongDetailViewModel). This is the higher-value step because it kills the "every grouping bug fix has to be made twice" risk if iOS ever adopts this UX.
Consider exposing decade/artist grouping in iOS too, now that the logic is shared. This is a product decision, not a cleanup one — skip if not desired.
Context
While wrapping up architecture review P2 #3 (shared view-model extraction for the three detail view pairs), we noticed that
apps/Mac/Views/SongDetailView.swiftis 1,626 lines versusapps/iOS/Views/SongDetailView.swiftat 887 lines. That's ~740 lines of asymmetry between two files that are supposed to render the same data.The difference breaks down into two independent causes.
Cause 1: iOS extracts subviews into component files; Mac inlines everything
iOS keeps these subviews in their own files under
apps/iOS/Components/:RecordingsSection.swiftBackingTracksSection.swiftTranscriptionsSection.swiftTranscriptionRowView.swiftMac defines the same material inline at the bottom of
SongDetailView.swift:RecordingCardFeaturedRecordingCardTranscriptionRowBackingTrackRowStreamingButtonsCause 2: Mac's main
SongDetailViewstruct is itself ~290 lines biggerMac's struct has recording filtering + grouping logic that iOS delegates to its
RecordingsSectioncomponent:availableInstruments(_:)— Mac/SongDetailView.swift:477filteredRecordings(_:)— :493groupedRecordings(_:)— :539groupByDecade(_:)— :549groupByArtistWithConsolidation(_:)— :574Plus the corresponding Mac-only filter UI state:
selectedFilter,selectedVocalFilter,selectedInstrument.These represent a Mac-only UX choice (decade grouping and artist consolidation) that iOS does not currently offer, so it is not purely "code in the wrong place" — but the asymmetry means a logic fix has to be made twice if iOS ever adopts the same grouping.
Proposed fix
Pure file moves first (low-risk): extract Mac's five inline subviews into
apps/Mac/Components/mirroring the iOS structure.RecordingCard.swiftFeaturedRecordingCard.swiftTranscriptionRow.swiftBackingTrackRow.swiftStreamingButtons.swiftSongDetailView.swiftdrops to ~980 lines. No behavior change. Diff reviewable line-by-line.Then share the filtering/grouping logic: move
availableInstruments/filteredRecordings/groupedRecordings/groupByDecade/groupByArtistWithConsolidationinto a shared utility (apps/Shared/Support/RecordingGrouping.swift, or methods onSongDetailViewModel). This is the higher-value step because it kills the "every grouping bug fix has to be made twice" risk if iOS ever adopts this UX.Consider exposing decade/artist grouping in iOS too, now that the logic is shared. This is a product decision, not a cleanup one — skip if not desired.
Context links
doc/architecture-review-2026-04.md(P2 Maybe cache Wikipedia search actions not just pages #3)58a1149,903d4a3,f0955e5apps/Shared/ViewModels/SongDetailViewModel.swiftis a natural home for any logic that should be platform-agnosticNot in scope for this issue
SongDetailView.swift— it is legitimately platform-specific layout.🤖 Generated with Claude Code