Skip to content

Commit 7e485fe

Browse files
jfuginayclaude
andcommitted
Fix Meshtastic BLE node data collection and breadcrumb toggle
Meshtastic BLE fixes: - Fix message queue draining - now reads all queued messages instead of just one - Add support for both sfixed32 and sint32/zigzag position encoding - Auto-create node entries when receiving position updates for unknown nodes - Add comprehensive debug logging for troubleshooting Breadcrumb trails fix: - Sync Settings toggle with MapOverlayCoordinator via UserDefaults observer - Settings changes now immediately reflect on the map Build: 5 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent f4fdf44 commit 7e485fe

File tree

3 files changed

+277
-40
lines changed

3 files changed

+277
-40
lines changed

apps/omnitak/OmniTAKMobile.xcodeproj/project.pbxproj

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
20CAAB4409715F7431C1DEAB /* AppPreviewRecordingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 786486F562966ED005A6E978 /* AppPreviewRecordingTests.swift */; };
3232
21F8CB94928A130D0CC47B88 /* CompassOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7C9A85F883C8B6FBEDC4EA /* CompassOverlay.swift */; };
3333
225E69B4E6B06F8CFCCC70CD /* DataPackageModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A282FADB8ACF4795AB133B /* DataPackageModels.swift */; };
34-
2262EE8CA832D8F3763D6EC9 /* MeshtasticTCPConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2393F697897173C8BD5B108A /* MeshtasticTCPConnectionView.swift */; };
34+
2262EE8CA832D8F3763D6EC9 /* OmniTAKMobile/Features/Meshtastic/Views/MeshtasticTCPConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2393F697897173C8BD5B108A /* OmniTAKMobile/Features/Meshtastic/Views/MeshtasticTCPConnectionView.swift */; };
3535
230A5E49E77C45D194BB82F0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D3F9166C79C04A21BA2FDAA5 /* Assets.xcassets */; };
3636
237C2BDF074F98E2885EF3E3 /* MGRSConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DDAA71A32AEB4CF7544E37 /* MGRSConverter.swift */; };
3737
23EDC8B191AA50D21625F194 /* KMLImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F19ABB28D4637C0AA1DC0FC3 /* KMLImportView.swift */; };
@@ -92,7 +92,7 @@
9292
6E4F6D38A5424D89D0EA55EC /* AppStoreScreenshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7977ED558650BCE30E87178 /* AppStoreScreenshotTests.swift */; };
9393
6F2940AD585B3FCC8F1E9CD6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2508DC9F3697513408E4A231 /* Assets.xcassets */; };
9494
6FE38F11F9AC0C33FA06A7C3 /* BreadcrumbTrailService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9AA2203CD168813C8B8F77 /* BreadcrumbTrailService.swift */; };
95-
714739C165C288B44EC3A6E8 /* MeshtasticTCPClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D391707FFAE79A3046AC4505 /* MeshtasticTCPClient.swift */; };
95+
714739C165C288B44EC3A6E8 /* OmniTAKMobile/Features/Meshtastic/Networking/MeshtasticTCPClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D391707FFAE79A3046AC4505 /* OmniTAKMobile/Features/Meshtastic/Networking/MeshtasticTCPClient.swift */; };
9696
729AB487769A2B685665B70A /* DrawingToolsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A407760F29BEEA3F0416893 /* DrawingToolsManager.swift */; };
9797
730B9E168F5B40DCF1209BFB /* RoutePlanningService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B550057AC0D0462051CA0B5 /* RoutePlanningService.swift */; };
9898
73C474FC499785F0456D017A /* BloodhoundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3611027C930D5BCF88C9FB3B /* BloodhoundView.swift */; };
@@ -156,10 +156,10 @@
156156
9D41D2F2BD209FCD028D5785 /* ImprovedErrorDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD37DB92FC41317D68DAAF0 /* ImprovedErrorDialog.swift */; };
157157
9D4DD979FA07D0D920CA576A /* MEDEVACRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C046FF14CC38A998A3C9C57A /* MEDEVACRequestView.swift */; };
158158
9F360AA41C05B15FC6B71F75 /* EchelonModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53D5A42ABFBE8EF268B187D8 /* EchelonModels.swift */; };
159-
A1645CC72ECC172B00B71E89 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
160-
A1645CC82ECC172B00B71E89 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
161-
A1645CC92ECC172B00B71E89 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
162-
A1645CCA2ECC172B00B71E89 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
159+
A1645CC72ECC172B00B71E89 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
160+
A1645CC82ECC172B00B71E89 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
161+
A1645CC92ECC172B00B71E89 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
162+
A1645CCA2ECC172B00B71E89 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
163163
A17A5AD62EDB678C0084ABC8 /* bundled-client.p12 in Resources */ = {isa = PBXBuildFile; fileRef = A17A5AD42EDB678C0084ABC8 /* bundled-client.p12 */; };
164164
A17A5AD72EDB678C0084ABC8 /* bundled-ca.p12 in Resources */ = {isa = PBXBuildFile; fileRef = A17A5AD52EDB678C0084ABC8 /* bundled-ca.p12 */; };
165165
A20F144DC6EC67643B8C77B0 /* MEDEVACModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE1D24BFD11E3D147A90D0D /* MEDEVACModels.swift */; };
@@ -296,7 +296,7 @@
296296
1EBC84DF2F7B1C325E9B3B16 /* SHGPUCA----.svg */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "SHGPUCA----.svg"; sourceTree = "<group>"; };
297297
21ECE157083843DC0D219677 /* ADSBTrafficView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ADSBTrafficView.swift; path = OmniTAKMobile/Features/ADSB/Views/ADSBTrafficView.swift; sourceTree = "<group>"; };
298298
2272CD08893F8EF861E29ED6 /* DrawingPersistence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DrawingPersistence.swift; path = OmniTAKMobile/Storage/DrawingPersistence.swift; sourceTree = "<group>"; };
299-
2393F697897173C8BD5B108A /* MeshtasticTCPConnectionView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OmniTAKMobile/Features/Meshtastic/Views/MeshtasticTCPConnectionView.swift; sourceTree = SOURCE_ROOT; };
299+
2393F697897173C8BD5B108A /* OmniTAKMobile/Features/Meshtastic/Views/MeshtasticTCPConnectionView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OmniTAKMobile/Features/Meshtastic/Views/MeshtasticTCPConnectionView.swift; sourceTree = SOURCE_ROOT; };
300300
2399F38E59FEB96764216BFB /* ConnectionStatusWidget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConnectionStatusWidget.swift; path = OmniTAKMobile/Shared/UI/Components/ConnectionStatusWidget.swift; sourceTree = "<group>"; };
301301
2464B06E0A6D6ACAFF5AA25D /* MeshtasticModels.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MeshtasticModels.swift; path = OmniTAKMobile/Features/Meshtastic/Models/MeshtasticModels.swift; sourceTree = "<group>"; };
302302
2508DC9F3697513408E4A231 /* Assets.xcassets */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = OmniTAKMobile/Assets.xcassets; sourceTree = "<group>"; };
@@ -480,7 +480,7 @@
480480
CF6787CE6D6A94F71A3003B9 /* MissionPackageSyncView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MissionPackageSyncView.swift; path = OmniTAKMobile/Features/DataPackages/Views/MissionPackageSyncView.swift; sourceTree = "<group>"; };
481481
D1103C5349FE3EE31708711A /* KMZHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KMZHandler.swift; path = OmniTAKMobile/Utilities/Parsers/KMZHandler.swift; sourceTree = "<group>"; };
482482
D1F628D2ABD2498188D0EACD /* KMLOverlayManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KMLOverlayManager.swift; path = OmniTAKMobile/Utilities/Integration/KMLOverlayManager.swift; sourceTree = "<group>"; };
483-
D391707FFAE79A3046AC4505 /* MeshtasticTCPClient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OmniTAKMobile/Features/Meshtastic/Networking/MeshtasticTCPClient.swift; sourceTree = SOURCE_ROOT; };
483+
D391707FFAE79A3046AC4505 /* OmniTAKMobile/Features/Meshtastic/Networking/MeshtasticTCPClient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OmniTAKMobile/Features/Meshtastic/Networking/MeshtasticTCPClient.swift; sourceTree = SOURCE_ROOT; };
484484
D3F9166C79C04A21BA2FDAA5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = OmniTAKMobile/Assets.xcassets; sourceTree = "<group>"; };
485485
D452667B584032AAC6C0C1FB /* PointDropperService.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PointDropperService.swift; path = OmniTAKMobile/Features/Drawing/Services/PointDropperService.swift; sourceTree = "<group>"; };
486486
D4CBBCEB56FF2843028ECFF3 /* TrackRecordingButton.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TrackRecordingButton.swift; path = OmniTAKMobile/Shared/UI/Components/TrackRecordingButton.swift; sourceTree = "<group>"; };
@@ -535,10 +535,10 @@
535535
isa = PBXFrameworksBuildPhase;
536536
buildActionMask = 2147483647;
537537
files = (
538-
A1645CC72ECC172B00B71E89 /* BuildFile in Frameworks */,
539-
A1645CC82ECC172B00B71E89 /* BuildFile in Frameworks */,
540-
A1645CC92ECC172B00B71E89 /* BuildFile in Frameworks */,
541-
A1645CCA2ECC172B00B71E89 /* BuildFile in Frameworks */,
538+
A1645CC72ECC172B00B71E89 /* (null) in Frameworks */,
539+
A1645CC82ECC172B00B71E89 /* (null) in Frameworks */,
540+
A1645CC92ECC172B00B71E89 /* (null) in Frameworks */,
541+
A1645CCA2ECC172B00B71E89 /* (null) in Frameworks */,
542542
39FEDA5607D661F389177B31 /* OmniTAKMobile.xcframework in Frameworks */,
543543
);
544544
runOnlyForDeploymentPostprocessing = 0;
@@ -1154,7 +1154,7 @@
11541154
6A0CC0556CB362F5809DA186 /* Networking */ = {
11551155
isa = PBXGroup;
11561156
children = (
1157-
D391707FFAE79A3046AC4505 /* MeshtasticTCPClient.swift */,
1157+
D391707FFAE79A3046AC4505 /* OmniTAKMobile/Features/Meshtastic/Networking/MeshtasticTCPClient.swift */,
11581158
61913B0068875742648C74C4 /* MeshtasticBLEClient.swift */,
11591159
);
11601160
name = Networking;
@@ -1319,7 +1319,7 @@
13191319
872B202E6F7CE42DEEC26D95 /* Views */ = {
13201320
isa = PBXGroup;
13211321
children = (
1322-
2393F697897173C8BD5B108A /* MeshtasticTCPConnectionView.swift */,
1322+
2393F697897173C8BD5B108A /* OmniTAKMobile/Features/Meshtastic/Views/MeshtasticTCPConnectionView.swift */,
13231323
B4A0DCCEFB04D08FB298E2FD /* MeshNodeMapView.swift */,
13241324
);
13251325
name = Views;
@@ -2157,8 +2157,8 @@
21572157
DA38337220E9661125D0036D /* DeepLinkHandler.swift in Sources */,
21582158
38FCC16B78867B6617B2B329 /* ServerValidator.swift in Sources */,
21592159
9D41D2F2BD209FCD028D5785 /* ImprovedErrorDialog.swift in Sources */,
2160-
714739C165C288B44EC3A6E8 /* MeshtasticTCPClient.swift in Sources */,
2161-
2262EE8CA832D8F3763D6EC9 /* MeshtasticTCPConnectionView.swift in Sources */,
2160+
714739C165C288B44EC3A6E8 /* OmniTAKMobile/Features/Meshtastic/Networking/MeshtasticTCPClient.swift in Sources */,
2161+
2262EE8CA832D8F3763D6EC9 /* OmniTAKMobile/Features/Meshtastic/Views/MeshtasticTCPConnectionView.swift in Sources */,
21622162
6DA119F217E6DEA6623A7EB8 /* MeshtasticBLEClient.swift in Sources */,
21632163
E696090A2C20C65D83CD1F3D /* MeshtasticCoTConverter.swift in Sources */,
21642164
1374EB3089F65B0141A84BC7 /* MeshNodeMapView.swift in Sources */,
@@ -2370,7 +2370,7 @@
23702370
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
23712371
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
23722372
CODE_SIGN_STYLE = Automatic;
2373-
CURRENT_PROJECT_VERSION = 2;
2373+
CURRENT_PROJECT_VERSION = 5;
23742374
ENABLE_PREVIEWS = YES;
23752375
FRAMEWORK_SEARCH_PATHS = (
23762376
"$(inherited)",
@@ -2417,7 +2417,7 @@
24172417
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
24182418
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
24192419
CODE_SIGN_STYLE = Automatic;
2420-
CURRENT_PROJECT_VERSION = 2;
2420+
CURRENT_PROJECT_VERSION = 5;
24212421
ENABLE_PREVIEWS = YES;
24222422
FRAMEWORK_SEARCH_PATHS = (
24232423
"$(inherited)",

apps/omnitak/OmniTAKMobile/Features/Map/Controllers/MapOverlayCoordinator.swift

Lines changed: 119 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,19 @@ class MapOverlayCoordinator: ObservableObject {
125125
private var cancellables = Set<AnyCancellable>()
126126
private var lastMGRSUpdateTime: Date = .distantPast
127127
private let mgrsUpdateThrottleInterval: TimeInterval = 0.1 // Update max once per 100ms
128+
private var userDefaultsObserver: NSObjectProtocol?
128129

129130
// MARK: - Initialization
130131

131132
init() {
132133
setupObservers()
134+
setupUserDefaultsObserver()
135+
}
136+
137+
deinit {
138+
if let observer = userDefaultsObserver {
139+
NotificationCenter.default.removeObserver(observer)
140+
}
133141
}
134142

135143
private func setupObservers() {
@@ -150,6 +158,77 @@ class MapOverlayCoordinator: ObservableObject {
150158
.store(in: &cancellables)
151159
}
152160

161+
/// Observe UserDefaults changes from Settings view (AppStorage)
162+
private func setupUserDefaultsObserver() {
163+
userDefaultsObserver = NotificationCenter.default.addObserver(
164+
forName: UserDefaults.didChangeNotification,
165+
object: nil,
166+
queue: .main
167+
) { [weak self] _ in
168+
self?.syncWithUserDefaults()
169+
}
170+
}
171+
172+
/// Sync overlay states with UserDefaults keys used by Settings
173+
private func syncWithUserDefaults() {
174+
let defaults = UserDefaults.standard
175+
176+
// Sync breadcrumb trails from Settings toggle
177+
let settingsBreadcrumbEnabled = defaults.bool(forKey: "breadcrumbTrailsEnabled")
178+
let currentBreadcrumbEnabled = isOverlayVisible(.breadcrumbTrails)
179+
180+
if settingsBreadcrumbEnabled != currentBreadcrumbEnabled {
181+
#if DEBUG
182+
print("🗺️ [MapOverlayCoordinator] Syncing breadcrumbTrails: \(settingsBreadcrumbEnabled)")
183+
#endif
184+
if settingsBreadcrumbEnabled {
185+
addOverlay(.breadcrumbTrails)
186+
} else {
187+
removeOverlay(.breadcrumbTrails)
188+
}
189+
}
190+
191+
// Sync trail settings
192+
let settingsTrailMaxLength = defaults.integer(forKey: "trailMaxLength")
193+
if settingsTrailMaxLength > 0 && settingsTrailMaxLength != trailMaxLength {
194+
trailMaxLength = settingsTrailMaxLength
195+
}
196+
197+
// Sync trail color
198+
let settingsTrailColorName = defaults.string(forKey: "trailColorName") ?? "cyan"
199+
let newTrailColor = colorFromName(settingsTrailColorName)
200+
if newTrailColor != trailColor {
201+
trailColor = newTrailColor
202+
}
203+
204+
// Sync MGRS grid from Settings toggle
205+
let settingsMGRSEnabled = defaults.bool(forKey: "mgrsGridEnabled")
206+
let currentMGRSEnabled = isOverlayVisible(.mgrsGrid)
207+
208+
if settingsMGRSEnabled != currentMGRSEnabled {
209+
#if DEBUG
210+
print("🗺️ [MapOverlayCoordinator] Syncing mgrsGrid: \(settingsMGRSEnabled)")
211+
#endif
212+
if settingsMGRSEnabled {
213+
addOverlay(.mgrsGrid)
214+
} else {
215+
removeOverlay(.mgrsGrid)
216+
}
217+
}
218+
}
219+
220+
/// Convert color name to UIColor
221+
private func colorFromName(_ name: String) -> UIColor {
222+
switch name.lowercased() {
223+
case "cyan": return .cyan
224+
case "green": return .green
225+
case "orange": return .orange
226+
case "red": return .red
227+
case "blue": return .blue
228+
default: return .cyan
229+
}
230+
}
231+
153232
// MARK: - Public API
154233

155234
func configure(with mapView: MKMapView) {
@@ -406,16 +485,19 @@ class MapOverlayCoordinator: ObservableObject {
406485
func saveSettings() {
407486
let defaults = UserDefaults.standard
408487

409-
// MGRS Grid settings
488+
// MGRS Grid settings - save to both keys for compatibility
410489
defaults.set(mgrsGridDensity.rawValue, forKey: "mgrsGridDensity")
411490
defaults.set(showMGRSLabels, forKey: "showMGRSLabels")
412491
defaults.set(isOverlayVisible(.mgrsGrid), forKey: "mgrsGridEnabled")
413492

414-
// Trail settings
493+
// Trail settings - save to Settings-compatible keys
415494
defaults.set(trailMaxLength, forKey: "trailMaxLength")
416495
defaults.set(Float(trailLineWidth), forKey: "trailLineWidth")
417496

418-
// Save overlay visibility
497+
// Save breadcrumb state to Settings-compatible key
498+
defaults.set(isOverlayVisible(.breadcrumbTrails), forKey: "breadcrumbTrailsEnabled")
499+
500+
// Save overlay visibility (legacy keys for other overlays)
419501
for (type, visible) in overlayVisibility {
420502
defaults.set(visible, forKey: "overlay_\(type.rawValue)_visible")
421503
}
@@ -436,7 +518,7 @@ class MapOverlayCoordinator: ObservableObject {
436518

437519
showMGRSLabels = defaults.bool(forKey: "showMGRSLabels")
438520

439-
// Trail settings
521+
// Trail settings from Settings view (AppStorage keys)
440522
let savedTrailLength = defaults.integer(forKey: "trailMaxLength")
441523
if savedTrailLength > 0 {
442524
trailMaxLength = savedTrailLength
@@ -447,11 +529,40 @@ class MapOverlayCoordinator: ObservableObject {
447529
trailLineWidth = CGFloat(savedTrailWidth)
448530
}
449531

450-
// Load overlay visibility and apply state
532+
// Load trail color from Settings
533+
let savedTrailColorName = defaults.string(forKey: "trailColorName") ?? "cyan"
534+
trailColor = colorFromName(savedTrailColorName)
535+
536+
// Load overlay visibility from Settings view (AppStorage keys)
537+
// These are the primary source of truth from the Settings screen
538+
let breadcrumbEnabled = defaults.bool(forKey: "breadcrumbTrailsEnabled")
539+
let mgrsEnabled = defaults.bool(forKey: "mgrsGridEnabled")
540+
541+
#if DEBUG
542+
print("🗺️ [MapOverlayCoordinator] Settings breadcrumbTrailsEnabled: \(breadcrumbEnabled)")
543+
print("🗺️ [MapOverlayCoordinator] Settings mgrsGridEnabled: \(mgrsEnabled)")
544+
#endif
545+
546+
// Apply breadcrumb trails state
547+
overlayVisibility[.breadcrumbTrails] = breadcrumbEnabled
548+
if breadcrumbEnabled && mapView != nil {
549+
DispatchQueue.main.async { [weak self] in
550+
self?.addOverlay(.breadcrumbTrails)
551+
}
552+
}
553+
554+
// Apply MGRS grid state (but respect the "start disabled" behavior for grid)
555+
// MGRS grid starts disabled to fix stuck grid issue, but we still sync the setting
556+
overlayVisibility[.mgrsGrid] = false // Always start disabled
557+
558+
// Load other overlay visibility states
451559
for type in MapOverlayType.allCases {
452-
// IMPORTANT: Always start with MGRS grid disabled to fix stuck grid issue
453-
// User can manually enable it via the toggle button
454-
let visible = type == .mgrsGrid ? false : defaults.bool(forKey: "overlay_\(type.rawValue)_visible")
560+
// Skip breadcrumbs and MGRS - already handled above
561+
if type == .breadcrumbTrails || type == .mgrsGrid {
562+
continue
563+
}
564+
565+
let visible = defaults.bool(forKey: "overlay_\(type.rawValue)_visible")
455566

456567
#if DEBUG
457568
print("🗺️ [MapOverlayCoordinator] Loaded \(type.rawValue): \(visible)")
@@ -461,7 +572,6 @@ class MapOverlayCoordinator: ObservableObject {
461572

462573
// Apply the loaded state to the map (if mapView is configured)
463574
if visible && mapView != nil {
464-
// Delay adding overlays until next run loop to ensure map is ready
465575
DispatchQueue.main.async { [weak self] in
466576
self?.addOverlay(type)
467577
}

0 commit comments

Comments
 (0)