Problem
ProjectDetailView.swift (192 lines) and WorktreeDetailView.swift (168 lines) share ~75% of their code:
- Identical overall structure:
VStack { header; Divider; tabBar; Divider; content }
- Identical tab bar (segmented picker for unstaged/PR diffs, same padding)
- Identical unstaged content section (delegates to
DiffListView)
- Nearly identical PR content section
- Identical
ghUnavailableView (already extracted to shared GHUnavailableView in recent cleanup)
- Same
@State private var diffState = DiffState() pattern
- Same
.task / .onDisappear lifecycle
The only real differences are:
- The header shows project info vs worktree info (icon, name, metadata)
- PR selection UI (list with back-navigation vs dropdown picker)
- The data loading call (
loadForProject vs loadForWorktree)
Suggested approach
Create a single DiffDetailView parameterized on the entity, with the header and PR selection UI injected via @ViewBuilder or a protocol. Estimated ~100 lines saved.
Files
apps/purepoint-macos/purepoint-macos/Views/Detail/ProjectDetailView.swift
apps/purepoint-macos/purepoint-macos/Views/Detail/WorktreeDetailView.swift
Problem
ProjectDetailView.swift(192 lines) andWorktreeDetailView.swift(168 lines) share ~75% of their code:VStack { header; Divider; tabBar; Divider; content }DiffListView)ghUnavailableView(already extracted to sharedGHUnavailableViewin recent cleanup)@State private var diffState = DiffState()pattern.task/.onDisappearlifecycleThe only real differences are:
loadForProjectvsloadForWorktree)Suggested approach
Create a single
DiffDetailViewparameterized on the entity, with the header and PR selection UI injected via@ViewBuilderor a protocol. Estimated ~100 lines saved.Files
apps/purepoint-macos/purepoint-macos/Views/Detail/ProjectDetailView.swiftapps/purepoint-macos/purepoint-macos/Views/Detail/WorktreeDetailView.swift