aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--iosApp/iosApp.xcodeproj/project.pbxproj17
-rw-r--r--iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved18
-rw-r--r--iosApp/iosApp/Details/Reports/UnitReportsView.swift1
-rw-r--r--iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift15
-rw-r--r--iosApp/iosApp/Map/MapView.swift9
-rw-r--r--iosApp/iosApp/Map/MapViewController.swift103
-rw-r--r--iosApp/iosApp/Map/UnitMapView.swift1
-rw-r--r--iosApp/iosApp/Units/UnitsViewModel.swift7
8 files changed, 167 insertions, 4 deletions
diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj
index 196675f..8aefd98 100644
--- a/iosApp/iosApp.xcodeproj/project.pbxproj
+++ b/iosApp/iosApp.xcodeproj/project.pbxproj
@@ -46,6 +46,7 @@
E39ABC4627A4EBD500965D05 /* DevicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39ABC4527A4EBD500965D05 /* DevicesView.swift */; };
E39ABC4827A4EDEC00965D05 /* DeviceRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39ABC4727A4EDEC00965D05 /* DeviceRow.swift */; };
E3C651E727CB5426002F6F4C /* Tabler in Frameworks */ = {isa = PBXBuildFile; productRef = E3C651E627CB5426002F6F4C /* Tabler */; };
+ E3C651EA27CB61EE002F6F4C /* GEOSwift in Frameworks */ = {isa = PBXBuildFile; productRef = E3C651E927CB61EE002F6F4C /* GEOSwift */; };
E3E77EE6279E6CE400150070 /* FlowCollector.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E77EE5279E6CE400150070 /* FlowCollector.swift */; };
/* End PBXBuildFile section */
@@ -114,6 +115,7 @@
E3C651E727CB5426002F6F4C /* Tabler in Frameworks */,
E36A5A8627B4BFC40070DED5 /* FirebaseMessaging in Frameworks */,
E33A236A27A6898700DD647F /* SwiftUIX in Frameworks */,
+ E3C651EA27CB61EE002F6F4C /* GEOSwift in Frameworks */,
E396281D27AF5723005D070E /* WhirlyGlobe.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -292,6 +294,7 @@
E33A236927A6898700DD647F /* SwiftUIX */,
E36A5A8527B4BFC40070DED5 /* FirebaseMessaging */,
E3C651E627CB5426002F6F4C /* Tabler */,
+ E3C651E927CB61EE002F6F4C /* GEOSwift */,
);
productName = iosApp;
productReference = 7555FF7B242A565900829871 /* iosApp.app */;
@@ -327,6 +330,7 @@
E33A236827A6898700DD647F /* XCRemoteSwiftPackageReference "SwiftUIX" */,
E36A5A8427B4BFC40070DED5 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
E3C651E527CB5425002F6F4C /* XCRemoteSwiftPackageReference "SwiftTabler" */,
+ E3C651E827CB61EE002F6F4C /* XCRemoteSwiftPackageReference "GEOSwift" */,
);
productRefGroup = 7555FF7C242A565900829871 /* Products */;
projectDirPath = "";
@@ -660,6 +664,14 @@
minimumVersion = 0.6.0;
};
};
+ E3C651E827CB61EE002F6F4C /* XCRemoteSwiftPackageReference "GEOSwift" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/GEOSwift/GEOSwift";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 9.0.0;
+ };
+ };
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
@@ -678,6 +690,11 @@
package = E3C651E527CB5425002F6F4C /* XCRemoteSwiftPackageReference "SwiftTabler" */;
productName = Tabler;
};
+ E3C651E927CB61EE002F6F4C /* GEOSwift */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = E3C651E827CB61EE002F6F4C /* XCRemoteSwiftPackageReference "GEOSwift" */;
+ productName = GEOSwift;
+ };
/* End XCSwiftPackageProductDependency section */
};
rootObject = 7555FF73242A565900829871 /* Project object */;
diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 3c172cd..2b63f64 100644
--- a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -29,6 +29,24 @@
}
},
{
+ "package": "geos",
+ "repositoryURL": "https://github.com/GEOSwift/geos.git",
+ "state": {
+ "branch": null,
+ "revision": "dc3a1e798e7ebb3cee1b6b219af2b0783820ff60",
+ "version": "7.0.0"
+ }
+ },
+ {
+ "package": "GEOSwift",
+ "repositoryURL": "https://github.com/GEOSwift/GEOSwift",
+ "state": {
+ "branch": null,
+ "revision": "ab813f1acbd92986e8733356b73b3f6d4ddc08e0",
+ "version": "9.0.0"
+ }
+ },
+ {
"package": "GoogleAppMeasurement",
"repositoryURL": "https://github.com/google/GoogleAppMeasurement.git",
"state": {
diff --git a/iosApp/iosApp/Details/Reports/UnitReportsView.swift b/iosApp/iosApp/Details/Reports/UnitReportsView.swift
index 910cea4..5a34ea5 100644
--- a/iosApp/iosApp/Details/Reports/UnitReportsView.swift
+++ b/iosApp/iosApp/Details/Reports/UnitReportsView.swift
@@ -100,6 +100,7 @@ struct UnitReportsView: View {
} else {
MapView(layer: $unitReportsViewModel.layer,
markers: $unitReportsViewModel.markers,
+ geofences: $unitReportsViewModel.flatGeofences,
selected: $unitReportsViewModel.selectedMarker,
isReport: true)
}
diff --git a/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift b/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift
index 5e85e89..4731a57 100644
--- a/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift
+++ b/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift
@@ -12,6 +12,7 @@ import shared
class UnitReportsViewModel: ObservableObject {
@Inject var reportController: ReportController
+ @Inject var geofencesController: GeofencesController
@Published var deviceId: Int32? = nil
@Published var reportType: ReportController.ReportType = .positions {
@@ -42,16 +43,30 @@ class UnitReportsViewModel: ObservableObject {
@Published var markers = [Marker]()
@Published var selectedMarker: Marker? = nil
+ @Published var geofences: [Int: Geofence] = [:] {
+ didSet {
+ flatGeofences = Array(geofences.values)
+ }
+ }
+ @Published var flatGeofences: [Geofence] = []
+
init(deviceId id: Int32?) {
deviceId = id
let collector = Collector<ReportController.Report>(callback: setReport)
reportController.reportFlow.collect(collector: collector) { _, _ in }
+
+ let geofencesCollector = Collector<[Int: Geofence]>(callback: setGeofences)
+ geofencesController.geofencesFlow.collect(collector: geofencesCollector) { unit, error in }
}
func setReport (report: ReportController.Report) {
self.report = report
}
+ private func setGeofences(geofences: [Int: Geofence]) {
+ self.geofences = geofences
+ }
+
func fetchReport(xlsx: Bool = false) {
if let id = deviceId {
reportController.fetchReport(deviceId: id,
diff --git a/iosApp/iosApp/Map/MapView.swift b/iosApp/iosApp/Map/MapView.swift
index 05bd9f9..84bdc05 100644
--- a/iosApp/iosApp/Map/MapView.swift
+++ b/iosApp/iosApp/Map/MapView.swift
@@ -25,6 +25,7 @@ struct MapView: UIViewControllerRepresentable {
@Binding var layer: MapLayer
@Binding var markers: [Marker]
+ @Binding var geofences: [Geofence]
@Binding var selected: Marker?
var isReport: Bool = false
var markerCallback: MarkerCallback?
@@ -32,6 +33,7 @@ struct MapView: UIViewControllerRepresentable {
class Coordinator {
var shouldCenter: Bool = true
var oldMarkers: [Marker] = []
+ var oldGeofences: [Geofence] = []
}
func makeCoordinator() -> Coordinator {
@@ -51,7 +53,6 @@ struct MapView: UIViewControllerRepresentable {
// MARK: - Set markers
if context.coordinator.oldMarkers != markers {
- print("center = \(context.coordinator.shouldCenter)")
uiViewController.display(markers: markers,
isReport: isReport,
center: context.coordinator.shouldCenter)
@@ -59,6 +60,12 @@ struct MapView: UIViewControllerRepresentable {
}
context.coordinator.oldMarkers = markers
+ // MARK: - Set geofences
+ if context.coordinator.oldGeofences != geofences {
+ uiViewController.display(geofences: geofences)
+ }
+ context.coordinator.oldGeofences = geofences
+
// MARK: - Center selected marker
if let selected = selected {
uiViewController.focusOn(marker: selected)
diff --git a/iosApp/iosApp/Map/MapViewController.swift b/iosApp/iosApp/Map/MapViewController.swift
index f068bf4..3c38b89 100644
--- a/iosApp/iosApp/Map/MapViewController.swift
+++ b/iosApp/iosApp/Map/MapViewController.swift
@@ -18,9 +18,23 @@
import UIKit
import WhirlyGlobe
import shared
+import GEOSwift
typealias MarkerCallback = (Int32?) -> ()
+extension Geometry {
+ func getCoordinates() -> [Point] {
+ switch self {
+ case let .polygon(polygon):
+ return polygon.exterior.points
+ case let .lineString(lineString):
+ return lineString.points
+ default:
+ return []
+ }
+ }
+}
+
class MapViewController: UIViewController {
var markerCallback: MarkerCallback? = nil
var mapLayer: MapLayer = MapLayer.companion.defaultLayer
@@ -84,6 +98,12 @@ class MapViewController: UIViewController {
}
}
+ func display(geofences: [Geofence]) {
+ mapView.runOnInit {
+ self.mapView.display(geofences: geofences)
+ }
+ }
+
func focusOn(marker: Marker) {
mapView.runOnInit {
self.mapView.focusOn(marker: marker)
@@ -206,8 +226,8 @@ class OurMaplyViewController: MaplyViewController {
let fontSize = 11.0
let colorReport = UIColor(red: 0.0, green: 0.5, blue: 0.0, alpha: 1.0)
- let colorLabel = UIColor.secondaryLabel
- let colorLabelOutline = UIColor.systemBackground
+ let colorLabel = UIColor.darkGray
+ let colorLabelOutline = UIColor.white
let vectorDesc: [AnyHashable : Any] = [
kMaplyColor: colorReport,
@@ -319,6 +339,85 @@ class OurMaplyViewController: MaplyViewController {
}
}
+ func display(geofences: [Geofence]) {
+ clear(geofences: true)
+
+ let fontSize = 11.0
+ let colorFill = UIColor(red: 0.10, green: 0.46, blue: 0.82, alpha: 1.00)
+ let colorLabel = UIColor(red: 0.10, green: 0.46, blue: 0.82, alpha: 1.00)
+ let colorLabelOutline = UIColor.white
+
+ let vectorDesc: [AnyHashable : Any] = [
+ kMaplyColor: colorFill,
+ kMaplyVecWidth: 12.0,
+ kMaplyWideVecImpl: kMaplyWideVecImplPerf
+ ]
+
+ let labelDesc: [AnyHashable : Any] = [
+ kMaplyFont: UIFont.boldSystemFont(ofSize: fontSize),
+ kMaplyTextColor: colorLabel,
+ kMaplyTextOutlineColor: colorLabelOutline,
+ kMaplyTextOutlineSize: 3.0
+ ]
+
+ let shapes = [MaplyShape]()
+ var vectors = [MaplyVectorObject]()
+ var labels = [MaplyScreenLabel]()
+
+ geofences.forEach { geofence in
+ if let area = geofence.area {
+ print ("Draw geofence with area = \(area)")
+ if let geometry = try? Geometry(wkt: area) {
+ switch geometry {
+ case .polygon(_):
+ let geoJSON: [AnyHashable : Any] = [
+ "type": "FeatureCollection",
+ "features": [
+ [
+ "type": "Feature",
+ "properties": [],
+ "geometry": [
+ "type": "Polygon",
+ "coordinates": [
+ geometry.getCoordinates().map { coordinate in
+ [coordinate.y, coordinate.x]
+ }
+ ]
+ ]
+ ]
+ ]
+ ]
+ if let vector = MaplyVectorObject(fromGeoJSONDictionary: geoJSON) {
+ vectors.append(vector)
+ }
+ default:
+ break
+ }
+
+ if let centroid = try? geometry.centroid() {
+ let label = MaplyScreenLabel()
+ label.text = geofence.name
+ label.loc = MaplyCoordinateMakeWithDegrees(Float(centroid.y),
+ Float(centroid.x))
+ label.layoutImportance = .infinity
+
+ labels.append(label)
+ }
+ }
+ }
+ }
+
+ if let objs = addShapes(shapes, desc: nil, mode: .any) {
+ geofenceObjects.append(objs)
+ }
+ if let objs = addWideVectors(vectors, desc: vectorDesc, mode: .any) {
+ geofenceObjects.append(objs)
+ }
+ if let objs = addScreenLabels(labels, desc: labelDesc, mode: .any) {
+ geofenceObjects.append(objs)
+ }
+ }
+
func setZoomLimits(minZoom: Int32, maxZoom: Int32) {
setZoomLimitsMin(
height(forMapScale: Float(truncating:
diff --git a/iosApp/iosApp/Map/UnitMapView.swift b/iosApp/iosApp/Map/UnitMapView.swift
index 533ac13..f416554 100644
--- a/iosApp/iosApp/Map/UnitMapView.swift
+++ b/iosApp/iosApp/Map/UnitMapView.swift
@@ -25,6 +25,7 @@ struct UnitMapView: View {
ZStack {
MapView(layer: $unitsViewModel.mapLayerType,
markers: $unitsViewModel.markers,
+ geofences: $unitsViewModel.flatGeofences,
selected: $unitsViewModel.selectedMarker,
markerCallback: unitsViewModel.selectUnitWith)
if let unit = unitsViewModel.selectedUnit {
diff --git a/iosApp/iosApp/Units/UnitsViewModel.swift b/iosApp/iosApp/Units/UnitsViewModel.swift
index 47adeb7..8ba6a4b 100644
--- a/iosApp/iosApp/Units/UnitsViewModel.swift
+++ b/iosApp/iosApp/Units/UnitsViewModel.swift
@@ -60,7 +60,12 @@ class UnitsViewModel: ObservableObject {
}
@Published var selectedMarker: Marker? = nil
@Published var mapLayerType: MapLayer = .companion.defaultLayer
- @Published var geofences: [Int: Geofence] = [:]
+ @Published var geofences: [Int: Geofence] = [:] {
+ didSet {
+ flatGeofences = Array(geofences.values)
+ }
+ }
+ @Published var flatGeofences: [Geofence] = []
init() {
unitsController.fetchUnits(scope: mainScope)