diff --git a/iOS/src/Malinki/Malinki.xcodeproj/project.pbxproj b/iOS/src/Malinki/Malinki.xcodeproj/project.pbxproj index ddd2858..7960fc8 100644 --- a/iOS/src/Malinki/Malinki.xcodeproj/project.pbxproj +++ b/iOS/src/Malinki/Malinki.xcodeproj/project.pbxproj @@ -697,7 +697,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.4; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -754,7 +754,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.4; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -775,7 +775,7 @@ DEVELOPMENT_TEAM = PM6R3BPDX5; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = Malinki/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -797,7 +797,7 @@ DEVELOPMENT_TEAM = PM6R3BPDX5; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = Malinki/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/iOS/src/Malinki/Malinki.xcodeproj/project.xcworkspace/xcuserdata/christophjung.xcuserdatad/UserInterfaceState.xcuserstate b/iOS/src/Malinki/Malinki.xcodeproj/project.xcworkspace/xcuserdata/christophjung.xcuserdatad/UserInterfaceState.xcuserstate index 82ec879..14fac12 100644 Binary files a/iOS/src/Malinki/Malinki.xcodeproj/project.xcworkspace/xcuserdata/christophjung.xcuserdatad/UserInterfaceState.xcuserstate and b/iOS/src/Malinki/Malinki.xcodeproj/project.xcworkspace/xcuserdata/christophjung.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/iOS/src/Malinki/Malinki/Configuration/MalinkiConfigurationProvider.swift b/iOS/src/Malinki/Malinki/Configuration/MalinkiConfigurationProvider.swift index 7d10d9f..5403966 100644 --- a/iOS/src/Malinki/Malinki/Configuration/MalinkiConfigurationProvider.swift +++ b/iOS/src/Malinki/Malinki/Configuration/MalinkiConfigurationProvider.swift @@ -169,7 +169,7 @@ class MalinkiConfigurationProvider { private func getExternalNameForDeviceLanguage(externalNames: MalinkiConfigurationExternalNames) -> String { var externalName: String = "" - switch Locale.current.languageCode { + switch Locale.current.language.languageCode?.identifier { case "en": externalName = externalNames.en break @@ -257,7 +257,7 @@ class MalinkiConfigurationProvider { func getSupportText() -> String { var localSupportText: String = "" - switch Locale.current.languageCode { + switch Locale.current.language.languageCode?.identifier { case "en": localSupportText = self.configData?.inAppPurchases?.supportText?.en ?? "" case "de": diff --git a/iOS/src/Malinki/Malinki/Data Interface/Annotations/MalinkiUserAnnotationsProvider.swift b/iOS/src/Malinki/Malinki/Data Interface/Annotations/MalinkiUserAnnotationsProvider.swift index cfd013e..5ef7b2e 100644 --- a/iOS/src/Malinki/Malinki/Data Interface/Annotations/MalinkiUserAnnotationsProvider.swift +++ b/iOS/src/Malinki/Malinki/Data Interface/Annotations/MalinkiUserAnnotationsProvider.swift @@ -31,11 +31,11 @@ class MalinkiUserAnnotationsProvider: ObservableObject { let fm = FileManager.default if let path = self.getUserAnnotationsPath(fileManager: fm) { - //create a bookmarks file if not existing + //create a user annotation file if not existing if !(fm.fileExists(atPath: path)) { fm.createFile(atPath: path, contents: self.encodeUserAnnotations()) } else { - //read the bookmarks file + //read the user annotation file do { let decoder = JSONDecoder() self.userAnnotationsRoot = try decoder.decode(MalinkiUserAnnotationsRoot.self, from: Data(contentsOf: URL(string: "file://\(path)")!)) diff --git a/iOS/src/Malinki/Malinki/Data Interface/Bookmarks/MalinkiBookmarksObjects.swift b/iOS/src/Malinki/Malinki/Data Interface/Bookmarks/MalinkiBookmarksObjects.swift index 0898c56..9c28d8d 100644 --- a/iOS/src/Malinki/Malinki/Data Interface/Bookmarks/MalinkiBookmarksObjects.swift +++ b/iOS/src/Malinki/Malinki/Data Interface/Bookmarks/MalinkiBookmarksObjects.swift @@ -21,6 +21,7 @@ struct MalinkiBookmarksObject: Codable { var layer_ids: [Int] var show_annotations: Bool var map: MalinkiBookmarksMap + var basemapID: Int? } //MARK: - map component of bookmarks diff --git a/iOS/src/Malinki/Malinki/Data Interface/RasterData/MalinkiRasterData.swift b/iOS/src/Malinki/Malinki/Data Interface/RasterData/MalinkiRasterData.swift index fe0c428..85a209b 100644 --- a/iOS/src/Malinki/Malinki/Data Interface/RasterData/MalinkiRasterData.swift +++ b/iOS/src/Malinki/Malinki/Data Interface/RasterData/MalinkiRasterData.swift @@ -90,4 +90,34 @@ struct MalinkiRasterData { return mapType } + /// This function returns the configuration of a map from apple. + /// This function should be used to access the data of the current configuration object, if the property isAppleMaps is true. + /// - Returns: the configuration of an MKMap + func getAppleMapConfiguration() -> MKMapConfiguration { + let appleMapsType = self.mapDataConfiguration.internalName + let mapConfig: MKMapConfiguration + + switch appleMapsType { + case "apple_roads": + let standardMapConfig = MKStandardMapConfiguration(elevationStyle: .realistic, emphasisStyle: .default) + standardMapConfig.showsTraffic = false + standardMapConfig.pointOfInterestFilter = .excludingAll + mapConfig = standardMapConfig + case "apple_aerial": + mapConfig = MKImageryMapConfiguration(elevationStyle: .realistic) + case "apple_hybrid": + let hybridMapConfig = MKHybridMapConfiguration(elevationStyle: .realistic) + hybridMapConfig.showsTraffic = false + hybridMapConfig.pointOfInterestFilter = .excludingAll + mapConfig = hybridMapConfig + default: + let standardMapConfig = MKStandardMapConfiguration(elevationStyle: .realistic, emphasisStyle: .muted) + standardMapConfig.showsTraffic = false + standardMapConfig.pointOfInterestFilter = .excludingAll + mapConfig = standardMapConfig + } + + return mapConfig + } + } diff --git a/iOS/src/Malinki/Malinki/Data Interface/VectorData/MalinkiFeatureDataContainer.swift b/iOS/src/Malinki/Malinki/Data Interface/VectorData/MalinkiFeatureDataContainer.swift index 27525e5..f1b4e9c 100644 --- a/iOS/src/Malinki/Malinki/Data Interface/VectorData/MalinkiFeatureDataContainer.swift +++ b/iOS/src/Malinki/Malinki/Data Interface/VectorData/MalinkiFeatureDataContainer.swift @@ -186,7 +186,7 @@ public class MalinkiFeatureDataContainer: MalinkiVectorData, ObservableObject { let data = try await self.fetchData(from: request) //parse data depending on info format - if config.infoFormat == "application/json" { + if config.infoFormat == "application/json" || config.infoFormat == "application/geojson" { //get geojson object and its data await self.getFeatureData(name: selectedAnnotation?.title ?? "", from: self.decodeGeoJSON(from: data), layerID: layerID) diff --git a/iOS/src/Malinki/Malinki/UserInterface/Alert/AlertControlView.swift b/iOS/src/Malinki/Malinki/UserInterface/Alert/AlertControlView.swift index 4c6f03e..db048eb 100644 --- a/iOS/src/Malinki/Malinki/UserInterface/Alert/AlertControlView.swift +++ b/iOS/src/Malinki/Malinki/UserInterface/Alert/AlertControlView.swift @@ -25,6 +25,7 @@ struct AlertControlView: UIViewControllerRepresentable { @EnvironmentObject var mapLayers: MalinkiLayerContainer @EnvironmentObject var mapRegion: MalinkiMapRegion + @Binding var basemapID: Int @Binding var showAlert: Bool var textString: String = "" @@ -80,7 +81,8 @@ struct AlertControlView: UIViewControllerRepresentable { latitude: self.mapRegion.mapRegion.center.latitude, longitude: self.mapRegion.mapRegion.center.longitude), span: MalinkiBookmarksMapSpan( delta_latitude: self.mapRegion.mapRegion.span.latitudeDelta, - delta_longitude: self.mapRegion.mapRegion.span.longitudeDelta)) + delta_longitude: self.mapRegion.mapRegion.span.longitudeDelta)), + basemapID: self.basemapID )) } case .updateBookmark: diff --git a/iOS/src/Malinki/Malinki/UserInterface/Annotations/MalinkiUserAnnotationsView.swift b/iOS/src/Malinki/Malinki/UserInterface/Annotations/MalinkiUserAnnotationsView.swift index 2a018c7..1eec46d 100644 --- a/iOS/src/Malinki/Malinki/UserInterface/Annotations/MalinkiUserAnnotationsView.swift +++ b/iOS/src/Malinki/Malinki/UserInterface/Annotations/MalinkiUserAnnotationsView.swift @@ -32,7 +32,7 @@ struct MalinkiUserAnnotationsView: View { var body: some View { ZStack { - AlertControlView(showAlert: self.$showAlert, title: String(localized: "Map Pin Name"), message: String(localized: "Insert the name of the map pin."), actionType: self.actionType, uuidString: self.uuidString) + AlertControlView(basemapID: .constant(0), showAlert: self.$showAlert, title: String(localized: "Map Pin Name"), message: String(localized: "Insert the name of the map pin."), actionType: self.actionType, uuidString: self.uuidString) VStack { NavigationView { diff --git a/iOS/src/Malinki/Malinki/UserInterface/Bookmarks/MalinkiBookmarksView.swift b/iOS/src/Malinki/Malinki/UserInterface/Bookmarks/MalinkiBookmarksView.swift index 8136aee..864e3de 100644 --- a/iOS/src/Malinki/Malinki/UserInterface/Bookmarks/MalinkiBookmarksView.swift +++ b/iOS/src/Malinki/Malinki/UserInterface/Bookmarks/MalinkiBookmarksView.swift @@ -19,6 +19,7 @@ struct MalinkiBookmarksView: View { @Binding private var sheetState: UISheetPresentationController.Detent.Identifier? @Binding private var isSheetShowing: Bool + @Binding private var basemapID: Int private var config = MalinkiConfigurationProvider.sharedInstance @@ -30,15 +31,16 @@ struct MalinkiBookmarksView: View { /// - Parameters: /// - sheetState: the state of the sheet /// - isSheetShowing: a boolean binding indicating, whether the sheet is open or closed - init(sheetState: Binding, isSheetShowing: Binding) { + init(sheetState: Binding, isSheetShowing: Binding, basemapID: Binding) { self._sheetState = sheetState self._isSheetShowing = isSheetShowing + self._basemapID = basemapID } var body: some View { ZStack { - AlertControlView(showAlert: self.$showAlert, title: String(localized: "Bookmark Name"), message: String(localized: "Insert the bookmark name."), actionType: self.actionType, uuidString: self.uuidString) + AlertControlView(basemapID: self.$basemapID, showAlert: self.$showAlert, title: String(localized: "Bookmark Name"), message: String(localized: "Insert the bookmark name."), actionType: self.actionType, uuidString: self.uuidString) VStack { NavigationView { @@ -70,6 +72,9 @@ struct MalinkiBookmarksView: View { //untoggle layers according to the bookmark _ = self.mapLayers.rasterLayers.filter({$0.themeID == bookmark.theme_id && !(bookmark.layer_ids.contains($0.id))}).map({$0.isToggled = false}) + //adjust the basemap + self.basemapID = bookmark.basemapID ?? self.basemapID + //change the bbox of the map self.mapRegion.mapRegion = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: bookmark.map.centre.latitude, longitude: bookmark.map.centre.longitude), span: MKCoordinateSpan(latitudeDelta: bookmark.map.span.delta_latitude, longitudeDelta: bookmark.map.span.delta_longitude)) @@ -170,7 +175,7 @@ struct MalinkiBookmarksView: View { @available(iOS 15.0.0, *) struct MalinkiBookmarksView_Previews: PreviewProvider { static var previews: some View { - MalinkiBookmarksView(sheetState: .constant(UISheetPresentationController.Detent.Identifier.medium), isSheetShowing: .constant(true)) + MalinkiBookmarksView(sheetState: .constant(UISheetPresentationController.Detent.Identifier.medium), isSheetShowing: .constant(true), basemapID: .constant(0)) .environmentObject(MalinkiBookmarksProvider.sharedInstance) .environmentObject(MalinkiLayerContainer(layers: MalinkiConfigurationProvider.sharedInstance.getAllMapLayersArray(), themes: MalinkiConfigurationProvider.sharedInstance.getAllMapLayersArray().map({MalinkiTheme(themeID: $0.themeID)}), selectedMapThemeID: 0)) .environmentObject(MalinkiMapRegion(mapRegion: MKCoordinateRegion())) diff --git a/iOS/src/Malinki/Malinki/UserInterface/MalinkiMap.swift b/iOS/src/Malinki/Malinki/UserInterface/MalinkiMap.swift index 8737a10..079c5ed 100644 --- a/iOS/src/Malinki/Malinki/UserInterface/MalinkiMap.swift +++ b/iOS/src/Malinki/Malinki/UserInterface/MalinkiMap.swift @@ -113,7 +113,7 @@ struct MalinkiMap: View { MalinkiSearchView(searchText: self.$searchText, sheetDetent: self.$selectedDetentIdentifier, isSheetShowing: self.$sheet.isShowing, isEditing: self.$isEditing) .environmentObject(self.mapLayers) case .bookmarks: - MalinkiBookmarksView(sheetState: self.$selectedDetentIdentifier, isSheetShowing: self.$sheet.isShowing) + MalinkiBookmarksView(sheetState: self.$selectedDetentIdentifier, isSheetShowing: self.$sheet.isShowing, basemapID: self.$basemapID) .environmentObject(self.bookmarks) .environmentObject(self.mapLayers) .environmentObject(self.mapRegion) diff --git a/iOS/src/Malinki/Malinki/UserInterface/MapView/MalinkiMapView.swift b/iOS/src/Malinki/Malinki/UserInterface/MapView/MalinkiMapView.swift index 15bf304..0815aad 100644 --- a/iOS/src/Malinki/Malinki/UserInterface/MapView/MalinkiMapView.swift +++ b/iOS/src/Malinki/Malinki/UserInterface/MapView/MalinkiMapView.swift @@ -164,11 +164,11 @@ struct MalinkiMapView: UIViewRepresentable { //add the basemap to the mapview if baseLayer.isAppleMaps { - mapView.mapType = baseLayer.getAppleMapType() + mapView.preferredConfiguration = baseLayer.getAppleMapConfiguration() } else { let overlay = baseLayer.getOverlay() overlay.canReplaceMapContent = true - mapView.addOverlay(overlay) + mapView.addOverlay(overlay, level: .aboveLabels) } } @@ -185,7 +185,7 @@ struct MalinkiMapView: UIViewRepresentable { } else { let overlay = layer.getOverlay() overlay.canReplaceMapContent = false - mapView.addOverlay(overlay) + mapView.addOverlay(overlay, level: .aboveLabels) } } @@ -209,17 +209,24 @@ struct MalinkiMapView: UIViewRepresentable { let linestrings = self.features.geometries.filter({$0.type == .linestring}) let multilinestring = self.features.geometries.filter({$0.type == .multilinestring}) + //get the layer id for user annotations + let layerID = self.features.featureData.first?.vectorLayerID ?? -99 + //create and add one multipolygon var allPolygons: [MKPolygon] = [] allPolygons.append(contentsOf: polygons.map({$0.polygon})) allPolygons.append(contentsOf: multipolygons.map({$0.multiPolygon.polygons}).flatMap({$0})) - mapView.addOverlay(MKMultiPolygon(allPolygons)) + let multiPolygon = MKMultiPolygon(allPolygons) + multiPolygon.subtitle = String(layerID) + mapView.addOverlay(multiPolygon, level: MKOverlayLevel(rawValue: 1)!) //create and add one multilinestring var allLinestrings: [MKPolyline] = [] allLinestrings.append(contentsOf: linestrings.map({$0.linestring})) allLinestrings.append(contentsOf: multilinestring.map({$0.multiLinestring.polylines}).flatMap({$0})) - mapView.addOverlay(MKMultiPolyline(allLinestrings)) + let multiLinestring = MKMultiPolyline(allLinestrings) + multiLinestring.subtitle = String(layerID) + mapView.addOverlay(multiLinestring, level: MKOverlayLevel(rawValue: 1)!) } } @@ -279,17 +286,43 @@ final class Coordinator: NSObject, MKMapViewDelegate { overlayRender.alpha = mto.alpha } else if overlay is MKMultiPolyline { let renderer = MKMultiPolylineRenderer(multiPolyline: overlay as! MKMultiPolyline) - let vectorStyle = MalinkiConfigurationProvider.sharedInstance.getVectorLayer(id: self.control.features.selectedAnnotation?.layerID ?? 0, theme: self.control.features.selectedAnnotation?.themeID ?? 0)?.style - renderer.strokeColor = UIColor(named: vectorStyle?.featureStyle?.outline.colour ?? "AccentColor") - renderer.lineWidth = vectorStyle?.featureStyle?.outline.width ?? 1.0 + if let vectorStyle = MalinkiConfigurationProvider.sharedInstance.getVectorLayer(id: self.control.features.selectedAnnotation?.layerID ?? -99, theme: self.control.features.selectedAnnotation?.themeID ?? -99)?.style { + //styling with information from the config file + renderer.strokeColor = UIColor(named: vectorStyle.featureStyle?.outline.colour ?? "AccentColor") + renderer.lineWidth = vectorStyle.featureStyle?.outline.width ?? 1.0 + } + else if let layerID = overlay.subtitle, let vectorStyle = MalinkiConfigurationProvider.sharedInstance.getVectorLayer(id: Int(layerID ?? "-99") ?? -99, theme: self.control.features.selectedAnnotation?.themeID ?? -99)?.style { + //styling with information from config using the layerid from the subtitle property of the overlay + renderer.strokeColor = UIColor(named: vectorStyle.featureStyle?.outline.colour ?? "AccentColor") + renderer.lineWidth = vectorStyle.featureStyle?.outline.width ?? 1.0 + } + else { + //default styling, e.g. for user annotations + renderer.strokeColor = UIColor(named: "AccentColor") + renderer.lineWidth = 1.0 + } overlayRender = renderer } else if overlay is MKMultiPolygon { let renderer = MKMultiPolygonRenderer(multiPolygon: overlay as! MKMultiPolygon) - let vectorStyle = MalinkiConfigurationProvider.sharedInstance.getVectorLayer(id: self.control.features.selectedAnnotation?.layerID ?? 0, theme: self.control.features.selectedAnnotation?.themeID ?? 0)?.style - renderer.strokeColor = UIColor(named: vectorStyle?.featureStyle?.outline.colour ?? "AccentColor") - renderer.fillColor = UIColor(named: vectorStyle?.featureStyle?.fill?.colour ?? "AccentColor")?.withAlphaComponent(vectorStyle?.featureStyle?.fill?.opacity ?? 0.5) - renderer.lineWidth = vectorStyle?.featureStyle?.outline.width ?? 1.0 + if let vectorStyle = MalinkiConfigurationProvider.sharedInstance.getVectorLayer(id: self.control.features.selectedAnnotation?.layerID ?? -99, theme: self.control.features.selectedAnnotation?.themeID ?? -99)?.style { + //styling with information from the config file + renderer.strokeColor = UIColor(named: vectorStyle.featureStyle?.outline.colour ?? "AccentColor") + renderer.fillColor = UIColor(named: vectorStyle.featureStyle?.fill?.colour ?? "AccentColor")?.withAlphaComponent(vectorStyle.featureStyle?.fill?.opacity ?? 0.5) + renderer.lineWidth = vectorStyle.featureStyle?.outline.width ?? 1.0 + } + else if let layerID = overlay.subtitle, let vectorStyle = MalinkiConfigurationProvider.sharedInstance.getVectorLayer(id: Int(layerID ?? "-99") ?? -99, theme: self.control.features.selectedAnnotation?.themeID ?? -99)?.style { + //styling with information from config using the layerid from the subtitle property of the overlay + renderer.strokeColor = UIColor(named: vectorStyle.featureStyle?.outline.colour ?? "AccentColor") + renderer.fillColor = UIColor(named: vectorStyle.featureStyle?.fill?.colour ?? "AccentColor")?.withAlphaComponent(vectorStyle.featureStyle?.fill?.opacity ?? 0.5) + renderer.lineWidth = vectorStyle.featureStyle?.outline.width ?? 1.0 + } + else { + //default styling, e.g. for user annotations + renderer.strokeColor = UIColor(named: "AccentColor") + renderer.fillColor = UIColor(named: "AccentColor")?.withAlphaComponent(0.5) + renderer.lineWidth = 1.0 + } overlayRender = renderer } else { overlayRender = MKOverlayRenderer()