Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ A new Flutter project.
s.source = { :path => '.' }
s.source_files = 'arcgis_map_sdk_ios/Sources/**/*'
s.dependency 'Flutter'
s.dependency 'ArcGIS-Runtime-Toolkit-iOS'
s.platform = :ios, '13.0'
s.platform = :ios, '16.0'

# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
Expand Down
6 changes: 3 additions & 3 deletions arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ import PackageDescription
let package = Package(
name: "arcgis_map_sdk_ios",
platforms: [
.iOS("14.0")
.iOS("16.0")
],
products: [
.library(name: "arcgis-map-sdk-ios", targets: ["arcgis_map_sdk_ios"])
],
dependencies: [
.package(url: "https://github.com/Esri/arcgis-runtime-ios", .upToNextMinor(from: "100.15.0")),
.package(url: "https://github.com/Esri/arcgis-maps-sdk-swift", .upToNextMinor(from: "200.7.0")),
],
targets: [
.target(
name: "arcgis_map_sdk_ios",
dependencies: [
.product(name: "ArcGIS", package: "arcgis-runtime-ios")
.product(name: "ArcGIS", package: "arcgis-maps-sdk-swift")
]
),
]
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ class GraphicsParser {
self.registrar = registrar
}

func parse(dictionary: Dictionary<String, Any>) throws -> [AGSGraphic] {
func parse(dictionary: Dictionary<String, Any>) throws -> [Graphic] {
let type = dictionary["type"] as! String

let newGraphics: [AGSGraphic]
let newGraphics: [Graphic]
switch (type) {
case "point":
newGraphics = try! parsePoint(dictionary)
Expand All @@ -31,26 +31,29 @@ class GraphicsParser {
throw ParseException(message: "Unknown graphic type: \(type)")
}

let attributes = dictionary["attributes"] as? Dictionary<String, Any>
if let attributes = attributes {
newGraphics.forEach {
$0.attributes.addEntries(from: attributes)
// Apply attributes to each graphic, if present
if let attributes = dictionary["attributes"] as? [String: Any] {
newGraphics.forEach { graphic in
for (key, value) in attributes {
graphic.setAttributeValue(value, forKey: key)
}
}
}

return newGraphics
}

private func parsePoint(_ dictionary: [String: Any]) throws -> [AGSGraphic] {
private func parsePoint(_ dictionary: [String: Any]) throws -> [Graphic] {
let point: LatLng = try! JsonUtil.objectOfJson(dictionary["point"] as! Dictionary<String, Any>)

let graphic = AGSGraphic()
let graphic = Graphic()
graphic.geometry = point.toAGSPoint()
graphic.symbol = try! parseSymbol(dictionary["symbol"] as! Dictionary<String, Any>)

return [graphic]
}

private func parsePolyline(_ dictionary: [String: Any]) throws -> [AGSGraphic] {
private func parsePolyline(_ dictionary: [String: Any]) throws -> [Graphic] {
let payload: PathPayload = try! JsonUtil.objectOfJson(dictionary)

return try payload.paths.map { coordinates in
Expand All @@ -59,28 +62,28 @@ class GraphicsParser {
throw ParseException(message: "Size of coordinates need to be at least 2. Got \(array)")
}
if(array.count > 2) {
return AGSPoint(x: array[0], y: array[1], z: array[2], spatialReference: .wgs84())
return Point(x: array[0], y: array[1], z: array[2], spatialReference: .wgs84)
}
return AGSPoint(x: array[0], y: array[1], spatialReference: .wgs84())
return Point(x: array[0], y: array[1], spatialReference: .wgs84)
}

let graphic = AGSGraphic()
graphic.geometry = AGSPolyline(points: points)
let graphic = Graphic()
graphic.geometry = Polyline(points: points)
graphic.symbol = try! parseSymbol(dictionary["symbol"] as! Dictionary<String, Any>)

return graphic
}
}

private func parsePolygon(_ dictionary: [String: Any]) throws -> [AGSGraphic] {
private func parsePolygon(_ dictionary: [String: Any]) throws -> [Graphic] {
let payload: PolygonPayload = try! JsonUtil.objectOfJson(dictionary)

return payload.rings.map { ring in
let graphic = AGSGraphic()
let graphic = Graphic()
let points = ring.map { coordinate in
AGSPoint(x: coordinate[0], y: coordinate[1], spatialReference: .wgs84())
Point(x: coordinate[0], y: coordinate[1], spatialReference: .wgs84)
}
graphic.geometry = AGSPolygon(points: points)
graphic.geometry = Polygon(points: points)
graphic.symbol = try! parseSymbol(dictionary["symbol"] as! Dictionary<String, Any>)

return graphic
Expand All @@ -89,7 +92,7 @@ class GraphicsParser {

// region symbol parsing

func parseSymbol(_ dictionary: [String: Any]) throws -> AGSSymbol {
func parseSymbol(_ dictionary: [String: Any]) throws -> Symbol {
let type = dictionary["type"] as! String;
switch (type) {
case "simple-marker":
Expand All @@ -105,48 +108,48 @@ class GraphicsParser {
}
}

private func parseSimpleMarkerSymbol(_ dictionary: [String: Any]) -> AGSSymbol {
private func parseSimpleMarkerSymbol(_ dictionary: [String: Any]) -> Symbol {
let payload: SimpleMarkerSymbolPayload = try! JsonUtil.objectOfJson(dictionary)

let symbol = AGSSimpleMarkerSymbol()
let symbol = SimpleMarkerSymbol()
symbol.color = payload.color.toUIColor()
symbol.size = payload.size
symbol.outline = AGSSimpleLineSymbol(
symbol.outline = SimpleLineSymbol(
style: .solid,
color: payload.outlineColor.toUIColor(),
width: payload.outlineWidth
)
return symbol
}

private func parseSimpleFillMarkerSymbol(_ dictionary: [String: Any]) -> AGSSymbol {
private func parseSimpleFillMarkerSymbol(_ dictionary: [String: Any]) -> Symbol {
let payload: SimpleFillSymbolPayload = try! JsonUtil.objectOfJson(dictionary)

let symbol = AGSSimpleFillSymbol()
let symbol = SimpleFillSymbol()
symbol.color = payload.fillColor.toUIColor()

let outline = AGSSimpleLineSymbol()
let outline = SimpleLineSymbol()
outline.width = payload.outlineWidth
outline.color = payload.outlineColor.toUIColor()
symbol.outline = outline

return symbol
}

private func parsePictureMarkerSymbol(_ dictionary: [String: Any]) -> AGSSymbol {
private func parsePictureMarkerSymbol(_ dictionary: [String: Any]) -> Symbol {
let payload: PictureMarkerSymbolPayload = try! JsonUtil.objectOfJson(dictionary)

if(!payload.assetUri.isWebUrl()) {
let uiImage = getFlutterUiImage(payload.assetUri)
let symbol = AGSPictureMarkerSymbol(image: uiImage!)
let symbol = PictureMarkerSymbol(image: uiImage!)
symbol.width = payload.width
symbol.height = payload.height
symbol.offsetX = payload.xOffset
symbol.offsetY = payload.yOffset
return symbol
}

let symbol = AGSPictureMarkerSymbol(url: URL(string: payload.assetUri)!)
let symbol = PictureMarkerSymbol(url: URL(string: payload.assetUri)!)
symbol.width = payload.width
symbol.height = payload.height
symbol.offsetX = payload.xOffset
Expand All @@ -161,9 +164,9 @@ class GraphicsParser {
return UIImage(named: path!)
}

private func parseSimpleLineSymbol(_ dictionary: [String: Any]) -> AGSSymbol {
private func parseSimpleLineSymbol(_ dictionary: [String: Any]) -> Symbol {
let payload: SimpleLineSymbolPayload = try! JsonUtil.objectOfJson(dictionary)
let symbol = AGSSimpleLineSymbol()
let symbol = SimpleLineSymbol()

if let color = payload.color {
symbol.color = color.toUIColor()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,38 @@
import Foundation
import ArcGIS

class ManualLocationDataSource: AGSLocationDataSource {
final class CustomLocationProvider: LocationProvider {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rename the file name to be CustomLocationProvider.swift?

private var locationContinuation: AsyncThrowingStream<Location, Error>.Continuation?
private var headingContinuation: AsyncThrowingStream<Double, Error>.Continuation?


// Exposed stream
var locations: AsyncThrowingStream<Location, Error> {
AsyncThrowingStream { continuation in
self.locationContinuation = continuation
}
}

var headings: AsyncThrowingStream<Double, Error> {
AsyncThrowingStream { continuation in
self.headingContinuation = continuation
}
}

// Push location from outside
public func setNewLocation(_ position: UserPosition) {
let loc = AGSLocation(
let loc = Location(
position: position.latLng.toAGSPoint(),
horizontalAccuracy: position.accuracy ?? 0,
velocity: position.velocity ?? 0,
verticalAccuracy: position.accuracy ?? 0,
speed: position.velocity ?? 0,
course: position.heading ?? 0,
lastKnown: false
isLastKnown: false
)
didUpdate(loc)
locationContinuation?.yield(loc)
if let heading = position.heading {
headingContinuation?.yield(heading)
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//
// Created by Tarek Tolba on 29/04/2025.
//

import SwiftUI
import ArcGIS
import CoreLocation


struct MapContentView: View {
@ObservedObject var viewModel: MapViewModel

init(viewModel: MapViewModel) {
self.viewModel = viewModel
}

var body: some View {
MapViewReader { mapViewProxy in
MapView(map: viewModel.map,
viewpoint: viewModel.viewpoint,
graphicsOverlays: [viewModel.defaultGraphicsOverlay])
.attributionBarHidden(viewModel.attributionBarHidden)
.locationDisplay(viewModel.locationDisplay)
.contentInsets(viewModel.contentInsets)
.interactionModes(viewModel.interactionModes)
.onViewpointChanged(kind: .centerAndScale) { newViewpoint in
viewModel.viewpoint = newViewpoint
}.onScaleChanged(perform: { scale in
viewModel.onScaleChanged?(scale)
}).onVisibleAreaChanged(perform: { polygon in
viewModel.onVisibleAreaChanged?(polygon)
})
.onChange(of: viewModel.map.basemap?.loadStatus) { newValue in
if let newValue {
viewModel.onLoadStatusChanged?(newValue)
}
}
.task {
// Store the mapViewProxy for external access
viewModel.mapViewProxy = mapViewProxy
}
.onDisappear {
viewModel.stopLocationDataSource()
// Clear the mapViewProxy reference when view disappears
viewModel.mapViewProxy = nil
}
.ignoresSafeArea(edges: .all)
}
}
}


class MapViewModel: ObservableObject {
let map = Map()
let locationDisplay = LocationDisplay()

@Published var viewpoint: Viewpoint
@Published var mapViewProxy: MapViewProxy?
@Published var attributionBarHidden: Bool = false
@Published var contentInsets: EdgeInsets = EdgeInsets()
@Published var interactionModes: MapViewInteractionModes = .all
@Published var defaultGraphicsOverlay = GraphicsOverlay()

var onScaleChanged: ((Double) -> Void)?
var onVisibleAreaChanged: ((Polygon) -> Void)?
var onLoadStatusChanged: ((LoadStatus) -> Void)?

init(viewpoint : Viewpoint) {
self.viewpoint = viewpoint
}

/// Stops the location data source.
func stopLocationDataSource() {
Task {
await locationDisplay.dataSource.stop()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,3 @@ struct AnimationOptions: Codable {
var animationCurve: String
}

extension AnimationOptions {
func arcgisAnimationCurve() -> AGSAnimationCurve {
switch animationCurve {
case "linear":
return .linear
case "easeIn":
return .easeInCirc
case "easeOut":
return .easeOutCirc
case "easeInOut":
return .easeInOutCirc
default:
return .linear
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct LatLng: Codable {
}

extension LatLng {
func toAGSPoint() -> AGSPoint {
AGSPoint(x: longitude, y: latitude, spatialReference: .wgs84())
func toAGSPoint() -> Point {
Point(x: longitude, y: latitude, spatialReference: .wgs84)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ enum PolylineStyle: String, Codable {
case shortDot
case solid

func toAGSStyle() -> AGSSimpleLineSymbolStyle {
func toAGSStyle() -> SimpleLineSymbol.Style {
switch (self) {
case .dash:
return .dash
Expand All @@ -48,7 +48,7 @@ enum PolylineStyle: String, Codable {
case .longDashDotDot:
return .longDashDot
case .none:
return .null
return .noLine
case .shortDash:
return .shortDash
case .shortDashDot:
Expand All @@ -68,7 +68,7 @@ enum MarkerPlacement: String, Codable {
case end
case beginEnd

func toAGSStyle() -> AGSSimpleLineSymbolMarkerPlacement {
func toAGSStyle() -> SimpleLineSymbol.MarkerPlacement {
switch (self) {
case .begin:
return .begin
Expand All @@ -88,12 +88,12 @@ enum MarkerStyle: String, Codable {
self = try MarkerStyle(rawValue: decoder.singleValueContainer().decode(RawValue.self)) ?? .none
}

func toAGSStyle() -> AGSSimpleLineSymbolMarkerStyle {
func toAGSStyle() -> SimpleLineSymbol.MarkerStyle {
switch (self) {
case .arrow:
return .arrow
case .none:
return .none
return .noMarkers
}
}
}
Loading