diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c8e87ce..6c9a234 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,7 +16,7 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/Theme.Places"> + android:theme="@style/Theme.Navigation"> + android:theme="@style/Theme.Navigation"> diff --git a/app/src/main/java/com/kouros/navigation/MainActivity.kt b/app/src/main/java/com/kouros/navigation/MainActivity.kt index ad4762e..c692f4f 100644 --- a/app/src/main/java/com/kouros/navigation/MainActivity.kt +++ b/app/src/main/java/com/kouros/navigation/MainActivity.kt @@ -48,12 +48,13 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Observer -import com.example.places.ui.theme.PlacesTheme +import com.kouros.navigation.ui.theme.NavigationTheme import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.rememberMultiplePermissionsState import com.kouros.android.cars.carappservice.R import com.kouros.navigation.car.BuildingLayer import com.kouros.navigation.car.Puck +import com.kouros.navigation.car.PuckState import com.kouros.navigation.car.RouteLayer import com.kouros.navigation.data.Category @@ -68,15 +69,11 @@ import com.kouros.navigation.utils.NavigationUtils.snapLocation import com.kouros.navigation.utils.calculateZoom import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.rememberCameraState -import org.maplibre.compose.expressions.dsl.const -import org.maplibre.compose.layers.FillLayer -import org.maplibre.compose.layers.LineLayer import org.maplibre.compose.location.DesiredAccuracy import org.maplibre.compose.location.LocationPuck import org.maplibre.compose.location.LocationPuckColors @@ -85,9 +82,7 @@ import org.maplibre.compose.location.LocationTrackingEffect import org.maplibre.compose.location.rememberDefaultLocationProvider import org.maplibre.compose.location.rememberUserLocationState import org.maplibre.compose.map.MaplibreMap -import org.maplibre.compose.sources.GeoJsonData import org.maplibre.compose.sources.getBaseSource -import org.maplibre.compose.sources.rememberGeoJsonSource import org.maplibre.compose.style.BaseStyle import org.maplibre.spatialk.geojson.Position import kotlin.time.Duration.Companion.seconds @@ -143,7 +138,7 @@ class MainActivity : ComponentActivity() { val scope = rememberCoroutineScope() val snackbarHostState = remember { SnackbarHostState() } - PlacesTheme { + NavigationTheme { ModalNavigationDrawer( drawerContent = { ModalDrawerSheet { @@ -271,7 +266,7 @@ class MainActivity : ComponentActivity() { @Composable fun MapView() { val locationProvider = rememberDefaultLocationProvider( - updateInterval = 0.1.seconds, + updateInterval = 0.5.seconds, desiredAccuracy = DesiredAccuracy.Highest ) val userLocationState = rememberUserLocationState(locationProvider) @@ -304,7 +299,7 @@ class MainActivity : ComponentActivity() { baseStyle = BaseStyle.Uri(Constants.STYLE), ) { getBaseSource(id = "openmaptiles")?.let { tiles -> - if (!getBooleanKeyValue(context = applicationContext, SHOW_THREED_BUILDING) && Constants.STYLE.contains("liberty")) { + if (!getBooleanKeyValue(context = applicationContext, SHOW_THREED_BUILDING)) { BuildingLayer(tiles) } RouteLayer(route, "") @@ -313,20 +308,8 @@ class MainActivity : ComponentActivity() { val location = Location(LocationManager.GPS_PROVIDER) location.longitude = userLocationState.location!!.position.longitude location.latitude = userLocationState.location!!.position.latitude - Puck(cameraState, location,) + PuckState(cameraState, userLocationState,) } - LocationPuck( - idPrefix = "user-location1", - locationState = userLocationState, - cameraState = cameraState, - accuracyThreshold = 10f, - showBearing = false, - sizes = LocationPuckSizes(dotRadius = 10.dp), - colors = LocationPuckColors( - dotFillColorCurrentLocation = Color.Cyan, - accuracyStrokeColor = Color.Green - ) - ) } LocationTrackingEffect( diff --git a/app/src/main/java/com/kouros/navigation/MainApplication.kt b/app/src/main/java/com/kouros/navigation/MainApplication.kt index 666f3f7..327b502 100644 --- a/app/src/main/java/com/kouros/navigation/MainApplication.kt +++ b/app/src/main/java/com/kouros/navigation/MainApplication.kt @@ -2,7 +2,8 @@ package com.kouros.navigation import android.app.Application import android.content.Context -import com.example.places.di.appModule +import com.kouros.navigation.data.ObjectBox +import com.kouros.navigation.di.appModule import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.startKoin @@ -11,6 +12,7 @@ class MainApplication : Application() { override fun onCreate() { super.onCreate() + ObjectBox.init(applicationContext); appContext = applicationContext startKoin { androidLogger(Level.DEBUG) diff --git a/app/src/main/java/com/kouros/navigation/di/appModule.kt b/app/src/main/java/com/kouros/navigation/di/appModule.kt index b18cf81..2e1800d 100644 --- a/app/src/main/java/com/kouros/navigation/di/appModule.kt +++ b/app/src/main/java/com/kouros/navigation/di/appModule.kt @@ -1,4 +1,4 @@ -package com.example.places.di +package com.kouros.navigation.di import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.model.ViewModel diff --git a/app/src/main/java/com/kouros/navigation/ui/theme/Color.kt b/app/src/main/java/com/kouros/navigation/ui/theme/Color.kt index 4e9db57..7e0434b 100644 --- a/app/src/main/java/com/kouros/navigation/ui/theme/Color.kt +++ b/app/src/main/java/com/kouros/navigation/ui/theme/Color.kt @@ -1,4 +1,4 @@ -package com.example.places.ui.theme +package com.kouros.navigation.ui.theme import androidx.compose.ui.graphics.Color diff --git a/app/src/main/java/com/kouros/navigation/ui/theme/Theme.kt b/app/src/main/java/com/kouros/navigation/ui/theme/Theme.kt index fc06ad4..2653667 100644 --- a/app/src/main/java/com/kouros/navigation/ui/theme/Theme.kt +++ b/app/src/main/java/com/kouros/navigation/ui/theme/Theme.kt @@ -1,4 +1,4 @@ -package com.example.places.ui.theme +package com.kouros.navigation.ui.theme import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme @@ -33,7 +33,7 @@ private val LightColorScheme = lightColorScheme( ) @Composable -fun PlacesTheme( +fun NavigationTheme( darkTheme: Boolean = isSystemInDarkTheme(), // Dynamic color is available on Android 12+ dynamicColor: Boolean = true, diff --git a/app/src/main/java/com/kouros/navigation/ui/theme/Type.kt b/app/src/main/java/com/kouros/navigation/ui/theme/Type.kt index c4d41ca..19a44e9 100644 --- a/app/src/main/java/com/kouros/navigation/ui/theme/Type.kt +++ b/app/src/main/java/com/kouros/navigation/ui/theme/Type.kt @@ -1,4 +1,4 @@ -package com.example.places.ui.theme +package com.kouros.navigation.ui.theme import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index f5a8103..10b109c 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/automotive/src/main/res/values/colors.xml b/automotive/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/automotive/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/automotive/src/main/res/values/strings.xml b/automotive/src/main/res/values/strings.xml new file mode 100644 index 0000000..f6be987 --- /dev/null +++ b/automotive/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + automotive + \ No newline at end of file diff --git a/automotive/src/main/res/values/themes.xml b/automotive/src/main/res/values/themes.xml new file mode 100644 index 0000000..23e83b0 --- /dev/null +++ b/automotive/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/automotive/src/test/java/com/kouros/navigation/automotive/ExampleUnitTest.kt b/automotive/src/test/java/com/kouros/navigation/automotive/ExampleUnitTest.kt new file mode 100644 index 0000000..45bc852 --- /dev/null +++ b/automotive/src/test/java/com/kouros/navigation/automotive/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.kouros.navigation.automotive + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/common/car/src/main/java/com/kouros/navigation/car/MapView.kt b/common/car/src/main/java/com/kouros/navigation/car/MapView.kt index deabca2..7b813d9 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/MapView.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/MapView.kt @@ -1,9 +1,6 @@ package com.kouros.navigation.car -import android.R.attr.strokeWidth -import android.graphics.Rect import android.location.Location -import androidx.car.app.CarContext import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize @@ -18,7 +15,6 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.res.vectorResource @@ -29,8 +25,8 @@ import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.kouros.android.cars.carappservice.R -import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING -import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue +import com.kouros.navigation.data.NavigationColor +import com.kouros.navigation.data.RouteColor import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.CameraState import org.maplibre.compose.camera.rememberCameraState @@ -38,8 +34,10 @@ import org.maplibre.compose.expressions.dsl.const import org.maplibre.compose.layers.Anchor import org.maplibre.compose.layers.FillLayer import org.maplibre.compose.layers.LineLayer +import org.maplibre.compose.location.LocationPuck import org.maplibre.compose.location.LocationPuckColors import org.maplibre.compose.location.LocationPuckSizes +import org.maplibre.compose.location.UserLocationState import org.maplibre.compose.sources.GeoJsonData import org.maplibre.compose.sources.Source import org.maplibre.compose.sources.rememberGeoJsonSource @@ -47,8 +45,8 @@ import org.maplibre.spatialk.geojson.Position @Composable -fun cameraState(position: CameraPosition?, tilt: Double, preview: Boolean): CameraState { - val padding = getPaddingValues(preview) +fun cameraState(width: Int, height: Int, position: CameraPosition?, tilt: Double, preview: Boolean): CameraState { + val padding = getPaddingValues(width, height, preview) return rememberCameraState( firstPosition = CameraPosition( @@ -77,7 +75,7 @@ fun RouteLayer(routeData: String?, previewRoute: String?) { LineLayer( id = "routes", source = routes, - color = const(Color.Blue), + color = const(RouteColor), width = const(14.dp), ) } @@ -93,7 +91,7 @@ fun RouteLayer(routeData: String?, previewRoute: String?) { LineLayer( id = "routes-pre", source = routes, - color = const(Color.Cyan), + color = const(RouteColor), width = const(4.dp), ) } @@ -116,7 +114,7 @@ fun DrawImage(location: Location) { val textMeasurer = rememberTextMeasurer() val vector = ImageVector.vectorResource(id = R.drawable.assistant_navigation_48px) val painter = rememberVectorPainter(image = vector) - val tint = remember { ColorFilter.tint(Color.Blue) } + val tint = remember { ColorFilter.tint(NavigationColor) } Box( modifier = Modifier @@ -138,11 +136,11 @@ fun DrawImage(location: Location) { val measuredText = textMeasurer.measure( AnnotatedString("${(location.speed * 3.6).toInt()}"), - style = TextStyle(fontSize = 22.sp) + style = TextStyle(color = Color.White, fontSize = 22.sp) ) onDrawBehind { drawCircle( - Color.LightGray, radius = 30.dp.toPx(), center = Offset(5f, 10f) + Color.Black, radius = 30.dp.toPx(), center = Offset(15f, 12f) ) drawText(measuredText) } @@ -167,8 +165,23 @@ fun Puck(cameraState: CameraState, location: Location) { ) } +@Composable +fun PuckState(cameraState: CameraState, userLocationState: UserLocationState) { + LocationPuck( + idPrefix = "user-location1", + locationState = userLocationState, + cameraState = cameraState, + accuracyThreshold = 10f, + showBearing = false, + sizes = LocationPuckSizes(dotRadius = 10.dp), + colors = LocationPuckColors( + dotFillColorCurrentLocation = Color.Cyan, + accuracyStrokeColor = Color.Green + ) + ) +} -fun getPaddingValues(preView: Boolean): PaddingValues { +fun getPaddingValues(width: Int, height: Int, preView: Boolean): PaddingValues { val padding = PaddingValues(start = 100.dp, top = 300.dp) val prePadding = PaddingValues(start = 150.dp, bottom = 0.dp) return if (preView) { diff --git a/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt b/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt index 20b03ab..46463a3 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt @@ -22,14 +22,16 @@ import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.car.screen.NavigationScreen import com.kouros.navigation.car.screen.RequestPermissionScreen import com.kouros.navigation.car.screen.SearchScreen +import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION import com.kouros.navigation.data.Constants.TAG import com.kouros.navigation.data.ObjectBox +import com.kouros.navigation.utils.NavigationUtils.snapLocation import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch -class NavigationSession : Session() { +class NavigationSession : Session(), NavigationScreen.Listener { val uriScheme = "samples"; val uriHost = "navigation"; @@ -40,7 +42,7 @@ class NavigationSession : Session() { lateinit var surfaceRenderer: SurfaceRenderer - var locationIndex = 100 + var locationIndex = 0 val simulate = true @@ -83,11 +85,10 @@ class NavigationSession : Session() { override fun onCreateScreen(intent: Intent): Screen { routeModel = RouteCarModel() - ObjectBox.init(carContext); surfaceRenderer = SurfaceRenderer(carContext, lifecycle, routeModel) - navigationScreen = NavigationScreen(carContext, surfaceRenderer, routeModel) + navigationScreen = NavigationScreen(carContext, surfaceRenderer, routeModel, this) if (carContext.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED @@ -159,7 +160,7 @@ class NavigationSession : Session() { updateLocation(location) locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, - /* minTimeMs= */ 10, + /* minTimeMs= */ 100, /* minDistanceM= */ 0f, mLocationListener ) @@ -183,8 +184,14 @@ class NavigationSession : Session() { ) val loc = routeModel.route.waypoints[locationIndex] val curLocation = Location(LocationManager.GPS_PROVIDER) - curLocation.longitude = loc[0] + 0.0003 - curLocation.latitude = loc[1] + 0.0002 + if ( locationIndex == 1500) { + curLocation.longitude = loc[0] + 0.003 + curLocation.latitude = loc[1] + 0.003 + } else { + curLocation.longitude = loc[0] + curLocation.latitude = loc[1] + } + curLocation.speed = 15F update(curLocation) locationIndex += 1 if (locationIndex > routeModel.route.waypoints.size) { @@ -203,6 +210,13 @@ class NavigationSession : Session() { routeModel.updateLocation(location) navigationScreen.updateTrip() } - surfaceRenderer.updateLocation(location) + val result = surfaceRenderer.updateLocation(location) + if (!result) { + navigationScreen.stopNavigation() + } + } + + override fun stopNavigation() { + routeModel.stopNavigation() } } \ No newline at end of file diff --git a/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt b/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt index 9354696..5d5d834 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt @@ -1,7 +1,6 @@ package com.kouros.navigation.car import android.app.Presentation -import android.content.res.Resources.getSystem import android.graphics.Rect import android.hardware.display.DisplayManager import android.hardware.display.VirtualDisplay @@ -12,6 +11,7 @@ import androidx.car.app.AppManager import androidx.car.app.CarContext import androidx.car.app.SurfaceCallback import androidx.car.app.SurfaceContainer +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -25,11 +25,13 @@ import androidx.lifecycle.setViewTreeLifecycleOwner import androidx.savedstate.setViewTreeSavedStateRegistryOwner import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.data.Constants +import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING import com.kouros.navigation.model.RouteModel import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.snapLocation import com.kouros.navigation.utils.calculateZoom +import com.kouros.navigation.utils.location import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.CameraState import org.maplibre.compose.map.MaplibreMap @@ -59,11 +61,9 @@ class SurfaceRenderer( var stableArea = Rect() - var containerWidth = 0 + var width = 0 - var containerHeight = 0 - - var containerDpi = 1 + var height = 0 var lastBearing = 0.0 val routeData = MutableLiveData("") @@ -107,17 +107,8 @@ class SurfaceRenderer( 0 ) - containerWidth = surfaceContainer.width - containerHeight = surfaceContainer.height - if (surfaceContainer.dpi != 0) { - containerDpi = surfaceContainer.dpi - } - println(surfaceContainer.toString()) - println(containerDpi) - println(carContext.resources.displayMetrics.density) - println(carContext.resources.displayMetrics.densityDpi) - println(getSystem().displayMetrics.density) - println(getSystem().displayMetrics.densityDpi) + width = surfaceContainer.width + height = surfaceContainer.height mapView = ComposeView(carContext).apply { this.setViewTreeLifecycleOwner(lifecycleOwner) @@ -175,15 +166,18 @@ class SurfaceRenderer( val position: CameraPosition? by cameraPosition.observeAsState() val route: String? by routeData.observeAsState() val previewRoute: String? by previewRouteData.observeAsState() - val cameraState = cameraState(position, tilt, preview) + val cameraState = cameraState(width, height, position, tilt, preview) + val baseStyle = + if (isSystemInDarkTheme()) BaseStyle.Uri(Constants.STYLE_DARK) else BaseStyle.Uri( + Constants.STYLE + ) MaplibreMap( cameraState = cameraState, - baseStyle = BaseStyle.Uri(Constants.STYLE), + baseStyle = baseStyle, ) { getBaseSource(id = "openmaptiles")?.let { tiles -> - if (!getBooleanKeyValue(context = carContext, SHOW_THREED_BUILDING) - && Constants.STYLE.contains("liberty")) { + if (!getBooleanKeyValue(context = carContext, SHOW_THREED_BUILDING)) { BuildingLayer(tiles) } RouteLayer(route, previewRoute) @@ -193,43 +187,36 @@ class SurfaceRenderer( ShowPosition(cameraState, position) } - - @Composable fun ShowPosition(cameraState: CameraState, position: CameraPosition?) { + var cameraDuration = duration(position) + var bearing = position!!.bearing + var zoom = position.zoom + var target = position.target + var localTilt = tilt if (!preview) { DrawImage(lastLocation) - val cameraDuration = duration(position) - LaunchedEffect(position) { - cameraState.animateTo( - finalPosition = CameraPosition( - bearing = position!!.bearing, - zoom = position.zoom, - target = position.target, - tilt = tilt, - padding = getPaddingValues(preview) - ), - duration = cameraDuration - ) - } } else { - LaunchedEffect(position) { - cameraState.animateTo( - finalPosition = CameraPosition( - bearing = 0.0, - zoom = 11.0, - target = Position(centerLocation.longitude, centerLocation.latitude), - tilt = 0.0, - padding = getPaddingValues(preview) - ), - duration = 3.seconds - ) - } + cameraDuration = 3.seconds + bearing = 0.0 + zoom = 11.0 + target = Position(centerLocation.longitude, centerLocation.latitude) + localTilt = 0.0 + } + LaunchedEffect(position) { + cameraState.animateTo( + finalPosition = CameraPosition( + bearing = bearing, + zoom = zoom, + target = target, + tilt = localTilt, + padding = getPaddingValues(width, height, preview) + ), + duration = cameraDuration + ) } } - - override fun onCreate(owner: LifecycleOwner) { Log.i(TAG, "SurfaceRenderer created") carContext.getCarService(AppManager::class.java) @@ -263,55 +250,56 @@ class SurfaceRenderer( } } - fun updateLocation(location: Location) { + fun updateLocation(location: Location) : Boolean { synchronized(this) { if (!preview) { var snapedLocation = location var bearing: Double + bearing = cameraPosition.value!!.bearing if (routeModel.isNavigating()) { snapedLocation = snapLocation(location, routeModel.route.maneuverLocations()) - // stimmt nicht - //bearing = routeModel.currentStep().bearing - } - bearing = cameraPosition.value!!.bearing - if (lastLocation.latitude != snapedLocation.latitude) { - if (lastLocation.distanceTo(snapedLocation) > 5) { - bearing = lastLocation.bearingTo(snapedLocation).toDouble() + bearing = routeModel.currentStep().bearing + if (snapedLocation.longitude == 0.0) { + //reRoute() + return false } } - val zoom = if (!panView) { calculateZoom(snapedLocation.speed.toDouble()) } else { cameraPosition.value!!.zoom } + updateCameraPosition(bearing, zoom, Position(snapedLocation.longitude, snapedLocation.latitude)) lastBearing = cameraPosition.value!!.bearing - cameraPosition.postValue( - cameraPosition.value!!.copy( - bearing = bearing, - zoom = zoom, - padding = getPaddingValues(preview), - target = Position(snapedLocation.longitude, snapedLocation.latitude), - ) - ) lastLocation = snapedLocation } else { val bearing = 0.0 val zoom = 14.0 - cameraPosition.postValue( - cameraPosition.value!!.copy( - bearing = bearing, - zoom = zoom, - tilt = 0.0, - target = Position(centerLocation.longitude, centerLocation.latitude) - ) + updateCameraPosition( + bearing, + zoom, + Position(centerLocation.longitude, centerLocation.latitude) ) } } + return true + } + + private fun updateCameraPosition(bearing: Double, zoom: Double, target: Position) { + cameraPosition.postValue( + cameraPosition.value!!.copy( + bearing = bearing, + zoom = zoom, + tilt = 0.0, + padding = getPaddingValues(width, height, preview), + target = target + ) + ) } fun setRouteData() { routeData.value = routeModel.route.routeGeoJson + previewRouteData.value = "" preview = false panView = false } diff --git a/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt b/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt index 3d82b97..95a68f4 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt @@ -29,9 +29,9 @@ import androidx.car.app.navigation.model.Step import androidx.car.app.navigation.model.TravelEstimate import androidx.core.graphics.drawable.IconCompat import com.kouros.android.cars.carappservice.R +import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD import com.kouros.navigation.data.ManeuverType import com.kouros.navigation.model.RouteModel -import org.json.JSONObject import java.util.TimeZone import java.util.concurrent.TimeUnit @@ -52,8 +52,8 @@ class RouteCarModel() : RouteModel() { routingData(ManeuverType.None.value, carContext) } when (stepData.leftDistance) { - in 0.0..100.0 -> { - if (route.currentIndex < route.maneuvers.size) { + in 0.0..NEXT_STEP_THRESHOLD -> { + if (route.currentManeuverIndex < route.maneuvers.size) { val maneuver = route.nextManeuver() val maneuverType = maneuver.type routing = routingData(maneuverType, carContext) @@ -76,7 +76,7 @@ class RouteCarModel() : RouteModel() { } /** Returns the next [Step] with information such as the cue text and images. */ - fun nextStep(carContext: CarContext): Step { + fun nextStep(carContext: CarContext): Step? { val maneuver = route.nextManeuver() val maneuverType = maneuver.type val routing = routingData(maneuverType, carContext) @@ -84,10 +84,11 @@ class RouteCarModel() : RouteModel() { val distanceLeft = leftStepDistance() * 1000 when (distanceLeft) { - in 0.0..100.0 -> { - if (maneuver.streetNames != null && maneuver.streetNames!!.isNotEmpty()) { - text = maneuver.streetNames!![0] - } + in 0.0..NEXT_STEP_THRESHOLD -> { + return null +// if (maneuver.streetNames != null && maneuver.streetNames!!.isNotEmpty()) { +// text = maneuver.streetNames!![0] +// } } else -> { diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt index 8ba4c33..8ba3fe3 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt @@ -24,6 +24,7 @@ import androidx.lifecycle.Observer import com.kouros.android.cars.carappservice.R import com.kouros.navigation.car.NavigationCarAppService import com.kouros.navigation.car.SurfaceRenderer +import com.kouros.navigation.car.navigation.NavigationMessage import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.Place @@ -32,10 +33,18 @@ import com.kouros.navigation.model.ViewModel class NavigationScreen( carContext: CarContext, private var surfaceRenderer: SurfaceRenderer, - private var routeModel: RouteCarModel + private var routeModel: RouteCarModel, + private var listener: Listener + ) : Screen(carContext) { + /** A listener for navigation start and stop signals. */ + interface Listener { + /** Stops navigation. */ + fun stopNavigation() + } + var currentNavigationLocation = Location(LocationManager.GPS_PROVIDER) val vieModel = ViewModel(NavigationRepository()) val observer = Observer { route -> @@ -77,7 +86,7 @@ class NavigationScreen( } } - private fun getNavigationTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate{ + private fun getNavigationTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate { actionStripBuilder.addAction( Action.Builder() .setTitle(carContext.getString(R.string.stop_action_title)) @@ -91,9 +100,7 @@ class NavigationScreen( .build() ) .setOnClickListener { - routeModel.stopNavigation() - surfaceRenderer.routeData.postValue("") - invalidate() + stopNavigation() } .build() ) @@ -107,16 +114,17 @@ class NavigationScreen( .setBackgroundColor(CarColor.GREEN) .build() } - private fun getNavigationEndTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate{ - if (routeModel.isArrived()) { - val timer = object: CountDownTimer(10000, 10000) { - override fun onTick(millisUntilFinished: Long) {} - override fun onFinish() { - routeModel.arrived = false - invalidate() - } - } - timer.start() + + private fun getNavigationEndTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate { + if (routeModel.isArrived()) { + val timer = object : CountDownTimer(10000, 10000) { + override fun onTick(millisUntilFinished: Long) {} + override fun onFinish() { + routeModel.arrived = false + invalidate() + } + } + timer.start() return NavigationTemplate.Builder() .setNavigationInfo( MessageInfo.Builder( @@ -139,7 +147,7 @@ class NavigationScreen( .setMapActionStrip(mapActionStripBuilder().build()) .build() } else { - return NavigationTemplate.Builder() + return NavigationTemplate.Builder() .setBackgroundColor(CarColor.SECONDARY) .setActionStrip(actionStripBuilder.build()) .setMapActionStrip(mapActionStripBuilder().build()) @@ -149,19 +157,29 @@ class NavigationScreen( fun getRoutingInfo(): RoutingInfo { var currentDistance = routeModel.currentDistance - val displayUnit = if (currentDistance > 1000.0) { - currentDistance /= 1000.0 - Distance.UNIT_KILOMETERS - } else { - Distance.UNIT_METERS - } + val displayUnit = if (currentDistance > 1000.0) { + currentDistance /= 1000.0 + Distance.UNIT_KILOMETERS + } else { + Distance.UNIT_METERS + } + val nextStep = routeModel.nextStep(carContext = carContext) + if (nextStep != null) { return RoutingInfo.Builder() .setCurrentStep( - routeModel.currentStep(carContext = carContext), + routeModel.currentStep(carContext = carContext), Distance.create(currentDistance, displayUnit) ) - .setNextStep(routeModel.nextStep(carContext = carContext)) + .setNextStep(nextStep) .build() + } else { + return RoutingInfo.Builder() + .setCurrentStep( + routeModel.currentStep(carContext = carContext), + Distance.create(currentDistance, displayUnit) + ) + .build() + } } @@ -196,23 +214,22 @@ class NavigationScreen( surfaceRenderer.handleScale(-1) } .build()) - if (surfaceRenderer.panView) - { + if (surfaceRenderer.panView) { actionStripBuilder.addAction( - Action.Builder() - .setIcon( - CarIcon.Builder( - IconCompat.createWithResource( - carContext, - R.drawable.ic_pan_24 - ) + Action.Builder() + .setIcon( + CarIcon.Builder( + IconCompat.createWithResource( + carContext, + R.drawable.ic_pan_24 ) - .build() - ).setOnClickListener { - surfaceRenderer.panView = false - } - .build() - ) + ) + .build() + ).setOnClickListener { + surfaceRenderer.panView = false + } + .build() + ) } return actionStripBuilder } @@ -258,9 +275,15 @@ class NavigationScreen( } } + fun stopNavigation() { + listener.stopNavigation() + surfaceRenderer.routeData.postValue("") + invalidate() + } + fun reRoute() { - //NavigationMessage(carContext).createAlert() - //vieModel.loadRoute(surfaceRenderer.lastLocation, currentNavigationLocation) + NavigationMessage(carContext).createAlert() + vieModel.loadRoute(surfaceRenderer.lastLocation, currentNavigationLocation) } fun updateTrip() { diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt index 3b382b9..c60e2b3 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt @@ -71,6 +71,7 @@ class RoutePreviewScreen( routeModel.startNavigation(route) surfaceRenderer.setPreviewRouteData(routeModel) val geocoder = Geocoder(carContext) + // nominatim -> geocoder.getFromLocation(destination.latitude, destination.longitude, 1) { for (address in it) { street = address.getAddressLine(0) diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt index d152372..ca57a6a 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt @@ -1,9 +1,7 @@ package com.kouros.navigation.car.screen import android.annotation.SuppressLint -import android.location.Geocoder import android.location.Location -import android.location.LocationManager import androidx.car.app.CarContext import androidx.car.app.Screen import androidx.car.app.model.Action @@ -12,12 +10,15 @@ import androidx.car.app.model.Row import androidx.car.app.model.SearchTemplate import androidx.car.app.model.SearchTemplate.SearchCallback import androidx.car.app.model.Template +import androidx.lifecycle.Observer import com.kouros.android.cars.carappservice.R import com.kouros.navigation.car.SurfaceRenderer import com.kouros.navigation.data.Category import com.kouros.navigation.data.Constants +import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.Place -import com.kouros.navigation.utils.NavigationUtils.getBoundingBox +import com.kouros.navigation.data.nominatim.Search +import com.kouros.navigation.model.ViewModel class SearchScreen( @@ -28,13 +29,25 @@ class SearchScreen( var isSearchComplete: Boolean = false - var isSearching: Boolean = false - var categories: List = listOf( Category(id = Constants.RECENT, name = carContext.getString(R.string.recent_destinations)), Category(id = Constants.CONTACTS, name = carContext.getString(R.string.contacts)) ) + lateinit var searchResult: Search + + val observer = Observer { newSearch -> + println(newSearch) + searchResult = newSearch + invalidate() + } + + val viewModel = ViewModel(NavigationRepository()) + + init { + viewModel.searchPlaces.observe(this, observer) + } + override fun onGetTemplate(): Template { val itemListBuilder = ItemList.Builder() @@ -42,7 +55,7 @@ class SearchScreen( val searchItemListBuilder = ItemList.Builder() .setNoItemsMessage("No search results to show") - if (!isSearching) { + if (!isSearchComplete) { categories.forEach { it.name itemListBuilder.addItem( @@ -68,9 +81,11 @@ class SearchScreen( .build() ) } + } else { + doSearch(searchItemListBuilder) } - val itemList = if (!isSearching) { + val itemList = if (!isSearchComplete) { itemListBuilder.build() } else { searchItemListBuilder.build() @@ -79,12 +94,12 @@ class SearchScreen( return SearchTemplate.Builder( object : SearchCallback { override fun onSearchTextChanged(searchText: String) { - doSearch(searchText, searchItemListBuilder) + //doSearch(searchText, searchItemListBuilder) } override fun onSearchSubmitted(searchTerm: String) { isSearchComplete = true - doSearch(searchTerm, searchItemListBuilder) + viewModel.searchPlaces(searchTerm) } }) .setHeaderAction(Action.BACK) @@ -94,55 +109,35 @@ class SearchScreen( } @SuppressLint("DefaultLocale") - fun doSearch(searchText: String, searchItemListBuilder: ItemList.Builder) { - isSearching = true - val geocoder = Geocoder(carContext) - val box = getBoundingBox(location.latitude, location.longitude, 100.0) - - val lowerLeft = box["sw"] - val lowerLeftLat = lowerLeft!!["lat"]!! - val lowerLeftLon = lowerLeft["lon"]!! - val upperRight = box["ne"] - val upperRightLat = upperRight!!["lat"]!! - val upperRightLon = upperRight["lon"]!! - val addressLocation = Location(LocationManager.GPS_PROVIDER) - - geocoder.getFromLocationName( - searchText, 5, - //lowerLeftLat, lowerLeftLon, upperRightLat, upperRightLon - ) { - for (address in it) { - val name: String = address.getAddressLine(0) - addressLocation.latitude = address.latitude - addressLocation.longitude = address.longitude - val distance = location.distanceTo(addressLocation) - val dist = String.format("%.1f", (distance / 1000)) - searchItemListBuilder.addItem( - Row.Builder() - .setTitle("$name $dist km") - .setOnClickListener { - val place = Place( - 0, - name, - name, - address.latitude, - address.longitude, - "0", - "city", - name - ) - setResult(place) - finish() - } - .setBrowsable(false) - .build() - ) - } + fun doSearch(searchItemListBuilder: ItemList.Builder) { + searchResult.forEach { + println(it.displayName) + //val name: String = address.getAddressLine(0) + //addressLocation.latitude = address.latitude + //adressLocation.longitude = address.longitude + //val distance = location.distanceTo(addressLocation) + //val dist = String.format("%.1f", (distance / 1000)) + searchItemListBuilder.addItem( + Row.Builder() + .setTitle(it.displayName) + .setOnClickListener { + val place = Place( + name = it.displayName, + latitude = it.lat.toDouble(), + longitude = it.lon.toDouble(), + street = it.address.road, + city = it.address.city, + postalCode = it.address.postcode + ) + setResult(place) + finish() + } + .setBrowsable(false) + .build() + ) } - if (searchText.isEmpty()) { - isSearching = false - } - val itemList = searchItemListBuilder.build() + + // val itemList = searchItemListBuilder.build() invalidate() } } \ No newline at end of file diff --git a/common/car/src/main/res/values/styles.xml b/common/car/src/main/res/values/styles.xml index 50fb61a..d983543 100644 --- a/common/car/src/main/res/values/styles.xml +++ b/common/car/src/main/res/values/styles.xml @@ -21,7 +21,6 @@ #5904DF #328E10 #1A6004 - @layout/permission_request #FF7F39FB #FF5904DF diff --git a/common/car/src/test/java/com/kouros/navigation/car/UnitTest.kt b/common/car/src/test/java/com/kouros/navigation/car/UnitTest.kt index 7c7e2a5..45395c9 100644 --- a/common/car/src/test/java/com/kouros/navigation/car/UnitTest.kt +++ b/common/car/src/test/java/com/kouros/navigation/car/UnitTest.kt @@ -9,21 +9,20 @@ import com.kouros.navigation.model.RouteModel import com.kouros.navigation.model.ViewModel import org.junit.Assert.assertEquals import org.junit.Test -import org.junit.runner.RunWith /** - * Example local unit test, which will execute on the development machine (host). - * + * * See [testing documentation](http://d.android.com/tools/testing). */ -class ExampleUnitTest { +class ViewModelTest { + + val repo = NavigationRepository() + val viewModel = ViewModel(repo) + val model = RouteModel() @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - val model = RouteModel() - val repo = NavigationRepository() - val viewModel = ViewModel(repo) + fun routeViewModelTest() { + val fromLocation = Location(LocationManager.GPS_PROVIDER) fromLocation.latitude = homeLocation.latitude fromLocation.longitude = homeLocation.longitude diff --git a/common/data/src/main/java/com/kouros/navigation/data/Color.kt b/common/data/src/main/java/com/kouros/navigation/data/Color.kt new file mode 100644 index 0000000..38520a3 --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/Color.kt @@ -0,0 +1,7 @@ +package com.kouros.navigation.data + +import androidx.compose.ui.graphics.Color + +val NavigationColor = Color(0xFF1965D9) + +val RouteColor = Color(0xFF2E75E1) diff --git a/common/data/src/main/java/com/kouros/navigation/data/Data.kt b/common/data/src/main/java/com/kouros/navigation/data/Data.kt index 8c2d370..54b4862 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/Data.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/Data.kt @@ -119,9 +119,10 @@ data class ValhallaLocation ( object Constants { const val STYLE: String = "https://kouros-online.de/liberty.json" + const val STYLE_DARK: String = "https://kouros-online.de/liberty_night.json" //const val STYLE: String = "https://tiles.openfreemap.org/styles/liberty" - //const val STYLE: String = "https://tiles.openfreemap.org/styles/dark" + const val TAG: String = "Navigation" const val CONTACTS: String = "Contacts" @@ -145,6 +146,10 @@ object Constants { const val SHOW_THREED_BUILDING = "Show3D" + const val NEXT_STEP_THRESHOLD = 100.0 + + const val MAXIMAL_ROUTE_DEVIATION = 70.0 + } diff --git a/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt b/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt index d0f7e64..dc21142 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt @@ -32,6 +32,7 @@ class NavigationRepository { private val routeUrl = "https://kouros-online.de/valhalla/route?json=" + private val nominatimUrl = "https://nominatim.openstreetmap.org/search?q=" fun getRoute(currentLocation : Location, location: Location): String { val vLocation = listOf( Locations(lat = currentLocation.latitude, lon = currentLocation.longitude), @@ -45,7 +46,7 @@ class NavigationRepository { language = "de-DE" ) val routeLocation = Json.encodeToString(valhallaLocation) - return fetchUrl(routeUrl + routeLocation) + return fetchUrl(routeUrl + routeLocation, true) } fun getRouteDistance(currentLocation : Location, location: Location): Double { @@ -55,9 +56,13 @@ class NavigationRepository { return routeModel.route.distance } + fun searchPlaces(search : String) : String { + return fetchUrl("$nominatimUrl$search&format=jsonv2&addressdetails=true&countrycodes=de", false) + } + fun getPlaces(): List { val places: MutableList = ArrayList() - val placesStr = fetchUrl(placesUrl) + val placesStr = fetchUrl(placesUrl, true) val jArray = JSONArray(placesStr) for (i in 0..() + +@OptIn(ExperimentalSerializationApi::class) +@JsonIgnoreUnknownKeys +data class SearchResult( + + @SerializedName("place_id") var placeId: Int = 0, + @SerializedName("licence") var licence: String = "", + @SerializedName("osm_type") var osmType: String = "", + @SerializedName("osm_id") var osmId: Long = 0, + @SerializedName("lat") var lat: String = "", + @SerializedName("lon") var lon: String = "", + @SerializedName("category") var category: String = "", + @SerializedName("type") var type: String = "", + @SerializedName("place_rank") var placeRank: Int = 0, + @SerializedName("importance") var importance: Double = 0.0, + @SerializedName("addresstype") var addresstype: String = "", + @SerializedName("address") var address: Address, + @SerializedName("name") var name: String = "", + @SerializedName("display_name") var displayName: String = "", + @SerializedName("boundingbox") var boundingbox: ArrayList = arrayListOf() + +) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt b/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt index a8d818e..6e87ee7 100644 --- a/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt +++ b/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt @@ -2,11 +2,10 @@ package com.kouros.navigation.model import android.location.Location import android.location.LocationManager -import com.kouros.navigation.data.Constants.homeLocation +import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD import com.kouros.navigation.data.Place import com.kouros.navigation.data.Route import com.kouros.navigation.data.StepData -import com.kouros.navigation.utils.NavigationUtils import com.kouros.navigation.utils.location import org.maplibre.geojson.FeatureCollection import org.maplibre.geojson.Point @@ -26,9 +25,9 @@ open class RouteModel() { var maneuverType = 0 /* - Index in a maneuver + current shapeIndex */ - var currentIndex = 0 + private var currentShapeIndex = 0 var distanceToStepEnd = 0F @@ -64,7 +63,7 @@ open class RouteModel() { fun updateLocation(location: Location) { var nearestDistance = 100000.0f - route.currentIndex = -1 + route.currentManeuverIndex = -1 // find maneuver for ((i, maneuver) in route.maneuvers.withIndex()) { val beginShapeIndex = maneuver.beginShapeIndex @@ -72,7 +71,7 @@ open class RouteModel() { val distance = calculateDistance(beginShapeIndex, endShapeIndex, location) if (distance < nearestDistance) { nearestDistance = distance - route.currentIndex = i + route.currentManeuverIndex = i calculateCurrentIndex(beginShapeIndex, endShapeIndex, location) } } @@ -84,13 +83,13 @@ open class RouteModel() { if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) { text = maneuver.streetNames[0] } - if (bearing == 0F) { - bearing = maneuver.bearingAfter.toFloat() - } + val curLocation = location(route.pointLocations[currentShapeIndex].latitude(), route.pointLocations[currentShapeIndex].longitude()) + val nextLocation = location(route.pointLocations[currentShapeIndex+1].latitude(), route.pointLocations[currentShapeIndex+1].longitude()) + bearing = curLocation.bearingTo(nextLocation) val distanceStepLeft = leftStepDistance() * 1000 when (distanceStepLeft) { - in 0.0..100.0 -> { - if (route.currentIndex < route.maneuvers.size) { + in 0.0..NEXT_STEP_THRESHOLD -> { + if (route.currentManeuverIndex < route.maneuvers.size) { val maneuver = route.nextManeuver() if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) { text = maneuver.streetNames[0] @@ -109,13 +108,13 @@ open class RouteModel() { ) { var nearestLocation = 100000.0f for (i in beginShapeIndex..endShapeIndex) { - val polylineLocation = Location(LocationManager.GPS_PROVIDER) - polylineLocation.longitude = route.waypoints[i][0] - polylineLocation.latitude = route.waypoints[i][1] - val distance: Float = location.distanceTo(polylineLocation) + val waypoint = Location(LocationManager.GPS_PROVIDER) + waypoint.longitude = route.waypoints[i][0] + waypoint.latitude = route.waypoints[i][1] + val distance: Float = location.distanceTo(waypoint) if (distance < nearestLocation) { nearestLocation = distance - currentIndex = i + currentShapeIndex = i beginIndex = beginShapeIndex endIndex = endShapeIndex distanceToStepEnd = 0F @@ -157,14 +156,14 @@ open class RouteModel() { fun travelLeftTime(): Double { var timeLeft = 0.0 - for (i in route.currentIndex + 1.. 0) { val maneuver = route.currentManeuver() val curTime = maneuver.time - val percent = 100 * (endIndex - currentIndex) / (endIndex - beginIndex) + val percent = 100 * (endIndex - currentShapeIndex) / (endIndex - beginIndex) val time = curTime * percent / 100 timeLeft += time } @@ -183,14 +182,14 @@ open class RouteModel() { fun travelLeftDistance(): Double { var leftDistance = 0.0 - for (i in route.currentIndex + 1.. 0) { val maneuver = route.currentManeuver() val curDistance = maneuver.length - val percent = 100 * (endIndex - currentIndex) / (endIndex - beginIndex) + val percent = 100 * (endIndex - currentShapeIndex) / (endIndex - beginIndex) val time = curDistance * percent / 100 leftDistance += time } @@ -208,10 +207,9 @@ open class RouteModel() { fun stopNavigation() { route.clear() navigating = false - currentIndex = 0 + currentShapeIndex = 0 distanceToStepEnd = 0F beginIndex = 0 endIndex = 0 - } } \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt b/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt index 3a4bc9e..54abc70 100644 --- a/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt +++ b/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt @@ -3,16 +3,16 @@ package com.kouros.navigation.model import android.content.Context import android.location.Geocoder import android.location.Location -import android.location.LocationManager import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.google.gson.GsonBuilder import com.kouros.navigation.data.Constants import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.ObjectBox.boxStore import com.kouros.navigation.data.Place import com.kouros.navigation.data.Place_ -import com.kouros.navigation.utils.NavigationUtils +import com.kouros.navigation.data.nominatim.Search import com.kouros.navigation.utils.location import io.objectbox.kotlin.boxFor import kotlinx.coroutines.Dispatchers @@ -32,6 +32,10 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { MutableLiveData>() } + val searchPlaces: MutableLiveData by lazy { + MutableLiveData() + } + val contactAddress: MutableLiveData> by lazy { MutableLiveData>() } @@ -85,11 +89,13 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { for (address in addresses) { val addressLines = address.address.split("\n") geocoder.getFromLocationName( - address.address, 5) { + address.address, 5 + ) { for (adr in it) { if (addressLines.size > 1) { val plLocation = location(adr.latitude, adr.longitude) - val distance = repository.getRouteDistance(currentLocation, plLocation) + val distance = + repository.getRouteDistance(currentLocation, plLocation) contactList.add( Place( id = address.contactId, @@ -115,6 +121,15 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { } } + fun searchPlaces(search: String) { + viewModelScope.launch(Dispatchers.IO) { + val placesJson = repository.searchPlaces(search) + val gson = GsonBuilder().serializeNulls().create() + val places = gson.fromJson(placesJson, Search::class.java) + searchPlaces.postValue(places) + } + } + fun saveRecent(place: Place) { viewModelScope.launch(Dispatchers.IO) { place.category = Constants.RECENT diff --git a/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt b/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt index c1ff837..5a16d57 100644 --- a/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt +++ b/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt @@ -4,6 +4,7 @@ import android.content.Context import android.location.Location import android.location.LocationManager import androidx.core.content.edit +import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION import com.kouros.navigation.data.Constants.SHARED_PREF_KEY import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING import com.kouros.navigation.data.GeoJsonFeature @@ -57,11 +58,17 @@ object NavigationUtils { } fun snapLocation(location: Location, stepCoordinates: List): Location { val oldPoint = Point.fromLngLat(location.longitude, location.latitude) + val oldLocation = location(location.latitude, location.longitude) if (stepCoordinates.size > 1) { val pointFeature = TurfMisc.nearestPointOnLine(oldPoint, stepCoordinates) val point = pointFeature.geometry() as Point location.latitude = point.latitude() location.longitude = point.longitude() + val distance = oldLocation.distanceTo(location) + if (distance > MAXIMAL_ROUTE_DEVIATION) { + println("Distance to big") + return location(0.0, 0.0) + } } return location } diff --git a/settings.gradle.kts b/settings.gradle.kts index f1a2a89..2553d80 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,3 +31,6 @@ include( +include(":common:automotive") +include(":app:automotive") +include(":automotive")