Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a delegate for MapboxNavigation called requireMapboxNavigation #6233

Merged
merged 2 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Mapbox welcomes participation and contributions from everyone.
## Unreleased
#### Features
- Improved the route refresh feature to also refresh _closures_ (`RouteLeg#closures`). [#6274](https://github.com/mapbox/mapbox-navigation-android/pull/6274)

- Added `requireMapboxNavigation` to offer a simple way to use `MapboxNavigationApp`. [#6233](https://github.com/mapbox/mapbox-navigation-android/pull/6233)
#### Bug fixes and improvements

## Mapbox Navigation SDK 2.8.0-beta.2 - 01 September, 2022
Expand Down
4 changes: 4 additions & 0 deletions libnavigation-core/api/current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,10 @@ package com.mapbox.navigation.core.lifecycle {
method public com.mapbox.navigation.base.options.NavigationOptions createNavigationOptions();
}

public final class RequireMapboxNavigation {
method @com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI public static kotlin.properties.ReadOnlyProperty<java.lang.Object,com.mapbox.navigation.core.MapboxNavigation> requireMapboxNavigation(androidx.lifecycle.LifecycleOwner, com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onCreatedObserver = null, com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onStartedObserver = null, com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onResumedObserver = null, kotlin.jvm.functions.Function0<kotlin.Unit>? onInitialize = null);
}

}

package com.mapbox.navigation.core.navigator {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
@file:JvmName("RequireMapboxNavigation")

package com.mapbox.navigation.core.lifecycle

import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp.lifecycleOwner
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
* Extension function to make it simple to create the [RequireMapboxNavigationDelegate].
* Below are a couple examples of how you may use the delegate.
*
* Default can be used when [MapboxNavigationApp] is setup elsewhere.
* ```
* val mapboxNavigation by requireMapboxNavigation()
* ```
*
* Initialize the [MapboxNavigationApp] when you are ready to use it
* ```
* val mapboxNavigation by requireMapboxNavigation {
* MapboxNavigationApp.setup(..)
* }
* ```
*
* Register subscriptions and setup MapboxNavigationApp
* ```
* private val mapboxNavigation by requireMapboxNavigation(
* onResumedObserver = object : MapboxNavigationObserver {
* override fun onAttached(mapboxNavigation: MapboxNavigation) {
* mapboxNavigation.registerLocationObserver(locationObserver)
* mapboxNavigation.registerRoutesObserver(routesObserver)
* }
* override fun onDetached(mapboxNavigation: MapboxNavigation) {
* mapboxNavigation.unregisterLocationObserver(locationObserver)
* mapboxNavigation.unregisterRoutesObserver(routesObserver)
* }
* }
* ) {
* MapboxNavigationApp.setup(
* NavigationOptions.Builder(this)
* .accessToken(accessToken)
* .build()
* )
* }
* ```
*
* @see [RequireMapboxNavigationDelegate] for more details.
*/
@ExperimentalPreviewMapboxNavigationAPI
kmadsen marked this conversation as resolved.
Show resolved Hide resolved
fun LifecycleOwner.requireMapboxNavigation(
onCreatedObserver: MapboxNavigationObserver? = null,
onStartedObserver: MapboxNavigationObserver? = null,
onResumedObserver: MapboxNavigationObserver? = null,
onInitialize: (() -> Unit)? = null,
): ReadOnlyProperty<Any, MapboxNavigation> = RequireMapboxNavigationDelegate(
lifecycleOwner = this,
onCreatedObserver = onCreatedObserver,
onStartedObserver = onStartedObserver,
onResumedObserver = onResumedObserver,
onInitialize = onInitialize
)

/**
* Attaches a [LifecycleOwner] to [MapboxNavigationApp] and provides access to [MapboxNavigation].
*
* You can choose to call [MapboxNavigationApp.setup] in the [onInitialize]. You can also setup in
* the onCreate calls, or any call that happens before this delegate is accessed. The delegate will
* crash if accessed when the app is not setup or an attached lifecycle has not been created.
*
* You can use the observers parameter to setup any subscriptions. This is important because the
* [MapboxNavigation] instance can be re-created with [MapboxNavigationApp.disable], or if all
* [MapboxNavigationApp.attach] lifecycles are destroyed.
*
* @param lifecycleOwner: LifecycleOwner
* @param onCreatedObserver registered to the [Lifecycle.State.CREATED] lifecycle
* @param onStartedObserver registered to the [Lifecycle.State.STARTED] lifecycle
* @param onResumedObserver registered to the [Lifecycle.State.RESUMED] lifecycle
* @param onInitialize called when the [lifecycleOwner] is [Lifecycle.State.CREATED]
*/
internal class RequireMapboxNavigationDelegate(
lifecycleOwner: LifecycleOwner,
private val onCreatedObserver: MapboxNavigationObserver? = null,
private val onStartedObserver: MapboxNavigationObserver? = null,
private val onResumedObserver: MapboxNavigationObserver? = null,
private val onInitialize: (() -> Unit)? = null
) : ReadOnlyProperty<Any, MapboxNavigation> {

private val lifecycleObserver = object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
onInitialize?.invoke()
onCreatedObserver?.let { MapboxNavigationApp.registerObserver(it) }
}

override fun onDestroy(owner: LifecycleOwner) {
onCreatedObserver?.let { MapboxNavigationApp.unregisterObserver(it) }
}

override fun onStart(owner: LifecycleOwner) {
onStartedObserver?.let { MapboxNavigationApp.registerObserver(it) }
}

override fun onStop(owner: LifecycleOwner) {
onStartedObserver?.let { MapboxNavigationApp.unregisterObserver(it) }
}

override fun onResume(owner: LifecycleOwner) {
onResumedObserver?.let { MapboxNavigationApp.registerObserver(it) }
}

override fun onPause(owner: LifecycleOwner) {
onResumedObserver?.let { MapboxNavigationApp.unregisterObserver(it) }
}
}

init {
MapboxNavigationApp.attach(lifecycleOwner)
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
}

/**
* Returns an instance of [MapboxNavigation]. If [MapboxNavigationApp.isSetup] is false after
* all observers and initializers, this property getter will crash.
*
* @param thisRef - the [LifecycleOwner] that needs access to [MapboxNavigation].
* @param property - ignored
*/
override fun getValue(thisRef: Any, property: KProperty<*>): MapboxNavigation {
val mapboxNavigation = MapboxNavigationApp.current()
checkNotNull(mapboxNavigation) {
"MapboxNavigation cannot be null. Ensure that MapboxNavigationApp is setup and an" +
" attached lifecycle is at least CREATED."
}
return mapboxNavigation
}
}
Loading