import SwiftUI import HealthKit import HealthKitExtensions import HealthDB import SFSafeSymbols struct DatabasesTab: View { @ObservedObject var database: Database @ObservedObject var databases: DatabaseList @State var navigationPath: NavigationPath = .init() @State private var showFailedToOpenAlert = false @State private var showDocumentPicker = false @State private var showOptionsForSelectedDatabase = false @State private var changedDatabaseName: String = "" @State private var showChangeDatabaseNameAlert = false @State private var selectedDatabase: DatabaseFile? = nil private var openCloseButtonText: String { database.file == selectedDatabase ? "Close" : "Open" } private var defaultSelectionButtonText: String { (selectedDatabase?.isDefault ?? false) ? "Remove as default" : "Set as default" } private func symbol(for database: DatabaseFile) -> SFSymbol { self.database.file == database ? .circleInsetFilled : .circle } var body: some View { NavigationStack(path: $navigationPath) { List { ForEach(databases.databases) { database in HStack(alignment: .center) { Image(systemSymbol: symbol(for: database)) VStack(alignment: .leading) { HStack(alignment: .firstTextBaseline) { Text(database.name) .font(.headline) if database.isDefault { Text("(Default)") .font(.caption) } } Text(database.file) .font(.caption) } } .onTapGesture { self.selectedDatabase = database self.showOptionsForSelectedDatabase = true } }.onDelete(perform: databases.deleteDatabases) } .navigationTitle("Databases") .toolbar { Button(action: displayDocumentPicker) { Label("Add", systemSymbol: .plus) } } .fileImporter(isPresented: $showDocumentPicker, allowedContentTypes: [.database], onCompletion: handle) .confirmationDialog("Change background", isPresented: $showOptionsForSelectedDatabase) { Button(openCloseButtonText, action: openOrCloseSelectedDatabase) Button("Rename", action: renameSelectedDatabase) Button(defaultSelectionButtonText, action: toggleDefaultForSelectedDatabase) Button("Cancel", role: .cancel) { } } message: { Text("Select a new color") } .alert("Update name", isPresented: $showChangeDatabaseNameAlert, actions: { TextField("Name", text: $changedDatabaseName) Button("Update", action: saveNewNameForSelectedDatabase) Button("Cancel", role: .cancel, action: {}) }, message: { Text("Please enter the new name for the database") }) .alert("Failed to open", isPresented: $showFailedToOpenAlert) { Button("Dismiss", role: .cancel, action: {}) } message: { Text("The selected database could not be opened. Make sure that it is a valid Health database.") } }.onAppear(perform: databases.load) } private func openOrCloseSelectedDatabase() { guard let selectedDatabase else { return } defer { self.selectedDatabase = nil } guard database.load(database: selectedDatabase) else { return } } private func renameSelectedDatabase() { guard let selectedDatabase else { return } self.changedDatabaseName = selectedDatabase.name self.showChangeDatabaseNameAlert = true } private func saveNewNameForSelectedDatabase() { defer { changedDatabaseName = "" } guard let selectedDatabase else { return } guard let updated = databases.update(name: changedDatabaseName, for: selectedDatabase) else { return } if database.file == selectedDatabase { // Update open database file database.file = updated } } private func toggleDefaultForSelectedDatabase() { guard let selectedDatabase else { return } defer { self.selectedDatabase = nil } databases.setAsDefault(database: selectedDatabase) } private func displayDocumentPicker() { showDocumentPicker = true } private func handle(result: Result) { do { let selectedFile: URL = try result.get() if selectedFile.startAccessingSecurityScopedResource() { defer { selectedFile.stopAccessingSecurityScopedResource() } databases.importDatabase(at: selectedFile) } else { print("No access to file") } } catch { print("No file selected: \(error)") } } private func handlePicked(urls: [URL]) { print("Files picked.") for url in urls { databases.importDatabase(at: url) } } } #Preview { DatabasesTab(database: Database(), databases: .init()) }