Initial commit

This commit is contained in:
Dimitris
2025-11-13 19:46:08 +01:00
commit d63747e811
119 changed files with 5833 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application
android:name="com.kouros.navigation.MainApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Places">
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" />
<activity
android:name="com.kouros.navigation.MainActivity"
android:exported="true"
android:theme="@style/Theme.Places">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,352 @@
/*
* Copyright 2023 Google LLC
*
* 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.
*/
package com.kouros.navigation
import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.core.location.LocationListenerCompat
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import com.example.places.ui.theme.PlacesTheme
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import com.kouros.navigation.data.Category
import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.TAG
import com.kouros.navigation.data.Constants.homeLocation
import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.model.RouteModel
import com.kouros.navigation.model.ViewModel
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.LocationPuck
import org.maplibre.compose.location.LocationPuckColors
import org.maplibre.compose.location.rememberDefaultLocationProvider
import org.maplibre.compose.location.rememberUserLocationState
import org.maplibre.compose.map.GestureOptions
import org.maplibre.compose.map.MapOptions
import org.maplibre.compose.map.MaplibreMap
import org.maplibre.compose.map.OrnamentOptions
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
val geojson = MutableLiveData("")
class MainActivity : ComponentActivity() {
val vieModel = ViewModel(NavigationRepository())
val routeModel = RouteModel()
val observer = Observer<String> { newRoute ->
routeModel.createNavigationRoute(newRoute)
geojson.value = routeModel.geoJson
homeLocation.latitude = 48.155782
homeLocation.longitude = 11.607921
}
val cameraPosition = MutableLiveData(
CameraPosition(
zoom = 15.0,
target = Position(latitude = 48.1857475, longitude = 11.5793627)
)
)
init {
vieModel.route.observe(this, observer)
vieModel.loadRoute(
homeLocation,
Constants.home2Location
)
}
var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? ->
updateLocation(location)
}
@SuppressLint("MissingPermission")
fun requestLocationUpdates() {
val locationManager =
getSystemService(LOCATION_SERVICE) as LocationManager
val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
updateLocation(location)
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
/* minTimeMs= */ 100,
/* minDistanceM= */ 0f,
mLocationListener
)
}
fun updateLocation(location: Location?) {
if (location != null) {
cameraPosition.postValue(
cameraPosition.value!!.copy(
zoom = 15.0,
target = Position(location.longitude, location.latitude),
)
)
}
}
fun test() {
for (i in 0..<routeModel.polylineLocations.size) {
val loc = routeModel.polylineLocations[i]
val curLocation = Location(LocationManager.GPS_PROVIDER)
curLocation.longitude = loc[0]
curLocation.latitude = loc[1]
routeModel.findManeuver(curLocation)
val leftTime = routeModel.travelLeftTime()
val leftDistance = routeModel.travelLeftDistance()
Log.i(TAG, " leftTime: ${leftTime / 60}")
Log.i(TAG, " leftDistance: $leftDistance")
Log.i(TAG, "Cue: ${routeModel.maneuvers[routeModel.maneuverIndex]}")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
PlacesTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Column(modifier = Modifier.padding(innerPadding)) {
CheckPermission()
}
}
}
}
}
override fun onPause() {
super.onPause()
val locationManager =
getSystemService(LOCATION_SERVICE) as LocationManager
locationManager.removeUpdates(mLocationListener)
}
@SuppressLint("PermissionLaunchedDuringComposition")
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun CheckPermission() {
var rationaleState by remember {
mutableStateOf<RationaleState?>(null)
}
@OptIn(ExperimentalPermissionsApi::class)
val fineLocationPermissionState = rememberMultiplePermissionsState(
listOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.READ_CONTACTS,
),
)
if (fineLocationPermissionState.allPermissionsGranted) {
Map()
}
// Show rationale dialog when needed
rationaleState?.run { PermissionRationaleDialog(rationaleState = this) }
PermissionRequestButton(
isGranted = fineLocationPermissionState.allPermissionsGranted,
title = "Precise location access",
) {
if (fineLocationPermissionState.shouldShowRationale) {
rationaleState = RationaleState(
"Request Precise Location",
"In order to use this feature please grant access by accepting " + "the location permission dialog." + "\n\nWould you like to continue?",
) { proceed ->
if (proceed) {
fineLocationPermissionState.launchMultiplePermissionRequest()
}
rationaleState = null
}
} else {
fineLocationPermissionState.launchMultiplePermissionRequest()
}
}
}
@Composable
fun Map() {
requestLocationUpdates()
val position: CameraPosition? by cameraPosition.observeAsState()
val geoJsonData: String? by geojson.observeAsState()
val cameraState =
rememberCameraState(
firstPosition =
CameraPosition(
target = Position(
position!!.target.latitude,
position!!.target.longitude
),
zoom = 15.0,
)
)
val locationProvider = rememberDefaultLocationProvider()
val locationState = rememberUserLocationState(locationProvider)
MaplibreMap(
cameraState = cameraState,
//baseStyle = BaseStyle.Uri("https://tiles.openfreemap.org/styles/liberty"),
baseStyle = BaseStyle.Uri("https://kouros-online.de/liberty"),
options =
MapOptions(
gestureOptions = GestureOptions(
isTiltEnabled = true,
isZoomEnabled = true,
isRotateEnabled = false,
isScrollEnabled = true,
),
ornamentOptions = OrnamentOptions(
isScaleBarEnabled = false
)
)
) {
LocationPuck(
idPrefix = "user-location",
locationState = locationState,
cameraState = cameraState,
accuracyThreshold = 10f,
colors = LocationPuckColors(accuracyStrokeColor = Color.Green)
)
getBaseSource(id = "openmaptiles")?.let { tiles ->
FillLayer(id = "example", visible = false, source = tiles, sourceLayer = "building")
RouteLayer(geoJsonData)
}
}
LaunchedEffect(position) {
cameraState.animateTo(
finalPosition = CameraPosition(
bearing = position!!.bearing,
zoom = position!!.zoom,
target = position!!.target,
),
duration = 3.seconds
)
}
}
@Composable
fun RouteLayer(geoJsonData: String?) {
val routes =
rememberGeoJsonSource(GeoJsonData.JsonString(geoJsonData!!))
LineLayer(
id = "routes-casing",
source = routes,
color = const(Color.White),
width = const(6.dp),
)
LineLayer(
id = "routes",
source = routes,
color = const(Color.Blue),
width = const(4.dp),
)
}
@Composable
fun PlaceList(viewModel: ViewModel = koinViewModel()) {
var categories: List<Category>
val places = viewModel.places.observeAsState().value ?: return
val countries = places.groupBy { it.category }.map {
Category(id = Constants.RECENT, name = it.key!!)
}
categories = countries
val context = LocalContext.current
LazyColumn {
items(categories.size) {
val place = categories[it]
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.border(
2.dp,
color = MaterialTheme.colorScheme.outline,
shape = RoundedCornerShape(8.dp)
)
.clip(RoundedCornerShape(8.dp))
//.clickable {
//context.startActivity(place.toIntent(Intent.ACTION_VIEW))
//}
.padding(8.dp)
) {
Column {
Text(
text = place.name,
style = MaterialTheme.typography.labelLarge
)
Text(
text = place.name,
style = MaterialTheme.typography.bodyMedium,
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
}
}
}
}
}
}

