mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
fixes
This commit is contained in:
parent
aa54a7aa73
commit
abe0144d48
6 changed files with 64 additions and 43 deletions
|
|
@ -60,7 +60,7 @@
|
|||
3D3417C82E29D38A006A988B /* GeoJSONOverlayConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D3417C72E29D38A006A988B /* GeoJSONOverlayConfig.swift */; };
|
||||
3D3417CB2E29D3B0006A988B /* Color+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D3417C92E29D3B0006A988B /* Color+Hex.swift */; };
|
||||
3D3417D22E2DC260006A988B /* MapDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D3417D12E2DC260006A988B /* MapDataManager.swift */; };
|
||||
3D3417D42E2DC293006A988B /* MapDataUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D3417D32E2DC293006A988B /* MapDataUpload.swift */; };
|
||||
3D3417D42E2DC293006A988B /* MapDataFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D3417D32E2DC293006A988B /* MapDataFiles.swift */; };
|
||||
6D825E622C34786C008DBEE4 /* CommonRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D825E612C34786C008DBEE4 /* CommonRegex.swift */; };
|
||||
6DA39D8E2A92DC52007E311C /* MeshtasticAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */; };
|
||||
6DEDA55A2A957B8E00321D2E /* DetectionSensorLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */; };
|
||||
|
|
@ -335,7 +335,7 @@
|
|||
3D3417C72E29D38A006A988B /* GeoJSONOverlayConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoJSONOverlayConfig.swift; sourceTree = "<group>"; };
|
||||
3D3417C92E29D3B0006A988B /* Color+Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Hex.swift"; sourceTree = "<group>"; };
|
||||
3D3417D12E2DC260006A988B /* MapDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapDataManager.swift; sourceTree = "<group>"; };
|
||||
3D3417D32E2DC293006A988B /* MapDataUpload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapDataUpload.swift; sourceTree = "<group>"; };
|
||||
3D3417D32E2DC293006A988B /* MapDataFiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapDataFiles.swift; sourceTree = "<group>"; };
|
||||
6D825E612C34786C008DBEE4 /* CommonRegex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonRegex.swift; sourceTree = "<group>"; };
|
||||
6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticAppDelegate.swift; sourceTree = "<group>"; };
|
||||
6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectionSensorLog.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -797,7 +797,7 @@
|
|||
DD4A911C2708C57100501B7E /* Settings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3D3417D32E2DC293006A988B /* MapDataUpload.swift */,
|
||||
3D3417D32E2DC293006A988B /* MapDataManager.swift */,
|
||||
DDD5BB0E2C285F92007E03CA /* Logs */,
|
||||
DD93800C2BA74CE3008BEC06 /* Channels */,
|
||||
DD61937A2863876A00E59241 /* Config */,
|
||||
|
|
@ -1453,7 +1453,7 @@
|
|||
DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */,
|
||||
DDDB444C29F8AAA600EE2349 /* Color.swift in Sources */,
|
||||
DDDFE73F2D0D48FF0044463C /* IgnoreNodeButton.swift in Sources */,
|
||||
3D3417D42E2DC293006A988B /* MapDataUpload.swift in Sources */,
|
||||
3D3417D42E2DC293006A988B /* MapDataManager.swift in Sources */,
|
||||
DDB8F4122A9EE5DD00230ECE /* UserList.swift in Sources */,
|
||||
DDB75A0F2A05920E006ED576 /* FileManager.swift in Sources */,
|
||||
DD3D17E02C3FB67200561584 /* LocalWeatherConditions.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import Foundation
|
||||
import MapKit
|
||||
import OSLog
|
||||
import Combine
|
||||
|
||||
/// Manager for handling user-uploaded map data files
|
||||
class MapDataManager {
|
||||
class MapDataManager: ObservableObject {
|
||||
static let shared = MapDataManager()
|
||||
private init() {}
|
||||
|
||||
|
|
@ -14,7 +15,7 @@ class MapDataManager {
|
|||
private let metadataFileName = "upload_history.json"
|
||||
|
||||
// MARK: - Properties
|
||||
private var uploadedFiles: [MapDataMetadata] = []
|
||||
@Published private var uploadedFiles: [MapDataMetadata] = []
|
||||
private var activeFeatureCollection: GeoJSONFeatureCollection?
|
||||
|
||||
// MARK: - File Management
|
||||
|
|
@ -90,13 +91,14 @@ class MapDataManager {
|
|||
// 5. Process and validate content
|
||||
let metadata = try await processFileContent(at: destURL, originalName: originalName)
|
||||
|
||||
// 6. Save metadata
|
||||
uploadedFiles.append(metadata)
|
||||
// 6. Save metadata and update UI on main thread
|
||||
await MainActor.run {
|
||||
uploadedFiles.append(metadata)
|
||||
// Clear cached configuration to force reload
|
||||
activeFeatureCollection = nil
|
||||
}
|
||||
try saveMetadata()
|
||||
|
||||
// 7. Clear cached configuration to force reload
|
||||
activeFeatureCollection = nil
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
||||
|
|
@ -181,7 +183,7 @@ class MapDataManager {
|
|||
guard let fileURL = getUserUploadedDirectory()?.appendingPathComponent(file.filename) else {
|
||||
throw MapDataError.fileNotFound
|
||||
}
|
||||
|
||||
|
||||
let data = try Data(contentsOf: fileURL)
|
||||
return try JSONDecoder().decode(GeoJSONFeatureCollection.self, from: data)
|
||||
}
|
||||
|
|
@ -193,9 +195,9 @@ class MapDataManager {
|
|||
guard !files.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
var allFeatures: [GeoJSONFeature] = []
|
||||
|
||||
|
||||
for file in files {
|
||||
do {
|
||||
if let featureCollection = try loadFeatureCollectionFromFile(file) {
|
||||
|
|
@ -206,7 +208,7 @@ class MapDataManager {
|
|||
continue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
guard !allFeatures.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -221,13 +223,13 @@ class MapDataManager {
|
|||
|
||||
// Find active user files
|
||||
let activeFiles = uploadedFiles.filter { $0.isActive }
|
||||
|
||||
|
||||
guard !activeFiles.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var allFeatures: [GeoJSONFeature] = []
|
||||
|
||||
|
||||
// Load features from all active files
|
||||
for activeFile in activeFiles {
|
||||
|
||||
|
|
@ -239,7 +241,7 @@ class MapDataManager {
|
|||
// Check if file exists before trying to load it
|
||||
if !FileManager.default.fileExists(atPath: fileURL.path) {
|
||||
Logger.services.error("📁 MapDataManager: Active file does not exist at path: \(fileURL.path, privacy: .public)")
|
||||
|
||||
|
||||
// Remove the missing file from our metadata
|
||||
if let index = uploadedFiles.firstIndex(where: { $0.filename == activeFile.filename }) {
|
||||
uploadedFiles.remove(at: index)
|
||||
|
|
@ -261,13 +263,13 @@ class MapDataManager {
|
|||
Logger.services.error("📁 MapDataManager: Failed to load feature collection from \(activeFile.filename, privacy: .public): \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create combined feature collection
|
||||
let combinedCollection = GeoJSONFeatureCollection(
|
||||
type: "FeatureCollection",
|
||||
features: allFeatures
|
||||
)
|
||||
|
||||
|
||||
activeFeatureCollection = combinedCollection
|
||||
return combinedCollection
|
||||
}
|
||||
|
|
@ -278,12 +280,12 @@ class MapDataManager {
|
|||
func getUploadedFiles() -> [MapDataMetadata] {
|
||||
return uploadedFiles
|
||||
}
|
||||
|
||||
|
||||
/// Toggle the active state of an uploaded file
|
||||
func toggleFileActive(_ fileId: UUID) {
|
||||
if let index = uploadedFiles.firstIndex(where: { $0.id == fileId }) {
|
||||
uploadedFiles[index].isActive.toggle()
|
||||
|
||||
|
||||
// Save metadata changes
|
||||
do {
|
||||
try saveMetadata()
|
||||
|
|
@ -297,13 +299,13 @@ class MapDataManager {
|
|||
|
||||
/// Delete uploaded file
|
||||
func deleteFile(_ metadata: MapDataMetadata) async throws {
|
||||
|
||||
|
||||
guard let fileURL = getUserUploadedDirectory()?.appendingPathComponent(metadata.filename) else {
|
||||
Logger.services.error("🗑️ MapDataManager: Could not construct file URL for: \(metadata.filename, privacy: .public)")
|
||||
throw MapDataError.fileNotFound
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Check if file exists before trying to delete
|
||||
if !FileManager.default.fileExists(atPath: fileURL.path) {
|
||||
Logger.services.warning("🗑️ MapDataManager: File does not exist at path: \(fileURL.path, privacy: .public)")
|
||||
|
|
@ -316,10 +318,13 @@ class MapDataManager {
|
|||
throw error
|
||||
}
|
||||
|
||||
if let index = uploadedFiles.firstIndex(where: { $0.filename == metadata.filename }) {
|
||||
uploadedFiles.remove(at: index)
|
||||
} else {
|
||||
Logger.services.warning("🗑️ MapDataManager: File not found in uploadedFiles array")
|
||||
// Update UI-related properties on main thread
|
||||
await MainActor.run {
|
||||
if let index = uploadedFiles.firstIndex(where: { $0.filename == metadata.filename }) {
|
||||
uploadedFiles.remove(at: index)
|
||||
} else {
|
||||
Logger.services.warning("🗑️ MapDataManager: File not found in uploadedFiles array")
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
|
|
@ -330,13 +335,20 @@ class MapDataManager {
|
|||
}
|
||||
|
||||
// Clear cache if this was the active file
|
||||
if activeFeatureCollection != nil {
|
||||
activeFeatureCollection = nil
|
||||
await MainActor.run {
|
||||
if activeFeatureCollection != nil {
|
||||
activeFeatureCollection = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clear GeoJSON overlay manager cache
|
||||
GeoJSONOverlayManager.shared.clearCache()
|
||||
|
||||
// Notify UI components that a file was deleted
|
||||
await MainActor.run {
|
||||
NotificationCenter.default.post(name: Foundation.Notification.Name.mapDataFileDeleted, object: metadata.id)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -446,4 +458,9 @@ enum MapDataError: Error, LocalizedError {
|
|||
return "Failed to save file."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Notification Names
|
||||
extension Foundation.Notification.Name {
|
||||
static let mapDataFileDeleted = Foundation.Notification.Name("mapDataFileDeleted")
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ struct MapSettingsForm: View {
|
|||
@AppStorage("enableMapWaypoints") private var enableMapWaypoints = true
|
||||
@AppStorage("enableMapShowFavorites") private var enableMapShowFavorites = false
|
||||
@AppStorage("mapOverlaysEnabled") private var mapOverlaysEnabled = false
|
||||
@State private var uploadedFiles: [MapDataMetadata] = []
|
||||
@ObservedObject private var mapDataManager = MapDataManager.shared
|
||||
@Binding var traffic: Bool
|
||||
@Binding var pointsOfInterest: Bool
|
||||
@Binding var mapLayer: MapLayer
|
||||
|
|
@ -142,7 +142,7 @@ struct MapSettingsForm: View {
|
|||
|
||||
// Show individual file toggles when overlays are enabled
|
||||
if mapOverlaysEnabled && hasUserData {
|
||||
if !uploadedFiles.isEmpty {
|
||||
if !mapDataManager.getUploadedFiles().isEmpty {
|
||||
// Data source info
|
||||
HStack {
|
||||
Image(systemName: "info.circle")
|
||||
|
|
@ -155,7 +155,7 @@ struct MapSettingsForm: View {
|
|||
.padding(.leading, 35)
|
||||
|
||||
// Individual file toggles
|
||||
ForEach(uploadedFiles) { file in
|
||||
ForEach(mapDataManager.getUploadedFiles()) { file in
|
||||
Toggle(isOn: Binding(
|
||||
get: {
|
||||
return enabledOverlayConfigs.contains(file.id)
|
||||
|
|
@ -193,7 +193,7 @@ struct MapSettingsForm: View {
|
|||
}
|
||||
|
||||
// Manage data link
|
||||
NavigationLink(destination: MapDataUpload()) {
|
||||
NavigationLink(destination: MapDataFiles()) {
|
||||
HStack {
|
||||
Image(systemName: "folder")
|
||||
.foregroundColor(.accentColor)
|
||||
|
|
@ -221,7 +221,7 @@ struct MapSettingsForm: View {
|
|||
}
|
||||
} else if !hasUserData {
|
||||
// Upload prompt when no data available
|
||||
NavigationLink(destination: MapDataUpload()) {
|
||||
NavigationLink(destination: MapDataFiles()) {
|
||||
HStack {
|
||||
Image(systemName: "arrow.up.doc")
|
||||
.foregroundColor(.accentColor)
|
||||
|
|
@ -257,8 +257,8 @@ Spacer()
|
|||
.presentationDragIndicator(.visible)
|
||||
.presentationBackgroundInteraction(.enabled(upThrough: .medium))
|
||||
.onAppear {
|
||||
// Load files on appear
|
||||
uploadedFiles = GeoJSONOverlayManager.shared.getUploadedFilesWithState()
|
||||
// Initialize map data manager
|
||||
mapDataManager.initialize()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,6 +220,11 @@ struct MeshMap: View {
|
|||
.onDisappear(perform: {
|
||||
UIApplication.shared.isIdleTimerDisabled = false
|
||||
})
|
||||
.onReceive(NotificationCenter.default.publisher(for: Foundation.Notification.Name.mapDataFileDeleted)) { notification in
|
||||
if let deletedFileId = notification.object as? UUID {
|
||||
enabledOverlayConfigs.remove(deletedFileId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// moves the map to a new coordinate
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ struct AppData: View {
|
|||
|
||||
// Map Data Section
|
||||
Section(header: Text("Map Data")) {
|
||||
NavigationLink(destination: MapDataUpload()) {
|
||||
NavigationLink(destination: MapDataFiles()) {
|
||||
HStack {
|
||||
Image(systemName: "map")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ import SwiftUI
|
|||
import UniformTypeIdentifiers
|
||||
import OSLog
|
||||
|
||||
struct MapDataUpload: View {
|
||||
struct MapDataFiles: View {
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@ObservedObject private var mapDataManager = MapDataManager.shared
|
||||
|
||||
@State private var isShowingFilePicker = false
|
||||
@State private var isProcessing = false
|
||||
|
|
@ -14,8 +15,6 @@ struct MapDataUpload: View {
|
|||
@State private var showSuccess = false
|
||||
@State private var successMessage = ""
|
||||
|
||||
private let mapDataManager = MapDataManager.shared
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 20) {
|
||||
// Header
|
||||
|
|
@ -251,6 +250,6 @@ struct MapDataFileRow: View {
|
|||
|
||||
#Preview {
|
||||
NavigationView {
|
||||
MapDataUpload()
|
||||
MapDataFiles()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue