HealthImport/HealthImport/Tabs/DatabasesTab.swift
2024-03-19 14:25:51 +01:00

167 lines
5.5 KiB
Swift

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<URL, Error>) {
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())
}