Speed radar
This commit is contained in:
@@ -9,6 +9,7 @@ data class Elements (
|
||||
@SerializedName("id" ) var id : Long? = null,
|
||||
@SerializedName("lat" ) var lat : Double? = null,
|
||||
@SerializedName("lon" ) var lon : Double? = null,
|
||||
@SerializedName("tags" ) var tags : Tags = Tags()
|
||||
@SerializedName("tags" ) var tags : Tags = Tags(),
|
||||
var distance : Double = 0.0
|
||||
|
||||
)
|
||||
@@ -12,21 +12,22 @@ import java.net.URL
|
||||
class Overpass {
|
||||
|
||||
val overpassUrl = "https://overpass.kumi.systems/api/interpreter"
|
||||
fun getAmenities(category: String, location: Location) : List<Elements> {
|
||||
val boundingBox = getOverpassBbox(location, 2.0)
|
||||
val bb = getBoundingBox2(location, 2.0)
|
||||
fun getAmenities(type: String, category: String, location: Location) : List<Elements> {
|
||||
val boundingBox = getOverpassBbox(location, 5.0)
|
||||
val httpURLConnection = URL(overpassUrl).openConnection() as HttpURLConnection
|
||||
httpURLConnection.requestMethod = "POST"
|
||||
httpURLConnection.setRequestProperty(
|
||||
"Accept",
|
||||
"application/json"
|
||||
)
|
||||
// node["highway"="speed_camera"]
|
||||
// node[amenity=$category]
|
||||
httpURLConnection.setDoOutput(true);
|
||||
// define a query
|
||||
val test = """
|
||||
// define search query
|
||||
val searchQuery = """
|
||||
|[out:json];
|
||||
|(
|
||||
| node[amenity=$category]
|
||||
| node[$type=$category]
|
||||
| ($boundingBox);
|
||||
|);
|
||||
|out body;
|
||||
@@ -34,7 +35,7 @@ class Overpass {
|
||||
|
||||
// Send the JSON we created
|
||||
val outputStreamWriter = OutputStreamWriter(httpURLConnection.outputStream)
|
||||
outputStreamWriter.write(test)
|
||||
outputStreamWriter.write(searchQuery)
|
||||
outputStreamWriter.flush()
|
||||
// Check if the connection is successful
|
||||
val responseCode = httpURLConnection.responseCode
|
||||
@@ -43,7 +44,7 @@ class Overpass {
|
||||
.use { it.readText() } // defaults to UTF-8
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val overpass = gson.fromJson(response, Amenity::class.java)
|
||||
println("Overpass: $response")
|
||||
println("Overpass: $type $response")
|
||||
return overpass.elements
|
||||
}
|
||||
return emptyList()
|
||||
|
||||
@@ -3,20 +3,22 @@ package com.kouros.navigation.data.overpass
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
|
||||
data class Tags (
|
||||
|
||||
@SerializedName("amenity" ) var amenity : String? = null,
|
||||
@SerializedName("authentication:none" ) var authenticationNone : String? = null,
|
||||
@SerializedName("capacity" ) var capacity : String? = null,
|
||||
@SerializedName("motorcar" ) var motorcar : String? = null,
|
||||
@SerializedName("network" ) var network : String? = null,
|
||||
@SerializedName("opening_hours" ) var openingHours : String? = null,
|
||||
@SerializedName("operator" ) var operator : String? = null,
|
||||
@SerializedName("operator:short" ) var operatorShort : String? = null,
|
||||
@SerializedName("operator:wikidata" ) var operatorWikidata : String? = null,
|
||||
@SerializedName("operator:wikipedia" ) var operatorWikipedia : String? = null,
|
||||
@SerializedName("ref" ) var ref : String? = null,
|
||||
@SerializedName("socket:type2" ) var socketType2 : String? = null,
|
||||
@SerializedName("socket:type2:output" ) var socketType2Output : String? = null
|
||||
data class Tags(
|
||||
@SerializedName("name") var name: String? = null,
|
||||
@SerializedName("amenity") var amenity: String? = null,
|
||||
@SerializedName("authentication:none") var authenticationNone: String? = null,
|
||||
@SerializedName("capacity") var capacity: String? = null,
|
||||
@SerializedName("motorcar") var motorcar: String? = null,
|
||||
@SerializedName("network") var network: String? = null,
|
||||
@SerializedName("opening_hours") var openingHours: String? = null,
|
||||
@SerializedName("operator") var operator: String? = null,
|
||||
@SerializedName("operator:short") var operatorShort: String? = null,
|
||||
@SerializedName("operator:wikidata") var operatorWikidata: String? = null,
|
||||
@SerializedName("operator:wikipedia") var operatorWikipedia: String? = null,
|
||||
@SerializedName("ref") var ref: String? = null,
|
||||
@SerializedName("socket:type2") var socketType2: String? = null,
|
||||
@SerializedName("socket:type2:output") var socketType2Output: String? = null,
|
||||
@SerializedName("maxspeed") var maxspeed: String? = null,
|
||||
@SerializedName("direction") var direction: String? = null,
|
||||
|
||||
)
|
||||
@@ -36,7 +36,7 @@ class Contacts(private var context: Context) {
|
||||
if (name.contains("Jola")
|
||||
|| name.contains("Dominic")
|
||||
|| name.contains("Martha")
|
||||
|| name.contains("Rena")
|
||||
|| name.contains("Groth")
|
||||
|| name.contains("David")) {
|
||||
val mimeType: String = getString(getColumnIndex(ContactsContract.Data.MIMETYPE))
|
||||
if (mimeType == ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) {
|
||||
|
||||
@@ -127,6 +127,7 @@ open class RouteModel() {
|
||||
maneuverType = relevantManeuver.type
|
||||
}
|
||||
val maneuverIconPair = maneuverIcon(maneuverType)
|
||||
routeState.maneuverType = maneuverIconPair.first
|
||||
// Construct and return the final StepData object
|
||||
return StepData(
|
||||
streetName,
|
||||
@@ -138,40 +139,7 @@ open class RouteModel() {
|
||||
)
|
||||
}
|
||||
|
||||
fun currentStepOld(): StepData {
|
||||
val maneuver = route.currentManeuver()
|
||||
var text = ""
|
||||
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
|
||||
text = maneuver.streetNames[0]
|
||||
}
|
||||
val distanceStepLeft = leftStepDistance()
|
||||
when (distanceStepLeft) {
|
||||
in 0.0..Constants.NEXT_STEP_THRESHOLD -> {
|
||||
if (route.currentManeuverIndex < route.maneuvers.size) {
|
||||
val maneuver = route.nextManeuver()
|
||||
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
|
||||
text = maneuver.streetNames[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val type = if (hasArrived(maneuver.type)) {
|
||||
maneuver.type
|
||||
} else {
|
||||
ManeuverType.None.value
|
||||
}
|
||||
var routing: (Pair<Int, Int>) = maneuverIcon(type)
|
||||
when (distanceStepLeft) {
|
||||
in 0.0..NEXT_STEP_THRESHOLD -> {
|
||||
if (route.currentManeuverIndex < route.maneuvers.size) {
|
||||
val maneuver = route.nextManeuver()
|
||||
val maneuverType = maneuver.type
|
||||
routing = maneuverIcon(maneuverType)
|
||||
}
|
||||
}
|
||||
}
|
||||
return StepData(text, distanceStepLeft, routing.first, routing.second, arrivalTime(), travelLeftDistance())
|
||||
}
|
||||
|
||||
fun nextStep(): StepData {
|
||||
val maneuver = route.nextManeuver()
|
||||
val maneuverType = maneuver.type
|
||||
@@ -181,7 +149,6 @@ open class RouteModel() {
|
||||
when (distanceLeft) {
|
||||
in 0.0..NEXT_STEP_THRESHOLD -> {
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
|
||||
text = maneuver.streetNames[0]
|
||||
@@ -319,7 +286,7 @@ open class RouteModel() {
|
||||
currentTurnIcon = R.drawable.ic_roundabout_ccw
|
||||
}
|
||||
}
|
||||
routeState.maneuverType = type
|
||||
//routeState.maneuverType = type
|
||||
return Pair(type, currentTurnIcon)
|
||||
}
|
||||
|
||||
@@ -331,7 +298,7 @@ open class RouteModel() {
|
||||
fun hasArrived(type: Int): Boolean {
|
||||
// return leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE && type == ManeuverType.DestinationRight.value
|
||||
return type == ManeuverType.DestinationRight.value
|
||||
|| routeState.maneuverType == ManeuverType.Destination.value
|
||||
|| routeState.maneuverType == ManeuverType.DestinationLeft.value
|
||||
|| type == ManeuverType.Destination.value
|
||||
|| type == ManeuverType.DestinationLeft.value
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.kouros.navigation.model
|
||||
|
||||
import android.content.Context
|
||||
import android.location.Geocoder
|
||||
import android.location.Location
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
@@ -10,16 +9,15 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Locations
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.ObjectBox.boxStore
|
||||
import com.kouros.navigation.data.overpass.Overpass
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.Place_
|
||||
import com.kouros.navigation.data.SearchFilter
|
||||
import com.kouros.navigation.data.nominatim.Search
|
||||
import com.kouros.navigation.data.nominatim.SearchResult
|
||||
import com.kouros.navigation.data.overpass.Elements
|
||||
import com.kouros.navigation.data.overpass.Overpass
|
||||
import com.kouros.navigation.utils.NavigationUtils
|
||||
import com.kouros.navigation.utils.location
|
||||
import io.objectbox.kotlin.boxFor
|
||||
@@ -31,34 +29,42 @@ import java.time.ZoneOffset
|
||||
class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
|
||||
val route: MutableLiveData<String> by lazy {
|
||||
MutableLiveData<String>()
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
val previewRoute: MutableLiveData<String> by lazy {
|
||||
MutableLiveData<String>()
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
val recentPlace: MutableLiveData<Place> by lazy {
|
||||
MutableLiveData<Place>()
|
||||
MutableLiveData()
|
||||
}
|
||||
val places: MutableLiveData<List<Place>> by lazy {
|
||||
MutableLiveData<List<Place>>()
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
val favorites: MutableLiveData<List<Place>> by lazy {
|
||||
MutableLiveData<List<Place>>()
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
val searchPlaces: MutableLiveData<List<SearchResult>> by lazy {
|
||||
MutableLiveData<List<SearchResult>>()
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
val placeLocation: MutableLiveData<SearchResult> by lazy {
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
val contactAddress: MutableLiveData<List<Place>> by lazy {
|
||||
MutableLiveData<List<Place>>()
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
val elements: MutableLiveData<List<Elements>> by lazy {
|
||||
MutableLiveData<List<Elements>>()
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
val speedCameras: MutableLiveData<List<Elements>> by lazy {
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
fun loadRecentPlace(location: Location) {
|
||||
@@ -98,9 +104,15 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
query.close()
|
||||
for (place in results) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
val distance =
|
||||
repository.getRouteDistance(location, plLocation, getSearchFilter(context))
|
||||
place.distance = distance.toFloat()
|
||||
if (place.latitude != 0.0) {
|
||||
val distance =
|
||||
repository.getRouteDistance(
|
||||
location,
|
||||
plLocation,
|
||||
getSearchFilter(context)
|
||||
)
|
||||
place.distance = distance.toFloat()
|
||||
}
|
||||
}
|
||||
places.postValue(results)
|
||||
} catch (e: Exception) {
|
||||
@@ -164,52 +176,54 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadContacts(context: Context, currentLocation: Location) {
|
||||
fun loadContacts(context: Context) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val geocoder = Geocoder(context)
|
||||
val contactList = mutableListOf<Place>()
|
||||
val contacts = Contacts(context = context)
|
||||
val addresses = contacts.retrieveContacts()
|
||||
for (address in addresses) {
|
||||
val addressLines = address.address.split("\n")
|
||||
geocoder.getFromLocationName(
|
||||
address.address, 5
|
||||
) {
|
||||
for (adr in it) {
|
||||
if (addressLines.size > 1) {
|
||||
val plLocation = location(adr.longitude, adr.latitude)
|
||||
val distance =
|
||||
repository.getRouteDistance(
|
||||
currentLocation,
|
||||
plLocation,
|
||||
getSearchFilter(context)
|
||||
)
|
||||
contactList.add(
|
||||
Place(
|
||||
id = address.contactId,
|
||||
name = address.name + " " + addressLines[0] + " " + addressLines[1],
|
||||
Constants.CONTACTS,
|
||||
street = addressLines[0],
|
||||
city = addressLines[1],
|
||||
latitude = adr.latitude,
|
||||
longitude = adr.longitude,
|
||||
avatar = address.avatar,
|
||||
distance = distance.toFloat()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
contactAddress.postValue(contactList)
|
||||
}
|
||||
val contactList = mutableListOf<Place>()
|
||||
val contacts = Contacts(context = context)
|
||||
val addresses = contacts.retrieveContacts()
|
||||
for (address in addresses) {
|
||||
val addressLines = address.address.split("\n")
|
||||
if (addressLines.size > 1) {
|
||||
contactList.add(
|
||||
Place(
|
||||
id = address.contactId,
|
||||
name = address.name + " " + addressLines[0] + " " + addressLines[1],
|
||||
Constants.CONTACTS,
|
||||
street = addressLines[0],
|
||||
city = addressLines[1],
|
||||
avatar = address.avatar,
|
||||
longitude = 0.0,
|
||||
latitude = 0.0,
|
||||
distance = 0F,
|
||||
)
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
contactAddress.postValue(contactList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun findAddress(search: String, location: Location) {
|
||||
var sortedList: List<SearchResult>
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val placesJson = repository.searchPlaces(search, location)
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val places = gson.fromJson(placesJson, Search::class.java)
|
||||
val distPlaces = mutableListOf<SearchResult>()
|
||||
places.forEach {
|
||||
val plLocation =
|
||||
location(longitude = it.lon.toDouble(), latitude = it.lat.toDouble())
|
||||
val distance = plLocation.distanceTo(location)
|
||||
it.distance = distance
|
||||
distPlaces.add(it)
|
||||
}
|
||||
sortedList = distPlaces.sortedWith(compareBy { it.distance })
|
||||
if (sortedList.isNotEmpty()) {
|
||||
placeLocation.postValue(sortedList.first())
|
||||
}
|
||||
}
|
||||
}
|
||||
fun searchPlaces(search: String, location: Location) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val placesJson = repository.searchPlaces(search, location)
|
||||
@@ -223,7 +237,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
it.distance = distance
|
||||
distPlaces.add(it)
|
||||
}
|
||||
val sortedList = distPlaces.sortedWith(compareBy({ it.distance }))
|
||||
val sortedList = distPlaces.sortedWith(compareBy { it.distance })
|
||||
searchPlaces.postValue(sortedList)
|
||||
}
|
||||
}
|
||||
@@ -237,8 +251,33 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
|
||||
fun getAmenities(category: String, location: Location) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val amenities = Overpass().getAmenities(category, location)
|
||||
elements.postValue(amenities)
|
||||
val amenities = Overpass().getAmenities("amenity", category, location)
|
||||
val distAmenities = mutableListOf<Elements>()
|
||||
amenities.forEach {
|
||||
val plLocation =
|
||||
location(longitude = it.lon!!, latitude = it.lat!!)
|
||||
val distance = plLocation.distanceTo(location)
|
||||
it.distance = distance.toDouble()
|
||||
distAmenities.add(it)
|
||||
}
|
||||
val sortedList = distAmenities.sortedWith(compareBy { it.distance })
|
||||
elements.postValue(sortedList)
|
||||
}
|
||||
}
|
||||
|
||||
fun getSpeedCameras(location: Location) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val amenities = Overpass().getAmenities("highway", "speed_camera", location)
|
||||
val distAmenities = mutableListOf<Elements>()
|
||||
amenities.forEach {
|
||||
val plLocation =
|
||||
location(longitude = it.lon!!, latitude = it.lat!!)
|
||||
val distance = plLocation.distanceTo(location)
|
||||
it.distance = distance.toDouble()
|
||||
distAmenities.add(it)
|
||||
}
|
||||
val sortedList = distAmenities.sortedWith(compareBy { it.distance })
|
||||
speedCameras.postValue(sortedList)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.kouros.navigation.utils
|
||||
|
||||
import android.location.Location
|
||||
import com.kouros.navigation.data.BoundingBox
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.put
|
||||
import org.maplibre.geojson.FeatureCollection
|
||||
import org.maplibre.geojson.Point
|
||||
import org.maplibre.spatialk.geojson.Feature
|
||||
@@ -102,12 +104,12 @@ object GeoUtils {
|
||||
return featureCollection.toJson()
|
||||
}
|
||||
|
||||
fun createPointCollection(lineCoordinates: List<List<Double>>): String {
|
||||
fun createPointCollection(lineCoordinates: List<List<Double>>, category: String): String {
|
||||
val featureCollection = buildFeatureCollection {
|
||||
lineCoordinates.forEach {
|
||||
addFeature {
|
||||
geometry = org.maplibre.spatialk.geojson.Point(it[0], it[1])
|
||||
properties = null
|
||||
properties = buildJsonObject { put("category", category) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,19 +4,7 @@ import android.content.Context
|
||||
import android.location.Location
|
||||
import android.location.LocationManager
|
||||
import androidx.core.content.edit
|
||||
import com.kouros.navigation.data.BoundingBox
|
||||
import com.kouros.navigation.data.Constants.SHARED_PREF_KEY
|
||||
import org.maplibre.geojson.FeatureCollection
|
||||
import org.maplibre.geojson.Point
|
||||
import org.maplibre.spatialk.geojson.Feature
|
||||
import org.maplibre.spatialk.geojson.dsl.addFeature
|
||||
import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection
|
||||
import org.maplibre.spatialk.geojson.dsl.buildLineString
|
||||
import org.maplibre.spatialk.geojson.toJson
|
||||
import org.maplibre.turf.TurfMeasurement
|
||||
import org.maplibre.turf.TurfMisc
|
||||
import java.lang.Math.toDegrees
|
||||
import java.lang.Math.toRadians
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.time.ZoneOffset
|
||||
@@ -24,7 +12,6 @@ import java.time.ZonedDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.time.Duration
|
||||
@@ -33,7 +20,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
object NavigationUtils {
|
||||
|
||||
fun getBooleanKeyValue(context: Context, key: String) : Boolean {
|
||||
fun getBooleanKeyValue(context: Context, key: String): Boolean {
|
||||
return context
|
||||
.getSharedPreferences(
|
||||
SHARED_PREF_KEY,
|
||||
@@ -56,7 +43,7 @@ object NavigationUtils {
|
||||
}
|
||||
}
|
||||
|
||||
fun getIntKeyValue(context: Context, key: String) : Int {
|
||||
fun getIntKeyValue(context: Context, key: String): Int {
|
||||
return context
|
||||
.getSharedPreferences(
|
||||
SHARED_PREF_KEY,
|
||||
@@ -88,9 +75,8 @@ fun calculateZoom(speed: Double?): Double {
|
||||
val zoom = when (speedKmh) {
|
||||
in 0..10 -> 18.0
|
||||
in 11..30 -> 17.0
|
||||
in 21..40 -> 16.0
|
||||
in 31..50 -> 15.0
|
||||
in 51..60 -> 15.0
|
||||
in 31..50 -> 16.0
|
||||
in 61..70 -> 15.0
|
||||
else -> 14
|
||||
}
|
||||
return zoom.toDouble()
|
||||
@@ -98,39 +84,34 @@ fun calculateZoom(speed: Double?): Double {
|
||||
|
||||
fun previewZoom(previewDistance: Double): Double {
|
||||
when (previewDistance) {
|
||||
in 0.0..10.0 -> {
|
||||
return 13.0
|
||||
}
|
||||
in 10.0..20.0 -> {
|
||||
return 11.0
|
||||
}
|
||||
in 20.0..30.0 -> {
|
||||
return 10.0
|
||||
}
|
||||
in 0.0..10.0 -> return 13.0
|
||||
in 10.0..20.0 -> return 11.0
|
||||
in 20.0..30.0 -> return 10.0
|
||||
}
|
||||
return 9.0
|
||||
}
|
||||
|
||||
|
||||
fun calcTilt(newZoom: Double, tilt: Double): Double = if (newZoom < 13) {
|
||||
0.0
|
||||
} else {
|
||||
if (tilt == 0.0) {
|
||||
55.0
|
||||
fun calculateTilt(newZoom: Double, tilt: Double): Double =
|
||||
if (newZoom < 13) {
|
||||
0.0
|
||||
} else {
|
||||
tilt
|
||||
if (tilt == 0.0) {
|
||||
55.0
|
||||
} else {
|
||||
tilt
|
||||
}
|
||||
}
|
||||
}
|
||||
fun bearing(fromLocation: Location, toLocation: Location, oldBearing: Double) : Double {
|
||||
|
||||
fun bearing(fromLocation: Location, toLocation: Location, oldBearing: Double): Double {
|
||||
val distance = fromLocation.distanceTo(toLocation)
|
||||
if (distance < 1.0) {
|
||||
return oldBearing
|
||||
}
|
||||
val bearing = fromLocation.bearingTo(toLocation).toInt().toDouble()
|
||||
return bearing
|
||||
return bearing
|
||||
}
|
||||
|
||||
fun location(longitude : Double, latitude: Double): Location {
|
||||
fun location(longitude: Double, latitude: Double): Location {
|
||||
val location = Location(LocationManager.GPS_PROVIDER)
|
||||
location.longitude = longitude
|
||||
location.latitude = latitude
|
||||
@@ -138,7 +119,7 @@ fun location(longitude : Double, latitude: Double): Location {
|
||||
}
|
||||
|
||||
fun formatDateTime(time: Long): String {
|
||||
val dateFormatter = DateTimeFormatter.ofLocalizedTime( FormatStyle.SHORT)
|
||||
val dateFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
|
||||
val dateTime = LocalDateTime.ofEpochSecond(time / 1000, 0, ZoneOffset.UTC)
|
||||
val zdt = ZonedDateTime.of(dateTime, ZoneId.of("Europe/Berlin"))
|
||||
return zdt.format(dateFormatter)
|
||||
|
||||
10
common/data/src/main/res/drawable/ev_station_24px.xml
Normal file
10
common/data/src/main/res/drawable/ev_station_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="M340,760L440,600L380,600L380,480L280,640L340,640L340,760ZM240,400L480,400L480,200Q480,200 480,200Q480,200 480,200L240,200Q240,200 240,200Q240,200 240,200L240,400ZM240,760L480,760L480,480L240,480L240,760ZM160,840L160,200Q160,167 183.5,143.5Q207,120 240,120L480,120Q513,120 536.5,143.5Q560,167 560,200L560,480L610,480Q639,480 659.5,500.5Q680,521 680,550L680,735Q680,752 694,766Q708,780 725,780Q743,780 756.5,766Q770,752 770,735L770,360L760,360Q743,360 731.5,348.5Q720,337 720,320L720,240L740,240L740,180L780,180L780,240L820,240L820,180L860,180L860,240L880,240L880,320Q880,337 868.5,348.5Q857,360 840,360L830,360L830,735Q830,777 799.5,808.5Q769,840 725,840Q682,840 651,808.5Q620,777 620,735L620,550Q620,545 617.5,542.5Q615,540 610,540L560,540L560,840L160,840ZM480,760L240,760L240,760L480,760Z"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/ev_station_48px.xml
Normal file
10
common/data/src/main/res/drawable/ev_station_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="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"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/local_gas_station_24px.xml
Normal file
10
common/data/src/main/res/drawable/local_gas_station_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="M160,840L160,200Q160,167 183.5,143.5Q207,120 240,120L480,120Q513,120 536.5,143.5Q560,167 560,200L560,480L600,480Q633,480 656.5,503.5Q680,527 680,560L680,740Q680,757 691.5,768.5Q703,780 720,780Q737,780 748.5,768.5Q760,757 760,740L760,452Q751,457 741,458.5Q731,460 720,460Q678,460 649,431Q620,402 620,360Q620,328 637.5,302.5Q655,277 684,266L600,182L642,140L790,284Q805,299 812.5,319Q820,339 820,360L820,740Q820,782 791,811Q762,840 720,840Q678,840 649,811Q620,782 620,740L620,540Q620,540 620,540Q620,540 620,540L560,540L560,840L160,840ZM240,400L480,400L480,200Q480,200 480,200Q480,200 480,200L240,200Q240,200 240,200Q240,200 240,200L240,400ZM720,400Q737,400 748.5,388.5Q760,377 760,360Q760,343 748.5,331.5Q737,320 720,320Q703,320 691.5,331.5Q680,343 680,360Q680,377 691.5,388.5Q703,400 720,400ZM240,760L480,760L480,480L240,480L240,760ZM480,760L240,760L240,760L480,760Z"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/local_gas_station_48px.xml
Normal file
10
common/data/src/main/res/drawable/local_gas_station_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="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"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/local_pharmacy_24px.xml
Normal file
10
common/data/src/main/res/drawable/local_pharmacy_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="M120,840L120,760L200,520L120,280L120,200L628,200L686,40L780,74L734,200L840,200L840,280L760,520L840,760L840,840L120,840ZM440,680L520,680L520,560L640,560L640,480L520,480L520,360L440,360L440,480L320,480L320,560L440,560L440,680ZM204,760L756,760L676,520L756,280L204,280L284,520L204,760ZM480,520L480,520L480,520L480,520L480,520L480,520Z"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/local_pharmacy_48px.xml
Normal file
10
common/data/src/main/res/drawable/local_pharmacy_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="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"/>
|
||||
</vector>
|
||||
Reference in New Issue
Block a user