Skip to content

Commit 9ce7fe2

Browse files
Merge pull request #65 from torlando-tech/columba-suite/issue-59-dark-mode-maps
feat(Map): follow app dark mode for OpenFreeMap style
2 parents 85331fa + 3049a49 commit 9ce7fe2

4 files changed

Lines changed: 58 additions & 7 deletions

File tree

Columba.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
T001 /* AudioRingBufferTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FT01 /* AudioRingBufferTests.swift */; };
1111
T002 /* AudioManagerConfigChangeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FT02 /* AudioManagerConfigChangeTests.swift */; };
1212
T004 /* CallManagerCallKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FT04 /* CallManagerCallKitTests.swift */; };
13+
T005 /* MapStyleURLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FT05 /* MapStyleURLTests.swift */; };
1314
001 /* ColumbaApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F001 /* ColumbaApp.swift */; };
1415
002 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = F002 /* Theme.swift */; };
1516
003 /* ChatsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F003 /* ChatsViewModel.swift */; };
@@ -147,6 +148,7 @@
147148
FT03 /* MicronParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MicronParserTests.swift; sourceTree = "<group>"; };
148149
FTAA /* AutoAnnouncePolicyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoAnnouncePolicyTests.swift; sourceTree = "<group>"; };
149150
FTPC /* PeerChildInterfaceRegistryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerChildInterfaceRegistryTests.swift; sourceTree = "<group>"; };
151+
FT05 /* MapStyleURLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapStyleURLTests.swift; sourceTree = "<group>"; };
150152
TPROD /* ColumbaAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ColumbaAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
151153
EPROD /* ColumbaNetworkExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ColumbaNetworkExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
152154
F001 /* ColumbaApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColumbaApp.swift; sourceTree = "<group>"; };
@@ -573,6 +575,7 @@
573575
FT04 /* CallManagerCallKitTests.swift */,
574576
FTAA /* AutoAnnouncePolicyTests.swift */,
575577
FTPC /* PeerChildInterfaceRegistryTests.swift */,
578+
FT05 /* MapStyleURLTests.swift */,
576579
);
577580
path = Tests/ColumbaAppTests;
578581
sourceTree = "<group>";
@@ -744,6 +747,7 @@
744747
T004 /* CallManagerCallKitTests.swift in Sources */,
745748
TAA0 /* AutoAnnouncePolicyTests.swift in Sources */,
746749
TPCR /* PeerChildInterfaceRegistryTests.swift in Sources */,
750+
T005 /* MapStyleURLTests.swift in Sources */,
747751
);
748752
runOnlyForDeploymentPostprocessing = 0;
749753
};

Sources/ColumbaApp/Views/Map/MapLibreMapView.swift

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,26 @@ import SwiftUI
1111
import MapLibre
1212
import LXMFSwift
1313

14+
/// Returns the OpenFreeMap style URL for the active color scheme.
15+
/// MLNOfflineStorage caches the style JSON + tiles during region download,
16+
/// so loading this URL offline serves everything from the local cache —
17+
/// but cached regions are pinned to one style at download time, so the
18+
/// dark style assets are not served offline if a region was downloaded
19+
/// while light was active. TODO(#59 follow-up): cache both style packs.
20+
func mapStyleURL(forDarkMode dark: Bool) -> URL {
21+
URL(string: dark
22+
? "https://tiles.openfreemap.org/styles/dark"
23+
: "https://tiles.openfreemap.org/styles/liberty")!
24+
}
25+
1426
@available(iOS 17.0, *)
1527
struct MapLibreMapView: UIViewRepresentable {
1628
@Binding var centerOnUser: Bool
1729
@Binding var metersPerPixel: Double
1830
var showsUserLocation: Bool
1931
var peerLocations: [PeerLocation]
2032
var httpEnabled: Bool
21-
22-
/// Style URL from OpenFreeMap — used for both online and offline modes.
23-
/// MLNOfflineStorage caches the style JSON + tiles during region download,
24-
/// so loading this URL offline serves everything from the local cache.
25-
private static let styleURL = URL(string: "https://tiles.openfreemap.org/styles/liberty")!
33+
var isDark: Bool
2634

2735
func makeUIView(context: Context) -> MLNMapView {
2836
// Set up network delegate to block HTTP when toggle is off.
@@ -31,7 +39,9 @@ struct MapLibreMapView: UIViewRepresentable {
3139
context.coordinator.httpEnabled = httpEnabled
3240
MLNNetworkConfiguration.sharedManager.delegate = context.coordinator
3341

34-
let mapView = MLNMapView(frame: .zero, styleURL: Self.styleURL)
42+
let initialStyleURL = mapStyleURL(forDarkMode: isDark)
43+
context.coordinator.lastStyleURL = initialStyleURL
44+
let mapView = MLNMapView(frame: .zero, styleURL: initialStyleURL)
3545
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
3646
mapView.showsUserLocation = showsUserLocation
3747
mapView.delegate = context.coordinator
@@ -53,6 +63,15 @@ struct MapLibreMapView: UIViewRepresentable {
5363
// Update network blocking state when HTTP toggle changes
5464
context.coordinator.httpEnabled = httpEnabled
5565

66+
// Swap style URL when color scheme changes; lastStyleURL avoids
67+
// a no-op assignment (which would still trigger a reload) on every
68+
// peer-location tick.
69+
let desiredStyleURL = mapStyleURL(forDarkMode: isDark)
70+
if context.coordinator.lastStyleURL != desiredStyleURL {
71+
context.coordinator.lastStyleURL = desiredStyleURL
72+
mapView.styleURL = desiredStyleURL
73+
}
74+
5675
if centerOnUser {
5776
DispatchQueue.main.async {
5877
centerOnUser = false
@@ -131,6 +150,11 @@ struct MapLibreMapView: UIViewRepresentable {
131150
/// Whether HTTP tile fetching is allowed.
132151
var httpEnabled = true
133152

153+
/// Last style URL applied to the underlying MLNMapView; used to skip
154+
/// no-op assignments on the frequent SwiftUI updates that don't change
155+
/// the color scheme.
156+
var lastStyleURL: URL?
157+
134158
/// Tracks peer annotations by hash for efficient updates.
135159
var peerAnnotations: [Data: PeerPointAnnotation] = [:]
136160

Sources/ColumbaApp/Views/Map/MapView.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ struct MapView: View {
3939
metersPerPixel: $metersPerPixel,
4040
showsUserLocation: locationAuthorized,
4141
peerLocations: locationSharingManager.map { Array($0.peerLocations.values) } ?? [],
42-
httpEnabled: mapHttpEnabled
42+
httpEnabled: mapHttpEnabled,
43+
isDark: ThemeManager.shared.isDarkMode
4344
)
4445
.ignoresSafeArea()
4546

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#if os(iOS)
2+
import XCTest
3+
@testable import ColumbaApp
4+
5+
@available(iOS 17.0, *)
6+
final class MapStyleURLTests: XCTestCase {
7+
8+
func testStyleURL_lightMode() {
9+
XCTAssertEqual(
10+
mapStyleURL(forDarkMode: false).absoluteString,
11+
"https://tiles.openfreemap.org/styles/liberty"
12+
)
13+
}
14+
15+
func testStyleURL_darkMode() {
16+
XCTAssertEqual(
17+
mapStyleURL(forDarkMode: true).absoluteString,
18+
"https://tiles.openfreemap.org/styles/dark"
19+
)
20+
}
21+
}
22+
#endif

0 commit comments

Comments
 (0)