react-native-google-maps-plus 1.7.0-dev.15 → 1.7.0-dev.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -77,7 +77,10 @@ class MapMarkerBuilder(
77
77
  val height = (svg.documentHeight.takeIf { it > 0 } ?: 128f).toInt()
78
78
 
79
79
  createBitmap(width, height).apply {
80
- Canvas(this).also(svg::renderToCanvas)
80
+ density = context.resources.displayMetrics.densityDpi
81
+ Canvas(this).also {
82
+ svg.renderToCanvas(it)
83
+ }
81
84
  }
82
85
  }
83
86
 
@@ -98,10 +101,12 @@ class MapMarkerBuilder(
98
101
  val innerSvg = SVG.getFromString(svgText)
99
102
  val w = innerSvg.documentWidth.takeIf { it > 0 } ?: 128f
100
103
  val h = innerSvg.documentHeight.takeIf { it > 0 } ?: 128f
101
- val bmp = createBitmap(w.toInt(), h.toInt())
102
- val canvas = Canvas(bmp)
103
- innerSvg.renderToCanvas(canvas)
104
- bmp
104
+ createBitmap(w.toInt(), h.toInt()).apply {
105
+ density = context.resources.displayMetrics.densityDpi
106
+ Canvas(this).also {
107
+ innerSvg.renderToCanvas(it)
108
+ }
109
+ }
105
110
  } else {
106
111
  conn.inputStream.use { BitmapFactory.decodeStream(it) }
107
112
  }
