diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2023-03-31 18:24:12 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2023-03-31 18:24:12 +0200 |
| commit | 7621bb162de0a721697c99d29ca91087803c8fa4 (patch) | |
| tree | 73d8703d5400f31ad5529df0e27c79cec8fb3355 | |
| parent | 3efcaabe2007e267c54964b96f7a9e02ce21d503 (diff) | |
| parent | 4457433e59466d032e9acece42dae9525e8f49db (diff) | |
| download | mullvadvpn-7621bb162de0a721697c99d29ca91087803c8fa4.tar.xz mullvadvpn-7621bb162de0a721697c99d29ca91087803c8fa4.zip | |
Merge branch 'migrate-to-mkgeojsondecoder-ios-47'
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 4 | ||||
| -rw-r--r-- | ios/MullvadVPN/View controllers/Tunnel/GeoJSON.swift | 156 | ||||
| -rw-r--r-- | ios/MullvadVPN/View controllers/Tunnel/MapViewController.swift | 28 |
3 files changed, 27 insertions, 161 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 622cfc0fc5..595fa0907b 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -358,7 +358,6 @@ 58FC040A27B3EE03001C21F0 /* TunnelMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FC040927B3EE03001C21F0 /* TunnelMonitor.swift */; }; 58FD5BF024238EB300112C88 /* SKProduct+Formatting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FD5BEF24238EB300112C88 /* SKProduct+Formatting.swift */; }; 58FD5BF42428C67600112C88 /* InAppPurchaseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FD5BF32428C67600112C88 /* InAppPurchaseButton.swift */; }; - 58FEEB46260A028D00A621A8 /* GeoJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FEEB45260A028D00A621A8 /* GeoJSON.swift */; }; 58FEEB58260B662E00A621A8 /* AutomaticKeyboardResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FEEB57260B662E00A621A8 /* AutomaticKeyboardResponder.swift */; }; 58FF2C03281BDE02009EF542 /* SettingsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF2C02281BDE02009EF542 /* SettingsManager.swift */; }; E1187ABC289BBB850024E748 /* OutOfTimeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1187ABA289BBB850024E748 /* OutOfTimeViewController.swift */; }; @@ -942,7 +941,6 @@ 58FC040927B3EE03001C21F0 /* TunnelMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelMonitor.swift; sourceTree = "<group>"; }; 58FD5BEF24238EB300112C88 /* SKProduct+Formatting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SKProduct+Formatting.swift"; sourceTree = "<group>"; }; 58FD5BF32428C67600112C88 /* InAppPurchaseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppPurchaseButton.swift; sourceTree = "<group>"; }; - 58FEEB45260A028D00A621A8 /* GeoJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeoJSON.swift; sourceTree = "<group>"; }; 58FEEB57260B662E00A621A8 /* AutomaticKeyboardResponder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomaticKeyboardResponder.swift; sourceTree = "<group>"; }; 58FF2C02281BDE02009EF542 /* SettingsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsManager.swift; sourceTree = "<group>"; }; 7AD8490C29BA1EC500878E53 /* SettingsCellFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsCellFactory.swift; sourceTree = "<group>"; }; @@ -1350,7 +1348,6 @@ 583FE01E29C197D5006E85F9 /* Tunnel */ = { isa = PBXGroup; children = ( - 58FEEB45260A028D00A621A8 /* GeoJSON.swift */, 58B43C1825F77DB60002C8C3 /* TunnelControlView.swift */, 58C3F4F82964B08300D72515 /* MapViewController.swift */, 58A1AA8B23F5584B009F7EA6 /* ConnectionPanelView.swift */, @@ -2723,7 +2720,6 @@ 5878F50229CDB989003D4BE2 /* ChangeLogCoordinator.swift in Sources */, 58B93A1326C3F13600A55733 /* TunnelState.swift in Sources */, 58B26E262943522400D5980C /* NotificationProvider.swift in Sources */, - 58FEEB46260A028D00A621A8 /* GeoJSON.swift in Sources */, 58CE5E64224146200008646E /* AppDelegate.swift in Sources */, 5878A27329091D6D0096FC88 /* TunnelBlockObserver.swift in Sources */, 5872D6E8286304DE00DB5F4E /* TermsOfService.swift in Sources */, diff --git a/ios/MullvadVPN/View controllers/Tunnel/GeoJSON.swift b/ios/MullvadVPN/View controllers/Tunnel/GeoJSON.swift deleted file mode 100644 index c33fab801b..0000000000 --- a/ios/MullvadVPN/View controllers/Tunnel/GeoJSON.swift +++ /dev/null @@ -1,156 +0,0 @@ -// -// GeoJSON.swift -// MullvadVPN -// -// Created by pronebird on 25/02/2021. -// Copyright © 2021 Mullvad VPN AB. All rights reserved. -// - -import CoreLocation -import Foundation -import MapKit - -enum GeoJSON {} - -extension GeoJSON { - struct FeatureCollection: Decodable { - let features: [Feature] - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let type = try container.decode(String.self, forKey: .type) - - if type == "FeatureCollection" { - features = try container.decode([Feature].self, forKey: .features) - } else { - throw DecodingError.dataCorruptedError( - forKey: .type, - in: container, - debugDescription: "FeatureCollection: Invalid type \(type)" - ) - } - } - - var mkOverlays: [MKOverlay] { - return features.flatMap { feature -> [MKOverlay] in - // Some tools like mapshaper output empty features after optimizing out the geometry - guard let geometry = feature.geometry else { return [] } - - switch geometry { - case let .polygon(polygon): - return polygon.mkPolygons - - case let .multiPolygon(multiPolygon): - return multiPolygon.mkPolygons - } - } - } - - private enum CodingKeys: String, CodingKey { - case type, features - } - } - - struct Feature: Decodable { - let geometry: Geometry? - - private enum CodingKeys: String, CodingKey { - case type, geometry - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let type = try container.decode(String.self, forKey: .type) - - if type == "Feature" { - geometry = try container.decodeIfPresent(Geometry.self, forKey: .geometry) - } else { - throw DecodingError.dataCorruptedError( - forKey: .type, - in: container, - debugDescription: "Feature: Invalid type \(type)" - ) - } - } - } - - enum Geometry: Decodable { - case polygon(Polygon) - case multiPolygon(MultiPolygon) - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let type = try container.decode(String.self, forKey: .type) - - switch type { - case "Polygon": - self = .polygon(try decoder.singleValueContainer().decode(Polygon.self)) - - case "MultiPolygon": - self = .multiPolygon(try decoder.singleValueContainer().decode(MultiPolygon.self)) - - default: - throw DecodingError.dataCorruptedError( - forKey: .type, - in: container, - debugDescription: "Geometry: Unknown type \(type)" - ) - } - } - - private enum CodingKeys: String, CodingKey { - case type - } - } - - struct Polygon: Decodable { - let coordinates: [[[Double]]] - - var mkPolygons: [MKPolygon] { - let coords = geoCoordinates - let exteriorCoordinates = coords.first ?? [] - - let exteriorPolygon = MKPolygon( - coordinates: exteriorCoordinates, - count: exteriorCoordinates.count, - interiorPolygons: nil - ) - - let interiorPolygons = coords.dropFirst().map { interiorCoords -> MKPolygon in - return MKPolygon( - coordinates: interiorCoords, - count: interiorCoords.count - ) - } - - return [exteriorPolygon] + interiorPolygons - } - - private var geoCoordinates: [[CLLocationCoordinate2D]] { - return coordinates.map { values -> [CLLocationCoordinate2D] in - return values.map { coordinates -> CLLocationCoordinate2D in - return CLLocationCoordinate2D( - latitude: coordinates[1], - longitude: coordinates[0] - ) - } - } - } - } - - struct MultiPolygon: Decodable { - let coordinates: [[[[Double]]]] - - var mkPolygons: [MKOverlay] { - return coordinates.flatMap { values -> [MKPolygon] in - return Polygon(coordinates: values).mkPolygons - } - } - } - - static func decodeGeoJSON(_ data: Data) throws -> [MKOverlay] { - return try JSONDecoder() - .decode(GeoJSON.FeatureCollection.self, from: data) - .mkOverlays - } -} diff --git a/ios/MullvadVPN/View controllers/Tunnel/MapViewController.swift b/ios/MullvadVPN/View controllers/Tunnel/MapViewController.swift index 9a8a434dd3..243672597a 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/MapViewController.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/MapViewController.swift @@ -171,7 +171,33 @@ final class MapViewController: UIViewController, MKMapViewDelegate { do { let data = try Data(contentsOf: fileURL) - let overlays = try GeoJSON.decodeGeoJSON(data) + guard let features = try MKGeoJSONDecoder().decode(data) as? [MKGeoJSONFeature] + else { return } + + var overlays = [MKOverlay]() + + for feature in features { + for geometry in feature.geometry { + if let polygon = geometry as? MKPolygon { + if let interiorPolygons = polygon.interiorPolygons, + !interiorPolygons.isEmpty + { + overlays + .append(MKPolygon( + points: polygon.points(), + count: polygon.pointCount + )) + overlays.append(contentsOf: interiorPolygons) + } else { + overlays.append(polygon) + } + } + + if let multiPolygon = geometry as? MKMultiPolygon { + overlays.append(contentsOf: multiPolygon.polygons) + } + } + } mapView.addOverlays(overlays, level: .aboveLabels) } catch { |
