Compare commits
5 Commits
e5c74f6fa2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b8abbd4eb | ||
|
|
d0a07e1315 | ||
|
|
ddae6f2189 | ||
|
|
01a4eb7fca | ||
|
|
8673380b9e |
@@ -14,8 +14,8 @@ android {
|
||||
applicationId = "com.kouros.navigation"
|
||||
minSdk = 33
|
||||
targetSdk = 36
|
||||
versionCode = 13
|
||||
versionName = "0.1.3.13"
|
||||
versionCode = 14
|
||||
versionName = "0.1.3.14"
|
||||
base.archivesName = "navi-$versionName"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
BIN
app/src/main/ic_launcher-playstore.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
@@ -41,12 +41,9 @@ import com.google.android.gms.location.LocationServices
|
||||
import com.kouros.navigation.MainApplication.Companion.navigationViewModel
|
||||
import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE
|
||||
import com.kouros.navigation.data.Constants.homeLocation
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.data.valhalla.ValhallaRepository
|
||||
import com.kouros.navigation.model.MockLocation
|
||||
import com.kouros.navigation.model.RouteModel
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
import com.kouros.navigation.ui.theme.NavigationTheme
|
||||
import com.kouros.navigation.utils.bearing
|
||||
import com.kouros.navigation.utils.calculateZoom
|
||||
@@ -114,13 +111,16 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
|
||||
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
|
||||
fusedLocationClient.lastLocation
|
||||
.addOnSuccessListener { location : android.location.Location? ->
|
||||
if (useMock) {
|
||||
mock = MockLocation(locationManager)
|
||||
mock.setMockLocation(
|
||||
homeLocation.latitude,
|
||||
homeLocation.longitude
|
||||
location?.latitude ?: homeLocation.latitude,
|
||||
location?.longitude ?: homeLocation.longitude
|
||||
)
|
||||
}
|
||||
}
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
CheckPermissionScreen()
|
||||
@@ -165,11 +165,6 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
val step: StepData? by stepData.observeAsState()
|
||||
val nextStep: StepData? by nextStepData.observeAsState()
|
||||
|
||||
fun openSheet() {
|
||||
scope.launch { scaffoldState.bottomSheetState.expand() }
|
||||
}
|
||||
|
||||
fun closeSheet() {
|
||||
scope.launch {
|
||||
scaffoldState.bottomSheetState.partialExpand()
|
||||
@@ -236,13 +231,13 @@ class MainActivity : ComponentActivity() {
|
||||
if (isNavigating()) {
|
||||
updateLocation(currentLocation, navigationViewModel)
|
||||
stepData.value = currentStep()
|
||||
if (route.currentManeuverIndex + 1 <= route.maneuvers.size) {
|
||||
if (route.currentStep + 1 <= legs.steps.size) {
|
||||
nextStepData.value = nextStep()
|
||||
}
|
||||
if (routeState.maneuverType == 39
|
||||
&& leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE
|
||||
) {
|
||||
stopNavigation()
|
||||
// stopNavigation()
|
||||
routeState = routeState.copy(arrived = true)
|
||||
routeData.value = ""
|
||||
}
|
||||
@@ -302,20 +297,21 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun simulate() = GlobalScope.async {
|
||||
for ((_, loc) in routeModel.route.waypoints.withIndex()) {
|
||||
if (routeModel.isNavigating()) {
|
||||
mock.setMockLocation(loc[1], loc[0])
|
||||
delay(500L) //
|
||||
for ((index, step) in routeModel.legs.steps.withIndex()) {
|
||||
for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
||||
mock.setMockLocation(waypoint[1], waypoint[0])
|
||||
delay(600L) //
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
for ((index, loc) in routeModel.route.waypoints.withIndex()) {
|
||||
if (index > 300) {
|
||||
routeModel.updateLocation(location(loc[0], loc[1]), navigationViewModel)
|
||||
for ((index, step) in routeModel.legs.steps.withIndex()) {
|
||||
println("${step.maneuver.waypoints.size}")
|
||||
for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
||||
routeModel.updateLocation(location(waypoint[0], waypoint[1]), navigationViewModel)
|
||||
routeModel.currentStep()
|
||||
if (routeModel.route.currentManeuverIndex + 1 <= routeModel.route.maneuvers.size) {
|
||||
if (index + 1 <= routeModel.legs.steps.size) {
|
||||
nextStepData.value = routeModel.nextStep()
|
||||
}
|
||||
println(routeModel.routeState.maneuverType)
|
||||
|
||||
@@ -55,7 +55,7 @@ fun NavigationSheet(
|
||||
simulateNavigation()
|
||||
}) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.assistant_navigation_48px),
|
||||
painter = painterResource(id = R.drawable.navigation_48px),
|
||||
"Simulate",
|
||||
modifier = Modifier.size(24.dp, 24.dp),
|
||||
)
|
||||
|
||||
@@ -151,7 +151,7 @@ fun SearchBar(
|
||||
SearchBarDefaults.InputField(
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_search_black36dp),
|
||||
painter = painterResource(id = R.drawable.search_48px),
|
||||
"Search",
|
||||
modifier = Modifier.size(24.dp, 24.dp),
|
||||
)
|
||||
|
||||
19
app/src/main/res/xml/automotive_app_desc.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<automotiveApp>
|
||||
<uses name="template" />
|
||||
</automotiveApp>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
4
automotive/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Navigation</string>
|
||||
</resources>
|
||||
19
automotive/src/main/res/xml/automotive_app_desc.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<automotiveApp>
|
||||
<uses name="template" />
|
||||
</automotiveApp>
|
||||
18
automotive/src/main/res/xml/file_provider_paths.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<paths>
|
||||
<files-path name="res" path="/res"/>
|
||||
</paths>
|
||||
BIN
common/car/src/main/ic_launcher-playstore.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
@@ -300,7 +300,7 @@ class SurfaceRenderer(
|
||||
with(routeModel) {
|
||||
routeData.value = route.routeGeoJson
|
||||
centerLocation = route.centerLocation
|
||||
previewDistance = route.distance
|
||||
previewDistance = route.summary!!.distance
|
||||
}
|
||||
updateCameraPosition(
|
||||
0.0,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.kouros.navigation.car.map
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.location.Location
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.Canvas
|
||||
@@ -15,6 +16,7 @@ import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.drawscope.scale
|
||||
@@ -164,6 +166,7 @@ fun AmenityLayer(routeData: String?) {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BuildingLayer(tiles: Source) {
|
||||
Anchor.Replace("building-3d") {
|
||||
@@ -177,7 +180,13 @@ fun BuildingLayer(tiles: Source) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DrawNavigationImages(padding: PaddingValues, speed: Float?, maxSpeed: Int, width: Int, height: Int) {
|
||||
fun DrawNavigationImages(
|
||||
padding: PaddingValues,
|
||||
speed: Float?,
|
||||
maxSpeed: Int,
|
||||
width: Int,
|
||||
height: Int
|
||||
) {
|
||||
NavigationImage(padding, width, height)
|
||||
CurrentSpeed(width, height, speed)
|
||||
if (speed != null && maxSpeed > 0 && (speed * 3.6) > maxSpeed) {
|
||||
@@ -187,7 +196,7 @@ fun DrawNavigationImages(padding: PaddingValues, speed: Float?, maxSpeed: Int, w
|
||||
|
||||
@Composable
|
||||
fun NavigationImage(padding: PaddingValues, width: Int, height: Int) {
|
||||
val imageSize = (height / 6)
|
||||
val imageSize = (height / 8)
|
||||
val color = remember { NavigationColor }
|
||||
Box(contentAlignment = Alignment.Center, modifier = Modifier.padding(padding)) {
|
||||
Canvas(
|
||||
@@ -195,14 +204,15 @@ fun NavigationImage(padding: PaddingValues, width: Int, height: Int) {
|
||||
.size(imageSize.dp, imageSize.dp)
|
||||
) {
|
||||
scale(scaleX = 1f, scaleY = 0.7f) {
|
||||
drawCircle(Color.DarkGray.copy(alpha = 0.2f))
|
||||
drawCircle(Color.DarkGray.copy(alpha = 0.3f))
|
||||
}
|
||||
}
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.navigation),
|
||||
painter = painterResource(id = R.drawable.navigation_48px),
|
||||
"Navigation",
|
||||
tint = color.copy(alpha = 1f),
|
||||
modifier = Modifier.size(imageSize.dp, imageSize.dp),
|
||||
tint = color.copy(alpha = 0.7f),
|
||||
modifier = Modifier.size(imageSize.dp, imageSize.dp)
|
||||
.scale(scaleX = 1f, scaleY = 0.7f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ class RouteCarModel() : RouteModel() {
|
||||
|
||||
val dismissAction: Action = createToastAction(
|
||||
carContext,
|
||||
R.string.speed_camera, R.string.exit_action_title,
|
||||
R.string.exit_action_title, R.string.exit_action_title,
|
||||
FLAG_DEFAULT
|
||||
)
|
||||
|
||||
|
||||
@@ -34,7 +34,9 @@ import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.nominatim.SearchResult
|
||||
import com.kouros.navigation.data.overpass.Elements
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
import com.kouros.navigation.utils.bearing
|
||||
import com.kouros.navigation.utils.location
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
class NavigationScreen(
|
||||
carContext: CarContext,
|
||||
@@ -294,7 +296,7 @@ class NavigationScreen(
|
||||
CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
carContext,
|
||||
R.drawable.assistant_navigation_48px
|
||||
R.drawable.navigation_48px
|
||||
)
|
||||
)
|
||||
.build()
|
||||
@@ -328,7 +330,7 @@ class NavigationScreen(
|
||||
|
||||
private fun searchAction(): Action {
|
||||
return Action.Builder()
|
||||
.setIcon(routeModel.createCarIcon(carContext, R.drawable.ic_search_black36dp))
|
||||
.setIcon(routeModel.createCarIcon(carContext, R.drawable.search_48px))
|
||||
.setOnClickListener {
|
||||
startSearchScreen()
|
||||
}
|
||||
@@ -337,7 +339,7 @@ class NavigationScreen(
|
||||
|
||||
private fun settingsAction(): Action {
|
||||
return Action.Builder()
|
||||
.setIcon(routeModel.createCarIcon(carContext, R.drawable.settings_24px))
|
||||
.setIcon(routeModel.createCarIcon(carContext, R.drawable.settings_applications_48px))
|
||||
.setOnClickListener {
|
||||
screenManager.push(SettingsScreen(carContext))
|
||||
}
|
||||
@@ -490,7 +492,12 @@ class NavigationScreen(
|
||||
}
|
||||
val sortedList = updatedCameras.sortedWith(compareBy { it.distance })
|
||||
val camera = sortedList.first()
|
||||
if (camera.distance < 80) {
|
||||
val bearingSpeedCamera = location.bearingTo(location(camera.lon!!, camera.lat!!))
|
||||
val bearingRoute = surfaceRenderer.lastLocation.bearingTo(location)
|
||||
|
||||
if (camera.distance < 80
|
||||
&& (bearingSpeedCamera.absoluteValue - bearingRoute.absoluteValue).absoluteValue < 15.0
|
||||
) {
|
||||
routeModel.showSpeedCamera(carContext, camera.distance, camera.tags.maxspeed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ class PlaceListScreen(
|
||||
.setIcon(
|
||||
RouteCarModel().createCarIcon(
|
||||
carContext,
|
||||
R.drawable.ic_delete_foreground
|
||||
R.drawable.ic_pan_24
|
||||
)
|
||||
)
|
||||
.setOnClickListener {
|
||||
|
||||
@@ -89,7 +89,7 @@ class RoutePreviewScreen(
|
||||
)
|
||||
.build()
|
||||
|
||||
val message = if (routeModel.isNavigating() && routeModel.route.waypoints.isNotEmpty()) {
|
||||
val message = if (routeModel.isNavigating() && routeModel.route.waypoints!!.isNotEmpty()) {
|
||||
createRouteText()
|
||||
} else {
|
||||
CarText.Builder("Wait")
|
||||
@@ -143,7 +143,7 @@ class RoutePreviewScreen(
|
||||
.getString(R.string.favorites)
|
||||
else
|
||||
carContext.getString(
|
||||
R.string.not_favorite_toast_msg
|
||||
R.string.favorites
|
||||
),
|
||||
CarToast.LENGTH_SHORT
|
||||
)
|
||||
@@ -165,7 +165,7 @@ class RoutePreviewScreen(
|
||||
CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
carContext,
|
||||
R.drawable.ic_delete_foreground
|
||||
R.drawable.ic_pan_24
|
||||
)
|
||||
)
|
||||
.build()
|
||||
@@ -173,8 +173,8 @@ class RoutePreviewScreen(
|
||||
.build()
|
||||
|
||||
private fun createRouteText(): CarText {
|
||||
val time = routeModel.route.summary.time
|
||||
val length = BigDecimal(routeModel.route.distance).setScale(1, RoundingMode.HALF_EVEN)
|
||||
val time = routeModel.route.summary!!.duration
|
||||
val length = BigDecimal(routeModel.route.summary!!.distance).setScale(1, RoundingMode.HALF_EVEN)
|
||||
val firstRoute = SpannableString(" \u00b7 $length km")
|
||||
firstRoute.setSpan(
|
||||
DurationSpan.create(time.toLong()), 0, 1, 0
|
||||
|
||||
@@ -137,7 +137,7 @@ class SearchScreen(
|
||||
R.drawable.ic_favorite_white_24dp
|
||||
}
|
||||
else -> {
|
||||
R.drawable.navigation
|
||||
R.drawable.navigation_48px
|
||||
}
|
||||
}
|
||||
return CarIcon.Builder(
|
||||
|
||||
10
common/car/src/main/res/drawable/navigation_48px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M190,840L160,810L480,80L800,810L770,840L480,708L190,840Z"/>
|
||||
</vector>
|
||||
@@ -179,3 +179,6 @@ object Constants {
|
||||
}
|
||||
|
||||
|
||||
enum class RouteEngine {
|
||||
VALHALLA, OSRM, GRAPHHOPPER
|
||||
}
|
||||
@@ -40,7 +40,7 @@ abstract class NavigationRepository {
|
||||
val route = getRoute(currentLocation, location, searchFilter)
|
||||
val routeModel = RouteModel()
|
||||
routeModel.startNavigation(route)
|
||||
return routeModel.route.distance
|
||||
return routeModel.route.summary!!.distance
|
||||
}
|
||||
|
||||
fun searchPlaces(search: String, location: Location) : String {
|
||||
|
||||
@@ -2,125 +2,97 @@ package com.kouros.navigation.data
|
||||
|
||||
import android.location.Location
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.kouros.navigation.data.valhalla.Maneuvers
|
||||
import com.kouros.navigation.data.valhalla.Summary
|
||||
import com.kouros.navigation.data.valhalla.Trip
|
||||
import com.kouros.navigation.data.valhalla.ValhallaJson
|
||||
import com.kouros.navigation.data.osrm.OsrmResponse
|
||||
import com.kouros.navigation.data.osrm.OsrmRoute
|
||||
import com.kouros.navigation.data.route.Leg
|
||||
import com.kouros.navigation.data.route.Step
|
||||
import com.kouros.navigation.data.route.Summary
|
||||
import com.kouros.navigation.data.valhalla.ValhallaResponse
|
||||
import com.kouros.navigation.data.valhalla.ValhallaRoute
|
||||
import com.kouros.navigation.utils.GeoUtils.createCenterLocation
|
||||
import com.kouros.navigation.utils.GeoUtils.createLineStringCollection
|
||||
import com.kouros.navigation.utils.GeoUtils.decodePolyline
|
||||
import com.kouros.navigation.utils.location
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import org.maplibre.geojson.Point
|
||||
|
||||
|
||||
data class Route(
|
||||
/**
|
||||
* A Leg is a route between only two waypoints.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
val maneuvers: List<Maneuvers>,
|
||||
|
||||
/**
|
||||
* The distance traveled from origin to destination.
|
||||
*
|
||||
* @return a double number with unit meters
|
||||
* @since 1.0.0
|
||||
*/
|
||||
val distance: Double,
|
||||
|
||||
/**
|
||||
* List of [List<Double>] objects. Each `waypoint` is an input coordinate
|
||||
* snapped to the road and path network. The `waypoint` appear in the list in the order of
|
||||
* the input coordinates.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
val waypoints: List<List<Double>>,
|
||||
|
||||
/**
|
||||
* List of [List<Point>] objects. Each `Point` is an input coordinate
|
||||
* snapped to the road and path network. The `waypoint` appear in the list in the order of
|
||||
* the input coordinates.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
val pointLocations: List<Point>,
|
||||
|
||||
val summary: Summary,
|
||||
|
||||
val trip: Trip,
|
||||
|
||||
val time: Double,
|
||||
|
||||
val routeGeoJson: String,
|
||||
|
||||
val currentManeuverIndex : Int,
|
||||
|
||||
val centerLocation: Location
|
||||
|
||||
val routeEngine: Int,
|
||||
val summary: Summary?,
|
||||
val legs: List<Leg>?,
|
||||
val routeGeoJson: String = "",
|
||||
val centerLocation : Location = location(0.0, 0.0),
|
||||
var currentStep : Int = 0,
|
||||
val waypoints: List<List<Double>>?,
|
||||
) {
|
||||
|
||||
class Builder {
|
||||
private lateinit var maneuvers: List<Maneuvers>
|
||||
private var distance: Double = 0.0
|
||||
private var time: Double = 0.0
|
||||
private lateinit var waypoints: List<List<Double>>
|
||||
private lateinit var pointLocations: List<Point>
|
||||
private lateinit var summary: Summary
|
||||
private lateinit var trip: Trip
|
||||
private var routeGeoJson = ""
|
||||
private var centerLocation = location(0.0, 0.0)
|
||||
data class Builder (
|
||||
|
||||
var routeEngine : Int = RouteEngine.VALHALLA.ordinal,
|
||||
var summary: Summary? = null,
|
||||
var legs: List<Leg>? = null,
|
||||
var routeGeoJson: String = "",
|
||||
var centerLocation: Location = location(0.0, 0.0),
|
||||
var waypoints : List<List<Double>>? = null,) {
|
||||
|
||||
fun routeType (routeEngine: Int) = apply {this.routeEngine = routeEngine }
|
||||
fun summary(summary: Summary) = apply { this.summary = summary }
|
||||
fun legs(legs: List<Leg>) = apply { this.legs = legs }
|
||||
fun routeGeoJson(routeGeoJson: String) = apply {
|
||||
this.routeGeoJson = routeGeoJson
|
||||
centerLocation = createCenterLocation(routeGeoJson)
|
||||
}
|
||||
fun waypoints(waypoints: List<List<Double>>) = apply { this.waypoints = waypoints }
|
||||
fun route(route: String) = apply {
|
||||
if (route.isNotEmpty() && route != "[]") {
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val routeJson = gson.fromJson(route, ValhallaJson::class.java)
|
||||
trip = routeJson.trip
|
||||
if (routeEngine == RouteEngine.VALHALLA.ordinal) {
|
||||
val jsonObject: Map<String, JsonElement> = Json.parseToJsonElement(route).jsonObject
|
||||
val routeJson = gson.fromJson(jsonObject["trip"].toString(), ValhallaResponse::class.java)
|
||||
ValhallaRoute().mapJsonToValhalla(routeJson, this)
|
||||
} else {
|
||||
val osrmJson = gson.fromJson(route, OsrmResponse::class.java)
|
||||
OsrmRoute().mapToOsrm(osrmJson, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun build(): Route {
|
||||
maneuvers = trip.legs[0].maneuvers
|
||||
summary = trip.summary
|
||||
distance = summary.length
|
||||
time = summary.time
|
||||
waypoints = decodePolyline(trip.legs[0].shape)
|
||||
val points = mutableListOf<Point>()
|
||||
for (loc in waypoints) {
|
||||
val point = Point.fromLngLat(loc[0], loc[1])
|
||||
points.add(point)
|
||||
}
|
||||
pointLocations = points
|
||||
routeGeoJson = createLineStringCollection( waypoints)
|
||||
centerLocation = createCenterLocation(routeGeoJson)
|
||||
return Route(
|
||||
maneuvers,
|
||||
distance,
|
||||
waypoints,
|
||||
pointLocations,
|
||||
summary,
|
||||
trip,
|
||||
time,
|
||||
routeGeoJson,
|
||||
0,
|
||||
centerLocation
|
||||
routeEngine = this.routeEngine,
|
||||
summary = this.summary,
|
||||
legs = this.legs,
|
||||
waypoints = this.waypoints,
|
||||
routeGeoJson = this.routeGeoJson,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun maneuverLocations(): List<Point> {
|
||||
return pointLocations
|
||||
val step = currentStep()
|
||||
val waypoints = step.maneuver.waypoints
|
||||
val points = mutableListOf<Point>()
|
||||
for (loc in waypoints) {
|
||||
val point = Point.fromLngLat(loc[0], loc[1])
|
||||
points.add(point)
|
||||
}
|
||||
return points
|
||||
}
|
||||
|
||||
fun currentManeuver(): Maneuvers {
|
||||
return maneuvers[currentManeuverIndex]
|
||||
fun currentStep(): Step {
|
||||
if (legs != null) {
|
||||
return legs.first().steps[currentStep]
|
||||
} else {
|
||||
throw IndexOutOfBoundsException("No legs available.")
|
||||
}
|
||||
}
|
||||
|
||||
fun nextManeuver(): Maneuvers {
|
||||
val nextIndex = currentManeuverIndex + 1
|
||||
return if (nextIndex < maneuvers.size) {
|
||||
maneuvers[nextIndex]
|
||||
fun nextStep(): Step {
|
||||
val nextIndex = currentStep + 1
|
||||
return if (nextIndex < legs!!.first().steps.size) {
|
||||
legs.first().steps[currentStep + 1]
|
||||
} else {
|
||||
throw IndexOutOfBoundsException("No next maneuver available.")
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.kouros.navigation.data.osrm
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
|
||||
data class OsrmJson (
|
||||
data class OsrmResponse (
|
||||
|
||||
@SerializedName("code" ) var code : String? = null,
|
||||
@SerializedName("routes" ) var routes : ArrayList<Routes> = arrayListOf(),
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.kouros.navigation.data.osrm
|
||||
|
||||
import com.kouros.navigation.data.Route
|
||||
import com.kouros.navigation.data.valhalla.ValhallaResponse
|
||||
|
||||
class OsrmRoute {
|
||||
|
||||
fun mapToOsrm(routeJson: OsrmResponse, builder: Route.Builder) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ class Overpass {
|
||||
|);
|
||||
|out body;
|
||||
""".trimMargin()
|
||||
println("way[highway](around:$radius,$linestring)")
|
||||
return overpassApi(httpURLConnection, searchQuery)
|
||||
}
|
||||
|
||||
@@ -60,7 +61,6 @@ class Overpass {
|
||||
}
|
||||
|
||||
fun overpassApi(httpURLConnection: HttpURLConnection, searchQuery: String) : List<Elements> {
|
||||
// Send the JSON we created
|
||||
val outputStreamWriter = OutputStreamWriter(httpURLConnection.outputStream)
|
||||
outputStreamWriter.write(searchQuery)
|
||||
outputStreamWriter.flush()
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.kouros.navigation.data.route
|
||||
|
||||
data class Leg(
|
||||
var steps : List<Step> = arrayListOf()
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.kouros.navigation.data.route
|
||||
|
||||
data class Maneuver(
|
||||
val bearingBefore : Int = 0,
|
||||
val bearingAfter : Int = 0,
|
||||
val type: Int = 0,
|
||||
val waypoints: List<List<Double>>,
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.kouros.navigation.data.route
|
||||
|
||||
class Step(
|
||||
var index : Int = 0,
|
||||
var waypointIndex : Int = 0,
|
||||
val maneuver: Maneuver,
|
||||
val duration: Double = 0.0,
|
||||
val distance: Double = 0.0,
|
||||
val name : String = "",
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.kouros.navigation.data.route
|
||||
|
||||
data class Summary(
|
||||
var duration : Double = 0.0,
|
||||
var distance : Double = 0.0,
|
||||
)
|
||||
@@ -2,7 +2,6 @@ package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@@ -11,7 +10,7 @@ import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
data class Legs (
|
||||
|
||||
@SerializedName("maneuvers" ) var maneuvers : ArrayList<Maneuvers> = arrayListOf(),
|
||||
@SerializedName("summary" ) var summary : Summary = Summary(),
|
||||
@SerializedName("summary" ) var summaryValhalla : SummaryValhalla = SummaryValhalla(),
|
||||
@SerializedName("shape" ) var shape : String = ""
|
||||
|
||||
)
|
||||
@@ -2,13 +2,12 @@ package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@JsonIgnoreUnknownKeys
|
||||
data class Summary (
|
||||
data class SummaryValhalla (
|
||||
|
||||
@SerializedName("has_time_restrictions" ) var hasTimeRestrictions : Boolean = false,
|
||||
@SerializedName("has_toll" ) var hasToll : Boolean = false,
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@JsonIgnoreUnknownKeys
|
||||
data class Trip (
|
||||
|
||||
@SerializedName("locations" ) var locations : ArrayList<Locations> = arrayListOf(),
|
||||
@SerializedName("legs" ) var legs : ArrayList<Legs> = arrayListOf(),
|
||||
@SerializedName("summary" ) var summary : Summary = Summary(),
|
||||
@SerializedName("status_message" ) var statusMessage : String = "",
|
||||
@SerializedName("status" ) var status : Int = 0,
|
||||
@SerializedName("units" ) var units : String = "",
|
||||
@SerializedName("language" ) var language : String = "",
|
||||
|
||||
)
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@JsonIgnoreUnknownKeys
|
||||
data class ValhallaJson (
|
||||
|
||||
@SerializedName("trip" ) var trip : Trip = Trip(),
|
||||
@SerializedName("id" ) var id : String = ""
|
||||
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@JsonIgnoreUnknownKeys
|
||||
data class ValhallaResponse(
|
||||
|
||||
@SerializedName("locations") var locations: ArrayList<Locations> = arrayListOf(),
|
||||
@SerializedName("legs") var legs: ArrayList<Legs> = arrayListOf(),
|
||||
@SerializedName("summary") var summaryValhalla: SummaryValhalla = SummaryValhalla(),
|
||||
@SerializedName("status_message") var statusMessage: String = "",
|
||||
@SerializedName("status") var status: Int = 0,
|
||||
@SerializedName("units") var units: String = "",
|
||||
@SerializedName("language") var language: String = "",
|
||||
|
||||
)
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.kouros.navigation.data.Route
|
||||
import com.kouros.navigation.data.route.Leg
|
||||
import com.kouros.navigation.data.route.Maneuver
|
||||
import com.kouros.navigation.data.route.Step
|
||||
import com.kouros.navigation.data.route.Summary
|
||||
import com.kouros.navigation.utils.GeoUtils.createLineStringCollection
|
||||
import com.kouros.navigation.utils.GeoUtils.decodePolyline
|
||||
|
||||
class ValhallaRoute {
|
||||
|
||||
fun mapJsonToValhalla(routeJson: ValhallaResponse, builder: Route.Builder) {
|
||||
val waypoints = decodePolyline(routeJson.legs[0].shape)
|
||||
val summary = Summary()
|
||||
summary.distance = routeJson.summaryValhalla.length
|
||||
summary.duration = routeJson.summaryValhalla.time
|
||||
val steps = mutableListOf<Step>()
|
||||
var stepIndex = 0
|
||||
routeJson.legs[0].maneuvers.forEach {
|
||||
val maneuver = Maneuver(
|
||||
bearingBefore = 0,
|
||||
bearingAfter = it.bearingAfter,
|
||||
type = it.type,
|
||||
waypoints =waypoints.subList(it.beginShapeIndex, it.endShapeIndex+1)
|
||||
)
|
||||
var name = ""
|
||||
if (it.streetNames != null && it.streetNames.isNotEmpty()) {
|
||||
name = it.streetNames[0]
|
||||
}
|
||||
val step = Step( index = stepIndex, name = name, distance = it.length, duration = it.time, maneuver = maneuver)
|
||||
steps.add(step)
|
||||
stepIndex += 1
|
||||
}
|
||||
val leg = Leg(steps)
|
||||
builder
|
||||
.routeType(1)
|
||||
.summary(summary)
|
||||
.routeGeoJson(createLineStringCollection(waypoints))
|
||||
.legs(listOf(leg))
|
||||
.waypoints(waypoints)
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import com.kouros.navigation.data.ManeuverType
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.Route
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.data.route.Leg
|
||||
import com.kouros.navigation.utils.location
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -24,15 +25,10 @@ open class RouteModel() {
|
||||
val destination: Place = Place(),
|
||||
val arrived: Boolean = false,
|
||||
val maneuverType: Int = 0,
|
||||
var currentShapeIndex: Int = 0,
|
||||
var distanceToStepEnd: Float = 0F,
|
||||
var beginIndex: Int = 0,
|
||||
var endIndex: Int = 0,
|
||||
val travelMessage: String = "",
|
||||
// max speed for street (maneuver)
|
||||
val lastSpeedLocation: Location = location(0.0, 0.0),
|
||||
val lastSpeedIndex: Int = 0,
|
||||
val maxSpeed: Int = 0,
|
||||
|
||||
)
|
||||
|
||||
var routeState = RouteState()
|
||||
@@ -43,6 +39,10 @@ open class RouteModel() {
|
||||
routeState = routeState.copy(route = value)
|
||||
}
|
||||
|
||||
|
||||
val legs: Leg
|
||||
get() = routeState.route!!.legs!!.first()
|
||||
|
||||
fun startNavigation(routeString: String) {
|
||||
val newRoute = Route.Builder()
|
||||
.route(routeString)
|
||||
@@ -59,40 +59,41 @@ open class RouteModel() {
|
||||
isNavigating = false,
|
||||
arrived = false,
|
||||
maneuverType = 0,
|
||||
currentShapeIndex = 0,
|
||||
distanceToStepEnd = 0F,
|
||||
beginIndex = 0,
|
||||
endIndex = 0
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun updateLocation(location: Location, viewModel: ViewModel) {
|
||||
var nearestDistance = 100000.0f
|
||||
var newShapeIndex = -1
|
||||
// find nearest waypoint and current shape index
|
||||
// start search at last shape index
|
||||
for (i in routeState.currentShapeIndex..<route.waypoints.size) {
|
||||
val waypoint = route.waypoints[i]
|
||||
val distance = location.distanceTo(location(waypoint[0], waypoint[1]))
|
||||
if (distance < nearestDistance) {
|
||||
nearestDistance = distance
|
||||
newShapeIndex = i
|
||||
}
|
||||
}
|
||||
// find maneuver
|
||||
// calculate distance to step end
|
||||
findManeuver(newShapeIndex)
|
||||
|
||||
findStep(location)
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
updateSpeedLimit(location, viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findStep(location: Location) {
|
||||
var nearestDistance = 100000.0f
|
||||
for ((index, step) in legs.steps.withIndex()) {
|
||||
if (index >= route.currentStep && nearestDistance > 0) {
|
||||
for ((wayIndex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
||||
if (wayIndex >= step.waypointIndex) {
|
||||
val distance = location.distanceTo(location(waypoint[0], waypoint[1]))
|
||||
if (distance < nearestDistance) {
|
||||
nearestDistance = distance
|
||||
route.currentStep = step.index
|
||||
step.waypointIndex = wayIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSpeedLimit(location: Location, viewModel: ViewModel) {
|
||||
// speed limit for each maneuver index
|
||||
if (routeState.lastSpeedIndex < route.currentManeuverIndex) {
|
||||
routeState = routeState.copy(lastSpeedIndex = route.currentManeuverIndex)
|
||||
// speed limit
|
||||
val distance = routeState.lastSpeedLocation.distanceTo(location)
|
||||
if (distance > 500 || routeState.lastSpeedIndex < route.currentStep) {
|
||||
routeState = routeState.copy(lastSpeedIndex = route.currentStep)
|
||||
routeState = routeState.copy(lastSpeedLocation = location)
|
||||
val elements = viewModel.getMaxSpeed(location)
|
||||
elements.forEach {
|
||||
if (it.tags.name != null && it.tags.maxspeed != null) {
|
||||
@@ -103,52 +104,30 @@ open class RouteModel() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun findManeuver(newShapeIndex: Int) {
|
||||
for (i in route.currentManeuverIndex..<route.maneuvers.size) {
|
||||
val maneuver = route.maneuvers[i]
|
||||
if (maneuver.beginShapeIndex <= newShapeIndex && maneuver.endShapeIndex >= newShapeIndex) {
|
||||
route = route.copy(currentManeuverIndex = i)
|
||||
routeState.apply {
|
||||
currentShapeIndex = newShapeIndex
|
||||
beginIndex = maneuver.beginShapeIndex
|
||||
endIndex = maneuver.endShapeIndex
|
||||
distanceToStepEnd = 0F
|
||||
// calculate shape distance to step end
|
||||
for (j in newShapeIndex + 1..maneuver.endShapeIndex) {
|
||||
val loc1 = location(route!!.waypoints[j - 1][0], route.waypoints[j - 1][1])
|
||||
val loc2 = location(route.waypoints[j][0], route.waypoints[j][1])
|
||||
distanceToStepEnd += loc1.distanceTo(loc2)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun currentStep(): StepData {
|
||||
val currentManeuver = route.currentManeuver()
|
||||
val currentStep = route.currentStep()
|
||||
// Determine if we should display the current or the next maneuver
|
||||
val distanceToNextStep = leftStepDistance()
|
||||
val isNearNextManeuver = distanceToNextStep in 0.0..NEXT_STEP_THRESHOLD
|
||||
val shouldAdvance =
|
||||
isNearNextManeuver && route.currentManeuverIndex < (route.maneuvers.size)
|
||||
isNearNextManeuver && route.currentStep < (route.legs!!.first().steps.size)
|
||||
|
||||
// Determine the maneuver type and corresponding icon
|
||||
var maneuverType = if (hasArrived(currentManeuver.type)) {
|
||||
currentManeuver.type
|
||||
var maneuverType = if (hasArrived(currentStep.maneuver.type)) {
|
||||
currentStep.maneuver.type
|
||||
} else {
|
||||
ManeuverType.None.value
|
||||
}
|
||||
// Get the single, correct maneuver for this state
|
||||
val relevantManeuver = if (shouldAdvance) {
|
||||
route.nextManeuver() // This advances the route's state
|
||||
route.nextStep() // This advances the route's state
|
||||
} else {
|
||||
route.currentManeuver()
|
||||
route.currentStep()
|
||||
}
|
||||
// Safely get the street name from the maneuver
|
||||
val streetName = relevantManeuver.streetNames?.firstOrNull() ?: ""
|
||||
val streetName = relevantManeuver.name
|
||||
if (shouldAdvance) {
|
||||
maneuverType = relevantManeuver.type
|
||||
maneuverType = relevantManeuver.maneuver.type
|
||||
}
|
||||
val maneuverIconPair = maneuverIcon(maneuverType)
|
||||
routeState = routeState.copy(maneuverType = maneuverIconPair.first)
|
||||
@@ -165,8 +144,8 @@ open class RouteModel() {
|
||||
|
||||
|
||||
fun nextStep(): StepData {
|
||||
val maneuver = route.nextManeuver()
|
||||
val maneuverType = maneuver.type
|
||||
val step = route.nextStep()
|
||||
val maneuverType = step.maneuver.type
|
||||
val distanceLeft = leftStepDistance()
|
||||
var text = ""
|
||||
|
||||
@@ -175,8 +154,8 @@ open class RouteModel() {
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
|
||||
text = maneuver.streetNames[0]
|
||||
if (step.name.isNotEmpty()) {
|
||||
text = step.name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,18 +174,16 @@ open class RouteModel() {
|
||||
|
||||
fun travelLeftTime(): Double {
|
||||
var timeLeft = 0.0
|
||||
for (i in route.currentManeuverIndex + 1..<route.maneuvers.size) {
|
||||
val maneuver = route.maneuvers[i]
|
||||
timeLeft += maneuver.time
|
||||
for (i in route.currentStep + 1..<legs.steps.size) {
|
||||
val step = legs.steps[i]
|
||||
timeLeft += step.duration
|
||||
}
|
||||
if (routeState.endIndex > 0) {
|
||||
val maneuver = route.currentManeuver()
|
||||
val curTime = maneuver.time
|
||||
val step = route.nextStep()
|
||||
val curTime = step.duration
|
||||
val percent =
|
||||
100 * (routeState.endIndex - routeState.currentShapeIndex) / (routeState.endIndex - routeState.beginIndex)
|
||||
100 * (step.maneuver.waypoints.size - step.waypointIndex) / (step.maneuver.waypoints.size)
|
||||
val time = curTime * percent / 100
|
||||
timeLeft += time
|
||||
}
|
||||
return timeLeft
|
||||
}
|
||||
|
||||
@@ -221,11 +198,11 @@ open class RouteModel() {
|
||||
|
||||
/** Returns the current [Step] left distance in m. */
|
||||
fun leftStepDistance(): Double {
|
||||
val maneuver = route.currentManeuver()
|
||||
var leftDistance = maneuver.length
|
||||
if (routeState.endIndex > 0) {
|
||||
leftDistance = (routeState.distanceToStepEnd / 1000).toDouble()
|
||||
}
|
||||
val step = route.currentStep()
|
||||
var leftDistance = step.distance
|
||||
val percent =
|
||||
100 * (step.maneuver.waypoints.size - step.waypointIndex) / (step.maneuver.waypoints.size)
|
||||
leftDistance = leftDistance * percent / 100
|
||||
// The remaining distance to the step, rounded to the nearest 10 units.
|
||||
return (leftDistance * 1000 / 10.0).roundToInt() * 10.0
|
||||
|
||||
@@ -234,18 +211,17 @@ open class RouteModel() {
|
||||
/** Returns the left distance in km. */
|
||||
fun travelLeftDistance(): Double {
|
||||
var leftDistance = 0.0
|
||||
for (i in route.currentManeuverIndex + 1..<route.maneuvers.size) {
|
||||
val maneuver = route.maneuvers[i]
|
||||
leftDistance += maneuver.length
|
||||
for (i in route.currentStep + 1..<legs.steps.size) {
|
||||
val step = route.legs!![0].steps[i]
|
||||
leftDistance += step.distance
|
||||
}
|
||||
if (routeState.endIndex > 0) {
|
||||
val maneuver = route.currentManeuver()
|
||||
val curDistance = maneuver.length
|
||||
|
||||
val step = route.currentStep()
|
||||
val curDistance = step.distance
|
||||
val percent =
|
||||
100 * (routeState.endIndex - routeState.currentShapeIndex) / (routeState.endIndex - routeState.beginIndex)
|
||||
100 * (step.maneuver.waypoints.size - step.waypointIndex) / (step.maneuver.waypoints.size)
|
||||
val time = curDistance * percent / 100
|
||||
leftDistance += time
|
||||
}
|
||||
return leftDistance
|
||||
}
|
||||
|
||||
@@ -311,7 +287,6 @@ open class RouteModel() {
|
||||
currentTurnIcon = R.drawable.ic_roundabout_ccw
|
||||
}
|
||||
}
|
||||
//routeState.maneuverType = type
|
||||
return Pair(type, currentTurnIcon)
|
||||
}
|
||||
|
||||
@@ -321,7 +296,6 @@ open class RouteModel() {
|
||||
|
||||
|
||||
fun hasArrived(type: Int): Boolean {
|
||||
// return leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE && type == ManeuverType.DestinationRight.value
|
||||
return type == ManeuverType.DestinationRight.value
|
||||
|| type == ManeuverType.Destination.value
|
||||
|| type == ManeuverType.DestinationLeft.value
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M220,408L489,408L489,180Q489,180 489,180Q489,180 489,180L220,180Q220,180 220,180Q220,180 220,180L220,408ZM160,840L160,180Q160,156 178,138Q196,120 220,120L489,120Q513,120 531,138Q549,156 549,180L549,468L614,468Q634.71,468 649.36,482.64Q664,497.29 664,518L664,737Q664,759 681.5,773.5Q699,788 722,788Q745,788 765,773.5Q785,759 785,737L785,350L770,350Q757.25,350 748.63,341.37Q740,332.75 740,320L740,230L760,230L760,180L790,180L790,230L830,230L830,180L860,180L860,230L880,230L880,320Q880,332.75 871.38,341.37Q862.75,350 850,350L835,350L835,736.69Q835,780 801,810Q767,840 721.82,840Q677.66,840 645.83,810Q614,780 614,737L614,518Q614,518 614,518Q614,518 614,518L549,518L549,840L160,840ZM337,746L425,606L372,606L372,501L285,641L337,641L337,746Z"/>
|
||||
android:pathData="M337,746L425,606L372,606L372,501L285,641L337,641L337,746ZM220,408L489,408L489,180Q489,180 489,180Q489,180 489,180L220,180Q220,180 220,180Q220,180 220,180L220,408ZM220,780L489,780L489,468L220,468L220,780ZM160,840L160,180Q160,156 178,138Q196,120 220,120L489,120Q513,120 531,138Q549,156 549,180L549,468L614,468Q634.71,468 649.36,482.64Q664,497.29 664,518L664,737Q664,759 681.5,773.5Q699,788 722,788Q745,788 765,773.5Q785,759 785,737L785,350L770,350Q757.25,350 748.63,341.37Q740,332.75 740,320L740,230L760,230L760,180L790,180L790,230L830,230L830,180L860,180L860,230L880,230L880,320Q880,332.75 871.38,341.37Q862.75,350 850,350L835,350L835,736.69Q835,780 801,810Q767,840 721.82,840Q677.66,840 645.83,810Q614,780 614,737L614,518Q614,518 614,518Q614,518 614,518L549,518L549,840L160,840ZM489,780L220,780L220,780L489,780Z"/>
|
||||
</vector>
|
||||
|
||||
26
common/data/src/main/res/drawable/ic_close_white_24dp.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright 2022 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M6.4,19 L5,17.6 10.6,12 5,6.4 6.4,5 12,10.6 17.6,5 19,6.4 13.4,12 19,17.6 17.6,19 12,13.4Z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright 2022 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,21 L10.55,19.7Q6.625,16.2 4.312,13.612Q2,11.025 2,8.15Q2,5.8 3.575,4.225Q5.15,2.65 7.5,2.65Q8.825,2.65 10,3.212Q11.175,3.775 12,4.75Q12.825,3.775 14,3.212Q15.175,2.65 16.5,2.65Q18.85,2.65 20.425,4.225Q22,5.8 22,8.15Q22,11.025 19.688,13.612Q17.375,16.2 13.45,19.7ZM12,18.3Q8.425,15.05 6.213,12.7Q4,10.35 4,8.15Q4,6.65 5,5.65Q6,4.65 7.5,4.65Q8.675,4.65 9.675,5.312Q10.675,5.975 11.05,7H12.95Q13.325,5.975 14.325,5.312Q15.325,4.65 16.5,4.65Q18,4.65 19,5.65Q20,6.65 20,8.15Q20,10.35 17.788,12.7Q15.575,15.05 12,18.3ZM12,18.3Q15.575,15.05 17.788,12.7Q20,10.35 20,8.15Q20,6.65 19,5.65Q18,4.65 16.5,4.65Q15.325,4.65 14.325,5.312Q13.325,5.975 12.95,7H11.05Q10.675,5.975 9.675,5.312Q8.675,4.65 7.5,4.65Q6,4.65 5,5.65Q4,6.65 4,8.15Q4,10.35 6.213,12.7Q8.425,15.05 12,18.3Z"/>
|
||||
</vector>
|
||||
26
common/data/src/main/res/drawable/ic_favorite_white_24dp.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright 2022 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,21 L10.55,19.7Q6.625,16.2 4.312,13.612Q2,11.025 2,8.15Q2,5.8 3.575,4.225Q5.15,2.65 7.5,2.65Q8.825,2.65 10,3.212Q11.175,3.775 12,4.75Q12.825,3.775 14,3.212Q15.175,2.65 16.5,2.65Q18.85,2.65 20.425,4.225Q22,5.8 22,8.15Q22,11.025 19.688,13.612Q17.375,16.2 13.45,19.7ZM12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475ZM12,18.3Q15.575,15.05 17.788,12.7Q20,10.35 20,8.15Q20,6.65 19,5.65Q18,4.65 16.5,4.65Q15.325,4.65 14.325,5.312Q13.325,5.975 12.95,7H11.05Q10.675,5.975 9.675,5.312Q8.675,4.65 7.5,4.65Q6,4.65 5,5.65Q4,6.65 4,8.15Q4,10.35 6.213,12.7Q8.425,15.05 12,18.3Z"/>
|
||||
</vector>
|
||||
28
common/data/src/main/res/drawable/ic_pan_24.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<!--
|
||||
Copyright 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M15.54,5.54L13.77,7.3 12,5.54 10.23,7.3 8.46,5.54 12,2zM18.46,15.54l-1.76,-1.77L18.46,12l-1.76,-1.77 1.76,-1.77L22,12zM8.46,18.46l1.77,-1.76L12,18.46l1.77,-1.76 1.77,1.76L12,22zM5.54,8.46l1.76,1.77L5.54,12l1.76,1.77 -1.76,1.77L2,12z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
|
||||
</vector>
|
||||
25
common/data/src/main/res/drawable/ic_place_white_24dp.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
Copyright 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,12c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM18,10.2C18,6.57 15.35,4 12,4s-6,2.57 -6,6.2c0,2.34 1.95,5.44 6,9.14 4.05,-3.7 6,-6.8 6,-9.14zM12,2c4.2,0 8,3.22 8,8.2 0,3.32 -2.67,7.25 -8,11.8 -5.33,-4.55 -8,-8.48 -8,-11.8C4,5.22 7.8,2 12,2z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
||||
BIN
common/data/src/main/res/drawable/ic_roundabout_ccw.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
common/data/src/main/res/drawable/ic_turn_destination.png
Normal file
|
After Width: | Height: | Size: 461 B |
BIN
common/data/src/main/res/drawable/ic_turn_name_change.png
Normal file
|
After Width: | Height: | Size: 396 B |
BIN
common/data/src/main/res/drawable/ic_turn_normal_left.png
Normal file
|
After Width: | Height: | Size: 650 B |
BIN
common/data/src/main/res/drawable/ic_turn_normal_right.png
Normal file
|
After Width: | Height: | Size: 651 B |
BIN
common/data/src/main/res/drawable/ic_turn_slight_left.png
Normal file
|
After Width: | Height: | Size: 463 B |
BIN
common/data/src/main/res/drawable/ic_turn_slight_right.png
Normal file
|
After Width: | Height: | Size: 464 B |
25
common/data/src/main/res/drawable/ic_zoom_in_24.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
Copyright 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
</vector>
|
||||
25
common/data/src/main/res/drawable/ic_zoom_out_24.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
Copyright 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,13H5v-2h14v2z"/>
|
||||
</vector>
|
||||
@@ -6,5 +6,5 @@
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M160,840L160,180Q160,156 178,138Q196,120 220,120L489,120Q513,120 531,138Q549,156 549,180L549,468L614,468Q634.63,468 649.31,482.69Q664,497.37 664,518L664,737Q664,758.68 679.5,773.34Q695,788 717,788Q739,788 754.5,773.34Q770,758.68 770,737L770,442Q759,448 747,451Q735,454 723,454Q683.52,454 656.26,426.74Q629,399.48 629,360Q629,328.39 647,303.19Q665,278 695,270L600,175L636,140L789,293Q803,307 811.5,323.5Q820,340 820,360L820,737Q820,780.26 790.18,810.13Q760.37,840 717.18,840Q674,840 644,810.13Q614,780.26 614,737L614,518Q614,518 614,518Q614,518 614,518L549,518L549,840L160,840ZM220,408L489,408L489,180Q489,180 489,180Q489,180 489,180L220,180Q220,180 220,180Q220,180 220,180L220,408ZM723,404Q741,404 754,391Q767,378 767,360Q767,342 754,329Q741,316 723,316Q705,316 692,329Q679,342 679,360Q679,378 692,391Q705,404 723,404Z"/>
|
||||
android:pathData="M160,840L160,180Q160,156 178,138Q196,120 220,120L489,120Q513,120 531,138Q549,156 549,180L549,468L614,468Q634.63,468 649.31,482.69Q664,497.37 664,518L664,737Q664,758.68 679.5,773.34Q695,788 717,788Q739,788 754.5,773.34Q770,758.68 770,737L770,442Q759,448 747,451Q735,454 723,454Q683.52,454 656.26,426.74Q629,399.48 629,360Q629,328.39 647,303.19Q665,278 695,270L600,175L636,140L789,293Q803,307 811.5,323.5Q820,340 820,360L820,737Q820,780.26 790.18,810.13Q760.37,840 717.18,840Q674,840 644,810.13Q614,780.26 614,737L614,518Q614,518 614,518Q614,518 614,518L549,518L549,840L160,840ZM220,408L489,408L489,180Q489,180 489,180Q489,180 489,180L220,180Q220,180 220,180Q220,180 220,180L220,408ZM723,404Q741,404 754,391Q767,378 767,360Q767,342 754,329Q741,316 723,316Q705,316 692,329Q679,342 679,360Q679,378 692,391Q705,404 723,404ZM220,780L489,780L489,468L220,468L220,780ZM489,780L220,780L220,780L489,780Z"/>
|
||||
</vector>
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M120,840L120,780L207,525L120,270L120,210L647,210L709,40L777,67L725,210L840,210L840,270L752,525L840,780L840,840L120,840ZM452,679L512,679L512,555L636,555L636,495L512,495L512,371L452,371L452,495L328,495L328,555L452,555L452,679Z"/>
|
||||
android:pathData="M120,840L120,780L207,525L120,270L120,210L647,210L709,40L777,67L725,210L840,210L840,270L752,525L840,780L840,840L120,840ZM452,679L512,679L512,555L636,555L636,495L512,495L512,371L452,371L452,495L328,495L328,555L452,555L452,679ZM182,780L778,780L690,525L778,270L182,270L270,525L182,780ZM480,525L480,525L480,525L480,525L480,525L480,525Z"/>
|
||||
</vector>
|
||||
|
||||
10
common/data/src/main/res/drawable/navigation_24px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M200,840L160,800L480,80L800,800L760,840L480,720L200,840ZM284,716L480,632L676,716L480,276L284,716ZM480,632L480,632L480,632L480,632Z"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/navigation_48px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M190,840L160,810L480,80L800,810L770,840L480,708L190,840ZM258,742L480,644L702,742L480,228L258,742ZM480,644L480,644L480,644L480,644Z"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/pan_tool_48px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M402,920Q375,920 350.5,907.5Q326,895 311,872L54,492L74,476Q91,461 113.5,457Q136,453 158.07,470.19L280,563L280,150Q280,137.25 288.68,128.62Q297.35,120 310.18,120Q323,120 331.5,128.62Q340,137.25 340,150L340,678L166,550L361,838Q368,849 378.5,854.5Q389,860 402,860L541,860L690,860Q728,860 754,834Q780,808 780,770L780,190Q780,177.25 788.68,168.62Q797.35,160 810.18,160Q823,160 831.5,168.62Q840,177.25 840,190L840,770Q840,833 796.5,876.5Q753,920 690,920L402,920ZM447,480L447,70Q447,57.25 455.68,48.62Q464.35,40 477.18,40Q490,40 498.5,48.62Q507,57.25 507,70L507,480L447,480ZM614,480L614,110Q614,97.25 622.68,88.62Q631.35,80 644.18,80Q657,80 665.5,88.62Q674,97.25 674,110L674,480L614,480ZM473,670Q473,670 473,670Q473,670 473,670L473,670L473,670L473,670L473,670L473,670Q473,670 473,670Q473,670 473,670Z"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/search_48px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M796,839L533,576Q503,602 463.04,616.5Q423.08,631 378,631Q269.84,631 194.92,556Q120,481 120,375Q120,269 195,194Q270,119 376.5,119Q483,119 557.5,194Q632,269 632,375.15Q632,418 618,458Q604,498 576,533L840,795L796,839ZM377,571Q458.25,571 515.13,513.5Q572,456 572,375Q572,294 515.13,236.5Q458.25,179 377,179Q294.92,179 237.46,236.5Q180,294 180,375Q180,456 237.46,513.5Q294.92,571 377,571Z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M452,674L508,674L518,620Q538,614 552,605Q566,596 578,584L640,603L666,549L619,519Q623,498 623,480Q623,462 619,441L666,411L640,357L578,376Q566,364 552,355Q538,346 518,340L508,286L452,286L442,340Q422,346 408,355Q394,364 382,376L320,357L294,411L341,441Q337,462 337,480Q337,498 341,519L294,549L320,603L382,584Q394,596 408,605Q422,614 442,620L452,674ZM480,565Q444,565 419.5,540.5Q395,516 395,480Q395,444 419.5,419.5Q444,395 480,395Q516,395 540.5,419.5Q565,444 565,480Q565,516 540.5,540.5Q516,565 480,565ZM180,840Q156,840 138,822Q120,804 120,780L120,180Q120,156 138,138Q156,120 180,120L780,120Q804,120 822,138Q840,156 840,180L840,780Q840,804 822,822Q804,840 780,840L180,840ZM180,780L780,780Q780,780 780,780Q780,780 780,780L780,180Q780,180 780,180Q780,180 780,180L180,180Q180,180 180,180Q180,180 180,180L180,780Q180,780 180,780Q180,780 180,780ZM180,180L180,180Q180,180 180,180Q180,180 180,180L180,780Q180,780 180,780Q180,780 180,780L180,780Q180,780 180,780Q180,780 180,780L180,180Q180,180 180,180Q180,180 180,180Z"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/speed_camera_48px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M715,592L647,553L772,460L840,499L715,592ZM518,493L648,397L333,219Q333,219 333,219Q333,219 333,219L258,346Q258,346 258,346Q258,346 258,346L518,493ZM453,356L453,356Q453,356 453,356Q453,356 453,356L453,356Q453,356 453,356Q453,356 453,356L453,356ZM160,800L160,740L370,740Q370,740 370,740Q370,740 370,740L370,478L228,398Q205.93,385.04 199.47,361.02Q193,337 206,315L281,190Q294,169 317.5,162.5Q341,156 362,168L757,391L522,564L430,512L430,740Q430,764.75 412.38,782.37Q394.75,800 370,800L160,800Z"/>
|
||||
</vector>
|
||||
23
common/data/src/main/res/values/attrs.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<declare-styleable name="ShowcaseTheme">
|
||||
<attr name="themedIconColor" format="color"/>
|
||||
<attr name="markerIconTintColor" format="color"/>
|
||||
<attr name="markerIconTintColorDark" format="color"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
33
common/data/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="speed_camera">Speed camera</string>
|
||||
<string name="exit_action_title">Dismiss</string>
|
||||
<string name="fuel_station">Gas station</string>
|
||||
<string name="pharmacy">Pharmacy</string>
|
||||
<string name="charging_station">Charging station</string>
|
||||
<string name="category_title">Category</string>
|
||||
<string name="on_action_title">On</string>
|
||||
<string name="off_action_title">Off</string>
|
||||
<string name="use_telephon_settings">Use telephon settings</string>
|
||||
<string name="dark_mode">Dark mode</string>
|
||||
<string name="display_settings">Display settings</string>
|
||||
<string name="threed_building">3D building</string>
|
||||
<string name="arrived_exclamation_msg">Arrived!</string>
|
||||
<string name="drive_now">Drive now</string>
|
||||
<string name="stop_action_title">Stop</string>
|
||||
<string name="avoid_highways_row_title">Avoid highways</string>
|
||||
<string name="avoid_tolls_row_title">Avoid tolls rows</string>
|
||||
<string name="no_places">No places</string>
|
||||
<string name="recent_destinations">Recent destination</string>
|
||||
<string name="contacts">Contacts</string>
|
||||
<string name="favorites">Favorites</string>
|
||||
<string name="recent_Item_deleted">Recent item deleted</string>
|
||||
<string name="route_preview">Route preview</string>
|
||||
<string name="display">Display</string>
|
||||
<string name="navigation_settings">Navigation settings</string>
|
||||
<string name="settings_action_title">Settings</string>
|
||||
<string name="accept_action_title">Accept</string>
|
||||
<string name="reject_action_title">Reject</string>
|
||||
<string name="ok_action_title">OK</string>
|
||||
<string name="search_action_title">Search</string>
|
||||
</resources>
|
||||
27
common/data/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<style name="CarAppTheme">
|
||||
<item name="themedIconColor">#FFFF0000</item>
|
||||
<item name="carColorPrimary">#ff7f39fb</item>
|
||||
<item name="carColorPrimaryDark">#5904DF</item>
|
||||
<item name="carColorSecondary">#328E10</item>
|
||||
<item name="carColorSecondaryDark">#1A6004</item>
|
||||
<item name="markerIconTintColor">#FF7F39FB</item>
|
||||
<item name="markerIconTintColorDark">#FF5904DF</item>
|
||||
</style>
|
||||
</resources>
|
||||