Meshtastic-Apple/Meshtastic/Views/Settings/AppData.swift
Copilot c388bf9b40 Add missing SwiftUI #Preview blocks across 65 views (#1649)
* Add SwiftUI previews for simple helper views

Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/a2a43e8c-24fd-443a-8a98-13b678770edd

Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>

* Add previews for action buttons, ChannelForm, MetricsColumnDetail, and DeviceOnboarding

Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/a2a43e8c-24fd-443a-8a98-13b678770edd

Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>

* Add previews for config views, log views, AppLog, Firmware, AppData, and UserConfig

Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/a2a43e8c-24fd-443a-8a98-13b678770edd

Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>

* Add preview for PositionConfig

Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/a2a43e8c-24fd-443a-8a98-13b678770edd

Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>

* Fix formatting bugs in #Preview blocks: restore missing .environmentObject/.environment modifiers and add proper tab indentation

Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/7eeb7a54-7928-466f-8e39-b00d0012a09d

Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>

* Linting fixes

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>
Co-authored-by: Garth Vander Houwen <garthvh@yahoo.com>
2026-04-16 06:06:55 +00:00

152 lines
4.2 KiB
Swift

//
// AppData.swift
// Meshtastic
//
// Copyright(c) Garth Vander Houwen 6/8/24.
//
import SwiftUI
import OSLog
import CoreData
import Foundation
struct AppData: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var accessoryManager: AccessoryManager
@State private var files = [URL]()
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
var body: some View {
VStack {
Section(header: Text("Phone GPS")) {
GPSStatus()
}
Divider()
// Map Data Section
Section(header: Text("Map Data")) {
NavigationLink(destination: MapDataFiles()) {
HStack {
Image(systemName: "map")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .callout : .title)
.frame(width: 35)
VStack(alignment: .leading) {
Text(NSLocalizedString("Upload Map Data", comment: "Title for map data upload screen"))
.font(.headline)
Text(NSLocalizedString("Manage custom map overlays", comment: "Subtitle for map data management"))
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
Image(systemName: "chevron.right")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
Divider()
}
List(files, id: \.self) { file in
HStack {
VStack(alignment: .leading ) {
if file.pathExtension.contains("sqlite") {
Label {
Text("Node Core Data Backup \(file.pathComponents[(idiom == .phone || idiom == .pad) ? 9 : 10])/\(file.lastPathComponent) - \(file.creationDate?.formatted() ?? "") - \(file.fileSizeString)")
.swipeActions {
Button(role: .destructive) {
do {
try FileManager.default.removeItem(at: file)
} catch {
Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)")
}
} label: {
Label("Delete", systemImage: "trash")
}
}
} icon: {
Image(systemName: "cylinder.split.1x2")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .callout : .title)
.frame(width: 35)
}
} else {
Label {
Text("\(file.lastPathComponent) - \(file.creationDate?.formatted() ?? "") - \(file.fileSizeString)")
.swipeActions {
Button(role: .destructive) {
do {
try FileManager.default.removeItem(at: file)
} catch {
Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)")
}
} label: {
Label("Delete", systemImage: "trash")
}
}
} icon: {
Image(systemName: "doc.text")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .callout : .title)
.frame(width: 35)
}
}
}
#if targetEnvironment(macCatalyst)
Spacer()
VStack(alignment: .trailing) {
Button {
do {
try FileManager.default.removeItem(at: file)
loadFiles()
} catch {
Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)")
}
} label: {
Label("", systemImage: "trash")
}
}
#endif
}
}
.navigationBarTitle("File Storage", displayMode: .inline)
.onAppear(perform: {
loadFiles()
})
.listStyle(.inset)
}
private func loadFiles() {
files = []
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
Logger.data.error("🗂️ nil default document directory path for backup, core data backup failed.")
return
}
if let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) {
for case let fileURL as URL in enumerator {
do {
let fileAttributes = try fileURL.resourceValues(forKeys: [.isRegularFileKey])
if fileAttributes.isRegularFile! {
files.append(fileURL)
}
} catch {
Logger.services.error("📁 Load file: \(fileURL, privacy: .public) error: \(error, privacy: .public)")
}
}
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return AppData()
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}