wire TOML export/import to iOS session browser
This commit is contained in:
parent
311fb8ecc7
commit
8e1153585b
|
|
@ -1,5 +1,6 @@
|
|||
import SwiftUI
|
||||
import GRDB
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
struct SessionView: View {
|
||||
@Bindable var state: AppState
|
||||
|
|
@ -191,6 +192,9 @@ struct SessionDetailView: View {
|
|||
@State private var editing = false
|
||||
@State private var editLabel = ""
|
||||
@State private var editNotes = ""
|
||||
@State private var showingFileImporter = false
|
||||
@State private var showingShareSheet = false
|
||||
@State private var exportFileURL: URL?
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
|
|
@ -201,6 +205,16 @@ struct SessionDetailView: View {
|
|||
.onAppear { loadMeasurements() }
|
||||
.onChange(of: session.id) { loadMeasurements() }
|
||||
.sheet(isPresented: $editing) { editSheet }
|
||||
.sheet(isPresented: $showingShareSheet) {
|
||||
if let url = exportFileURL {
|
||||
ShareSheet(items: [url])
|
||||
}
|
||||
}
|
||||
.fileImporter(
|
||||
isPresented: $showingFileImporter,
|
||||
allowedContentTypes: [.plainText],
|
||||
onCompletion: handleImportedFile
|
||||
)
|
||||
}
|
||||
|
||||
private func loadMeasurements() {
|
||||
|
|
@ -208,6 +222,40 @@ struct SessionDetailView: View {
|
|||
measurements = (try? Storage.shared.fetchMeasurements(sessionId: sid)) ?? []
|
||||
}
|
||||
|
||||
private func exportSession() {
|
||||
guard let sid = session.id else { return }
|
||||
do {
|
||||
let toml = try Storage.shared.exportSession(sid)
|
||||
let name = (session.label ?? "session").replacingOccurrences(of: " ", with: "_")
|
||||
let url = FileManager.default.temporaryDirectory.appendingPathComponent("\(name).toml")
|
||||
try toml.write(to: url, atomically: true, encoding: .utf8)
|
||||
exportFileURL = url
|
||||
showingShareSheet = true
|
||||
} catch {
|
||||
state.status = "Export failed: \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
|
||||
private func handleImportedFile(_ result: Result<URL, Error>) {
|
||||
switch result {
|
||||
case .success(let url):
|
||||
guard url.startAccessingSecurityScopedResource() else {
|
||||
state.status = "Cannot access file"
|
||||
return
|
||||
}
|
||||
defer { url.stopAccessingSecurityScopedResource() }
|
||||
do {
|
||||
let toml = try String(contentsOf: url, encoding: .utf8)
|
||||
let _ = try Storage.shared.importSession(from: toml)
|
||||
state.status = "Session imported"
|
||||
} catch {
|
||||
state.status = "Import failed: \(error.localizedDescription)"
|
||||
}
|
||||
case .failure(let error):
|
||||
state.status = "File error: \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
|
||||
private var header: some View {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack {
|
||||
|
|
@ -222,6 +270,14 @@ struct SessionDetailView: View {
|
|||
Image(systemName: "pencil.circle")
|
||||
.imageScale(.large)
|
||||
}
|
||||
Button(action: { exportSession() }) {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
.imageScale(.large)
|
||||
}
|
||||
Button(action: { showingFileImporter = true }) {
|
||||
Image(systemName: "square.and.arrow.down")
|
||||
.imageScale(.large)
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
Text(session.startedAt, style: .date)
|
||||
|
|
@ -368,3 +424,11 @@ struct MeasurementRow: View {
|
|||
return (try? Storage.shared.dataPointCount(measurementId: mid)) ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
struct ShareSheet: UIViewControllerRepresentable {
|
||||
let items: [Any]
|
||||
func makeUIViewController(context: Context) -> UIActivityViewController {
|
||||
UIActivityViewController(activityItems: items, applicationActivities: nil)
|
||||
}
|
||||
func updateUIViewController(_ vc: UIActivityViewController, context: Context) {}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue