Files
yattee/Yattee/Views/Settings/AddSource/AddLocalFolderView.swift
2026-02-08 18:33:56 +01:00

179 lines
4.7 KiB
Swift

//
// AddLocalFolderView.swift
// Yattee
//
// View for adding a local folder as a media source.
//
import SwiftUI
#if !os(tvOS)
struct AddLocalFolderView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.appEnvironment) private var appEnvironment
// MARK: - State
@State private var name = ""
@State private var selectedFolderURL: URL?
@State private var testResult: SourceTestResult?
#if os(iOS)
@State private var showingFolderPicker = false
#endif
// Closure to dismiss the parent sheet
var dismissSheet: DismissAction?
// MARK: - Computed Properties
private var canAdd: Bool {
!name.isEmpty && selectedFolderURL != nil
}
// MARK: - Body
var body: some View {
Form {
nameSection
folderSection
if let result = testResult {
SourceTestResultSection(result: result)
}
actionSection
}
.navigationTitle(String(localized: "sources.addLocalFolder"))
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
.sheet(isPresented: $showingFolderPicker) {
FolderPickerView { url in
handleFolderSelection(url)
}
}
#endif
}
// MARK: - Sections
private var nameSection: some View {
Section {
TextField(String(localized: "sources.field.name"), text: $name)
} footer: {
Text(String(localized: "sources.footer.displayName"))
}
}
private var folderSection: some View {
Section {
#if os(iOS)
Button {
showingFolderPicker = true
} label: {
HStack {
if let url = selectedFolderURL {
Label(url.lastPathComponent, systemImage: "folder.fill")
} else {
Label(String(localized: "sources.selectFolder"), systemImage: "folder.badge.plus")
}
Spacer()
Image(systemName: "chevron.right")
.foregroundStyle(.tertiary)
}
}
#elseif os(macOS)
Button {
selectFolderMacOS()
} label: {
HStack {
if let url = selectedFolderURL {
Label(url.lastPathComponent, systemImage: "folder.fill")
} else {
Label(String(localized: "sources.selectFolder"), systemImage: "folder.badge.plus")
}
Spacer()
}
}
#endif
} header: {
Text(String(localized: "sources.header.folder"))
} footer: {
Text(String(localized: "sources.footer.folder"))
}
}
private var actionSection: some View {
Section {
Button {
addSource()
} label: {
Text(String(localized: "sources.addSource"))
}
.disabled(!canAdd)
}
}
// MARK: - Actions
private func handleFolderSelection(_ url: URL) {
selectedFolderURL = url
if name.isEmpty {
name = url.lastPathComponent
}
}
#if os(macOS)
private func selectFolderMacOS() {
let panel = NSOpenPanel()
panel.canChooseFiles = false
panel.canChooseDirectories = true
panel.allowsMultipleSelection = false
panel.canCreateDirectories = false
if panel.runModal() == .OK, let url = panel.url {
handleFolderSelection(url)
}
}
#endif
private func addSource() {
guard let appEnvironment,
let url = selectedFolderURL else { return }
Task {
do {
let bookmarkData = try await appEnvironment.localFileClient.createBookmark(for: url)
await MainActor.run {
let source = MediaSource.localFolder(
name: name,
url: url,
bookmarkData: bookmarkData
)
appEnvironment.mediaSourcesManager.add(source)
if let dismissSheet {
dismissSheet()
} else {
dismiss()
}
}
} catch {
await MainActor.run {
testResult = .failure(String(localized: "sources.error.folderAccess \(error.localizedDescription)"))
}
}
}
}
}
// MARK: - Preview
#Preview {
NavigationStack {
AddLocalFolderView()
.appEnvironment(.preview)
}
}
#endif