native macOS codings agent orchestrator
6
fork

Configure Feed

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

fix(repo-appearance): open icon image picker at the repo's working directory

SwiftUI's `.fileImporter()` doesn't expose an initial directory, so the
"Choose Image…" panel always opened at the user's last-used location
(usually `~/Documents` or `~/Downloads`). Most users keep their icon
asset next to the project, so they had to navigate to the repo by hand
every time.

Switch to `NSOpenPanel.begin` and seed `directoryURL` from
`store.rootURL` so Finder lands directly inside the repo. Drop the now-
redundant `isImageImporterPresented` state and `.fileImporter` modifier;
the rest of the import flow (security-scoped access isn't needed for
`NSOpenPanel`-returned URLs in this non-sandboxed app) collapses to a
single `store.send(.importUserImage(url))` on `.OK`.

The reducer's `userImageImportFailed` action stays — it's still emitted
from the in-reducer copy-failure path.

onevcat 5aca2e9c 0bf6122b

+21 -30
+21 -30
supacode/Features/RepositorySettings/Views/RepositoryAppearancePickerView.swift
··· 18 18 @Bindable var store: StoreOf<RepositorySettingsFeature> 19 19 20 20 @State private var isSymbolPickerPresented = false 21 - @State private var isImageImporterPresented = false 22 21 @State private var isHoveringIconTile = false 23 22 24 23 private let previewSize: CGFloat = 40 ··· 56 55 onCancel: { isSymbolPickerPresented = false } 57 56 ) 58 57 } 59 - // Accept any image UTType — PNG / JPEG / WebP / HEIC / TIFF / GIF 60 - // / etc. all flow through the same `NSImage(contentsOf:)` render 61 - // path. SVG is listed explicitly because it's a structured-text 62 - // format that doesn't always conform to `.image` in older 63 - // UTType conformance tables. Anything that fails to decode falls 64 - // back to the dashed placeholder at render time. 65 - .fileImporter( 66 - isPresented: $isImageImporterPresented, 67 - allowedContentTypes: [.image, .svg], 68 - allowsMultipleSelection: false 69 - ) { result in 70 - handleImageImportResult(result) 71 - } 72 58 } 73 59 74 60 // MARK: - Icon row ··· 112 98 isSymbolPickerPresented = true 113 99 } 114 100 Button("Choose Image…") { 115 - isImageImporterPresented = true 101 + presentImageImporter() 116 102 } 117 103 if store.appearance.icon != nil { 118 104 Divider() ··· 338 324 } 339 325 } 340 326 341 - private func handleImageImportResult(_ result: Result<[URL], Error>) { 342 - isImageImporterPresented = false 343 - switch result { 344 - case .success(let urls): 345 - guard let url = urls.first else { return } 346 - // `fileImporter` returns security-scoped URLs on macOS — we need 347 - // to start access before reading and stop it on the way out so 348 - // the import store can copy the bytes into the sandboxed app 349 - // support directory. 350 - let needsScope = url.startAccessingSecurityScopedResource() 351 - defer { 352 - if needsScope { url.stopAccessingSecurityScopedResource() } 353 - } 327 + // Uses `NSOpenPanel` (rather than SwiftUI's `.fileImporter`) so the 328 + // panel can open at the repo's working directory — most users keep 329 + // their icon assets next to the project. Accepts any image UTType — 330 + // PNG / JPEG / WebP / HEIC / TIFF / GIF / etc. all flow through the 331 + // same `NSImage(contentsOf:)` render path. SVG is listed explicitly 332 + // because it's a structured-text format that doesn't always conform 333 + // to `.image` in older UTType conformance tables. Anything that fails 334 + // to decode falls back to the dashed placeholder at render time. 335 + private func presentImageImporter() { 336 + let panel = NSOpenPanel() 337 + panel.directoryURL = store.rootURL 338 + panel.allowedContentTypes = [.image, .svg] 339 + panel.canChooseDirectories = false 340 + panel.canChooseFiles = true 341 + panel.allowsMultipleSelection = false 342 + panel.prompt = "Choose" 343 + panel.message = "Choose an image to use as this repository's icon." 344 + 345 + panel.begin { response in 346 + guard response == .OK, let url = panel.url else { return } 354 347 store.send(.importUserImage(url)) 355 - case .failure(let error): 356 - store.send(.userImageImportFailed(error.localizedDescription)) 357 348 } 358 349 } 359 350 }