native macOS codings agent orchestrator
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

Surface custom repo title in settings list, settings nav title, and repo detail view

Extracts the per-leaf @Shared(.repositorySettings(rootURL))
subscription used by the sidebar header into a reusable
`RepoDisplayName` view, then applies it to the settings repository
list and `RepositoryDetailView`. The settings detail's
`.navigationTitle` needs a `String`, so a thin
`RepositorySettingsDetailContainer` wrapper holds the @Shared
subscription and resolves the title.

Hot-path readers (Shelf spine, Canvas card title, toolbar
notification groups) are left on `repository.name` for now — those
methods rebuild a fresh @Shared wrapper per call per frame and
trigger a write/notify storm through the global settings file.
A safe fix needs a single shared subscription threaded through
those methods rather than per-call wrappers.

+92 -53
+48
supacode/Features/Repositories/Views/RepoDisplayName.swift
··· 1 + import Sharing 2 + import SwiftUI 3 + 4 + /// Renders the repository display label, preferring the user's custom 5 + /// title from `RepositorySettings` over the folder-derived fallback. 6 + /// 7 + /// Subscription is isolated to this leaf view so callers don't pull in 8 + /// `@Shared(.repositorySettings(...))` themselves and parent views 9 + /// don't churn on settings changes. Mirrors the per-leaf-subscription 10 + /// pattern used by `RepoHeaderTabCountBadge`. 11 + /// 12 + /// The view emits a plain `Text` — callers apply their own font / 13 + /// foreground style modifiers so this view stays appearance-agnostic. 14 + struct RepoDisplayName: View { 15 + let fallbackName: String 16 + let repositoryRootURL: URL? 17 + var tooltip: String? 18 + 19 + var body: some View { 20 + if let repositoryRootURL { 21 + RepoDisplayNameResolved( 22 + rootURL: repositoryRootURL, 23 + fallbackName: fallbackName, 24 + tooltip: tooltip 25 + ) 26 + } else { 27 + Text(fallbackName) 28 + .help(tooltip ?? "") 29 + } 30 + } 31 + } 32 + 33 + private struct RepoDisplayNameResolved: View { 34 + let fallbackName: String 35 + let tooltip: String? 36 + @Shared private var settings: RepositorySettings 37 + 38 + init(rootURL: URL, fallbackName: String, tooltip: String?) { 39 + self.fallbackName = fallbackName 40 + self.tooltip = tooltip 41 + _settings = Shared(wrappedValue: .default, .repositorySettings(rootURL)) 42 + } 43 + 44 + var body: some View { 45 + Text(settings.customTitle ?? fallbackName) 46 + .help(tooltip ?? "") 47 + } 48 + }
+3 -45
supacode/Features/Repositories/Views/RepoHeaderRow.swift
··· 1 - import Sharing 2 1 import SwiftUI 3 2 4 3 struct RepoHeaderRow: View { ··· 26 25 size: 14 27 26 ) 28 27 } 29 - RepoHeaderTitleText( 28 + RepoDisplayName( 30 29 fallbackName: name, 31 30 repositoryRootURL: repositoryRootURL, 32 - nameTooltip: nameTooltip 31 + tooltip: nameTooltip 33 32 ) 33 + .foregroundStyle(.secondary) 34 34 if isRemoving { 35 35 Text("Removing...") 36 36 .font(.caption) ··· 47 47 } 48 48 } 49 49 } 50 - } 51 - } 52 - 53 - /// Resolves the repo header label, preferring the user's custom 54 - /// title from `RepositorySettings` over the folder-derived fallback. 55 - /// Subscription is isolated to this leaf so the parent header view 56 - /// doesn't re-evaluate when unrelated settings churn. 57 - private struct RepoHeaderTitleText: View { 58 - let fallbackName: String 59 - let repositoryRootURL: URL? 60 - let nameTooltip: String? 61 - 62 - var body: some View { 63 - if let repositoryRootURL { 64 - RepoHeaderTitleTextResolved( 65 - rootURL: repositoryRootURL, 66 - fallbackName: fallbackName, 67 - nameTooltip: nameTooltip 68 - ) 69 - } else { 70 - Text(fallbackName) 71 - .foregroundStyle(.secondary) 72 - .help(nameTooltip ?? "") 73 - } 74 - } 75 - } 76 - 77 - private struct RepoHeaderTitleTextResolved: View { 78 - let fallbackName: String 79 - let nameTooltip: String? 80 - @Shared private var settings: RepositorySettings 81 - 82 - init(rootURL: URL, fallbackName: String, nameTooltip: String?) { 83 - self.fallbackName = fallbackName 84 - self.nameTooltip = nameTooltip 85 - _settings = Shared(wrappedValue: .default, .repositorySettings(rootURL)) 86 - } 87 - 88 - var body: some View { 89 - Text(settings.customTitle ?? fallbackName) 90 - .foregroundStyle(.secondary) 91 - .help(nameTooltip ?? "") 92 50 } 93 51 } 94 52
+5 -2
supacode/Features/Repositories/Views/RepositoryDetailView.swift
··· 8 8 Image(systemName: repository.kind == .git ? "folder.badge.gearshape" : "folder") 9 9 .font(.largeTitle) 10 10 .accessibilityHidden(true) 11 - Text(repository.name) 12 - .font(.title3.weight(.semibold)) 11 + RepoDisplayName( 12 + fallbackName: repository.name, 13 + repositoryRootURL: repository.rootURL 14 + ) 15 + .font(.title3.weight(.semibold)) 13 16 Text(repository.rootURL.path(percentEncoded: false)) 14 17 .font(.subheadline.monospaced()) 15 18 .foregroundStyle(.secondary)
+36 -6
supacode/Features/Settings/Views/SettingsView.swift
··· 1 1 import ComposableArchitecture 2 + import Sharing 2 3 import SwiftUI 3 4 4 5 extension View { ··· 46 47 47 48 Section("Repositories") { 48 49 ForEach(repositories) { repository in 49 - Text(repository.name) 50 - .tag(SettingsSection.repository(repository.id)) 50 + RepoDisplayName( 51 + fallbackName: repository.name, 52 + repositoryRootURL: repository.rootURL 53 + ) 54 + .tag(SettingsSection.repository(repository.id)) 51 55 } 52 56 } 53 57 } ··· 106 110 IfLetStore( 107 111 settingsStore.scope(state: \.repositorySettings, action: \.repositorySettings) 108 112 ) { repositorySettingsStore in 109 - RepositorySettingsView(store: repositorySettingsStore) 110 - .id(repository.id) 111 - .navigationTitle(repository.name) 112 - .navigationSubtitle(repository.rootURL.path(percentEncoded: false)) 113 + RepositorySettingsDetailContainer( 114 + store: repositorySettingsStore, 115 + repository: repository 116 + ) 113 117 } 114 118 } 115 119 } else { ··· 132 136 .ignoresSafeArea(.container, edges: .top) 133 137 } 134 138 } 139 + 140 + /// Wraps `RepositorySettingsView` with a `@Shared` subscription on the 141 + /// repo's settings file so the navigation title can reflect the user's 142 + /// custom title (when set) instead of the folder-derived `Repository.name`. 143 + /// Lives here rather than inside `RepositorySettingsView` because the 144 + /// `.navigationTitle` modifier needs a `String`, not a view, and reading 145 + /// `@Shared` requires a struct property — wrapping at this layer keeps 146 + /// `RepositorySettingsView`'s interface untouched. 147 + private struct RepositorySettingsDetailContainer: View { 148 + let store: StoreOf<RepositorySettingsFeature> 149 + let repository: Repository 150 + @Shared private var settings: RepositorySettings 151 + 152 + init(store: StoreOf<RepositorySettingsFeature>, repository: Repository) { 153 + self.store = store 154 + self.repository = repository 155 + _settings = Shared(wrappedValue: .default, .repositorySettings(repository.rootURL)) 156 + } 157 + 158 + var body: some View { 159 + RepositorySettingsView(store: store) 160 + .id(repository.id) 161 + .navigationTitle(settings.customTitle ?? repository.name) 162 + .navigationSubtitle(repository.rootURL.path(percentEncoded: false)) 163 + } 164 + }