@lugg/maps 1.0.0-beta.2 → 1.0.0-beta.20
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.
- package/README.md +3 -0
- package/android/src/main/java/com/luggmaps/LuggCalloutView.kt +9 -2
- package/android/src/main/java/com/luggmaps/LuggCalloutViewManager.kt +4 -3
- package/android/src/main/java/com/luggmaps/LuggCircleView.kt +85 -0
- package/android/src/main/java/com/luggmaps/LuggCircleViewManager.kt +79 -0
- package/android/src/main/java/com/luggmaps/LuggGroundOverlayView.kt +81 -0
- package/android/src/main/java/com/luggmaps/LuggGroundOverlayViewManager.kt +82 -0
- package/android/src/main/java/com/luggmaps/LuggMapView.kt +90 -0
- package/android/src/main/java/com/luggmaps/LuggMapViewManager.kt +45 -0
- package/android/src/main/java/com/luggmaps/LuggMapWrapperView.kt +27 -2
- package/android/src/main/java/com/luggmaps/LuggMarkerView.kt +30 -2
- package/android/src/main/java/com/luggmaps/LuggMarkerViewManager.kt +13 -0
- package/android/src/main/java/com/luggmaps/LuggPackage.kt +4 -1
- package/android/src/main/java/com/luggmaps/LuggPolylineView.kt +3 -23
- package/android/src/main/java/com/luggmaps/LuggTileOverlayView.kt +92 -0
- package/android/src/main/java/com/luggmaps/LuggTileOverlayViewManager.kt +80 -0
- package/android/src/main/java/com/luggmaps/core/GoogleMapProvider.kt +676 -36
- package/android/src/main/java/com/luggmaps/core/MapProviderDelegate.kt +15 -0
- package/android/src/main/java/com/luggmaps/core/PolylineAnimator.kt +65 -11
- package/android/src/main/java/com/luggmaps/events/CirclePressEvent.kt +12 -0
- package/android/src/main/java/com/luggmaps/events/GroundOverlayPressEvent.kt +12 -0
- package/android/src/main/java/com/luggmaps/events/TileOverlayPressEvent.kt +12 -0
- package/android/src/main/java/com/luggmaps/extensions/ViewExtensions.kt +11 -0
- package/ios/LuggCalloutView.h +1 -1
- package/ios/LuggCalloutView.mm +21 -11
- package/ios/LuggCircleView.h +31 -0
- package/ios/LuggCircleView.mm +133 -0
- package/ios/LuggGroundOverlayView.h +30 -0
- package/ios/LuggGroundOverlayView.mm +125 -0
- package/ios/LuggMapView.mm +254 -4
- package/ios/LuggMapWrapperView.h +5 -0
- package/ios/LuggMapWrapperView.mm +18 -0
- package/ios/LuggMarkerView.h +3 -0
- package/ios/LuggMarkerView.mm +25 -0
- package/ios/LuggTileOverlayView.h +31 -0
- package/ios/LuggTileOverlayView.mm +130 -0
- package/ios/core/AppleMapProvider.h +8 -0
- package/ios/core/AppleMapProvider.mm +663 -29
- package/ios/core/AppleStaticMapProvider.h +14 -0
- package/ios/core/AppleStaticMapProvider.mm +159 -0
- package/ios/core/GMSPolylineAnimator.m +46 -18
- package/ios/core/GoogleMapProvider.h +10 -0
- package/ios/core/GoogleMapProvider.mm +430 -51
- package/ios/core/GoogleStaticMapProvider.h +21 -0
- package/ios/core/GoogleStaticMapProvider.mm +213 -0
- package/ios/core/MKPolylineAnimator.m +67 -43
- package/ios/core/MapProviderDelegate.h +27 -1
- package/ios/core/StaticMapProviderBase.h +75 -0
- package/ios/core/StaticMapProviderBase.mm +845 -0
- package/ios/events/CameraIdleEvent.h +4 -2
- package/ios/events/CameraMoveEvent.h +4 -2
- package/ios/events/CirclePressEvent.h +22 -0
- package/ios/events/GroundOverlayPressEvent.h +22 -0
- package/ios/events/LongPressEvent.h +4 -2
- package/ios/events/MarkerDragEvent.h +12 -6
- package/ios/events/MarkerPressEvent.h +4 -2
- package/ios/events/PolygonPressEvent.h +4 -2
- package/ios/events/PressEvent.h +4 -2
- package/ios/events/ReadyEvent.h +4 -2
- package/ios/events/TileOverlayPressEvent.h +22 -0
- package/ios/extensions/MKMapView+Zoom.h +20 -0
- package/ios/extensions/MKMapView+Zoom.m +28 -18
- package/ios/extensions/UIView+Snapshot.h +16 -0
- package/ios/extensions/UIView+Snapshot.m +27 -0
- package/lib/module/MapProvider.web.js +4 -1
- package/lib/module/MapProvider.web.js.map +1 -1
- package/lib/module/MapView.js +19 -1
- package/lib/module/MapView.js.map +1 -1
- package/lib/module/MapView.web.js +30 -22
- package/lib/module/MapView.web.js.map +1 -1
- package/lib/module/components/Circle.js +46 -0
- package/lib/module/components/Circle.js.map +1 -0
- package/lib/module/components/Circle.types.js +4 -0
- package/lib/module/components/Circle.types.js.map +1 -0
- package/lib/module/components/Circle.web.js +79 -0
- package/lib/module/components/Circle.web.js.map +1 -0
- package/lib/module/components/GeoJson.js +3 -3
- package/lib/module/components/GeoJson.js.map +1 -1
- package/lib/module/components/GroundOverlay.js +45 -0
- package/lib/module/components/GroundOverlay.js.map +1 -0
- package/lib/module/components/GroundOverlay.types.js +4 -0
- package/lib/module/components/GroundOverlay.types.js.map +1 -0
- package/lib/module/components/GroundOverlay.web.js +77 -0
- package/lib/module/components/GroundOverlay.web.js.map +1 -0
- package/lib/module/components/Marker.js +22 -4
- package/lib/module/components/Marker.js.map +1 -1
- package/lib/module/components/Marker.web.js +23 -10
- package/lib/module/components/Marker.web.js.map +1 -1
- package/lib/module/components/Polygon.web.js +3 -3
- package/lib/module/components/Polygon.web.js.map +1 -1
- package/lib/module/components/Polyline.web.js +6 -12
- package/lib/module/components/Polyline.web.js.map +1 -1
- package/lib/module/components/TileOverlay.js +44 -0
- package/lib/module/components/TileOverlay.js.map +1 -0
- package/lib/module/components/TileOverlay.types.js +4 -0
- package/lib/module/components/TileOverlay.types.js.map +1 -0
- package/lib/module/components/TileOverlay.web.js +69 -0
- package/lib/module/components/TileOverlay.web.js.map +1 -0
- package/lib/module/components/index.js +3 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/components/index.web.js +3 -0
- package/lib/module/components/index.web.js.map +1 -1
- package/lib/module/fabric/LuggCalloutViewNativeComponent.ts +1 -1
- package/lib/module/fabric/LuggCircleViewNativeComponent.ts +25 -0
- package/lib/module/fabric/LuggGroundOverlayViewNativeComponent.ts +29 -0
- package/lib/module/fabric/LuggMapViewNativeComponent.ts +16 -5
- package/lib/module/fabric/LuggMarkerViewNativeComponent.ts +14 -2
- package/lib/module/fabric/LuggTileOverlayViewNativeComponent.ts +30 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +3 -0
- package/lib/module/index.web.js.map +1 -1
- package/lib/typescript/src/MapProvider.web.d.ts +3 -2
- package/lib/typescript/src/MapProvider.web.d.ts.map +1 -1
- package/lib/typescript/src/MapView.d.ts +1 -1
- package/lib/typescript/src/MapView.d.ts.map +1 -1
- package/lib/typescript/src/MapView.types.d.ts +60 -1
- package/lib/typescript/src/MapView.types.d.ts.map +1 -1
- package/lib/typescript/src/MapView.web.d.ts +1 -1
- package/lib/typescript/src/MapView.web.d.ts.map +1 -1
- package/lib/typescript/src/components/Circle.d.ts +10 -0
- package/lib/typescript/src/components/Circle.d.ts.map +1 -0
- package/lib/typescript/src/components/Circle.types.d.ts +33 -0
- package/lib/typescript/src/components/Circle.types.d.ts.map +1 -0
- package/lib/typescript/src/components/Circle.web.d.ts +3 -0
- package/lib/typescript/src/components/Circle.web.d.ts.map +1 -0
- package/lib/typescript/src/components/GeoJson.d.ts +2 -1
- package/lib/typescript/src/components/GeoJson.d.ts.map +1 -1
- package/lib/typescript/src/components/GroundOverlay.d.ts +10 -0
- package/lib/typescript/src/components/GroundOverlay.d.ts.map +1 -0
- package/lib/typescript/src/components/GroundOverlay.types.d.ts +35 -0
- package/lib/typescript/src/components/GroundOverlay.types.d.ts.map +1 -0
- package/lib/typescript/src/components/GroundOverlay.web.d.ts +3 -0
- package/lib/typescript/src/components/GroundOverlay.web.d.ts.map +1 -0
- package/lib/typescript/src/components/Marker.d.ts +6 -3
- package/lib/typescript/src/components/Marker.d.ts.map +1 -1
- package/lib/typescript/src/components/Marker.types.d.ts +18 -6
- package/lib/typescript/src/components/Marker.types.d.ts.map +1 -1
- package/lib/typescript/src/components/Marker.web.d.ts +3 -2
- package/lib/typescript/src/components/Marker.web.d.ts.map +1 -1
- package/lib/typescript/src/components/Polygon.web.d.ts +1 -1
- package/lib/typescript/src/components/Polygon.web.d.ts.map +1 -1
- package/lib/typescript/src/components/Polyline.web.d.ts +1 -1
- package/lib/typescript/src/components/Polyline.web.d.ts.map +1 -1
- package/lib/typescript/src/components/TileOverlay.d.ts +10 -0
- package/lib/typescript/src/components/TileOverlay.d.ts.map +1 -0
- package/lib/typescript/src/components/TileOverlay.types.d.ts +36 -0
- package/lib/typescript/src/components/TileOverlay.types.d.ts.map +1 -0
- package/lib/typescript/src/components/TileOverlay.web.d.ts +3 -0
- package/lib/typescript/src/components/TileOverlay.web.d.ts.map +1 -0
- package/lib/typescript/src/components/index.d.ts +7 -1
- package/lib/typescript/src/components/index.d.ts.map +1 -1
- package/lib/typescript/src/components/index.web.d.ts +6 -0
- package/lib/typescript/src/components/index.web.d.ts.map +1 -1
- package/lib/typescript/src/fabric/LuggCalloutViewNativeComponent.d.ts +1 -1
- package/lib/typescript/src/fabric/LuggCircleViewNativeComponent.d.ts +18 -0
- package/lib/typescript/src/fabric/LuggCircleViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/LuggGroundOverlayViewNativeComponent.d.ts +21 -0
- package/lib/typescript/src/fabric/LuggGroundOverlayViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts +13 -5
- package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts +8 -1
- package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/fabric/LuggTileOverlayViewNativeComponent.d.ts +21 -0
- package/lib/typescript/src/fabric/LuggTileOverlayViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +9 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/index.web.d.ts +7 -1
- package/lib/typescript/src/index.web.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +0 -4
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +17 -11
- package/src/MapProvider.web.tsx +5 -3
- package/src/MapView.tsx +19 -1
- package/src/MapView.types.ts +142 -1
- package/src/MapView.web.tsx +379 -340
- package/src/components/Circle.tsx +52 -0
- package/src/components/Circle.types.ts +33 -0
- package/src/components/Circle.web.tsx +95 -0
- package/src/components/GeoJson.tsx +3 -3
- package/src/components/GroundOverlay.tsx +47 -0
- package/src/components/GroundOverlay.types.ts +36 -0
- package/src/components/GroundOverlay.web.tsx +81 -0
- package/src/components/Marker.tsx +32 -6
- package/src/components/Marker.types.ts +19 -6
- package/src/components/Marker.web.tsx +196 -150
- package/src/components/Polygon.web.tsx +93 -89
- package/src/components/Polyline.web.tsx +235 -235
- package/src/components/TileOverlay.tsx +44 -0
- package/src/components/TileOverlay.types.ts +37 -0
- package/src/components/TileOverlay.web.tsx +97 -0
- package/src/components/index.ts +10 -0
- package/src/components/index.web.ts +9 -0
- package/src/fabric/LuggCalloutViewNativeComponent.ts +1 -1
- package/src/fabric/LuggCircleViewNativeComponent.ts +25 -0
- package/src/fabric/LuggGroundOverlayViewNativeComponent.ts +29 -0
- package/src/fabric/LuggMapViewNativeComponent.ts +16 -5
- package/src/fabric/LuggMarkerViewNativeComponent.ts +14 -2
- package/src/fabric/LuggTileOverlayViewNativeComponent.ts +30 -0
- package/src/index.ts +12 -1
- package/src/index.web.ts +15 -0
- package/src/types.ts +0 -5
- package/plugin/build/withMapsAndroid.d.ts +0 -5
- package/plugin/build/withMapsAndroid.js +0 -15
- package/plugin/build/withMapsIOS.d.ts +0 -5
- package/plugin/build/withMapsIOS.js +0 -27
|
@@ -1,26 +1,41 @@
|
|
|
1
1
|
package com.luggmaps.core
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.ComponentCallbacks2
|
|
4
5
|
import android.content.Context
|
|
6
|
+
import android.content.res.Configuration
|
|
5
7
|
import android.view.View
|
|
6
8
|
import android.widget.ImageView
|
|
7
9
|
import androidx.core.graphics.createBitmap
|
|
10
|
+
import androidx.core.view.ViewCompat
|
|
11
|
+
import androidx.core.view.WindowInsetsCompat
|
|
8
12
|
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
9
13
|
import com.google.android.gms.maps.CameraUpdateFactory
|
|
10
14
|
import com.google.android.gms.maps.GoogleMap
|
|
11
15
|
import com.google.android.gms.maps.GoogleMapOptions
|
|
12
16
|
import com.google.android.gms.maps.MapView
|
|
13
17
|
import com.google.android.gms.maps.OnMapReadyCallback
|
|
14
|
-
import com.google.android.gms.maps.model.AdvancedMarker
|
|
15
|
-
import com.google.android.gms.maps.model.AdvancedMarkerOptions
|
|
16
18
|
import com.google.android.gms.maps.model.BitmapDescriptorFactory
|
|
19
|
+
import com.google.android.gms.maps.model.CameraPosition
|
|
20
|
+
import com.google.android.gms.maps.model.Circle
|
|
21
|
+
import com.google.android.gms.maps.model.CircleOptions
|
|
22
|
+
import com.google.android.gms.maps.model.GroundOverlay
|
|
23
|
+
import com.google.android.gms.maps.model.GroundOverlayOptions
|
|
17
24
|
import com.google.android.gms.maps.model.LatLng
|
|
25
|
+
import com.google.android.gms.maps.model.LatLngBounds
|
|
18
26
|
import com.google.android.gms.maps.model.MapColorScheme
|
|
19
27
|
import com.google.android.gms.maps.model.Marker
|
|
28
|
+
import com.google.android.gms.maps.model.MarkerOptions
|
|
20
29
|
import com.google.android.gms.maps.model.Polygon
|
|
21
30
|
import com.google.android.gms.maps.model.PolygonOptions
|
|
22
31
|
import com.google.android.gms.maps.model.PolylineOptions
|
|
32
|
+
import com.google.android.gms.maps.model.TileOverlayOptions
|
|
33
|
+
import com.google.android.gms.maps.model.UrlTileProvider
|
|
23
34
|
import com.luggmaps.LuggCalloutView
|
|
35
|
+
import com.luggmaps.LuggCircleView
|
|
36
|
+
import com.luggmaps.LuggCircleViewDelegate
|
|
37
|
+
import com.luggmaps.LuggGroundOverlayView
|
|
38
|
+
import com.luggmaps.LuggGroundOverlayViewDelegate
|
|
24
39
|
import com.luggmaps.LuggMapWrapperView
|
|
25
40
|
import com.luggmaps.LuggMarkerView
|
|
26
41
|
import com.luggmaps.LuggMarkerViewDelegate
|
|
@@ -28,6 +43,16 @@ import com.luggmaps.LuggPolygonView
|
|
|
28
43
|
import com.luggmaps.LuggPolygonViewDelegate
|
|
29
44
|
import com.luggmaps.LuggPolylineView
|
|
30
45
|
import com.luggmaps.LuggPolylineViewDelegate
|
|
46
|
+
import com.luggmaps.LuggTileOverlayView
|
|
47
|
+
import com.luggmaps.LuggTileOverlayViewDelegate
|
|
48
|
+
import com.luggmaps.extensions.findViewByTag
|
|
49
|
+
import java.net.URL
|
|
50
|
+
import kotlin.math.atan
|
|
51
|
+
import kotlin.math.ln
|
|
52
|
+
import kotlin.math.log2
|
|
53
|
+
import kotlin.math.pow
|
|
54
|
+
import kotlin.math.sin
|
|
55
|
+
import kotlin.math.sinh
|
|
31
56
|
|
|
32
57
|
class GoogleMapProvider(private val context: Context) :
|
|
33
58
|
MapProvider,
|
|
@@ -35,22 +60,33 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
35
60
|
LuggMarkerViewDelegate,
|
|
36
61
|
LuggPolylineViewDelegate,
|
|
37
62
|
LuggPolygonViewDelegate,
|
|
63
|
+
LuggCircleViewDelegate,
|
|
64
|
+
LuggGroundOverlayViewDelegate,
|
|
65
|
+
LuggTileOverlayViewDelegate,
|
|
38
66
|
GoogleMap.OnCameraMoveStartedListener,
|
|
39
67
|
GoogleMap.OnCameraMoveListener,
|
|
40
68
|
GoogleMap.OnCameraIdleListener,
|
|
41
69
|
GoogleMap.OnMapClickListener,
|
|
42
70
|
GoogleMap.OnMapLongClickListener,
|
|
43
71
|
GoogleMap.OnPolygonClickListener,
|
|
72
|
+
GoogleMap.OnCircleClickListener,
|
|
73
|
+
GoogleMap.OnGroundOverlayClickListener,
|
|
44
74
|
GoogleMap.OnMarkerClickListener,
|
|
45
75
|
GoogleMap.OnMarkerDragListener,
|
|
46
|
-
GoogleMap.InfoWindowAdapter
|
|
76
|
+
GoogleMap.InfoWindowAdapter,
|
|
77
|
+
ComponentCallbacks2 {
|
|
47
78
|
|
|
48
79
|
override var delegate: MapProviderDelegate? = null
|
|
49
80
|
override val isMapReady: Boolean get() = _isMapReady
|
|
50
81
|
|
|
51
82
|
var mapId: String = DEMO_MAP_ID
|
|
52
83
|
|
|
84
|
+
// Renders a non-interactive static map — lite mode when the view fits
|
|
85
|
+
// the lite bitmap cap, a gesture-less full map otherwise. Creation-time only.
|
|
86
|
+
var staticMode: Boolean = false
|
|
87
|
+
|
|
53
88
|
private var wrapperView: LuggMapWrapperView? = null
|
|
89
|
+
private var currentNightMode: Int = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
|
54
90
|
private var mapView: MapView? = null
|
|
55
91
|
private var googleMap: GoogleMap? = null
|
|
56
92
|
private var _isMapReady = false
|
|
@@ -58,10 +94,16 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
58
94
|
private val pendingMarkerViews = mutableSetOf<LuggMarkerView>()
|
|
59
95
|
private val pendingPolylineViews = mutableSetOf<LuggPolylineView>()
|
|
60
96
|
private val pendingPolygonViews = mutableSetOf<LuggPolygonView>()
|
|
97
|
+
private val pendingCircleViews = mutableSetOf<LuggCircleView>()
|
|
98
|
+
private val pendingGroundOverlayViews = mutableSetOf<LuggGroundOverlayView>()
|
|
99
|
+
private val pendingTileOverlayViews = mutableSetOf<LuggTileOverlayView>()
|
|
61
100
|
private val polylineAnimators = mutableMapOf<LuggPolylineView, PolylineAnimator>()
|
|
62
101
|
private val polygonToViewMap = mutableMapOf<Polygon, LuggPolygonView>()
|
|
102
|
+
private val circleToViewMap = mutableMapOf<Circle, LuggCircleView>()
|
|
103
|
+
private val groundOverlayToViewMap = mutableMapOf<GroundOverlay, LuggGroundOverlayView>()
|
|
63
104
|
private val markerToViewMap = mutableMapOf<Marker, LuggMarkerView>()
|
|
64
105
|
private val liveMarkerViews = mutableSetOf<LuggMarkerView>()
|
|
106
|
+
private var staticProjectionReady = false
|
|
65
107
|
private var activeNonBubbledMarker: Marker? = null
|
|
66
108
|
private var tapLocation: LatLng? = null
|
|
67
109
|
|
|
@@ -75,6 +117,7 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
75
117
|
private var scrollEnabled: Boolean = true
|
|
76
118
|
private var rotateEnabled: Boolean = true
|
|
77
119
|
private var pitchEnabled: Boolean = true
|
|
120
|
+
private var compassEnabled: Boolean = true
|
|
78
121
|
private var userLocationEnabled: Boolean = false
|
|
79
122
|
private var userLocationButtonEnabled: Boolean = false
|
|
80
123
|
|
|
@@ -88,6 +131,10 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
88
131
|
// Edge Insets
|
|
89
132
|
private var edgeInsets: EdgeInsets = EdgeInsets()
|
|
90
133
|
|
|
134
|
+
// Inset adjustment
|
|
135
|
+
private var insetAdjustment: String = "never"
|
|
136
|
+
private var systemInsets: EdgeInsets = EdgeInsets()
|
|
137
|
+
|
|
91
138
|
// region MapProvider
|
|
92
139
|
|
|
93
140
|
override fun initializeMap(wrapperView: View, latitude: Double, longitude: Double, zoom: Float) {
|
|
@@ -98,18 +145,45 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
98
145
|
initialZoom = zoom
|
|
99
146
|
|
|
100
147
|
val wrapper = wrapperView as LuggMapWrapperView
|
|
148
|
+
wrapper.relayoutChildOnRequest = staticMode
|
|
101
149
|
this.wrapperView = wrapper
|
|
102
150
|
|
|
103
|
-
|
|
151
|
+
context.applicationContext.registerComponentCallbacks(this)
|
|
152
|
+
|
|
153
|
+
// Static mode needs the view size to pick lite vs full map, so wait
|
|
154
|
+
// for the first layout if it hasn't happened yet
|
|
155
|
+
if (staticMode && (wrapper.width == 0 || wrapper.height == 0)) {
|
|
156
|
+
wrapper.onLayoutReady = { createMapView() }
|
|
157
|
+
} else {
|
|
158
|
+
createMapView()
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private fun createMapView() {
|
|
163
|
+
if (mapView != null) return
|
|
164
|
+
val wrapper = wrapperView ?: return
|
|
165
|
+
|
|
166
|
+
// Lite mode renders the map as a single bitmap capped at ~2048px per
|
|
167
|
+
// dimension, centered in the view — bigger views get letterboxed. Fall
|
|
168
|
+
// back to a full map (gestures disabled) when the view exceeds the cap
|
|
169
|
+
val useLite = staticMode && maxOf(wrapper.width, wrapper.height) <= LITE_MODE_MAX_SIZE
|
|
170
|
+
val options = GoogleMapOptions().liteMode(useLite)
|
|
171
|
+
// Lite mode doesn't support map IDs (cloud-based styling); setting one
|
|
172
|
+
// makes the static map render blank
|
|
173
|
+
if (!useLite) options.mapId(mapId)
|
|
104
174
|
mapView = MapView(context, options).also { view ->
|
|
105
175
|
view.onCreate(null)
|
|
106
176
|
view.onResume()
|
|
107
177
|
view.getMapAsync(this)
|
|
108
178
|
wrapper.addView(view)
|
|
109
179
|
}
|
|
180
|
+
wrapper.onLayoutReady = null
|
|
110
181
|
}
|
|
111
182
|
|
|
112
183
|
override fun destroy() {
|
|
184
|
+
wrapperView?.onLayoutReady = null
|
|
185
|
+
detachWindowInsetsListener()
|
|
186
|
+
context.applicationContext.unregisterComponentCallbacks(this)
|
|
113
187
|
dismissNonBubbledCallout()
|
|
114
188
|
for (markerView in liveMarkerViews) {
|
|
115
189
|
markerView.onUpdate = null
|
|
@@ -118,9 +192,14 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
118
192
|
pendingMarkerViews.clear()
|
|
119
193
|
pendingPolylineViews.clear()
|
|
120
194
|
pendingPolygonViews.clear()
|
|
195
|
+
pendingCircleViews.clear()
|
|
196
|
+
pendingGroundOverlayViews.clear()
|
|
197
|
+
pendingTileOverlayViews.clear()
|
|
121
198
|
polylineAnimators.values.forEach { it.destroy() }
|
|
122
199
|
polylineAnimators.clear()
|
|
123
200
|
polygonToViewMap.clear()
|
|
201
|
+
circleToViewMap.clear()
|
|
202
|
+
groundOverlayToViewMap.clear()
|
|
124
203
|
markerToViewMap.clear()
|
|
125
204
|
wrapperView?.touchEventHandler = null
|
|
126
205
|
wrapperView = null
|
|
@@ -130,6 +209,8 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
130
209
|
googleMap?.setOnMapClickListener(null)
|
|
131
210
|
googleMap?.setOnMapLongClickListener(null)
|
|
132
211
|
googleMap?.setOnPolygonClickListener(null)
|
|
212
|
+
googleMap?.setOnCircleClickListener(null)
|
|
213
|
+
googleMap?.setOnGroundOverlayClickListener(null)
|
|
133
214
|
googleMap?.setOnMarkerClickListener(null)
|
|
134
215
|
googleMap?.setOnMarkerDragListener(null)
|
|
135
216
|
googleMap?.setInfoWindowAdapter(null)
|
|
@@ -145,7 +226,18 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
145
226
|
googleMap = map
|
|
146
227
|
_isMapReady = true
|
|
147
228
|
|
|
148
|
-
|
|
229
|
+
if (staticMode) {
|
|
230
|
+
// Tapping the map otherwise shows an "open in Google Maps" toolbar
|
|
231
|
+
map.uiSettings.isMapToolbarEnabled = false
|
|
232
|
+
// The projection is only valid once the map has rendered, and no
|
|
233
|
+
// camera events fire afterwards to correct live marker positions
|
|
234
|
+
map.setOnMapLoadedCallback {
|
|
235
|
+
staticProjectionReady = true
|
|
236
|
+
positionLiveMarkers()
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
val position = if (staticMode) staticCameraTarget() else LatLng(initialLatitude, initialLongitude)
|
|
149
241
|
map.moveCamera(CameraUpdateFactory.newLatLngZoom(position, initialZoom))
|
|
150
242
|
|
|
151
243
|
map.setOnCameraMoveStartedListener(this)
|
|
@@ -154,6 +246,8 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
154
246
|
map.setOnMapClickListener(this)
|
|
155
247
|
map.setOnMapLongClickListener(this)
|
|
156
248
|
map.setOnPolygonClickListener(this)
|
|
249
|
+
map.setOnCircleClickListener(this)
|
|
250
|
+
map.setOnGroundOverlayClickListener(this)
|
|
157
251
|
map.setOnMarkerClickListener(this)
|
|
158
252
|
map.setOnMarkerDragListener(this)
|
|
159
253
|
map.setInfoWindowAdapter(this)
|
|
@@ -167,11 +261,15 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
167
261
|
applyUiSettings()
|
|
168
262
|
applyZoomLimits()
|
|
169
263
|
applyEdgeInsets()
|
|
264
|
+
applyInsetAdjustment()
|
|
170
265
|
applyTheme()
|
|
171
266
|
applyUserLocation()
|
|
172
267
|
processPendingMarkers()
|
|
173
268
|
processPendingPolylines()
|
|
174
269
|
processPendingPolygons()
|
|
270
|
+
processPendingCircles()
|
|
271
|
+
processPendingGroundOverlays()
|
|
272
|
+
processPendingTileOverlays()
|
|
175
273
|
|
|
176
274
|
delegate?.mapProviderDidReady()
|
|
177
275
|
}
|
|
@@ -227,6 +325,22 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
227
325
|
}
|
|
228
326
|
}
|
|
229
327
|
|
|
328
|
+
override fun onCircleClick(circle: Circle) {
|
|
329
|
+
val circleView = circleToViewMap[circle]
|
|
330
|
+
if (circleView?.tappable == true) {
|
|
331
|
+
circleView.emitPressEvent()
|
|
332
|
+
} else {
|
|
333
|
+
onMapClick(tapLocation ?: return)
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
override fun onGroundOverlayClick(groundOverlay: GroundOverlay) {
|
|
338
|
+
val view = groundOverlayToViewMap[groundOverlay]
|
|
339
|
+
if (view?.tappable == true) {
|
|
340
|
+
view.emitPressEvent()
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
230
344
|
override fun onMarkerClick(marker: Marker): Boolean {
|
|
231
345
|
dismissNonBubbledCallout()
|
|
232
346
|
|
|
@@ -236,10 +350,17 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
236
350
|
|
|
237
351
|
val calloutView = view.calloutView
|
|
238
352
|
if (calloutView != null && !calloutView.bubbled && calloutView.hasCustomContent) {
|
|
239
|
-
|
|
353
|
+
if (view.centerOnPress) {
|
|
354
|
+
googleMap?.animateCamera(CameraUpdateFactory.newLatLng(marker.position))
|
|
355
|
+
}
|
|
240
356
|
showNonBubbledCallout(marker, calloutView)
|
|
241
357
|
return true
|
|
242
358
|
}
|
|
359
|
+
|
|
360
|
+
if (!view.centerOnPress) {
|
|
361
|
+
marker.showInfoWindow()
|
|
362
|
+
return true
|
|
363
|
+
}
|
|
243
364
|
}
|
|
244
365
|
return false
|
|
245
366
|
}
|
|
@@ -353,8 +474,8 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
353
474
|
val map = googleMap ?: return
|
|
354
475
|
|
|
355
476
|
val point = map.projection.toScreenLocation(marker.position)
|
|
356
|
-
contentView.translationX = point.x - contentView.width
|
|
357
|
-
contentView.translationY = point.y - contentView.height
|
|
477
|
+
contentView.translationX = point.x - contentView.width / 2f + calloutView.offsetX
|
|
478
|
+
contentView.translationY = point.y - markerView.scaledContentHeight * markerView.anchorY - contentView.height + calloutView.offsetY
|
|
358
479
|
}
|
|
359
480
|
|
|
360
481
|
// endregion
|
|
@@ -363,24 +484,33 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
363
484
|
|
|
364
485
|
override fun setZoomEnabled(enabled: Boolean) {
|
|
365
486
|
zoomEnabled = enabled
|
|
487
|
+
if (staticMode) return
|
|
366
488
|
googleMap?.uiSettings?.isZoomGesturesEnabled = enabled
|
|
367
489
|
}
|
|
368
490
|
|
|
369
491
|
override fun setScrollEnabled(enabled: Boolean) {
|
|
370
492
|
scrollEnabled = enabled
|
|
493
|
+
if (staticMode) return
|
|
371
494
|
googleMap?.uiSettings?.isScrollGesturesEnabled = enabled
|
|
372
495
|
}
|
|
373
496
|
|
|
374
497
|
override fun setRotateEnabled(enabled: Boolean) {
|
|
375
498
|
rotateEnabled = enabled
|
|
499
|
+
if (staticMode) return
|
|
376
500
|
googleMap?.uiSettings?.isRotateGesturesEnabled = enabled
|
|
377
501
|
}
|
|
378
502
|
|
|
379
503
|
override fun setPitchEnabled(enabled: Boolean) {
|
|
380
504
|
pitchEnabled = enabled
|
|
505
|
+
if (staticMode) return
|
|
381
506
|
googleMap?.uiSettings?.isTiltGesturesEnabled = enabled
|
|
382
507
|
}
|
|
383
508
|
|
|
509
|
+
override fun setCompassEnabled(enabled: Boolean) {
|
|
510
|
+
compassEnabled = enabled
|
|
511
|
+
googleMap?.uiSettings?.isCompassEnabled = enabled
|
|
512
|
+
}
|
|
513
|
+
|
|
384
514
|
@SuppressLint("MissingPermission")
|
|
385
515
|
override fun setUserLocationEnabled(enabled: Boolean) {
|
|
386
516
|
userLocationEnabled = enabled
|
|
@@ -398,6 +528,15 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
398
528
|
googleMap?.uiSettings?.isMyLocationButtonEnabled = enabled
|
|
399
529
|
}
|
|
400
530
|
|
|
531
|
+
override fun setMapType(value: String) {
|
|
532
|
+
googleMap?.mapType = when (value) {
|
|
533
|
+
"satellite" -> GoogleMap.MAP_TYPE_SATELLITE
|
|
534
|
+
"terrain" -> GoogleMap.MAP_TYPE_TERRAIN
|
|
535
|
+
"hybrid" -> GoogleMap.MAP_TYPE_HYBRID
|
|
536
|
+
else -> GoogleMap.MAP_TYPE_NORMAL
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
401
540
|
override fun setTheme(value: String) {
|
|
402
541
|
theme = value
|
|
403
542
|
applyTheme()
|
|
@@ -418,6 +557,11 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
418
557
|
}
|
|
419
558
|
|
|
420
559
|
override fun setEdgeInsets(edgeInsets: EdgeInsets) {
|
|
560
|
+
if (staticMode) {
|
|
561
|
+
setStaticEdgeInsets(edgeInsets)
|
|
562
|
+
return
|
|
563
|
+
}
|
|
564
|
+
|
|
421
565
|
val oldInsets = this.edgeInsets
|
|
422
566
|
this.edgeInsets = edgeInsets
|
|
423
567
|
applyEdgeInsets()
|
|
@@ -431,13 +575,18 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
431
575
|
}
|
|
432
576
|
|
|
433
577
|
override fun setEdgeInsets(edgeInsets: EdgeInsets, duration: Int) {
|
|
578
|
+
if (staticMode) {
|
|
579
|
+
setStaticEdgeInsets(edgeInsets)
|
|
580
|
+
return
|
|
581
|
+
}
|
|
582
|
+
|
|
434
583
|
val map = googleMap
|
|
435
584
|
val oldInsets = this.edgeInsets
|
|
436
585
|
this.edgeInsets = edgeInsets
|
|
437
586
|
|
|
438
587
|
if (map != null && oldInsets != edgeInsets) {
|
|
439
588
|
val cameraUpdate = CameraUpdateFactory.newCameraPosition(map.cameraPosition)
|
|
440
|
-
applyEdgeInsets()
|
|
589
|
+
applyEdgeInsets(duration)
|
|
441
590
|
when {
|
|
442
591
|
duration < 0 -> map.animateCamera(cameraUpdate)
|
|
443
592
|
duration > 0 -> map.animateCamera(cameraUpdate, duration, null)
|
|
@@ -448,6 +597,17 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
448
597
|
}
|
|
449
598
|
}
|
|
450
599
|
|
|
600
|
+
override fun setInsetAdjustment(value: String) {
|
|
601
|
+
insetAdjustment = value
|
|
602
|
+
applyInsetAdjustment()
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
override fun setPoiEnabled(enabled: Boolean) {}
|
|
606
|
+
|
|
607
|
+
override fun setPoiFilterMode(mode: String) {}
|
|
608
|
+
|
|
609
|
+
override fun setPoiFilterCategories(categories: List<String>) {}
|
|
610
|
+
|
|
451
611
|
// endregion
|
|
452
612
|
|
|
453
613
|
// region MarkerViewDelegate
|
|
@@ -469,6 +629,30 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
469
629
|
syncMarkerView(markerView)
|
|
470
630
|
}
|
|
471
631
|
|
|
632
|
+
override fun showCalloutForMarkerView(markerView: LuggMarkerView) {
|
|
633
|
+
val marker = markerView.marker ?: return
|
|
634
|
+
val calloutView = markerView.calloutView
|
|
635
|
+
|
|
636
|
+
if (calloutView != null && calloutView.hasCustomContent) {
|
|
637
|
+
dismissNonBubbledCallout()
|
|
638
|
+
if (calloutView.bubbled) {
|
|
639
|
+
marker.showInfoWindow()
|
|
640
|
+
} else {
|
|
641
|
+
showNonBubbledCallout(marker, calloutView)
|
|
642
|
+
}
|
|
643
|
+
return
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (!markerView.title.isNullOrEmpty()) {
|
|
647
|
+
marker.showInfoWindow()
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
override fun hideCalloutForMarkerView(markerView: LuggMarkerView) {
|
|
652
|
+
dismissNonBubbledCallout()
|
|
653
|
+
markerView.marker?.hideInfoWindow()
|
|
654
|
+
}
|
|
655
|
+
|
|
472
656
|
// endregion
|
|
473
657
|
|
|
474
658
|
// region PolylineViewDelegate
|
|
@@ -477,6 +661,10 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
477
661
|
syncPolylineView(polylineView)
|
|
478
662
|
}
|
|
479
663
|
|
|
664
|
+
override fun polylineViewDidDrop(polylineView: LuggPolylineView) {
|
|
665
|
+
teardownPolyline(polylineView)
|
|
666
|
+
}
|
|
667
|
+
|
|
480
668
|
// endregion
|
|
481
669
|
|
|
482
670
|
// region PolygonViewDelegate
|
|
@@ -487,6 +675,30 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
487
675
|
|
|
488
676
|
// endregion
|
|
489
677
|
|
|
678
|
+
// region CircleViewDelegate
|
|
679
|
+
|
|
680
|
+
override fun circleViewDidUpdate(circleView: LuggCircleView) {
|
|
681
|
+
syncCircleView(circleView)
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// endregion
|
|
685
|
+
|
|
686
|
+
// region GroundOverlayViewDelegate
|
|
687
|
+
|
|
688
|
+
override fun groundOverlayViewDidUpdate(groundOverlayView: LuggGroundOverlayView) {
|
|
689
|
+
syncGroundOverlayView(groundOverlayView)
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// endregion
|
|
693
|
+
|
|
694
|
+
// region TileOverlayViewDelegate
|
|
695
|
+
|
|
696
|
+
override fun tileOverlayViewDidUpdate(tileOverlayView: LuggTileOverlayView) {
|
|
697
|
+
syncTileOverlayView(tileOverlayView)
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// endregion
|
|
701
|
+
|
|
490
702
|
// region Marker Management
|
|
491
703
|
|
|
492
704
|
override fun addMarkerView(markerView: LuggMarkerView) {
|
|
@@ -546,12 +758,12 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
546
758
|
val map = googleMap ?: return
|
|
547
759
|
|
|
548
760
|
val position = LatLng(markerView.latitude, markerView.longitude)
|
|
549
|
-
val options =
|
|
761
|
+
val options = MarkerOptions()
|
|
550
762
|
.position(position)
|
|
551
763
|
.title(markerView.title)
|
|
552
764
|
.snippet(markerView.description)
|
|
553
765
|
|
|
554
|
-
val marker = map.addMarker(options)
|
|
766
|
+
val marker = map.addMarker(options) ?: return
|
|
555
767
|
marker.setAnchor(markerView.anchorX, markerView.anchorY)
|
|
556
768
|
marker.zIndex = markerView.zIndex
|
|
557
769
|
marker.rotation = markerView.rotate
|
|
@@ -569,9 +781,8 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
569
781
|
}
|
|
570
782
|
}
|
|
571
783
|
|
|
572
|
-
//
|
|
573
|
-
//
|
|
574
|
-
// marker uses a transparent bitmap matching the content size so taps still trigger onMarkerClick.
|
|
784
|
+
// Live marker: content view is added to the wrapper and positioned via screen projection.
|
|
785
|
+
// The underlying marker uses a transparent bitmap matching the content size so taps still trigger onMarkerClick.
|
|
575
786
|
private fun showLiveMarker(markerView: LuggMarkerView) {
|
|
576
787
|
val wrapper = wrapperView ?: return
|
|
577
788
|
|
|
@@ -582,6 +793,10 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
582
793
|
|
|
583
794
|
val contentView = markerView.contentView
|
|
584
795
|
contentView.pointerEvents = com.facebook.react.uimanager.PointerEvents.NONE
|
|
796
|
+
// Until the lite map's projection is valid, hide the marker instead of
|
|
797
|
+
// flashing it at a wrong position; onMapLoaded positions and shows it
|
|
798
|
+
contentView.visibility =
|
|
799
|
+
if (staticMode && !staticProjectionReady) View.INVISIBLE else View.VISIBLE
|
|
585
800
|
(contentView.parent as? android.view.ViewGroup)?.removeView(contentView)
|
|
586
801
|
wrapper.addView(contentView)
|
|
587
802
|
liveMarkerViews.add(markerView)
|
|
@@ -613,10 +828,12 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
613
828
|
|
|
614
829
|
private fun positionLiveMarker(markerView: LuggMarkerView) {
|
|
615
830
|
val map = googleMap ?: return
|
|
831
|
+
if (staticMode && !staticProjectionReady) return
|
|
616
832
|
val contentView = markerView.contentView
|
|
617
833
|
val point = map.projection.toScreenLocation(LatLng(markerView.latitude, markerView.longitude))
|
|
618
834
|
contentView.translationX = point.x - contentView.width * markerView.anchorX
|
|
619
835
|
contentView.translationY = point.y - contentView.height * markerView.anchorY
|
|
836
|
+
contentView.visibility = View.VISIBLE
|
|
620
837
|
}
|
|
621
838
|
|
|
622
839
|
// endregion
|
|
@@ -629,8 +846,12 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
629
846
|
}
|
|
630
847
|
|
|
631
848
|
override fun removePolylineView(polylineView: LuggPolylineView) {
|
|
632
|
-
|
|
633
|
-
|
|
849
|
+
teardownPolyline(polylineView)
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
private fun teardownPolyline(polylineView: LuggPolylineView) {
|
|
853
|
+
pendingPolylineViews.remove(polylineView)
|
|
854
|
+
polylineAnimators.remove(polylineView)?.destroy()
|
|
634
855
|
polylineView.polyline?.remove()
|
|
635
856
|
polylineView.polyline = null
|
|
636
857
|
}
|
|
@@ -646,15 +867,13 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
646
867
|
return
|
|
647
868
|
}
|
|
648
869
|
|
|
649
|
-
polylineView.polyline?.width = polylineView.strokeWidth.dpToPx()
|
|
650
|
-
polylineView.polyline?.zIndex = polylineView.zIndex
|
|
651
|
-
|
|
652
870
|
polylineAnimators[polylineView]?.apply {
|
|
653
871
|
coordinates = polylineView.coordinates
|
|
654
872
|
strokeColors = polylineView.strokeColors
|
|
655
873
|
strokeWidth = polylineView.strokeWidth.dpToPx()
|
|
874
|
+
zIndex = polylineView.zIndex
|
|
656
875
|
animatedOptions = polylineView.animatedOptions
|
|
657
|
-
animated = polylineView.animated
|
|
876
|
+
animated = polylineView.animated && !staticMode
|
|
658
877
|
update()
|
|
659
878
|
}
|
|
660
879
|
}
|
|
@@ -668,6 +887,8 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
668
887
|
private fun addPolylineViewToMap(polylineView: LuggPolylineView) {
|
|
669
888
|
val map = googleMap ?: return
|
|
670
889
|
|
|
890
|
+
polylineAnimators.remove(polylineView)?.destroy()
|
|
891
|
+
|
|
671
892
|
val options = PolylineOptions()
|
|
672
893
|
.width(polylineView.strokeWidth.dpToPx())
|
|
673
894
|
.zIndex(polylineView.zIndex)
|
|
@@ -680,8 +901,10 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
680
901
|
coordinates = polylineView.coordinates
|
|
681
902
|
strokeColors = polylineView.strokeColors
|
|
682
903
|
strokeWidth = polylineView.strokeWidth.dpToPx()
|
|
904
|
+
zIndex = polylineView.zIndex
|
|
683
905
|
animatedOptions = polylineView.animatedOptions
|
|
684
|
-
|
|
906
|
+
// Static maps render once; show the full polyline instead of animating
|
|
907
|
+
animated = polylineView.animated && !staticMode
|
|
685
908
|
update()
|
|
686
909
|
}
|
|
687
910
|
|
|
@@ -753,6 +976,218 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
753
976
|
|
|
754
977
|
// endregion
|
|
755
978
|
|
|
979
|
+
// region Circle Management
|
|
980
|
+
|
|
981
|
+
override fun addCircleView(circleView: LuggCircleView) {
|
|
982
|
+
circleView.delegate = this
|
|
983
|
+
syncCircleView(circleView)
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
override fun removeCircleView(circleView: LuggCircleView) {
|
|
987
|
+
circleView.circle?.let { circleToViewMap.remove(it) }
|
|
988
|
+
circleView.circle?.remove()
|
|
989
|
+
circleView.circle = null
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
private fun syncCircleView(circleView: LuggCircleView) {
|
|
993
|
+
if (googleMap == null) {
|
|
994
|
+
pendingCircleViews.add(circleView)
|
|
995
|
+
return
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
if (circleView.circle == null) {
|
|
999
|
+
addCircleViewToMap(circleView)
|
|
1000
|
+
return
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
circleView.circle?.apply {
|
|
1004
|
+
center = circleView.center
|
|
1005
|
+
radius = circleView.radius
|
|
1006
|
+
fillColor = circleView.fillColor
|
|
1007
|
+
strokeColor = circleView.strokeColor
|
|
1008
|
+
strokeWidth = circleView.strokeWidth.dpToPx()
|
|
1009
|
+
zIndex = circleView.zIndex
|
|
1010
|
+
isClickable = true
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
private fun processPendingCircles() {
|
|
1015
|
+
if (googleMap == null) return
|
|
1016
|
+
pendingCircleViews.forEach { addCircleViewToMap(it) }
|
|
1017
|
+
pendingCircleViews.clear()
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
private fun addCircleViewToMap(circleView: LuggCircleView) {
|
|
1021
|
+
val map = googleMap ?: return
|
|
1022
|
+
|
|
1023
|
+
val options = CircleOptions()
|
|
1024
|
+
.center(circleView.center)
|
|
1025
|
+
.radius(circleView.radius)
|
|
1026
|
+
.fillColor(circleView.fillColor)
|
|
1027
|
+
.strokeColor(circleView.strokeColor)
|
|
1028
|
+
.strokeWidth(circleView.strokeWidth.dpToPx())
|
|
1029
|
+
.zIndex(circleView.zIndex)
|
|
1030
|
+
.clickable(true)
|
|
1031
|
+
|
|
1032
|
+
val circle = map.addCircle(options)
|
|
1033
|
+
circleView.circle = circle
|
|
1034
|
+
circleToViewMap[circle] = circleView
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// endregion
|
|
1038
|
+
|
|
1039
|
+
// region Ground Overlay Management
|
|
1040
|
+
|
|
1041
|
+
override fun addGroundOverlayView(groundOverlayView: LuggGroundOverlayView) {
|
|
1042
|
+
groundOverlayView.delegate = this
|
|
1043
|
+
syncGroundOverlayView(groundOverlayView)
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
override fun removeGroundOverlayView(groundOverlayView: LuggGroundOverlayView) {
|
|
1047
|
+
groundOverlayView.delegate = null
|
|
1048
|
+
groundOverlayView.groundOverlay?.let { groundOverlayToViewMap.remove(it) }
|
|
1049
|
+
groundOverlayView.groundOverlay?.remove()
|
|
1050
|
+
groundOverlayView.groundOverlay = null
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
private fun syncGroundOverlayView(groundOverlayView: LuggGroundOverlayView) {
|
|
1054
|
+
if (googleMap == null) {
|
|
1055
|
+
pendingGroundOverlayViews.add(groundOverlayView)
|
|
1056
|
+
return
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
val imageUri = groundOverlayView.imageUri
|
|
1060
|
+
if (imageUri.isEmpty()) return
|
|
1061
|
+
|
|
1062
|
+
// Remove old overlay
|
|
1063
|
+
groundOverlayView.groundOverlay?.let { groundOverlayToViewMap.remove(it) }
|
|
1064
|
+
groundOverlayView.groundOverlay?.remove()
|
|
1065
|
+
groundOverlayView.groundOverlay = null
|
|
1066
|
+
|
|
1067
|
+
// Load image async and add overlay
|
|
1068
|
+
Thread {
|
|
1069
|
+
try {
|
|
1070
|
+
val connection = URL(imageUri).openConnection() as java.net.HttpURLConnection
|
|
1071
|
+
connection.instanceFollowRedirects = true
|
|
1072
|
+
connection.connect()
|
|
1073
|
+
val bitmap = android.graphics.BitmapFactory.decodeStream(connection.inputStream)
|
|
1074
|
+
connection.disconnect()
|
|
1075
|
+
if (bitmap != null) {
|
|
1076
|
+
mapView?.post {
|
|
1077
|
+
addGroundOverlayToMap(groundOverlayView, bitmap)
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
} catch (_: Exception) {}
|
|
1081
|
+
}.start()
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
private fun addGroundOverlayToMap(groundOverlayView: LuggGroundOverlayView, bitmap: android.graphics.Bitmap) {
|
|
1085
|
+
val map = googleMap ?: return
|
|
1086
|
+
|
|
1087
|
+
val bounds = LatLngBounds(groundOverlayView.southwest, groundOverlayView.northeast)
|
|
1088
|
+
val options = GroundOverlayOptions()
|
|
1089
|
+
.image(BitmapDescriptorFactory.fromBitmap(bitmap))
|
|
1090
|
+
.positionFromBounds(bounds)
|
|
1091
|
+
.transparency(1f - groundOverlayView.overlayOpacity)
|
|
1092
|
+
.bearing(groundOverlayView.bearing)
|
|
1093
|
+
.zIndex(groundOverlayView.zIndex)
|
|
1094
|
+
.clickable(groundOverlayView.tappable)
|
|
1095
|
+
|
|
1096
|
+
val overlay = map.addGroundOverlay(options)
|
|
1097
|
+
if (overlay != null) {
|
|
1098
|
+
groundOverlayView.groundOverlay = overlay
|
|
1099
|
+
groundOverlayToViewMap[overlay] = groundOverlayView
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
private fun processPendingGroundOverlays() {
|
|
1104
|
+
if (googleMap == null) return
|
|
1105
|
+
pendingGroundOverlayViews.forEach { syncGroundOverlayView(it) }
|
|
1106
|
+
pendingGroundOverlayViews.clear()
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
// endregion
|
|
1110
|
+
|
|
1111
|
+
// region Tile Overlay Management
|
|
1112
|
+
|
|
1113
|
+
override fun addTileOverlayView(tileOverlayView: LuggTileOverlayView) {
|
|
1114
|
+
tileOverlayView.delegate = this
|
|
1115
|
+
syncTileOverlayView(tileOverlayView)
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
override fun removeTileOverlayView(tileOverlayView: LuggTileOverlayView) {
|
|
1119
|
+
tileOverlayView.delegate = null
|
|
1120
|
+
tileOverlayView.tileOverlay?.remove()
|
|
1121
|
+
tileOverlayView.tileOverlay = null
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
private fun syncTileOverlayView(tileOverlayView: LuggTileOverlayView) {
|
|
1125
|
+
if (googleMap == null) {
|
|
1126
|
+
pendingTileOverlayViews.add(tileOverlayView)
|
|
1127
|
+
return
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
val urlTemplate = tileOverlayView.urlTemplate
|
|
1131
|
+
if (urlTemplate.isEmpty()) return
|
|
1132
|
+
|
|
1133
|
+
// Remove old overlay
|
|
1134
|
+
tileOverlayView.tileOverlay?.remove()
|
|
1135
|
+
tileOverlayView.tileOverlay = null
|
|
1136
|
+
|
|
1137
|
+
val tileSize = tileOverlayView.tileSize
|
|
1138
|
+
val hasBounds = tileOverlayView.hasBounds
|
|
1139
|
+
val swLat = tileOverlayView.boundsSwLat
|
|
1140
|
+
val swLng = tileOverlayView.boundsSwLng
|
|
1141
|
+
val neLat = tileOverlayView.boundsNeLat
|
|
1142
|
+
val neLng = tileOverlayView.boundsNeLng
|
|
1143
|
+
|
|
1144
|
+
val tileProvider = object : UrlTileProvider(tileSize, tileSize) {
|
|
1145
|
+
override fun getTileUrl(x: Int, y: Int, zoom: Int): URL? {
|
|
1146
|
+
if (hasBounds) {
|
|
1147
|
+
val n = 2.0.pow(zoom.toDouble())
|
|
1148
|
+
val tileSWLat = Math.toDegrees(atan(sinh(Math.PI * (1 - 2.0 * (y + 1) / n))))
|
|
1149
|
+
val tileNELat = Math.toDegrees(atan(sinh(Math.PI * (1 - 2.0 * y / n))))
|
|
1150
|
+
val tileSWLng = x / n * 360.0 - 180.0
|
|
1151
|
+
val tileNELng = (x + 1) / n * 360.0 - 180.0
|
|
1152
|
+
|
|
1153
|
+
if (tileNELat < swLat ||
|
|
1154
|
+
tileSWLat > neLat ||
|
|
1155
|
+
tileNELng < swLng ||
|
|
1156
|
+
tileSWLng > neLng
|
|
1157
|
+
) {
|
|
1158
|
+
return null
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
val url = urlTemplate
|
|
1163
|
+
.replace("{x}", x.toString())
|
|
1164
|
+
.replace("{y}", y.toString())
|
|
1165
|
+
.replace("{z}", zoom.toString())
|
|
1166
|
+
return try {
|
|
1167
|
+
URL(url)
|
|
1168
|
+
} catch (_: Exception) {
|
|
1169
|
+
null
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
val options = TileOverlayOptions()
|
|
1175
|
+
.tileProvider(tileProvider)
|
|
1176
|
+
.transparency(1f - tileOverlayView.overlayOpacity)
|
|
1177
|
+
.zIndex(tileOverlayView.zIndex)
|
|
1178
|
+
|
|
1179
|
+
val overlay = googleMap?.addTileOverlay(options)
|
|
1180
|
+
tileOverlayView.tileOverlay = overlay
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
private fun processPendingTileOverlays() {
|
|
1184
|
+
if (googleMap == null) return
|
|
1185
|
+
pendingTileOverlayViews.forEach { syncTileOverlayView(it) }
|
|
1186
|
+
pendingTileOverlayViews.clear()
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// endregion
|
|
1190
|
+
|
|
756
1191
|
// region Lifecycle
|
|
757
1192
|
|
|
758
1193
|
override fun pauseAnimations() {
|
|
@@ -768,10 +1203,25 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
768
1203
|
// region Commands
|
|
769
1204
|
|
|
770
1205
|
override fun moveCamera(latitude: Double, longitude: Double, zoom: Double, duration: Int) {
|
|
1206
|
+
if (staticMode) {
|
|
1207
|
+
// Static maps don't animate; re-center at the final camera
|
|
1208
|
+
initialLatitude = latitude
|
|
1209
|
+
initialLongitude = longitude
|
|
1210
|
+
if (zoom > 0) initialZoom = zoom.toFloat()
|
|
1211
|
+
val map = googleMap ?: return
|
|
1212
|
+
map.moveCamera(CameraUpdateFactory.newLatLngZoom(staticCameraTarget(), initialZoom))
|
|
1213
|
+
positionLiveMarkers()
|
|
1214
|
+
return
|
|
1215
|
+
}
|
|
1216
|
+
|
|
771
1217
|
val map = googleMap ?: return
|
|
772
1218
|
val position = LatLng(latitude, longitude)
|
|
773
1219
|
val targetZoom = if (zoom > 0) zoom.toFloat() else map.cameraPosition.zoom
|
|
774
|
-
val
|
|
1220
|
+
val cameraPosition = CameraPosition.Builder(map.cameraPosition)
|
|
1221
|
+
.target(position)
|
|
1222
|
+
.zoom(targetZoom)
|
|
1223
|
+
.build()
|
|
1224
|
+
val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
|
|
775
1225
|
when {
|
|
776
1226
|
duration < 0 -> map.animateCamera(cameraUpdate)
|
|
777
1227
|
duration > 0 -> map.animateCamera(cameraUpdate, duration, null)
|
|
@@ -790,23 +1240,29 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
790
1240
|
val map = googleMap ?: return
|
|
791
1241
|
if (coordinates.isEmpty()) return
|
|
792
1242
|
|
|
793
|
-
val
|
|
794
|
-
if (
|
|
795
|
-
|
|
796
|
-
val boundsBuilder = com.google.android.gms.maps.model.LatLngBounds.Builder()
|
|
797
|
-
latLngs.forEach { boundsBuilder.include(it) }
|
|
798
|
-
val bounds = boundsBuilder.build()
|
|
1243
|
+
val latLongs = coordinates.filterIsInstance<LatLng>()
|
|
1244
|
+
if (latLongs.isEmpty()) return
|
|
799
1245
|
|
|
800
1246
|
val top = edgeInsetsTop.toFloat().dpToPx().toInt()
|
|
801
1247
|
val left = edgeInsetsLeft.toFloat().dpToPx().toInt()
|
|
802
1248
|
val bottom = edgeInsetsBottom.toFloat().dpToPx().toInt()
|
|
803
1249
|
val right = edgeInsetsRight.toFloat().dpToPx().toInt()
|
|
804
1250
|
|
|
1251
|
+
if (staticMode) {
|
|
1252
|
+
fitStaticCoordinates(latLongs, top, left, bottom, right)
|
|
1253
|
+
return
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
val boundsBuilder = LatLngBounds.Builder()
|
|
1257
|
+
latLongs.forEach { boundsBuilder.include(it) }
|
|
1258
|
+
val bounds = boundsBuilder.build()
|
|
1259
|
+
|
|
1260
|
+
val combined = combinedEdgeInsets()
|
|
805
1261
|
map.setPadding(
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1262
|
+
combined.left + left,
|
|
1263
|
+
combined.top + top,
|
|
1264
|
+
combined.right + right,
|
|
1265
|
+
combined.bottom + bottom
|
|
810
1266
|
)
|
|
811
1267
|
|
|
812
1268
|
val cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 0)
|
|
@@ -817,7 +1273,7 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
817
1273
|
else -> map.moveCamera(cameraUpdate)
|
|
818
1274
|
}
|
|
819
1275
|
|
|
820
|
-
map.setPadding(
|
|
1276
|
+
map.setPadding(combined.left, combined.top, combined.right, combined.bottom)
|
|
821
1277
|
}
|
|
822
1278
|
|
|
823
1279
|
// endregion
|
|
@@ -826,10 +1282,17 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
826
1282
|
|
|
827
1283
|
private fun applyUiSettings() {
|
|
828
1284
|
googleMap?.uiSettings?.apply {
|
|
1285
|
+
if (staticMode) {
|
|
1286
|
+
// The non-lite fallback is a full map; keep it behaving like a
|
|
1287
|
+
// static image (lite mode ignores gestures anyway)
|
|
1288
|
+
setAllGesturesEnabled(false)
|
|
1289
|
+
return
|
|
1290
|
+
}
|
|
829
1291
|
isZoomGesturesEnabled = zoomEnabled
|
|
830
1292
|
isScrollGesturesEnabled = scrollEnabled
|
|
831
1293
|
isRotateGesturesEnabled = rotateEnabled
|
|
832
1294
|
isTiltGesturesEnabled = pitchEnabled
|
|
1295
|
+
isCompassEnabled = compassEnabled
|
|
833
1296
|
isMyLocationButtonEnabled = userLocationButtonEnabled
|
|
834
1297
|
}
|
|
835
1298
|
}
|
|
@@ -841,17 +1304,190 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
841
1304
|
}
|
|
842
1305
|
}
|
|
843
1306
|
|
|
844
|
-
private fun
|
|
845
|
-
|
|
1307
|
+
private fun applyInsetAdjustment() {
|
|
1308
|
+
if (insetAdjustment == "automatic") {
|
|
1309
|
+
attachWindowInsetsListener()
|
|
1310
|
+
} else {
|
|
1311
|
+
detachWindowInsetsListener()
|
|
1312
|
+
systemInsets = EdgeInsets()
|
|
1313
|
+
}
|
|
1314
|
+
applyEdgeInsets()
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
private fun combinedEdgeInsets(): EdgeInsets =
|
|
1318
|
+
if (insetAdjustment == "automatic") {
|
|
1319
|
+
EdgeInsets(
|
|
1320
|
+
edgeInsets.top + systemInsets.top,
|
|
1321
|
+
edgeInsets.left + systemInsets.left,
|
|
1322
|
+
edgeInsets.bottom + systemInsets.bottom,
|
|
1323
|
+
edgeInsets.right + systemInsets.right
|
|
1324
|
+
)
|
|
1325
|
+
} else {
|
|
1326
|
+
edgeInsets
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
private fun applyEdgeInsets(duration: Int = 0) {
|
|
1330
|
+
val combined = combinedEdgeInsets()
|
|
1331
|
+
// Lite mode misrenders padding: the static image is drawn only within
|
|
1332
|
+
// the padded viewport instead of the full view. The camera target shift
|
|
1333
|
+
// (staticCameraTarget) compensates for insets instead.
|
|
1334
|
+
if (!staticMode) {
|
|
1335
|
+
googleMap?.setPadding(combined.left, combined.top, combined.right, combined.bottom)
|
|
1336
|
+
}
|
|
1337
|
+
applyWatermarkTranslation(combined, duration)
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// Insets are applied by shifting the camera target so the coordinate
|
|
1341
|
+
// centers in the inset viewport like a live map would (see
|
|
1342
|
+
// applyEdgeInsets for why padding can't be used)
|
|
1343
|
+
private fun setStaticEdgeInsets(edgeInsets: EdgeInsets) {
|
|
1344
|
+
val oldInsets = this.edgeInsets
|
|
1345
|
+
this.edgeInsets = edgeInsets
|
|
1346
|
+
applyEdgeInsets()
|
|
1347
|
+
|
|
1348
|
+
val map = googleMap
|
|
1349
|
+
if (map != null && oldInsets != edgeInsets) {
|
|
1350
|
+
map.moveCamera(CameraUpdateFactory.newLatLngZoom(staticCameraTarget(), initialZoom))
|
|
1351
|
+
positionLiveMarkers()
|
|
1352
|
+
}
|
|
846
1353
|
}
|
|
847
1354
|
|
|
1355
|
+
private fun staticCameraTarget(): LatLng {
|
|
1356
|
+
val offsetX = (edgeInsets.left - edgeInsets.right) / 2.0
|
|
1357
|
+
val offsetY = (edgeInsets.top - edgeInsets.bottom) / 2.0
|
|
1358
|
+
if (offsetX == 0.0 && offsetY == 0.0) return LatLng(initialLatitude, initialLongitude)
|
|
1359
|
+
|
|
1360
|
+
val worldSize = mercatorWorldSize(initialZoom)
|
|
1361
|
+
return latLngFromMercator(
|
|
1362
|
+
mercatorX(initialLongitude) - offsetX / worldSize,
|
|
1363
|
+
mercatorY(initialLatitude) - offsetY / worldSize
|
|
1364
|
+
)
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
// A static camera can't fit with map padding (lite mode misrenders it);
|
|
1368
|
+
// compute the fitted camera in mercator space instead, shifting the
|
|
1369
|
+
// center for asymmetric padding like edge insets
|
|
1370
|
+
private fun fitStaticCoordinates(
|
|
1371
|
+
coordinates: List<LatLng>,
|
|
1372
|
+
top: Int,
|
|
1373
|
+
left: Int,
|
|
1374
|
+
bottom: Int,
|
|
1375
|
+
right: Int
|
|
1376
|
+
) {
|
|
1377
|
+
val map = googleMap ?: return
|
|
1378
|
+
val wrapper = wrapperView ?: return
|
|
1379
|
+
if (wrapper.width == 0 || wrapper.height == 0) return
|
|
1380
|
+
|
|
1381
|
+
var minX = Double.MAX_VALUE
|
|
1382
|
+
var minY = Double.MAX_VALUE
|
|
1383
|
+
var maxX = -Double.MAX_VALUE
|
|
1384
|
+
var maxY = -Double.MAX_VALUE
|
|
1385
|
+
for (coordinate in coordinates) {
|
|
1386
|
+
val x = mercatorX(coordinate.longitude)
|
|
1387
|
+
val y = mercatorY(coordinate.latitude)
|
|
1388
|
+
minX = minOf(minX, x)
|
|
1389
|
+
maxX = maxOf(maxX, x)
|
|
1390
|
+
minY = minOf(minY, y)
|
|
1391
|
+
maxY = maxOf(maxY, y)
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
val insets = combinedEdgeInsets()
|
|
1395
|
+
val availWidth = (wrapper.width - insets.left - insets.right - left - right).coerceAtLeast(1)
|
|
1396
|
+
val availHeight = (wrapper.height - insets.top - insets.bottom - top - bottom).coerceAtLeast(1)
|
|
1397
|
+
|
|
1398
|
+
// World size in px at which the bounds fit the padded viewport;
|
|
1399
|
+
// infinite for coincident coordinates - keep the current zoom then
|
|
1400
|
+
val fitWorldSize = minOf(availWidth / (maxX - minX), availHeight / (maxY - minY))
|
|
1401
|
+
if (fitWorldSize.isFinite()) {
|
|
1402
|
+
initialZoom = log2(fitWorldSize / 256f.dpToPx())
|
|
1403
|
+
.toFloat()
|
|
1404
|
+
.coerceIn(map.minZoomLevel, map.maxZoomLevel)
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
val worldSize = mercatorWorldSize(initialZoom)
|
|
1408
|
+
val center = latLngFromMercator(
|
|
1409
|
+
(minX + maxX) / 2.0 - (left - right) / 2.0 / worldSize,
|
|
1410
|
+
(minY + maxY) / 2.0 - (top - bottom) / 2.0 / worldSize
|
|
1411
|
+
)
|
|
1412
|
+
initialLatitude = center.latitude
|
|
1413
|
+
initialLongitude = center.longitude
|
|
1414
|
+
|
|
1415
|
+
map.moveCamera(CameraUpdateFactory.newLatLngZoom(staticCameraTarget(), initialZoom))
|
|
1416
|
+
positionLiveMarkers()
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
// Web mercator world space in [0, 1]
|
|
1420
|
+
private fun mercatorX(longitude: Double): Double = (longitude + 180.0) / 360.0
|
|
1421
|
+
|
|
1422
|
+
private fun mercatorY(latitude: Double): Double {
|
|
1423
|
+
val sinLat = sin(Math.toRadians(latitude))
|
|
1424
|
+
return 0.5 - ln((1.0 + sinLat) / (1.0 - sinLat)) / (4.0 * Math.PI)
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
private fun latLngFromMercator(x: Double, y: Double): LatLng =
|
|
1428
|
+
LatLng(Math.toDegrees(atan(sinh(Math.PI * (1.0 - 2.0 * y)))), x * 360.0 - 180.0)
|
|
1429
|
+
|
|
1430
|
+
// World size in px at the given zoom
|
|
1431
|
+
private fun mercatorWorldSize(zoom: Float): Double = 256f.dpToPx().toDouble() * 2.0.pow(zoom.toDouble())
|
|
1432
|
+
|
|
1433
|
+
private fun applyWatermarkTranslation(insets: EdgeInsets, duration: Int = 0) {
|
|
1434
|
+
val view = mapView ?: return
|
|
1435
|
+
view.findViewByTag("GoogleWatermark")?.let { watermark ->
|
|
1436
|
+
val targetY = -insets.bottom.toFloat()
|
|
1437
|
+
val targetX = insets.left.toFloat()
|
|
1438
|
+
if (duration > 0) {
|
|
1439
|
+
watermark.animate()
|
|
1440
|
+
.translationY(targetY)
|
|
1441
|
+
.translationX(targetX)
|
|
1442
|
+
.setDuration(duration.toLong())
|
|
1443
|
+
.start()
|
|
1444
|
+
} else if (duration < 0) {
|
|
1445
|
+
watermark.animate()
|
|
1446
|
+
.translationY(targetY)
|
|
1447
|
+
.translationX(targetX)
|
|
1448
|
+
.start()
|
|
1449
|
+
} else {
|
|
1450
|
+
watermark.translationY = targetY
|
|
1451
|
+
watermark.translationX = targetX
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
private fun attachWindowInsetsListener() {
|
|
1457
|
+
val view = mapView ?: return
|
|
1458
|
+
ViewCompat.setOnApplyWindowInsetsListener(view) { _, windowInsets ->
|
|
1459
|
+
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
|
1460
|
+
systemInsets = EdgeInsets(insets.top, insets.left, insets.bottom, insets.right)
|
|
1461
|
+
applyEdgeInsets()
|
|
1462
|
+
windowInsets
|
|
1463
|
+
}
|
|
1464
|
+
ViewCompat.requestApplyInsets(view)
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
private fun detachWindowInsetsListener() {
|
|
1468
|
+
mapView?.let { ViewCompat.setOnApplyWindowInsetsListener(it, null) }
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
1472
|
+
val newNightMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
|
1473
|
+
if (newNightMode != currentNightMode) {
|
|
1474
|
+
currentNightMode = newNightMode
|
|
1475
|
+
applyTheme()
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
@Deprecated("Deprecated in Java")
|
|
1480
|
+
override fun onLowMemory() {}
|
|
1481
|
+
|
|
1482
|
+
override fun onTrimMemory(level: Int) {}
|
|
1483
|
+
|
|
848
1484
|
private fun applyTheme() {
|
|
849
1485
|
val colorScheme = when (theme) {
|
|
850
1486
|
"dark" -> MapColorScheme.DARK
|
|
851
1487
|
"light" -> MapColorScheme.LIGHT
|
|
852
1488
|
else -> MapColorScheme.FOLLOW_SYSTEM
|
|
853
1489
|
}
|
|
854
|
-
googleMap?.
|
|
1490
|
+
googleMap?.mapColorScheme = colorScheme
|
|
855
1491
|
}
|
|
856
1492
|
|
|
857
1493
|
@SuppressLint("MissingPermission")
|
|
@@ -870,5 +1506,9 @@ class GoogleMapProvider(private val context: Context) :
|
|
|
870
1506
|
|
|
871
1507
|
companion object {
|
|
872
1508
|
const val DEMO_MAP_ID = "DEMO_MAP_ID"
|
|
1509
|
+
|
|
1510
|
+
// Undocumented cap on the lite mode bitmap (2048 minus a 2px border,
|
|
1511
|
+
// measured empirically)
|
|
1512
|
+
private const val LITE_MODE_MAX_SIZE = 2046
|
|
873
1513
|
}
|
|
874
1514
|
}
|