Skip to content

Commit 13d8c9f

Browse files
committed
feat: add StreetViewPanorama view
1 parent a92e4b2 commit 13d8c9f

40 files changed

Lines changed: 1783 additions & 116 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
[![API Docs](https://img.shields.io/static/v1?label=typedoc&message=docs&color=informational)](https://pinpong.github.io/react-native-google-maps-plus)
77
![React Native](https://img.shields.io/badge/react--native-%3E%3D0.82.0-61dafb.svg?logo=react)
88

9-
React Native wrapper for Android & iOS Google Maps SDK.
9+
React Native wrapper for Android & iOS Google Maps SDK with Street View support.
1010

1111
## Documentation
1212

android/src/main/java/com/rngooglemapsplus/GoogleMapsViewImpl.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ class GoogleMapsViewImpl(
199199
lifecycleObserver = MapLifecycleEventObserver(it, locationHandler)
200200
super.addView(it)
201201
it.getMapAsync { map ->
202+
if (destroyed) return@getMapAsync
202203
googleMap = map
203204
googleMap?.setLocationSource(locationHandler)
204205
googleMap?.setOnMapLoadedCallback {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.rngooglemapsplus;
2+
3+
import androidx.annotation.NonNull;
4+
import androidx.annotation.Nullable;
5+
import com.google.android.gms.maps.StreetViewPanorama;
6+
import com.google.android.gms.maps.model.StreetViewPanoramaLocation;
7+
8+
public interface OnStreetViewPanoramaChangeListenerNullSafe
9+
extends StreetViewPanorama.OnStreetViewPanoramaChangeListener {
10+
11+
@Override
12+
default void onStreetViewPanoramaChange(@NonNull StreetViewPanoramaLocation location) {
13+
onStreetViewPanoramaChangeNullable(location);
14+
}
15+
16+
void onStreetViewPanoramaChangeNullable(@Nullable StreetViewPanoramaLocation location);
17+
}

android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusPackage.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.facebook.react.bridge.ReactApplicationContext
66
import com.facebook.react.module.model.ReactModuleInfoProvider
77
import com.facebook.react.uimanager.ViewManager
88
import com.rngooglemapsplus.RNGoogleMapsPlusPackage.AppContextHolder.context
9+
import com.rngooglemapsplus.views.HybridRNGoogleMapsPlusStreetViewManager
910
import com.rngooglemapsplus.views.HybridRNGoogleMapsPlusViewManager
1011

1112
class RNGoogleMapsPlusPackage : BaseReactPackage() {
@@ -20,6 +21,7 @@ class RNGoogleMapsPlusPackage : BaseReactPackage() {
2021
context = reactContext
2122
return listOf(
2223
HybridRNGoogleMapsPlusViewManager(),
24+
HybridRNGoogleMapsPlusStreetViewManager(),
2325
)
2426
}
2527

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package com.rngooglemapsplus
2+
3+
import com.facebook.proguard.annotations.DoNotStrip
4+
import com.facebook.react.uimanager.ThemedReactContext
5+
import com.google.android.gms.maps.StreetViewPanoramaOptions
6+
import com.google.android.gms.maps.model.StreetViewSource
7+
import com.margelo.nitro.core.Promise
8+
import com.rngooglemapsplus.PermissionHandler
9+
import com.rngooglemapsplus.extensions.toLatLng
10+
import com.rngooglemapsplus.extensions.toStreetViewPanoramaCamera
11+
import com.rngooglemapsplus.extensions.toStreetViewSource
12+
13+
@DoNotStrip
14+
class RNGoogleMapsPlusStreetView(
15+
private val context: ThemedReactContext,
16+
) : HybridRNGoogleMapsPlusStreetViewSpec() {
17+
private val mapErrorHandler = MapErrorHandler()
18+
private val permissionHandler = PermissionHandler(context)
19+
private val locationHandler = LocationHandler(context)
20+
private val playServiceHandler = PlayServicesHandler(context)
21+
22+
override val view =
23+
StreetViewPanoramaViewImpl(
24+
context,
25+
locationHandler,
26+
playServiceHandler,
27+
mapErrorHandler,
28+
)
29+
30+
override fun onDropView() {
31+
view.destroyInternal()
32+
}
33+
34+
override var initialProps: RNStreetViewInitialProps? = null
35+
set(value) {
36+
if (field == value) return
37+
field = value
38+
39+
val options =
40+
StreetViewPanoramaOptions().apply {
41+
panoramaId(initialProps?.panoramaId)
42+
initialProps?.position?.let {
43+
position(
44+
it.toLatLng(),
45+
initialProps?.radius?.toInt(),
46+
initialProps?.source.toStreetViewSource(),
47+
)
48+
}
49+
initialProps?.camera?.toStreetViewPanoramaCamera()?.let { panoramaCamera(it) }
50+
}
51+
52+
view.streetViewPanoramaOptions = options
53+
}
54+
55+
override var uiSettings: RNStreetViewUiSettings? = null
56+
set(value) {
57+
if (field == value) return
58+
field = value
59+
view.uiSettings = value
60+
}
61+
62+
override var onPanoramaReady: ((Boolean) -> Unit)? = null
63+
set(cb) {
64+
view.onPanoramaReady = cb
65+
}
66+
67+
override var onLocationUpdate: ((RNLocation) -> Unit)? = null
68+
set(cb) {
69+
view.onLocationUpdate = cb
70+
}
71+
72+
override var onLocationError: ((RNLocationErrorCode) -> Unit)? = null
73+
set(cb) {
74+
view.onLocationError = cb
75+
}
76+
77+
override var onPanoramaChange: ((RNStreetViewPanoramaLocation) -> Unit)? = null
78+
set(cb) {
79+
view.onPanoramaChange = cb
80+
}
81+
82+
override var onCameraChange: ((RNStreetViewCamera) -> Unit)? = null
83+
set(cb) {
84+
view.onCameraChange = cb
85+
}
86+
87+
override var onPanoramaPress: ((RNStreetViewOrientation) -> Unit)? = null
88+
set(cb) {
89+
view.onPanoramaPress = cb
90+
}
91+
92+
override var onPanoramaError: ((RNMapErrorCode, String) -> Unit)? = null
93+
set(cb) {
94+
field = cb
95+
mapErrorHandler.callback = cb
96+
}
97+
98+
override fun setCamera(
99+
camera: RNStreetViewCamera,
100+
animated: Boolean?,
101+
durationMs: Double?,
102+
) {
103+
val current = view.currentCamera
104+
view.setPanoramaCamera(
105+
camera.toStreetViewPanoramaCamera(current),
106+
animated ?: false,
107+
durationMs?.toInt() ?: 1000,
108+
)
109+
}
110+
111+
override fun setPosition(
112+
position: RNLatLng,
113+
radius: Double?,
114+
source: RNStreetViewSource?,
115+
) {
116+
view.setPosition(
117+
position.toLatLng(),
118+
radius?.toInt(),
119+
source.toStreetViewSource(),
120+
)
121+
}
122+
123+
override fun setPositionById(panoramaId: String) {
124+
view.setPositionById(panoramaId)
125+
}
126+
127+
override fun showLocationDialog() {
128+
locationHandler.showLocationDialog()
129+
}
130+
131+
override fun openLocationSettings() {
132+
locationHandler.openLocationSettings()
133+
}
134+
135+
override fun requestLocationPermission(): Promise<RNLocationPermissionResult> = permissionHandler.requestLocationPermission()
136+
137+
override fun isGooglePlayServicesAvailable(): Boolean = playServiceHandler.isPlayServicesAvailable()
138+
}

android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusView.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ class RNGoogleMapsPlusView(
2727
private val mapErrorHandler = MapErrorHandler()
2828

2929
private var currentCustomMapStyle: String? = null
30-
private var permissionHandler = PermissionHandler(context)
31-
private var locationHandler = LocationHandler(context)
32-
private var playServiceHandler = PlayServicesHandler(context)
30+
private val permissionHandler = PermissionHandler(context)
31+
private val locationHandler = LocationHandler(context)
32+
private val playServiceHandler = PlayServicesHandler(context)
3333

3434
private val markerBuilder = MapMarkerBuilder(context, mapErrorHandler)
3535
private val polylineBuilder = MapPolylineBuilder()
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.rngooglemapsplus
2+
3+
import android.os.Bundle
4+
import androidx.lifecycle.Lifecycle
5+
import androidx.lifecycle.LifecycleEventObserver
6+
import androidx.lifecycle.LifecycleOwner
7+
import com.google.android.gms.maps.StreetViewPanoramaView
8+
9+
class StreetViewLifecycleEventObserver(
10+
private val streetViewPanoramaView: StreetViewPanoramaView?,
11+
private val locationHandler: LocationHandler,
12+
) : LifecycleEventObserver {
13+
private var currentState: Lifecycle.State = Lifecycle.State.INITIALIZED
14+
15+
override fun onStateChanged(
16+
source: LifecycleOwner,
17+
event: Lifecycle.Event,
18+
) {
19+
when (event) {
20+
Lifecycle.Event.ON_DESTROY -> toCreatedState()
21+
else -> toState(event.targetState)
22+
}
23+
}
24+
25+
fun toCreatedState() {
26+
if (currentState > Lifecycle.State.CREATED) {
27+
toState(Lifecycle.State.CREATED)
28+
}
29+
}
30+
31+
fun toDestroyedState() {
32+
if (currentState > Lifecycle.State.INITIALIZED) {
33+
toState(Lifecycle.State.DESTROYED)
34+
}
35+
}
36+
37+
private fun toState(state: Lifecycle.State) {
38+
if (currentState == Lifecycle.State.DESTROYED) return
39+
while (currentState != state) {
40+
when {
41+
currentState < state -> upFromCurrentState()
42+
currentState > state -> downFromCurrentState()
43+
}
44+
}
45+
}
46+
47+
private fun downFromCurrentState() {
48+
Lifecycle.Event.downFrom(currentState)?.also { invokeEvent(it) }
49+
}
50+
51+
private fun upFromCurrentState() {
52+
Lifecycle.Event.upFrom(currentState)?.also { invokeEvent(it) }
53+
}
54+
55+
private fun invokeEvent(event: Lifecycle.Event) {
56+
when (event) {
57+
Lifecycle.Event.ON_CREATE -> {
58+
streetViewPanoramaView?.onCreate(Bundle())
59+
}
60+
61+
Lifecycle.Event.ON_START -> {
62+
streetViewPanoramaView?.onStart()
63+
}
64+
65+
Lifecycle.Event.ON_RESUME -> {
66+
locationHandler.start()
67+
streetViewPanoramaView?.onResume()
68+
}
69+
70+
Lifecycle.Event.ON_PAUSE -> {
71+
streetViewPanoramaView?.onPause()
72+
locationHandler.stop()
73+
}
74+
75+
Lifecycle.Event.ON_STOP -> {
76+
streetViewPanoramaView?.onStop()
77+
}
78+
79+
Lifecycle.Event.ON_DESTROY -> {
80+
streetViewPanoramaView?.onDestroy()
81+
}
82+
83+
Lifecycle.Event.ON_ANY -> {}
84+
}
85+
currentState = event.targetState
86+
}
87+
}

0 commit comments

Comments
 (0)