View File

@@ -0,0 +1,26 @@
package com.kouros.navigation
import android.app.Application
import android.content.Context
import com.example.places.di.appModule
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
import org.koin.core.logger.Level
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
appContext = applicationContext
startKoin {
androidLogger(Level.DEBUG)
androidContext(this@MainApplication)
modules(appModule)
}
}
companion object {
var appContext: Context? = null
private set
}
}

View File

@@ -0,0 +1,129 @@
package com.kouros.navigation
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.MultiplePermissionsState
import com.google.accompanist.permissions.PermissionState
import com.google.accompanist.permissions.rememberMultiplePermissionsState
/**
* Simple screen that manages the location permission state
*/
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun Permissions(text: String, rationale: String, locationState: PermissionState) {
Permissions(
text = text,
rationale = rationale,
locationState = rememberMultiplePermissionsState(
permissions = listOf(
locationState.permission
)
)
)
}
/**
* Simple screen that manages the location permission state
*/
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun Permissions(text: String, rationale: String, locationState: MultiplePermissionsState) {
var showRationale by remember(locationState) {
mutableStateOf(false)
}
if (showRationale) {
PermissionRationaleDialog(rationaleState = RationaleState(
title = "Permission Access",
rationale = rationale,
onRationaleReply = { proceed ->
if (proceed) {
locationState.launchMultiplePermissionRequest()
}
showRationale = false
}
))
}
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
PermissionRequestButton(isGranted = false, title = text) {
if (locationState.shouldShowRationale) {
showRationale = true
} else {
locationState.launchMultiplePermissionRequest()
}
}
}
}
/**
* A button that shows the title or the request permission action.
*/
@Composable
fun PermissionRequestButton(isGranted: Boolean, title: String, onClick: () -> Unit) {
if (isGranted) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
// Icon(Icons.Outlined.CheckCircle, title, modifier = Modifier.size(48.dp))
Spacer(Modifier.size(10.dp))
Text(text = title, modifier = Modifier.background(Color.Transparent))
}
} else {
Button(onClick = onClick) {
Text("Request $title")
}
}
}
/**
* Simple AlertDialog that displays the given rationale state
*/
@Composable
fun PermissionRationaleDialog(rationaleState: RationaleState) {
AlertDialog(onDismissRequest = { rationaleState.onRationaleReply(false) }, title = {
Text(text = rationaleState.title)
}, text = {
Text(text = rationaleState.rationale)
}, confirmButton = {
TextButton(onClick = {
rationaleState.onRationaleReply(true)
}) {
Text("Continue")
}
}, dismissButton = {
TextButton(onClick = {
rationaleState.onRationaleReply(false)
}) {
Text("Dismiss")
}
})
}
data class RationaleState(
val title: String,
val rationale: String,
val onRationaleReply: (proceed: Boolean) -> Unit,
)

