From a5b2a0bac50d7e9dea02d9f2319c1cb76daecd1a Mon Sep 17 00:00:00 2001 From: Abhishek Kejriwal Date: Tue, 16 Mar 2021 10:48:26 -0700 Subject: [PATCH] add route overview --- LICENSE.md | 35 ++++++ libnavui-maps/api/current.txt | 14 +++ libnavui-maps/build.gradle | 6 + .../camera/view/MapboxRouteOverviewButton.kt | 113 ++++++++++++++++++ .../res/drawable/mapbox_ic_route_overview.xml | 19 +++ .../layout/mapbox_route_overview_layout.xml | 37 ++++++ libnavui-maps/src/main/res/values/attrs.xml | 7 ++ libnavui-maps/src/main/res/values/colors.xml | 4 + libnavui-maps/src/main/res/values/strings.xml | 4 + libnavui-maps/src/main/res/values/styles.xml | 6 + .../main/res/drawable/mapbox_bg_circle.xml | 5 + .../src/main/res/values/dimens.xml | 1 + .../ui/utils/internal/extensions/ViewEx.kt | 99 +++++++++++++++ .../examples/core/MapboxNavigationActivity.kt | 6 + .../res/layout/layout_activity_navigation.xml | 10 ++ 15 files changed, 366 insertions(+) create mode 100644 libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/camera/view/MapboxRouteOverviewButton.kt create mode 100644 libnavui-maps/src/main/res/drawable/mapbox_ic_route_overview.xml create mode 100644 libnavui-maps/src/main/res/layout/mapbox_route_overview_layout.xml create mode 100644 libnavui-maps/src/main/res/values/attrs.xml create mode 100644 libnavui-maps/src/main/res/values/colors.xml create mode 100644 libnavui-maps/src/main/res/values/strings.xml create mode 100644 libnavui-maps/src/main/res/values/styles.xml create mode 100644 libnavui-resources/src/main/res/drawable/mapbox_bg_circle.xml create mode 100644 libnavui-util/src/main/java/com/mapbox/navigation/ui/utils/internal/extensions/ViewEx.kt diff --git a/LICENSE.md b/LICENSE.md index ce2b5d9ccff..8a28fda7d05 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -947,6 +947,12 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== +Mapbox Navigation uses portions of the Android Support Library Coordinator Layout (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). +URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + Mapbox Navigation uses portions of the Android Support Library core utils (The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.). URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1013,6 +1019,12 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== +Mapbox Navigation uses portions of the Android Support RecyclerView v7. +URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + Mapbox Navigation uses portions of the Android Support VectorDrawable. URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1025,6 +1037,18 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== +Mapbox Navigation uses portions of the Android Transition Support Library. +URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox Navigation uses portions of the AndroidX Widget ViewPager2. +URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + Mapbox Navigation uses portions of the Core Kotlin Extensions (Kotlin extensions for 'core' artifact). URL: [https://developer.android.com/jetpack/androidx](https://developer.android.com/jetpack/androidx) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1162,6 +1186,12 @@ License: [BSD](https://opensource.org/licenses/BSD-2-Clause) =========================================================================== +Mapbox Navigation uses portions of the Material Components for Android (Material Components for Android is a static library that you can add to your Android application in order to use APIs that provide implementations of the Material Design specification. Compatible on devices running API 14 or later.). +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + Mapbox Navigation uses portions of the OkHttp. License: [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1256,6 +1286,11 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== +Mapbox Navigation uses portions of the viewbinding. +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + #### Navigation UI Util SDK module diff --git a/libnavui-maps/api/current.txt b/libnavui-maps/api/current.txt index 3fee7989478..164c2befcf4 100644 --- a/libnavui-maps/api/current.txt +++ b/libnavui-maps/api/current.txt @@ -257,6 +257,20 @@ package com.mapbox.navigation.ui.maps.camera.utils { } +package com.mapbox.navigation.ui.maps.camera.view { + + public final class MapboxRouteOverviewButton extends androidx.constraintlayout.widget.ConstraintLayout { + ctor public MapboxRouteOverviewButton(android.content.Context context, android.util.AttributeSet? attrs = null, int defStyleAttr = 0); + ctor public MapboxRouteOverviewButton(android.content.Context context, android.util.AttributeSet? attrs = null); + ctor public MapboxRouteOverviewButton(android.content.Context context); + method public void showTextAndExtend(long duration); + method public void updateStyle(@StyleRes int style); + field public static final int EXTEND_TO_WIDTH = 450; // 0x1c2 + field public static final long SLIDE_DURATION = 300L; // 0x12cL + } + +} + package com.mapbox.navigation.ui.maps.internal.route.line { public final class MapboxRouteLineUtils { diff --git a/libnavui-maps/build.gradle b/libnavui-maps/build.gradle index 613cbab8b38..81fc027e930 100644 --- a/libnavui-maps/build.gradle +++ b/libnavui-maps/build.gradle @@ -27,6 +27,10 @@ android { consumerProguardFiles 'proguard-rules.pro', "${rootDir}/proguard/proguard-project.pro" } + buildFeatures { + viewBinding true + } + testOptions { unitTests.returnDefaultValues = true unitTests.includeAndroidResources = true @@ -35,6 +39,7 @@ android { dependencies { api project(":libnavui-base") + api project(":libnavui-resources") api dependenciesList.mapboxMapSdk api dependenciesList.mapboxSdkTurf @@ -42,6 +47,7 @@ dependencies { implementation dependenciesList.androidXAppCompat implementation dependenciesList.androidXCardView implementation dependenciesList.androidXConstraintLayout + implementation dependenciesList.materialDesign implementation dependenciesList.kotlinStdLib implementation dependenciesList.timber diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/camera/view/MapboxRouteOverviewButton.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/camera/view/MapboxRouteOverviewButton.kt new file mode 100644 index 00000000000..40c02daac14 --- /dev/null +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/camera/view/MapboxRouteOverviewButton.kt @@ -0,0 +1,113 @@ +package com.mapbox.navigation.ui.maps.camera.view + +import android.content.Context +import android.content.res.TypedArray +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.annotation.StyleRes +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat +import com.mapbox.navigation.ui.maps.R +import com.mapbox.navigation.ui.maps.databinding.MapboxRouteOverviewLayoutBinding +import com.mapbox.navigation.ui.utils.internal.extensions.afterMeasured +import com.mapbox.navigation.ui.utils.internal.extensions.extend +import com.mapbox.navigation.ui.utils.internal.extensions.shrink +import com.mapbox.navigation.ui.utils.internal.extensions.slideWidth + +/** + * Default view to allow user to switch to route overview mode. + * @property textWidth Int + * @property binding MapboxRouteOverviewLayoutBinding + * @constructor + */ +class MapboxRouteOverviewButton @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : ConstraintLayout(context, attrs, defStyleAttr) { + + private var textWidth = 0 + private var isAnimationRunning = false + private val binding = MapboxRouteOverviewLayoutBinding.inflate( + LayoutInflater.from(context), + this + ) + + init { + initAttributes(attrs) + } + + override fun onFinishInflate() { + super.onFinishInflate() + binding.routeOverviewText.afterMeasured { + textWidth = width + } + } + + /** + * Allows you to change the style of [MapboxRouteOverviewButton]. + * @param style Int + */ + fun updateStyle(@StyleRes style: Int) { + val typedArray = context.obtainStyledAttributes( + style, + R.styleable.MapboxRouteOverviewButton + ) + applyAttributes(typedArray) + typedArray.recycle() + } + + /** + * Invoke the function to show optional text associated with the view. + * @param duration for the view to be in the extended mode before it starts to shrink. + */ + fun showTextAndExtend(duration: Long) { + if (!isAnimationRunning) { + isAnimationRunning = true + val extendToWidth = EXTEND_TO_WIDTH * context.resources.displayMetrics.density + val animator = getAnimator(textWidth, extendToWidth.toInt()) + binding.routeOverviewText.extend(animator) { + binding.routeOverviewText.text = context.getString(R.string.mapbox_route_overview) + postDelayed( + { + val endAnimator = getAnimator(extendToWidth.toInt(), textWidth) + binding.routeOverviewText.shrink(endAnimator) { + binding.routeOverviewText.text = "" + isAnimationRunning = false + } + }, + duration + ) + } + } + } + + private fun initAttributes(attrs: AttributeSet?) { + val typedArray = context.obtainStyledAttributes( + attrs, + R.styleable.MapboxRouteOverviewButton + ) + applyAttributes(typedArray) + typedArray.recycle() + } + + private fun applyAttributes(typedArray: TypedArray) { + ContextCompat.getDrawable( + context, + typedArray.getResourceId( + R.styleable.MapboxRouteOverviewButton_overviewButtonDrawable, + R.drawable.mapbox_ic_route_overview + ) + ).also { + binding.routeOverviewIcon.setImageDrawable(it) + } + } + + private fun getAnimator(from: Int, to: Int) = + binding.routeOverviewText.slideWidth(from, to, SLIDE_DURATION) + + private companion object { + const val SLIDE_DURATION = 300L + const val EXTEND_TO_WIDTH = 175 + } +} diff --git a/libnavui-maps/src/main/res/drawable/mapbox_ic_route_overview.xml b/libnavui-maps/src/main/res/drawable/mapbox_ic_route_overview.xml new file mode 100644 index 00000000000..91fac99c434 --- /dev/null +++ b/libnavui-maps/src/main/res/drawable/mapbox_ic_route_overview.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/libnavui-maps/src/main/res/layout/mapbox_route_overview_layout.xml b/libnavui-maps/src/main/res/layout/mapbox_route_overview_layout.xml new file mode 100644 index 00000000000..7c6ef6ba78e --- /dev/null +++ b/libnavui-maps/src/main/res/layout/mapbox_route_overview_layout.xml @@ -0,0 +1,37 @@ + + + + + + + \ No newline at end of file diff --git a/libnavui-maps/src/main/res/values/attrs.xml b/libnavui-maps/src/main/res/values/attrs.xml new file mode 100644 index 00000000000..1db524d817c --- /dev/null +++ b/libnavui-maps/src/main/res/values/attrs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/libnavui-maps/src/main/res/values/colors.xml b/libnavui-maps/src/main/res/values/colors.xml new file mode 100644 index 00000000000..5ba7c2140ee --- /dev/null +++ b/libnavui-maps/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + @color/colorOnSurface + \ No newline at end of file diff --git a/libnavui-maps/src/main/res/values/strings.xml b/libnavui-maps/src/main/res/values/strings.xml new file mode 100644 index 00000000000..4ff65702987 --- /dev/null +++ b/libnavui-maps/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Overview + \ No newline at end of file diff --git a/libnavui-maps/src/main/res/values/styles.xml b/libnavui-maps/src/main/res/values/styles.xml new file mode 100644 index 00000000000..72f6d8a01cc --- /dev/null +++ b/libnavui-maps/src/main/res/values/styles.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/libnavui-resources/src/main/res/drawable/mapbox_bg_circle.xml b/libnavui-resources/src/main/res/drawable/mapbox_bg_circle.xml new file mode 100644 index 00000000000..aa7a2b1770a --- /dev/null +++ b/libnavui-resources/src/main/res/drawable/mapbox_bg_circle.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/libnavui-resources/src/main/res/values/dimens.xml b/libnavui-resources/src/main/res/values/dimens.xml index eb86ba9afcb..b4e437e4430 100644 --- a/libnavui-resources/src/main/res/values/dimens.xml +++ b/libnavui-resources/src/main/res/values/dimens.xml @@ -20,6 +20,7 @@ 36dp 48dp 54dp + 56dp 64dp 72dp 96dp diff --git a/libnavui-util/src/main/java/com/mapbox/navigation/ui/utils/internal/extensions/ViewEx.kt b/libnavui-util/src/main/java/com/mapbox/navigation/ui/utils/internal/extensions/ViewEx.kt new file mode 100644 index 00000000000..dc499138adb --- /dev/null +++ b/libnavui-util/src/main/java/com/mapbox/navigation/ui/utils/internal/extensions/ViewEx.kt @@ -0,0 +1,99 @@ +@file:JvmName("ViewEx") + +package com.mapbox.navigation.ui.utils.internal.extensions + +import android.animation.Animator +import android.animation.AnimatorSet +import android.animation.ValueAnimator +import android.view.View +import android.view.ViewTreeObserver +import android.view.animation.AccelerateDecelerateInterpolator + +fun View.afterMeasured(f: View.() -> Unit) { + viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + if (measuredWidth > 0 && measuredHeight > 0) { + viewTreeObserver.removeOnGlobalLayoutListener(this) + f() + } + } + }) +} + +fun View.slideWidth(fromWidth: Int, toWidth: Int, duration: Long): ValueAnimator { + return ValueAnimator + .ofInt(fromWidth, toWidth) + .setDuration(duration).also { + it.addUpdateListener { animation -> + val value = animation.animatedValue as Int + layoutParams.width = value + requestLayout() + } + } +} + +fun View.slideHeight(fromHeight: Int, toHeight: Int, duration: Long): ValueAnimator { + return ValueAnimator + .ofInt(fromHeight, toHeight) + .setDuration(duration).also { + it.addUpdateListener { animation -> + val value = animation.animatedValue as Int + layoutParams.height = value + requestLayout() + } + } +} + +fun View.extend( + animator: ValueAnimator, + doOnEnd: () -> Unit +) { + val set = AnimatorSet() + set.play(animator) + set.interpolator = AccelerateDecelerateInterpolator() + set.addListener(object : Animator.AnimatorListener { + override fun onAnimationStart(animation: Animator?) { + // No implementation + } + + override fun onAnimationEnd(animation: Animator?) { + doOnEnd() + } + + override fun onAnimationCancel(animation: Animator?) { + // No implementation + } + + override fun onAnimationRepeat(animation: Animator?) { + // No implementation + } + }) + set.start() +} + +fun View.shrink( + animator: ValueAnimator, + doOnStart: () -> Unit +) { + val set = AnimatorSet() + set.play(animator) + set.interpolator = AccelerateDecelerateInterpolator() + set.addListener(object : Animator.AnimatorListener { + override fun onAnimationStart(animation: Animator?) { + doOnStart() + } + + override fun onAnimationEnd(animation: Animator?) { + // No implementation + } + + override fun onAnimationCancel(animation: Animator?) { + // No implementation + } + + override fun onAnimationRepeat(animation: Animator?) { + // No implementation + } + }) + set.start() +} diff --git a/test-app/src/main/java/com/mapbox/navigation/examples/core/MapboxNavigationActivity.kt b/test-app/src/main/java/com/mapbox/navigation/examples/core/MapboxNavigationActivity.kt index 0cce3d111ac..4e432566dc8 100644 --- a/test-app/src/main/java/com/mapbox/navigation/examples/core/MapboxNavigationActivity.kt +++ b/test-app/src/main/java/com/mapbox/navigation/examples/core/MapboxNavigationActivity.kt @@ -398,13 +398,19 @@ class MapboxNavigationActivity : binding.start.setOnClickListener { startNavigation() binding.start.visibility = GONE + binding.routeOverview.visibility = VISIBLE binding.tripProgressCard.visibility = VISIBLE } binding.stop.setOnClickListener { stopNavigation() binding.maneuverView.visibility = GONE + binding.routeOverview.visibility = GONE binding.tripProgressCard.visibility = GONE } + binding.routeOverview.setOnClickListener { + binding.routeOverview.showTextAndExtend(2000L) + updateCameraToOverview() + } } @SuppressLint("MissingPermission") diff --git a/test-app/src/main/res/layout/layout_activity_navigation.xml b/test-app/src/main/res/layout/layout_activity_navigation.xml index 8c68f4908ea..e632ee6def3 100644 --- a/test-app/src/main/res/layout/layout_activity_navigation.xml +++ b/test-app/src/main/res/layout/layout_activity_navigation.xml @@ -64,4 +64,14 @@ android:visibility="gone" /> + +