@@ -328,27 +333,28 @@ class MapMarkerBuilder(
328
333
  coroutineContext.ensureActive()
329
334
  val svg = SVG.getFromString(m.iconSvg.svgString)
330
335
 
331
- coroutineContext.ensureActive()
332
- svg.setDocumentWidth(m.iconSvg.width.dpToPx())
333
- svg.setDocumentHeight(m.iconSvg.height.dpToPx())
336
+ val wPx =
337
+ m.iconSvg.width
338
+ .dpToPx()
339
+ .toInt()
340
+ val hPx =
341
+ m.iconSvg.height
342
+ .dpToPx()
343
+ .toInt()
334
344
 
335
345
  coroutineContext.ensureActive()
336
- bmp =
337
- createBitmap(
338
- m.iconSvg.width
339
- .dpToPx()
340
- .toInt(),
341
- m.iconSvg.height
342
- .dpToPx()
343
- .toInt(),
344
- Bitmap.Config.ARGB_8888,
345
- )
346
+ svg.setDocumentWidth(wPx.toFloat())
347
+ svg.setDocumentHeight(hPx.toFloat())
346
348
 
347
349
  coroutineContext.ensureActive()
348
- val canvas = Canvas(bmp)
349
- svg.renderToCanvas(canvas)
350
+ bmp =
351
+ createBitmap(wPx, hPx, Bitmap.Config.ARGB_8888).apply {
352
+ density = context.resources.displayMetrics.densityDpi
353
+ Canvas(this).also {
354
+ svg.renderToCanvas(it)
355
+ }
356
+ }
350
357
 
351
- coroutineContext.ensureActive()
352
358
  return bmp
353
359
  } catch (t: Throwable) {
354
360
  try {
@@ -444,7 +444,10 @@ GMSIndoorDisplayDelegate {
444
444
 
445
445
  @MainActor
446
446
  func removeMarker(id: String) {
447
- markersById.removeValue(forKey: id).map { $0.map = nil }
447
+ markersById.removeValue(forKey: id).map {
448
+ $0.icon = nil
449
+ $0.map = nil
450
+ }
448
451
  }
449
452
 
450
453
  @MainActor
@@ -35,6 +35,8 @@ final class LocationHandler: NSObject, CLLocationManagerDelegate {
35
35
 
36
36
  func showLocationDialog() {
37
37
  onMainAsync { [weak self] in
38
+ guard let self = self else { return }
39
+
38
40
  guard let vc = Self.topMostViewController() else { return }
39
41
  let title =
40
42
  Bundle.main.object(forInfoDictionaryKey: "LocationNotAvailableTitle")
@@ -61,7 +63,7 @@ final class LocationHandler: NSObject, CLLocationManagerDelegate {
61
63
  title: openLocationSettingsButton ?? "Open settings",
62
64
  style: .default
63
65
  ) { _ in
64
- self?.openLocationSettings()
66
+ self.openLocationSettings()
65
67
  }
66
68
  )
67
69
  vc.present(alert, animated: true, completion: nil)
@@ -32,11 +32,9 @@ func onMain(_ block: @escaping @MainActor () -> Void) {
32
32
 
33
33
  @inline(__always)
34
34
  func onMainAsync(
35
- _ block: @MainActor @escaping () async -> Void
35
+ _ block: @escaping @MainActor () async -> Void
36
36
  ) {
37
- if Thread.isMainThread {
38
- Task { @MainActor in await block() }
39
- } else {
40
- Task { @MainActor in await block() }
37
+ Task { @MainActor in
38
+ await block()
41
39
  }
42
40
  }
@@ -46,15 +46,35 @@ final class MapMarkerBuilder {
46
46
 
47
47
  @MainActor
48
48
  func update(_ prev: RNMarker, _ next: RNMarker, _ m: GMSMarker) {
49
- if !prev.coordinateEquals(next) {
50
- m.position = next.coordinate.toCLLocationCoordinate2D()
51
- }
49
+ withCATransaction(disableActions: true) {
50
+
51
+ var tracksViewChanges = false
52
+ var tracksInfoWindowChanges = false
52
53
 
53
- if !prev.markerStyleEquals(next) {
54
- buildIconAsync(next.id, next) { img in
55
- m.tracksViewChanges = true
56
- m.icon = img
54
+ if !prev.coordinateEquals(next) {
55
+ m.position = next.coordinate.toCLLocationCoordinate2D()
56
+ }
57
57
 
58
+ if !prev.markerStyleEquals(next) {
59
+ self.buildIconAsync(next) { img in
60
+ tracksViewChanges = true
61
+ m.icon = img
62
+
63
+ if !prev.anchorEquals(next) {
64
+ m.groundAnchor = CGPoint(
65
+ x: next.anchor?.x ?? 0.5,
66
+ y: next.anchor?.y ?? 1
67
+ )
68
+ }
69
+
70
+ if !prev.infoWindowAnchorEquals(next) {
71
+ m.infoWindowAnchor = CGPoint(
72
+ x: next.infoWindowAnchor?.x ?? 0.5,
73
+ y: next.infoWindowAnchor?.y ?? 0
74
+ )
75
+ }
76
+ }
77
+ } else {
58
78
  if !prev.anchorEquals(next) {
59
79
  m.groundAnchor = CGPoint(
60
80
  x: next.anchor?.x ?? 0.5,
@@ -68,79 +88,70 @@ final class MapMarkerBuilder {
68
88
  y: next.infoWindowAnchor?.y ?? 0
69
89
  )
70
90
  }
71
-
72
- onMainAsync { [weak m] in
73
- try? await Task.sleep(nanoseconds: 250_000_000)
74
- m?.tracksViewChanges = false
75
- }
76
91
  }
77
- } else {
78
- if !prev.anchorEquals(next) {
79
- m.groundAnchor = CGPoint(
80
- x: next.anchor?.x ?? 0.5,
81
- y: next.anchor?.y ?? 1
82
- )
92
+
93
+ if prev.title != next.title {
94
+ tracksInfoWindowChanges = true
95
+ m.title = next.title
83
96
  }
84
97
 
85
- if !prev.infoWindowAnchorEquals(next) {
86
- m.infoWindowAnchor = CGPoint(
87
- x: next.infoWindowAnchor?.x ?? 0.5,
88
- y: next.infoWindowAnchor?.y ?? 0
89
- )
98
+ if prev.snippet != next.snippet {
99
+ tracksInfoWindowChanges = true
100
+ m.snippet = next.snippet
90
101
  }
91
- }
92
102
 
93
- var tracksInfoWindowChanges = false
103
+ if prev.opacity != next.opacity {
104
+ let opacity = Float(next.opacity ?? 1)
105
+ m.opacity = opacity
106
+ m.iconView?.alpha = CGFloat(opacity)
107
+ }
94
108
 
95
- if prev.title != next.title {
96
- tracksInfoWindowChanges = true
97
- m.title = next.title
98
- }
109
+ if prev.flat != next.flat {
110
+ m.isFlat = next.flat ?? false
111
+ }
99
112
 
100
- if prev.snippet != next.snippet {
101
- tracksInfoWindowChanges = true
102
- m.snippet = next.snippet
103
- }
113
+ if prev.draggable != next.draggable {
114
+ m.isDraggable = next.draggable ?? false
115
+ }
104
116
 
105
- if(tracksInfoWindowChanges) {
106
- m.tracksInfoWindowChanges = true
107
- onMainAsync { [weak m] in
108
- try? await Task.sleep(nanoseconds: 250_000_000)
109
- m?.tracksInfoWindowChanges = false
117
+ if prev.rotation != next.rotation {
118
+ m.rotation = next.rotation ?? 0
110
119
  }
111
- }
112
120
 
113
- if prev.opacity != next.opacity {
114
- let opacity = Float(next.opacity ?? 1)
115
- m.opacity = opacity
116
- m.iconView?.alpha = CGFloat(opacity)
117
- }
121
+ if prev.zIndex != next.zIndex {
122
+ m.zIndex = Int32(next.zIndex ?? 0)
123
+ }
118
124
 
119
- if prev.flat != next.flat {
120
- m.isFlat = next.flat ?? false
121
- }
125
+ if !prev.markerInfoWindowStyleEquals(next) {
126
+ m.tagData = MarkerTag(
127
+ id: next.id,
128
+ iconSvg: next.infoWindowIconSvg
129
+ )
130
+ }
122
131
 
123
- if prev.draggable != next.draggable {
124
- m.isDraggable = next.draggable ?? false
125
- }
132
+ if tracksViewChanges {
133
+ m.tracksViewChanges = tracksViewChanges
134
+ }
135
+ if tracksInfoWindowChanges {
136
+ m.tracksInfoWindowChanges = tracksInfoWindowChanges
137
+ }
126
138
 
127
- if prev.rotation != next.rotation {
128
- m.rotation = next.rotation ?? 0
129
- }
139
+ if tracksViewChanges || tracksInfoWindowChanges {
140
+ onMain { [weak m] in
141
+ guard let m = m else { return }
130
142
 
131
- if prev.zIndex != next.zIndex {
132
- m.zIndex = Int32(next.zIndex ?? 0)
133
- }
143
+ if tracksViewChanges {
144
+ m.tracksViewChanges = false
145
+ }
134
146
 
135
- if !prev.markerInfoWindowStyleEquals(next) {
136
- m.tagData = MarkerTag(
137
- id: next.id,
138
- iconSvg: next.infoWindowIconSvg
139
- )
147
+ if tracksInfoWindowChanges {
148
+ m.tracksInfoWindowChanges = false
149
+ }
150
+ }
151
+ }
140
152
  }
141
153
  }
142
154
 
143
- @MainActor
144
155
  func buildIconAsync(
145
156
  _ m: RNMarker,
146
157
  onReady: @escaping (UIImage?) -> Void
@@ -158,12 +169,15 @@ final class MapMarkerBuilder {
158
169
  return
159
170
  }
160
171
 
172
+ let scale = UIScreen.main.scale
173
+
161
174
  let task = Task(priority: .userInitiated) { [weak self] in
162
175
  guard let self else { return }
163
- defer { self.tasks.removeValue(forKey: m.id) }
176
+ defer {
177
+ Task { @MainActor in self.tasks.removeValue(forKey: m.id) }
178
+ }
164
179
 
165
- let scale = UIScreen.main.scale
166
- let img = await self.renderUIImage(m, scale)
180
+ let img = self.renderUIImage(m, scale)
167
181
  guard let img, !Task.isCancelled else { return }
168
182
 
169
183
  self.iconCache.setObject(img, forKey: key)
@@ -212,18 +226,11 @@ final class MapMarkerBuilder {
212
226
 
213
227
  svgImg.size = size
214
228
 
215
- guard let base = svgImg.uiImage else {
229
+ guard let finalImage = SVGKExporterUIImage.export(asUIImage: svgImg) else {
230
+ svgImg.clear()
216
231
  return nil
217
232
  }
218
-
219
- let fmt = UIGraphicsImageRendererFormat.default()
220
- fmt.opaque = false
221
- fmt.scale = UIScreen.main.scale
222
- let renderer = UIGraphicsImageRenderer(size: size, format: fmt)
223
-
224
- let finalImage = renderer.image { _ in
225
- base.draw(in: CGRect(origin: .zero, size: size))
226
- }
233
+ svgImg.clear()
227
234
 
228
235
  let imageView = UIImageView(image: finalImage)
229
236
  imageView.frame = CGRect(origin: .zero, size: size)
@@ -233,10 +240,10 @@ final class MapMarkerBuilder {
233
240
  return imageView
234
241
  }
235
242
 
236
- @MainActor
237
- private func renderUIImage(_ m: RNMarker, _ scale: CGFloat) async -> UIImage? {
238
- guard let iconSvg = m.iconSvg,
239
- let data = iconSvg.svgString.data(using: .utf8)
243
+ private func renderUIImage(_ m: RNMarker, _ scale: CGFloat) -> UIImage? {
244
+ guard
245
+ let iconSvg = m.iconSvg,
246
+ let data = iconSvg.svgString.data(using: .utf8)
240
247
  else { return nil }
241
248
 
242
249
  let size = CGSize(
@@ -244,28 +251,21 @@ final class MapMarkerBuilder {
244
251
  height: max(1, CGFloat(iconSvg.height))
245
252
  )
246
253
 
247
- return await Task.detached(priority: .userInitiated) {
248
- autoreleasepool {
249
- guard let svgImg = SVGKImage(data: data) else { return nil }
250
- svgImg.size = size
254
+ return autoreleasepool { () -> UIImage? in
255
+ guard !Task.isCancelled else { return nil }
256
+ guard let svgImg = SVGKImage(data: data) else { return nil }
251
257
 
252
- guard !Task.isCancelled else { return nil }
253
- guard let base = svgImg.uiImage else { return nil }
258
+ svgImg.size = size
254
259
 
255
- if let cg = base.cgImage {
256
- return UIImage(cgImage: cg, scale: scale, orientation: .up)
257
- }
258
- guard !Task.isCancelled else { return nil }
259
- let fmt = UIGraphicsImageRendererFormat.default()
260
- fmt.opaque = false
261
- fmt.scale = scale
262
- guard !Task.isCancelled else { return nil }
263
- let renderer = UIGraphicsImageRenderer(size: size, format: fmt)
264
- return renderer.image { _ in
265
- base.draw(in: CGRect(origin: .zero, size: size))
266
- }
260
+ guard !Task.isCancelled else {
261
+ svgImg.clear()
262
+ return nil
267
263
  }
268
- }.value
264
+
265
+ let uiImage = SVGKExporterUIImage.export(asUIImage: svgImg)
266
+ svgImg.clear()
267
+ return uiImage
268
+ }
269
269
  }
270
270
 
271
271
  }
@@ -131,26 +131,26 @@ final class RNGoogleMapsPlusView: HybridRNGoogleMapsPlusViewSpec {
131
131
  )
132
132
 
133
133
  let removed = Set(prevById.keys).subtracting(nextById.keys)
134
- withCATransaction(disableActions: true) {
135
134
 
136
- removed.forEach {
137
- self.impl.removeMarker(id: $0)
138
- self.markerBuilder.cancelIconTask($0)
139
- }
135
+ removed.forEach {
136
+ self.impl.removeMarker(id: $0)
137
+ self.markerBuilder.cancelIconTask($0)
138
+ }
140
139
 
141
- for (id, next) in nextById {
142
- if let prev = prevById[id] {
143
- if !prev.markerEquals(next) {
144
- self.impl.updateMarker(id: id) { m in
145
- self.markerBuilder.update(prev, next, m)
146
- }
147
- }
148
- } else {
149
- self.markerBuilder.buildIconAsync(next) { icon in
150
- let marker = self.markerBuilder.build(next, icon: icon)
151
- self.impl.addMarker(id: id, marker: marker)
140
+ for (id, next) in nextById {
141
+ if let prev = prevById[id] {
142
+ if !prev.markerEquals(next) {
143
+ self.impl.updateMarker(id: id) { [weak self] m in
144
+ guard let self else { return }
145
+ self.markerBuilder.update(prev, next, m)
152
146
  }
153
147
  }
148
+ } else {
149
+ self.markerBuilder.buildIconAsync(next) { [weak self] icon in
150
+ guard let self else { return }
151
+ let marker = self.markerBuilder.build(next, icon: icon)
152
+ self.impl.addMarker(id: id, marker: marker)
153
+ }
154
154
  }
155
155
  }
156
156
  }
@@ -174,7 +174,8 @@ final class RNGoogleMapsPlusView: HybridRNGoogleMapsPlusViewSpec {
174
174
  for (id, next) in nextById {
175
175
  if let prev = prevById[id] {
176
176
  if !prev.polylineEquals(next) {
177
- impl.updatePolyline(id: id) { pl in
177
+ impl.updatePolyline(id: id) { [weak self] pl in
178
+ guard let self else { return }
178
179
  self.polylineBuilder.update(prev, next, pl)
179
180
  }
180
181
  }
@@ -206,7 +207,8 @@ final class RNGoogleMapsPlusView: HybridRNGoogleMapsPlusViewSpec {
206
207
  for (id, next) in nextById {
207
208
  if let prev = prevById[id] {
208
209
  if !prev.polygonEquals(next) {
209
- impl.updatePolygon(id: id) { pg in
210
+ impl.updatePolygon(id: id) { [weak self] pg in
211
+ guard let self else { return }
210
212
  self.polygonBuilder.update(prev, next, pg)
211
213
  }
212
214
  }
@@ -235,7 +237,8 @@ final class RNGoogleMapsPlusView: HybridRNGoogleMapsPlusViewSpec {
235
237
  for (id, next) in nextById {
236
238
  if let prev = prevById[id] {
237
239
  if !prev.circleEquals(next) {
238
- impl.updateCircle(id: id) { circle in
240
+ impl.updateCircle(id: id) { [weak self] circle in
241
+ guard let self else { return }
239
242
  self.circleBuilder.update(prev, next, circle)
240
243
  }
241
244
  }
@@ -422,12 +425,12 @@ final class RNGoogleMapsPlusView: HybridRNGoogleMapsPlusViewSpec {
422
425
 
423
426
  @MainActor
424
427
  func showMarkerInfoWindow(id: String) {
425
- impl.showMarkerInfoWindow(id: id);
428
+ impl.showMarkerInfoWindow(id: id)
426
429
  }
427
430
 
428
431
  @MainActor
429
432
  func hideMarkerInfoWindow(id: String) {
430
- impl.hideMarkerInfoWindow(id: id);
433
+ impl.hideMarkerInfoWindow(id: id)
431
434
  }
432
435
 
433
436
  @MainActor
@@ -0,0 +1,22 @@
1
+ import SVGKit
2
+
3
+ extension SVGKImage {
4
+ @inline(__always)
5
+ func clear() {
6
+ caLayerTree?.sublayers?.forEach { $0.removeFromSuperlayer() }
7
+ if let layer = caLayerTree {
8
+ layer.sublayers?.forEach { $0.removeFromSuperlayer() }
9
+ layer.removeFromSuperlayer()
10
+ }
11
+
12
+ if let dom = domDocument {
13
+ dom.childNodes = nil
14
+ }
15
+
16
+ if let root = domTree {
17
+ root.childNodes = nil
18
+ }
19
+
20
+ caLayerTree.sublayers?.removeAll()
21
+ }
22
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-google-maps-plus",
3
- "version": "1.7.0-dev.15",
3
+ "version": "1.7.0-dev.17",
4
4
  "description": "React Native wrapper for Android & iOS Google Maps SDK",
5
5
  "main": "./lib/module/index.js",
6
6
  "module": "./lib/module/index.js",