View File

@@ -0,0 +1,12 @@
package com.example.places.di
import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.model.ViewModel
import org.koin.core.module.dsl.singleOf
import org.koin.core.module.dsl.viewModelOf
import org.koin.dsl.module
val appModule = module {
viewModelOf(::ViewModel)
singleOf(::NavigationRepository)
}

View File

@@ -0,0 +1,11 @@
package com.example.places.ui.theme
import androidx.compose.ui.graphics.Color
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)

View File

@@ -0,0 +1,57 @@
package com.example.places.ui.theme
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
@Composable
fun PlacesTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}

View File

@@ -0,0 +1,34 @@
package com.example.places.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
/* Other default text styles to override
titleLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 22.sp,
lineHeight = 28.sp,
letterSpacing = 0.sp
),
labelSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
*/
)

View File

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -0,0 +1,58 @@
<!--
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
https://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="512dp"
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
<group>
<clip-path android:pathData="M256,256m-256,0a256,256 0,1 1,512 0a256,256 0,1 1,-512 0 M 0,0"/>
<path
android:pathData="M0.3,-1h512v512h-512z"
android:fillColor="#9334E6"/>
<path
android:pathData="M668,-2.1v-4.8h-73.2v-69.8h73v-4.8h-73.2v-73.7h-4.8v73.7h-70v-73.7H515v73.7h-70v-73.7h-4.8v73.7h-70v-73.7h-4.8v73.7h-70v-73.7h-4.8v73.7h-69.8v-73.7H216v73.7h-70v-73.7h-4.8v73.7h-70v-73.7h-4.8v73.7h-70v-73.7h-4.8v73.7h-70v-73.7h-4.8v73.7h-73.2v4.8h73.2v69.8h-73.2v4.8h73.2v69.7h-73.2v4.8h73.2v69.8h-73.2v4.8h73.2v69.7h-73.2v4.8h73.2v69.8h-73.2v4.8h73.2v69.7h-73.2v4.8h73.2v69.8h-73.2v4.8h73.2V515h-73.2v4.8h73.2v69.8h-73.2v4.8h73.2v73.8h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7H668v-4.8h-73.2v-69.8H668v-4.8h-73.2v-69.7H668v-4.8h-73.2v-69.8H668V366h-73.2v-69.7H668v-4.8h-73.2v-69.8H668v-4.8h-73.2v-69.7H668v-4.8h-73.2V72.5H668v-4.8h-73.2V-2.1H668zM440.3,519.9v69.8h-70v-69.8H440.3zM440.3,445.4v69.7h-70v-69.7L440.3,445.4L440.3,445.4zM440.3,370.8v69.8h-70v-69.8H440.3zM440.3,296.3V366h-70v-69.7H440.3zM440.3,221.7v69.8h-70v-69.8H440.3zM440.3,147v69.7h-70V147H440.3zM440.3,72.4v69.8h-70V72.4H440.3zM440.3,-2.1v69.7h-70V-2.1H440.3zM440.3,-76.8V-7h-70v-69.8H440.3zM365.4,519.9v69.8h-70v-69.8H365.4zM365.4,445.4v69.7h-70v-69.7L365.4,445.4L365.4,445.4zM365.4,370.8v69.8h-70v-69.8H365.4zM365.4,296.3V366h-70v-69.7H365.4zM365.4,221.7v69.8h-70v-69.8H365.4zM365.4,147v69.7h-70V147H365.4zM365.4,72.4v69.8h-70V72.4H365.4zM365.4,-2.1v69.7h-70V-2.1H365.4zM295.5,-6.9v-69.8h70v69.8C365.5,-6.9 295.5,-6.9 295.5,-6.9zM290.8,519.9v69.8h-70v-69.8H290.8zM290.8,445.4v69.7h-70v-69.7L290.8,445.4L290.8,445.4zM290.8,370.8v69.8h-70v-69.8H290.8zM220.8,291.3v-69.8h69.8v69.8H220.8zM290.8,296.3V366h-70v-69.7H290.8zM220.8,67.6V-2.1h70v69.7H220.8zM290.8,142.2h-70V72.4h70V142.2zM290.8,147v69.7h-70V147H290.8zM220.8,-6.9v-69.8h69.8v69.8C290.6,-6.9 220.8,-6.9 220.8,-6.9zM589.9,519.9v69.8h-70v-69.8H589.9zM589.9,445.4v69.7h-70v-69.7L589.9,445.4L589.9,445.4zM589.9,370.8v69.8h-70v-69.8H589.9zM589.9,296.3V366h-70v-69.7H589.9zM589.9,221.7v69.8h-70v-69.8H589.9zM589.9,147v69.7h-70V147H589.9zM589.9,72.4v69.8h-70V72.4H589.9zM589.9,-2.1v69.7h-70V-2.1H589.9zM589.9,-76.8V-7h-70v-69.8H589.9zM515.1,519.9v69.8h-70v-69.8H515.1zM515.1,445.4v69.7h-70v-69.7L515.1,445.4L515.1,445.4zM515.1,370.8v69.8h-70v-69.8H515.1zM515.1,296.3V366h-70v-69.7H515.1zM515.1,221.7v69.8h-70v-69.8H515.1zM515.1,147v69.7h-70V147H515.1zM515.1,72.4v69.8h-70V72.4H515.1zM445.1,67.6V-2.1h70v69.7H445.1zM445.1,-6.9v-69.8h70v69.8C515.1,-6.9 445.1,-6.9 445.1,-6.9zM216,519.9v69.8h-70v-69.8H216zM216,445.4v69.7h-70v-69.7L216,445.4L216,445.4zM216,370.8v69.8h-70v-69.8H216zM216,296.3V366h-70v-69.7H216zM216,221.5v69.8h-70v-69.8L216,221.5L216,221.5zM216,147v69.7h-70V147H216zM216,72.4v69.8h-70V72.4H216zM216,-2.1v69.7h-70V-2.1H216zM216,-76.8V-7h-70v-69.8H216zM141.2,519.9v69.8h-70v-69.8H141.2zM141.2,445.4v69.7h-70v-69.7L141.2,445.4L141.2,445.4zM141.2,370.8v69.8h-70v-69.8H141.2zM141.2,296.3V366h-70v-69.7H141.2zM141.2,221.5v69.8h-70v-69.8L141.2,221.5L141.2,221.5zM141.2,147v69.7h-70V147H141.2zM141.2,72.4v69.8h-70V72.4H141.2zM141.2,-2.1v69.7h-70V-2.1H141.2zM141.2,-76.8V-7h-70v-69.8H141.2zM66.4,519.9v69.8h-70v-69.8H66.4zM66.4,445.4v69.7h-70v-69.7L66.4,445.4L66.4,445.4zM66.4,370.8v69.8h-70v-69.8H66.4zM66.4,296.3V366h-70v-69.7H66.4zM66.4,221.5v69.8h-70v-69.8L66.4,221.5L66.4,221.5zM66.4,147v69.7h-70V147H66.4zM66.4,72.4v69.8h-70V72.4H66.4zM66.4,-2.1v69.7h-70V-2.1H66.4zM66.4,-76.8V-7h-70v-69.8H66.4zM-8.4,519.9v69.8h-70v-69.8H-8.4zM-8.4,445.4v69.7h-70v-69.7L-8.4,445.4L-8.4,445.4zM-8.4,370.8v69.8h-70v-69.8H-8.4zM-8.4,296.3V366h-70v-69.7H-8.4zM-8.4,221.5v69.8h-70v-69.8L-8.4,221.5L-8.4,221.5zM-8.4,147v69.7h-70V147H-8.4zM-8.4,72.4v69.8h-70V72.4H-8.4zM-8.4,-2.1v69.7h-70V-2.1H-8.4zM-8.4,-76.8V-7h-70v-69.8H-8.4z"
android:strokeAlpha="0.7"
android:fillColor="#C58AF9"
android:fillAlpha="0.7"/>
<path
android:pathData="M95.9,333.5l151.6,-250.3l18.7,3.8l164,272l-108,30l-70.5,-29.5l-89.4,39.5l-18,-10l25,-33l-63,-1.5z"
android:fillColor="#9334E6"/>
<path
android:pathData="M415.5,321.6L279.2,90.3C274.4,82 265.6,77 256.1,77s-18.4,5 -23.2,13.3L95,322.9c-4.9,7.9 -4.9,17.9 0,25.8c4.9,8.2 13.7,13.2 23.2,13.3h41.2l-15.1,27.4l16.8,16.8l94.9,-38.1l94.8,38.5l16.8,-16.8l-15.1,-27.2h39.9c14.3,0.9 26.6,-10 27.5,-24.3c0.4,-5.8 -1.2,-11.5 -4.5,-16.3L415.5,321.6zM347.5,389.5l-91.4,-37.1l-91.5,37.1l-2.6,-2.6l94.1,-168.6L350,386.9L347.5,389.5zM392.5,348h-46.8l-28.5,-48l-61.1,-111l-60.4,107.8l-29.4,51H119c-4.5,-0.1 -8.7,-2.5 -11,-6.4c-2.2,-3.5 -2.2,-7.9 0,-11.4L245,97.2c4,-6 12.2,-7.6 18.2,-3.6c1.4,1 2.7,2.2 3.6,3.6l136.4,231.5l0,0c1.4,2.1 2.2,4.5 2.1,7c-0.2,6.9 -6,12.3 -12.8,12.1L392.5,348z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M362.8,354m-86.3,0a86.3,86.3 0,1 1,172.6 0a86.3,86.3 0,1 1,-172.6 0"
android:fillColor="#9334E6"
android:fillType="evenOdd"/>
<group>
<clip-path android:pathData="M362.8,351.9c-5.7,0 -10.3,-4.6 -10.3,-10.3c0,-5.7 4.6,-10.3 10.3,-10.3s10.3,4.6 10.3,10.3C373.2,347.3 368.5,351.9 362.8,351.9zM362.8,315.9c-14.8,0 -26.6,11.9 -26.6,26.6c0,19.9 26.6,49.4 26.6,49.4s26.6,-29.4 26.6,-49.4C389.4,327.9 377.5,315.9 362.8,315.9zM293.9,353.9c0,-35.7 27,-65.1 61.8,-68.7v14c-27,3.6 -48,26.8 -48,54.8s20.9,51.2 48,54.8v14C321,419 293.9,389.6 293.9,353.9zM406.6,300.5c-10.4,-8.6 -23.3,-13.9 -36.7,-15.3v14c10.1,1.3 19.3,5.3 26.9,11.2L406.6,300.5zM417.8,347h14c-1.4,-13.9 -6.9,-26.5 -15.3,-36.7l-9.9,9.9C412.5,327.8 416.5,336.9 417.8,347zM406.6,387.8l9.9,9.8c8.6,-10.4 13.9,-23.3 15.3,-36.7h-14C416.5,370.7 412.6,380 406.6,387.8zM369.8,408.8v14c13.9,-1.4 26.5,-6.9 36.7,-15.3l-9.8,-9.9C389,403.6 379.6,407.5 369.8,408.8z M 0,0"/>
<group>
<clip-path android:pathData="M279.9,271.1h165.8v165.8h-165.8z M 0,0"/>
<group>
<clip-path android:pathData="M279.9,271.1h165.8v165.8h-165.8z M 0,0"/>
<group>
<clip-path android:pathData="M279.9,271.1h165.8v165.8h-165.8z M 0,0"/>
<path
android:pathData="M245.3,236.5h235v235h-235z"
android:fillColor="#FFFFFF"/>
</group>
</group>
</group>
</group>
</group>
</vector>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -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>

View File

@@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name" translatable="false">Navigation</string>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Places" parent="android:Theme.Material.Light.NoActionBar" />
</resources>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older than API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>