Skip to content

Commit cf2980c

Browse files
authored
[Drop-In UI] NAVAND-634: introduce compass (#6395)
1 parent a72f9ce commit cf2980c

16 files changed

Lines changed: 343 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Mapbox welcomes participation and contributions from everyone.
1313
- Fixed an issue with restricted road visualization on the route line that occurred during route refreshes. [#6399](https://github.com/mapbox/mapbox-navigation-android/pull/6399)
1414
- Improved precision of restricted sections visualization, especially for long routes. [#6399](https://github.com/mapbox/mapbox-navigation-android/pull/6399)
1515
- Fixed a rare issue where alternative route would not be vanished until deviation point for `MapboxRouteLineApi#setNavigationRoutes(routes, metadata)` when the route's geometry contained duplicate points. [#6399](https://github.com/mapbox/mapbox-navigation-android/pull/6399)
16+
- Introduced `ViewStyleCutomization.compassButtonParams` property to configure compass. [#6395](https://github.com/mapbox/mapbox-navigation-android/pull/6395)
17+
- Introduced `MapboxExtendableButtonParams.enabled` property to enable/disable a button. [#6395](https://github.com/mapbox/mapbox-navigation-android/pull/6395)
1618

1719
## Mapbox Navigation SDK 2.9.0-alpha.4 - 30 September, 2022
1820
### Changelog

libnavui-dropin/api/current.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ package com.mapbox.navigation.dropin {
77
}
88

99
public final class MapboxExtendableButtonParams {
10+
ctor public MapboxExtendableButtonParams(@StyleRes int style, android.widget.LinearLayout.LayoutParams layoutParams, boolean enabled = true);
1011
ctor public MapboxExtendableButtonParams(@StyleRes int style, android.widget.LinearLayout.LayoutParams layoutParams);
12+
method public boolean getEnabled();
1113
method public android.widget.LinearLayout.LayoutParams getLayoutParams();
1214
method public int getStyle();
15+
property public final boolean enabled;
1316
property public final android.widget.LinearLayout.LayoutParams layoutParams;
1417
property public final int style;
1518
}
@@ -168,6 +171,7 @@ package com.mapbox.navigation.dropin {
168171
method public Integer? getArrivalTextAppearance();
169172
method public com.mapbox.navigation.dropin.MapboxExtendableButtonParams? getAudioGuidanceButtonParams();
170173
method public com.mapbox.navigation.dropin.MapboxExtendableButtonParams? getCameraModeButtonParams();
174+
method public com.mapbox.navigation.dropin.MapboxExtendableButtonParams? getCompassButtonParams();
171175
method public com.mapbox.maps.plugin.annotation.generated.PointAnnotationOptions? getDestinationMarkerAnnotationOptions();
172176
method public com.mapbox.navigation.dropin.MapboxExtendableButtonParams? getEndNavigationButtonParams();
173177
method public Integer? getInfoPanelBackground();
@@ -189,6 +193,7 @@ package com.mapbox.navigation.dropin {
189193
method public void setArrivalTextAppearance(Integer?);
190194
method public void setAudioGuidanceButtonParams(com.mapbox.navigation.dropin.MapboxExtendableButtonParams?);
191195
method public void setCameraModeButtonParams(com.mapbox.navigation.dropin.MapboxExtendableButtonParams?);
196+
method public void setCompassButtonParams(com.mapbox.navigation.dropin.MapboxExtendableButtonParams?);
192197
method public void setDestinationMarkerAnnotationOptions(com.mapbox.maps.plugin.annotation.generated.PointAnnotationOptions?);
193198
method public void setEndNavigationButtonParams(com.mapbox.navigation.dropin.MapboxExtendableButtonParams?);
194199
method public void setInfoPanelBackground(Integer?);
@@ -210,6 +215,7 @@ package com.mapbox.navigation.dropin {
210215
property public final Integer? arrivalTextAppearance;
211216
property public final com.mapbox.navigation.dropin.MapboxExtendableButtonParams? audioGuidanceButtonParams;
212217
property public final com.mapbox.navigation.dropin.MapboxExtendableButtonParams? cameraModeButtonParams;
218+
property public final com.mapbox.navigation.dropin.MapboxExtendableButtonParams? compassButtonParams;
213219
property public final com.mapbox.maps.plugin.annotation.generated.PointAnnotationOptions? destinationMarkerAnnotationOptions;
214220
property public final com.mapbox.navigation.dropin.MapboxExtendableButtonParams? endNavigationButtonParams;
215221
property public final Integer? infoPanelBackground;
@@ -235,6 +241,7 @@ package com.mapbox.navigation.dropin {
235241
method @StyleRes public int defaultArrivalTextAppearance();
236242
method public com.mapbox.navigation.dropin.MapboxExtendableButtonParams defaultAudioGuidanceButtonParams(android.content.Context context);
237243
method public com.mapbox.navigation.dropin.MapboxExtendableButtonParams defaultCameraModeButtonParams(android.content.Context context);
244+
method public com.mapbox.navigation.dropin.MapboxExtendableButtonParams defaultCompassButtonParams(android.content.Context context);
238245
method public com.mapbox.maps.plugin.annotation.generated.PointAnnotationOptions defaultDestinationMarkerAnnotationOptions(android.content.Context context);
239246
method public com.mapbox.navigation.dropin.MapboxExtendableButtonParams defaultEndNavigationButtonParams(android.content.Context context);
240247
method @DrawableRes public int defaultInfoPanelBackground();

libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/MapboxExtendableButtonParams.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@ import androidx.annotation.StyleRes
88
*
99
* @param style style res of a button.
1010
* @param layoutParams layout params of a button.
11+
* @param enabled `true` if the button should be enabled, `false` otherwise
1112
*/
12-
class MapboxExtendableButtonParams(
13+
class MapboxExtendableButtonParams @JvmOverloads constructor(
1314
@StyleRes
1415
val style: Int,
1516
val layoutParams: LinearLayout.LayoutParams,
17+
val enabled: Boolean = true
1618
) {
19+
1720
/**
1821
* Regenerate whenever a change is made
1922
*/
@@ -25,6 +28,7 @@ class MapboxExtendableButtonParams(
2528

2629
if (style != other.style) return false
2730
if (layoutParams != other.layoutParams) return false
31+
if (enabled != other.enabled) return false
2832

2933
return true
3034
}
@@ -35,6 +39,7 @@ class MapboxExtendableButtonParams(
3539
override fun hashCode(): Int {
3640
var result = style
3741
result = 31 * result + layoutParams.hashCode()
42+
result = 31 * result + enabled.hashCode()
3843
return result
3944
}
4045

@@ -44,7 +49,8 @@ class MapboxExtendableButtonParams(
4449
override fun toString(): String {
4550
return "MapboxExtendableButtonParams(" +
4651
"style=$style, " +
47-
"layoutParams=$layoutParams" +
52+
"layoutParams=$layoutParams, " +
53+
"enabled=$enabled" +
4854
")"
4955
}
5056
}

libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/ViewStyleCustomization.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,12 @@ class ViewStyleCustomization {
179179
*/
180180
var mapScalebarParams: MapboxMapScalebarParams? = null
181181

182+
/**
183+
* Map compass params.
184+
* Use [defaultCompassButtonParams] to reset to default.
185+
*/
186+
var compassButtonParams: MapboxExtendableButtonParams? = null
187+
182188
companion object {
183189
/**
184190
* Default info panel peek height in pixels.
@@ -392,6 +398,19 @@ class ViewStyleCustomization {
392398
fun defaultMapScalebarParams(context: Context): MapboxMapScalebarParams =
393399
MapboxMapScalebarParams.Builder(context).build()
394400

401+
/**
402+
* Default map compass [MapboxExtendableButtonParams] parameters.
403+
*/
404+
fun defaultCompassButtonParams(context: Context): MapboxExtendableButtonParams =
405+
MapboxExtendableButtonParams(
406+
R.style.DropInStyleCompassButton,
407+
context.defaultLayoutParams().apply {
408+
topMargin = context.defaultSpacing()
409+
bottomMargin = context.defaultSpacing()
410+
},
411+
false
412+
)
413+
395414
private fun Context.defaultSpacing() =
396415
resources.getDimensionPixelSize(R.dimen.mapbox_actionList_spacing)
397416

libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/actionbutton/ActionButtonBinder.kt

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import android.view.View
77
import android.view.ViewGroup
88
import android.widget.LinearLayout
99
import androidx.lifecycle.viewModelScope
10+
import com.mapbox.maps.MapView
1011
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
1112
import com.mapbox.navigation.core.internal.extensions.navigationListOf
1213
import com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver
@@ -23,6 +24,7 @@ import com.mapbox.navigation.ui.app.internal.navigation.NavigationState
2324
import com.mapbox.navigation.ui.base.lifecycle.UIBinder
2425
import com.mapbox.navigation.ui.base.view.MapboxExtendableButton
2526
import com.mapbox.navigation.ui.maps.internal.ui.CameraModeButtonComponent
27+
import com.mapbox.navigation.ui.maps.internal.ui.CompassButtonComponent
2628
import com.mapbox.navigation.ui.maps.internal.ui.RecenterButtonComponent
2729
import com.mapbox.navigation.ui.maps.view.MapboxCameraModeButton
2830
import com.mapbox.navigation.ui.voice.internal.ui.AudioComponentContract
@@ -37,6 +39,7 @@ internal class ActionButtonBinder(
3739
private val customButtons: List<ActionButtonDescription>
3840
) : UIBinder {
3941

42+
private var compassButton: MapboxExtendableButton? = null
4043
private var audioButton: MapboxAudioGuidanceButton? = null
4144
private var recenterButton: MapboxExtendableButton? = null
4245
private var cameraButton: MapboxCameraModeButton? = null
@@ -49,6 +52,12 @@ internal class ActionButtonBinder(
4952

5053
val store = context.store
5154
return navigationListOf(
55+
reloadOnChange(
56+
context.styles.compassButtonParams,
57+
context.mapViewOwner.mapViews
58+
) { params, mapView ->
59+
compassButtonComponent(binding, params, mapView)
60+
},
5261
reloadOnChange(context.styles.cameraModeButtonParams) { params ->
5362
cameraModeButtonComponent(binding, params, store)
5463
},
@@ -84,6 +93,22 @@ internal class ActionButtonBinder(
8493
.forEach { it.view.setMargins(top = spacing, bottom = spacing) }
8594
}
8695

96+
private fun compassButtonComponent(
97+
binding: MapboxActionButtonsLayoutBinding,
98+
customParams: MapboxExtendableButtonParams,
99+
mapView: MapView?
100+
): CompassButtonComponent {
101+
compassButton.recreate(
102+
::MapboxExtendableButton,
103+
customParams,
104+
binding.buttonContainer,
105+
COMPASS_BUTTON_POSITION
106+
).let {
107+
compassButton = it
108+
return CompassButtonComponent(it, mapView, customParams.enabled)
109+
}
110+
}
111+
87112
private fun audioGuidanceButtonComponent(
88113
binding: MapboxActionButtonsLayoutBinding,
89114
customParams: MapboxExtendableButtonParams,
@@ -165,9 +190,10 @@ internal class ActionButtonBinder(
165190
}
166191

167192
private companion object {
168-
private const val AUDIO_BUTTON_POSITION = 1
169-
private const val CAMERA_BUTTON_POSITION = 0
170-
private const val RECENTER_BUTTON_POSITION = 2
193+
private const val COMPASS_BUTTON_POSITION = 0
194+
private const val CAMERA_BUTTON_POSITION = 1
195+
private const val AUDIO_BUTTON_POSITION = 2
196+
private const val RECENTER_BUTTON_POSITION = 3
171197
}
172198
}
173199

libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/map/MapViewOwner.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,21 @@ package com.mapbox.navigation.dropin.map
22

33
import com.mapbox.maps.MapView
44
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
5+
import kotlinx.coroutines.flow.MutableStateFlow
6+
import kotlinx.coroutines.flow.asStateFlow
57
import java.util.concurrent.CopyOnWriteArraySet
68

79
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
810
internal class MapViewOwner {
911

1012
private var mapView: MapView? = null
13+
set(value) {
14+
field = value
15+
_mapViews.value = value
16+
}
1117
private val listeners = CopyOnWriteArraySet<MapViewObserver>()
18+
private val _mapViews = MutableStateFlow(mapView)
19+
val mapViews = _mapViews.asStateFlow()
1220

1321
fun registerObserver(observer: MapViewObserver) {
1422
if (listeners.add(observer)) {

libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/navigationview/NavigationViewStyles.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ internal class NavigationViewStyles(context: Context) {
5858
private val _mapScalebarParams: MutableStateFlow<MapboxMapScalebarParams> = MutableStateFlow(
5959
ViewStyleCustomization.defaultMapScalebarParams(context)
6060
)
61+
private val _compassButtonParams: MutableStateFlow<MapboxExtendableButtonParams> =
62+
MutableStateFlow(ViewStyleCustomization.defaultCompassButtonParams(context))
6163

6264
val infoPanelPeekHeight: StateFlow<Int> = _infoPanelPeekHeight.asStateFlow()
6365
val infoPanelMarginStart: StateFlow<Int> = _infoPanelMarginStart.asStateFlow()
@@ -87,6 +89,8 @@ internal class NavigationViewStyles(context: Context) {
8789
val arrivalTextAppearance: StateFlow<Int> = _arrivalTextAppearance.asStateFlow()
8890
val locationPuck: StateFlow<LocationPuck> = _locationPuck.asStateFlow()
8991
val mapScalebarParams: StateFlow<MapboxMapScalebarParams> = _mapScalebarParams.asStateFlow()
92+
val compassButtonParams: StateFlow<MapboxExtendableButtonParams> =
93+
_compassButtonParams.asStateFlow()
9094

9195
fun applyCustomization(customization: ViewStyleCustomization) {
9296
customization.infoPanelPeekHeight?.also { _infoPanelPeekHeight.value = it }
@@ -112,5 +116,6 @@ internal class NavigationViewStyles(context: Context) {
112116
customization.arrivalTextAppearance?.also { _arrivalTextAppearance.value = it }
113117
customization.locationPuck?.also { _locationPuck.value = it }
114118
customization.mapScalebarParams?.also { _mapScalebarParams.value = it }
119+
customization.compassButtonParams?.also { _compassButtonParams.value = it }
115120
}
116121
}

libnavui-dropin/src/main/res/values/styles.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,9 @@
150150
<item name="extendableButtonIcon">@drawable/mapbox_ic_camera_recenter</item>
151151
</style>
152152

153+
<!-- Compass button -->
154+
<style name="DropInStyleCompassButton" parent="MapboxStyleExtendableButton">
155+
<item name="extendableButtonIcon">@drawable/mapbox_ic_compass</item>
156+
</style>
157+
153158
</resources>

libnavui-dropin/src/test/java/com/mapbox/navigation/dropin/actionbutton/ActionButtonBinderTest.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import com.mapbox.navigation.dropin.databinding.MapboxActionButtonsLayoutBinding
1212
import com.mapbox.navigation.dropin.navigationview.NavigationViewContext
1313
import com.mapbox.navigation.dropin.navigationview.NavigationViewStyles
1414
import com.mapbox.navigation.dropin.util.TestStore
15-
import io.mockk.MockKAnnotations
1615
import io.mockk.every
1716
import io.mockk.mockk
1817
import kotlinx.coroutines.MainScope
@@ -33,11 +32,10 @@ internal class ActionButtonBinderTest {
3332

3433
@Before
3534
fun setUp() {
36-
MockKAnnotations.init(this, relaxUnitFun = true)
3735
ctx = ApplicationProvider.getApplicationContext()
3836
viewGroup = FrameLayout(ctx)
3937

40-
navContext = mockk {
38+
navContext = mockk(relaxed = true) {
4139
every { store } returns TestStore()
4240
every { styles } returns NavigationViewStyles(ctx)
4341
every { viewModel } returns mockk {

libnavui-dropin/src/test/java/com/mapbox/navigation/dropin/map/MapViewOwnerTest.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
55
import io.mockk.mockk
66
import io.mockk.spyk
77
import io.mockk.verify
8+
import org.junit.Assert.assertEquals
9+
import org.junit.Assert.assertNull
810
import org.junit.Test
911

1012
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
@@ -114,6 +116,27 @@ internal class MapViewOwnerTest {
114116
verify(exactly = 1) { observer.onDetached(mapView1) }
115117
verify(exactly = 1) { observer.onAttached(mapView2) }
116118
}
119+
120+
@Test
121+
fun `flow value is null by default`() {
122+
val sut = MapViewOwner()
123+
assertNull(sut.mapViews.value)
124+
}
125+
126+
@Test
127+
fun `flow value is chanhed when mapView is updated`() {
128+
val sut = MapViewOwner()
129+
val mapView1 = mockk<MapView>()
130+
val mapView2 = mockk<MapView>()
131+
132+
sut.updateMapView(mapView1)
133+
134+
assertEquals(mapView1, sut.mapViews.value)
135+
136+
sut.updateMapView(mapView2)
137+
138+
assertEquals(mapView2, sut.mapViews.value)
139+
}
117140
}
118141

119142
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)

0 commit comments

Comments
 (0)