mirror of
https://github.com/ev-map/EVMap.git
synced 2026-01-20 04:47:47 -05:00
implement availability detector with NewMotion API
This commit is contained in:
@@ -12,7 +12,7 @@ import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.johan.evmap.api.ChargeLocation
|
||||
import com.johan.evmap.api.goingelectric.ChargeLocation
|
||||
|
||||
const val REQUEST_LOCATION_PERMISSION = 1
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.johan.evmap.BR
|
||||
import com.johan.evmap.R
|
||||
import com.johan.evmap.api.ChargeLocation
|
||||
import com.johan.evmap.api.Chargepoint
|
||||
import com.johan.evmap.api.ChargepointStatus
|
||||
import com.johan.evmap.api.availability.ChargepointStatus
|
||||
import com.johan.evmap.api.goingelectric.ChargeLocation
|
||||
import com.johan.evmap.api.goingelectric.Chargepoint
|
||||
|
||||
interface Equatable {
|
||||
override fun equals(other: Any?): Boolean;
|
||||
|
||||
@@ -8,7 +8,7 @@ import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.johan.evmap.R
|
||||
import com.johan.evmap.api.ChargerPhoto
|
||||
import com.johan.evmap.api.goingelectric.ChargerPhoto
|
||||
import com.ortiz.touchview.TouchImageView
|
||||
import com.squareup.picasso.Callback
|
||||
import com.squareup.picasso.Picasso
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.johan.evmap.api
|
||||
|
||||
import android.location.Location
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.Response
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
||||
@@ -35,4 +35,13 @@ suspend fun Call.await(): Response {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun distanceBetween(
|
||||
startLatitude: Double, startLongitude: Double,
|
||||
endLatitude: Double, endLongitude: Double
|
||||
): Float {
|
||||
val distance = floatArrayOf(0f)
|
||||
Location.distanceBetween(startLatitude, startLongitude, endLatitude, endLongitude, distance)
|
||||
return distance[0]
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.johan.evmap.api.availability
|
||||
|
||||
import com.facebook.stetho.okhttp3.StethoInterceptor
|
||||
import com.johan.evmap.api.await
|
||||
import com.johan.evmap.api.goingelectric.ChargeLocation
|
||||
import com.johan.evmap.api.goingelectric.Chargepoint
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
interface AvailabilityDetector {
|
||||
suspend fun getAvailability(location: ChargeLocation): ChargeLocationStatus
|
||||
}
|
||||
|
||||
abstract class BaseAvailabilityDetector(private val client: OkHttpClient) : AvailabilityDetector {
|
||||
protected suspend fun httpGet(url: String): String {
|
||||
val request = Request.Builder().url(url).build()
|
||||
val response = client.newCall(request).await()
|
||||
|
||||
if (!response.isSuccessful) throw IOException(response.message())
|
||||
|
||||
val str = response.body()!!.string()
|
||||
return str
|
||||
}
|
||||
|
||||
protected fun getCorrespondingChargepoint(
|
||||
cps: Iterable<Chargepoint>, type: String, power: Double
|
||||
): Chargepoint? {
|
||||
var filter = cps.filter {
|
||||
it.type == type
|
||||
}
|
||||
if (filter.size > 1) {
|
||||
filter = filter.filter {
|
||||
if (power > 0) {
|
||||
it.power == power
|
||||
} else true
|
||||
}
|
||||
// TODO: handle not matching powers
|
||||
/*if (filter.isEmpty()) {
|
||||
filter = listOfNotNull(cps.minBy {
|
||||
abs(it.power - power)
|
||||
})
|
||||
}*/
|
||||
}
|
||||
return filter.getOrNull(0)
|
||||
}
|
||||
}
|
||||
|
||||
data class ChargeLocationStatus(
|
||||
val status: Map<Chargepoint, List<ChargepointStatus>>,
|
||||
val source: String
|
||||
)
|
||||
|
||||
enum class ChargepointStatus {
|
||||
AVAILABLE, UNKNOWN, CHARGING, OCCUPIED, FAULTED
|
||||
}
|
||||
|
||||
class AvailabilityDetectorException(message: String) : Exception(message)
|
||||
|
||||
private val okhttp = OkHttpClient.Builder()
|
||||
.addNetworkInterceptor(StethoInterceptor())
|
||||
.readTimeout(10, TimeUnit.SECONDS)
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.build()
|
||||
val availabilityDetectors = listOf(
|
||||
NewMotionAvailabilityDetector(okhttp)
|
||||
/*ChargecloudAvailabilityDetector(
|
||||
okhttp,
|
||||
"606a0da0dfdd338ee4134605653d4fd8"
|
||||
), // Maingau
|
||||
ChargecloudAvailabilityDetector(
|
||||
okhttp,
|
||||
"6336fe713f2eb7fa04b97ff6651b76f8"
|
||||
) // SW Kiel*/
|
||||
)
|
||||
@@ -1,51 +1,35 @@
|
||||
package com.johan.evmap.api
|
||||
package com.johan.evmap.api.availability
|
||||
|
||||
import com.facebook.stetho.okhttp3.StethoInterceptor
|
||||
import com.johan.evmap.api.goingelectric.ChargeLocation
|
||||
import com.johan.evmap.api.goingelectric.Chargepoint
|
||||
import com.johan.evmap.api.iterator
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
private const val radius = 200 // max radius in meters
|
||||
|
||||
interface AvailabilityDetector {
|
||||
suspend fun getAvailability(location: ChargeLocation): ChargeLocationStatus
|
||||
}
|
||||
|
||||
data class ChargeLocationStatus(
|
||||
val status: Map<Chargepoint, List<ChargepointStatus>>,
|
||||
val source: String
|
||||
)
|
||||
|
||||
enum class ChargepointStatus {
|
||||
AVAILABLE, UNKNOWN, CHARGING, OCCUPIED, FAULTED
|
||||
}
|
||||
|
||||
class AvailabilityDetectorException(message: String) : Exception(message)
|
||||
|
||||
class ChargecloudAvailabilityDetector(
|
||||
private val client: OkHttpClient,
|
||||
client: OkHttpClient,
|
||||
private val operatorId: String
|
||||
) : AvailabilityDetector {
|
||||
) : BaseAvailabilityDetector(client) {
|
||||
@ExperimentalCoroutinesApi
|
||||
override suspend fun getAvailability(location: ChargeLocation): ChargeLocationStatus {
|
||||
val url =
|
||||
"https://app.chargecloud.de/emobility:ocpi/$operatorId/app/2.0/locations?latitude=${location.coordinates.lat}&longitude=${location.coordinates.lng}&radius=$radius&offset=0&limit=10"
|
||||
val request = Request.Builder().url(url).build()
|
||||
val response = client.newCall(request).await()
|
||||
|
||||
if (!response.isSuccessful) throw IOException(response.message())
|
||||
|
||||
val json = JSONObject(response.body()!!.string())
|
||||
val json = JSONObject(httpGet(url))
|
||||
|
||||
val statusMessage = json.getString("status_message")
|
||||
if (statusMessage != "Success") throw IOException(statusMessage)
|
||||
|
||||
val data = json.getJSONArray("data")
|
||||
if (data.length() > 1) throw AvailabilityDetectorException("found multiple candidates.")
|
||||
if (data.length() == 0) throw AvailabilityDetectorException("no candidates found.")
|
||||
if (data.length() > 1) throw AvailabilityDetectorException(
|
||||
"found multiple candidates."
|
||||
)
|
||||
if (data.length() == 0) throw AvailabilityDetectorException(
|
||||
"no candidates found."
|
||||
)
|
||||
|
||||
val evses = data.getJSONObject(0).getJSONArray("evses")
|
||||
val chargepointStatus = mutableMapOf<Chargepoint, List<ChargepointStatus>>()
|
||||
@@ -61,15 +45,25 @@ class ChargecloudAvailabilityDetector(
|
||||
// find corresponding chargepoint from goingelectric to get correct power
|
||||
val geChargepoint =
|
||||
getCorrespondingChargepoint(location.chargepoints, type, power)
|
||||
?: throw AvailabilityDetectorException("Chargepoints from chargecloud API and goingelectric do not match.")
|
||||
chargepoint = Chargepoint(type, geChargepoint.power, 1)
|
||||
?: throw AvailabilityDetectorException(
|
||||
"Chargepoints from chargecloud API and goingelectric do not match."
|
||||
)
|
||||
chargepoint = Chargepoint(
|
||||
type,
|
||||
geChargepoint.power,
|
||||
1
|
||||
)
|
||||
statusList = listOf(status)
|
||||
} else {
|
||||
val previousStatus = chargepointStatus[chargepoint]!!
|
||||
statusList = previousStatus + listOf(status)
|
||||
chargepointStatus.remove(chargepoint)
|
||||
chargepoint =
|
||||
Chargepoint(chargepoint.type, chargepoint.power, chargepoint.count + 1)
|
||||
Chargepoint(
|
||||
chargepoint.type,
|
||||
chargepoint.power,
|
||||
chargepoint.count + 1
|
||||
)
|
||||
}
|
||||
|
||||
chargepointStatus[chargepoint] = statusList
|
||||
@@ -79,32 +73,17 @@ class ChargecloudAvailabilityDetector(
|
||||
|
||||
|
||||
if (chargepointStatus.keys == location.chargepoints.toSet()) {
|
||||
return ChargeLocationStatus(chargepointStatus, "chargecloud.de")
|
||||
return ChargeLocationStatus(
|
||||
chargepointStatus,
|
||||
"chargecloud.de"
|
||||
)
|
||||
} else {
|
||||
throw AvailabilityDetectorException("Chargepoints from chargecloud API and goingelectric do not match.")
|
||||
throw AvailabilityDetectorException(
|
||||
"Chargepoints from chargecloud API and goingelectric do not match."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCorrespondingChargepoint(
|
||||
cps: Iterable<Chargepoint>, type: String, power: Double
|
||||
): Chargepoint? {
|
||||
var filter = cps.filter {
|
||||
it.type == type &&
|
||||
if (power > 0) {
|
||||
it.power in power - 2..power + 2
|
||||
} else true
|
||||
}
|
||||
if (filter.size > 1) {
|
||||
filter = cps.filter {
|
||||
it.type == type &&
|
||||
if (power > 0) {
|
||||
it.power == power
|
||||
} else true
|
||||
}
|
||||
}
|
||||
return filter.getOrNull(0)
|
||||
}
|
||||
|
||||
private fun getType(string: String): String {
|
||||
return when (string) {
|
||||
"IEC_62196_T2" -> Chargepoint.TYPE_2
|
||||
@@ -114,14 +93,4 @@ class ChargecloudAvailabilityDetector(
|
||||
else -> throw IllegalArgumentException("unrecognized type $string")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val okhttp = OkHttpClient.Builder()
|
||||
.addNetworkInterceptor(StethoInterceptor())
|
||||
.readTimeout(10, TimeUnit.SECONDS)
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.build()
|
||||
val availabilityDetectors = listOf(
|
||||
ChargecloudAvailabilityDetector(okhttp, "606a0da0dfdd338ee4134605653d4fd8"), // Maingau
|
||||
ChargecloudAvailabilityDetector(okhttp, "6336fe713f2eb7fa04b97ff6651b76f8") // SW Kiel
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package com.johan.evmap.api.availability
|
||||
|
||||
import com.johan.evmap.api.distanceBetween
|
||||
import com.johan.evmap.api.goingelectric.ChargeLocation
|
||||
import com.johan.evmap.api.goingelectric.Chargepoint
|
||||
import com.squareup.moshi.JsonClass
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
|
||||
private const val coordRange = 0.1 // range of latitude and longitude for loading the map
|
||||
private const val maxDistance = 15 // max distance between reported positions in meters
|
||||
|
||||
interface NewMotionApi {
|
||||
@GET("markers/{lngMin}/{lngMax}/{latMin}/{latMax}")
|
||||
suspend fun getMarkers(
|
||||
@Path("lngMin") lngMin: Double,
|
||||
@Path("lngMax") lngMax: Double,
|
||||
@Path("latMin") latMin: Double,
|
||||
@Path("latMax") latMax: Double
|
||||
): List<NMMarker>
|
||||
|
||||
@GET("locations/{id}")
|
||||
suspend fun getLocation(@Path("id") id: Long): NMLocation
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NMMarker(val coordinates: NMCoordinates, val locationUid: Long)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NMCoordinates(val latitude: Double, val longitude: Double)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NMLocation(
|
||||
val uid: Long,
|
||||
val coordinates: NMCoordinates,
|
||||
val operatorName: String,
|
||||
val evses: List<NMEvse>
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NMEvse(val evseId: String, val status: String, val connectors: List<NMConnector>)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NMConnector(
|
||||
val connectorType: String,
|
||||
val electricalProperties: NMElectricalProperties
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NMElectricalProperties(val powerType: String, val voltage: Int, val amperage: Int) {
|
||||
fun getPower(): Double {
|
||||
val phases = when (powerType) {
|
||||
"AC1Phase" -> 1
|
||||
"AC3Phase" -> 3
|
||||
else -> 1
|
||||
}
|
||||
val volt = when (voltage) {
|
||||
277 -> 230
|
||||
else -> voltage
|
||||
}
|
||||
val power = volt * amperage * phases
|
||||
return when (power) {
|
||||
3680 -> 3.7
|
||||
11040 -> 11.0
|
||||
22080 -> 22.0
|
||||
43470 -> 43.0
|
||||
else -> power / 1000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(client: OkHttpClient): NewMotionApi {
|
||||
val retrofit = Retrofit.Builder()
|
||||
.baseUrl("https://my.newmotion.com/api/map/v2/")
|
||||
.addConverterFactory(MoshiConverterFactory.create())
|
||||
.client(client)
|
||||
.build()
|
||||
return retrofit.create(NewMotionApi::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NewMotionAvailabilityDetector(client: OkHttpClient) : BaseAvailabilityDetector(client) {
|
||||
val api = NewMotionApi.create(client)
|
||||
|
||||
override suspend fun getAvailability(location: ChargeLocation): ChargeLocationStatus {
|
||||
val lat = location.coordinates.lat
|
||||
val lng = location.coordinates.lng
|
||||
|
||||
// find nearest station to this position
|
||||
var markers =
|
||||
api.getMarkers(lng - coordRange, lng + coordRange, lat - coordRange, lat + coordRange)
|
||||
val nearest = markers.minBy { marker ->
|
||||
distanceBetween(marker.coordinates.latitude, marker.coordinates.longitude, lat, lng)
|
||||
} ?: throw AvailabilityDetectorException("no candidates found.")
|
||||
|
||||
// combine related stations
|
||||
markers = markers.filter { marker ->
|
||||
distanceBetween(
|
||||
marker.coordinates.latitude,
|
||||
marker.coordinates.longitude,
|
||||
nearest.coordinates.latitude,
|
||||
nearest.coordinates.longitude
|
||||
) < maxDistance
|
||||
}
|
||||
|
||||
// load details
|
||||
var details = markers.map {
|
||||
api.getLocation(it.locationUid)
|
||||
}
|
||||
// only include stations from same operator
|
||||
details = details.filter {
|
||||
it.operatorName == details[0].operatorName
|
||||
}
|
||||
val connectorStatus = details.flatMap { it.evses }.flatMap { evse ->
|
||||
evse.connectors.map { connector ->
|
||||
connector to evse.status
|
||||
}
|
||||
}
|
||||
|
||||
val chargepointStatus = mutableMapOf<Chargepoint, List<ChargepointStatus>>()
|
||||
connectorStatus.forEach { (connector, statusStr) ->
|
||||
val power = connector.electricalProperties.getPower()
|
||||
val type = when (connector.connectorType) {
|
||||
"Type2" -> Chargepoint.TYPE_2
|
||||
"Domestic" -> Chargepoint.SCHUKO
|
||||
"Type2Combo" -> Chargepoint.CCS
|
||||
"TepcoCHAdeMO" -> Chargepoint.CHADEMO
|
||||
else -> throw IllegalArgumentException("unrecognized type ${connector.connectorType}")
|
||||
}
|
||||
val status = when (statusStr) {
|
||||
"Unavailable" -> ChargepointStatus.FAULTED
|
||||
"Available" -> ChargepointStatus.AVAILABLE
|
||||
"Occupied" -> ChargepointStatus.CHARGING
|
||||
"Unspecified" -> ChargepointStatus.UNKNOWN
|
||||
else -> ChargepointStatus.UNKNOWN
|
||||
}
|
||||
|
||||
var chargepoint = getCorrespondingChargepoint(chargepointStatus.keys, type, power)
|
||||
val statusList: List<ChargepointStatus>
|
||||
if (chargepoint == null) {
|
||||
// find corresponding chargepoint from goingelectric to get correct power
|
||||
val geChargepoint =
|
||||
getCorrespondingChargepoint(location.chargepoints, type, power)
|
||||
?: throw AvailabilityDetectorException(
|
||||
"Chargepoints from NewMotion API and goingelectric do not match."
|
||||
)
|
||||
chargepoint = Chargepoint(
|
||||
type,
|
||||
geChargepoint.power,
|
||||
1
|
||||
)
|
||||
statusList = listOf(status)
|
||||
} else {
|
||||
val previousStatus = chargepointStatus[chargepoint]!!
|
||||
statusList = previousStatus + listOf(status)
|
||||
chargepointStatus.remove(chargepoint)
|
||||
chargepoint =
|
||||
Chargepoint(
|
||||
chargepoint.type,
|
||||
chargepoint.power,
|
||||
chargepoint.count + 1
|
||||
)
|
||||
}
|
||||
|
||||
chargepointStatus[chargepoint] = statusList
|
||||
}
|
||||
|
||||
if (chargepointStatus.keys == location.chargepoints.toSet()) {
|
||||
return ChargeLocationStatus(
|
||||
chargepointStatus,
|
||||
"NewMotion"
|
||||
)
|
||||
} else {
|
||||
throw AvailabilityDetectorException(
|
||||
"Chargepoints from NewMotion API and goingelectric do not match."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.johan.evmap.api
|
||||
package com.johan.evmap.api.goingelectric
|
||||
|
||||
import com.squareup.moshi.*
|
||||
import java.lang.reflect.Type
|
||||
@@ -12,7 +12,9 @@ internal class ChargepointListItemJsonAdapterFactory : JsonAdapter.Factory {
|
||||
moshi: Moshi
|
||||
): JsonAdapter<*>? {
|
||||
if (Types.getRawType(type) == ChargepointListItem::class.java) {
|
||||
return ChargepointListItemJsonAdapter(moshi)
|
||||
return ChargepointListItemJsonAdapter(
|
||||
moshi
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
@@ -24,9 +26,13 @@ internal class ChargepointListItemJsonAdapterFactory : JsonAdapter.Factory {
|
||||
internal class ChargepointListItemJsonAdapter(val moshi: Moshi) :
|
||||
JsonAdapter<ChargepointListItem>() {
|
||||
private val clusterAdapter =
|
||||
moshi.adapter<ChargeLocationCluster>(ChargeLocationCluster::class.java)
|
||||
moshi.adapter<ChargeLocationCluster>(
|
||||
ChargeLocationCluster::class.java
|
||||
)
|
||||
|
||||
private val locationAdapter = moshi.adapter<ChargeLocation>(ChargeLocation::class.java)
|
||||
private val locationAdapter = moshi.adapter<ChargeLocation>(
|
||||
ChargeLocation::class.java
|
||||
)
|
||||
|
||||
@FromJson
|
||||
override fun fromJson(reader: JsonReader): ChargepointListItem {
|
||||
@@ -69,9 +75,13 @@ internal class JsonObjectOrFalseAdapter<T> private constructor(
|
||||
moshi: Moshi
|
||||
): JsonAdapter<*>? {
|
||||
val clazz = Types.getRawType(type)
|
||||
return when (hasJsonObjectOrFalseAnnotation(annotations)) {
|
||||
return when (hasJsonObjectOrFalseAnnotation(
|
||||
annotations
|
||||
)) {
|
||||
false -> null
|
||||
true -> JsonObjectOrFalseAdapter(moshi.adapter(clazz))
|
||||
true -> JsonObjectOrFalseAdapter(
|
||||
moshi.adapter(clazz)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.johan.evmap.api
|
||||
package com.johan.evmap.api.goingelectric
|
||||
|
||||
import com.facebook.stetho.okhttp3.StethoInterceptor
|
||||
import com.squareup.moshi.Moshi
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.johan.evmap.api
|
||||
package com.johan.evmap.api.goingelectric
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
@@ -37,10 +37,10 @@ import com.johan.evmap.REQUEST_LOCATION_PERMISSION
|
||||
import com.johan.evmap.adapter.ConnectorAdapter
|
||||
import com.johan.evmap.adapter.DetailAdapter
|
||||
import com.johan.evmap.adapter.GalleryAdapter
|
||||
import com.johan.evmap.api.ChargeLocation
|
||||
import com.johan.evmap.api.ChargeLocationCluster
|
||||
import com.johan.evmap.api.ChargepointListItem
|
||||
import com.johan.evmap.api.ChargerPhoto
|
||||
import com.johan.evmap.api.goingelectric.ChargeLocation
|
||||
import com.johan.evmap.api.goingelectric.ChargeLocationCluster
|
||||
import com.johan.evmap.api.goingelectric.ChargepointListItem
|
||||
import com.johan.evmap.api.goingelectric.ChargerPhoto
|
||||
import com.johan.evmap.databinding.FragmentMapBinding
|
||||
import com.johan.evmap.ui.*
|
||||
import com.johan.evmap.viewmodel.MapPosition
|
||||
|
||||
@@ -12,7 +12,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.johan.evmap.R
|
||||
import com.johan.evmap.api.Chargepoint
|
||||
import com.johan.evmap.api.goingelectric.Chargepoint
|
||||
|
||||
|
||||
@BindingAdapter("goneUnless")
|
||||
|
||||
@@ -6,7 +6,7 @@ import androidx.interpolator.view.animation.FastOutLinearInInterpolator
|
||||
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
|
||||
import com.google.android.gms.maps.model.Marker
|
||||
import com.johan.evmap.R
|
||||
import com.johan.evmap.api.ChargeLocation
|
||||
import com.johan.evmap.api.goingelectric.ChargeLocation
|
||||
|
||||
fun getMarkerTint(charger: ChargeLocation): Int = when {
|
||||
charger.maxPower >= 100 -> R.color.charger_100kw
|
||||
|
||||
@@ -5,7 +5,13 @@ import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.android.gms.maps.model.LatLngBounds
|
||||
import com.johan.evmap.api.*
|
||||
import com.johan.evmap.api.availability.AvailabilityDetectorException
|
||||
import com.johan.evmap.api.availability.ChargeLocationStatus
|
||||
import com.johan.evmap.api.availability.availabilityDetectors
|
||||
import com.johan.evmap.api.goingelectric.ChargeLocation
|
||||
import com.johan.evmap.api.goingelectric.ChargepointList
|
||||
import com.johan.evmap.api.goingelectric.ChargepointListItem
|
||||
import com.johan.evmap.api.goingelectric.GoingElectricApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<data>
|
||||
|
||||
<import type="com.johan.evmap.api.ChargerPhoto" />
|
||||
<import type="com.johan.evmap.api.goingelectric.ChargerPhoto" />
|
||||
|
||||
<import type="java.util.List" />
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
<data>
|
||||
|
||||
<import type="com.johan.evmap.api.ChargeLocation" />
|
||||
<import type="com.johan.evmap.api.goingelectric.ChargeLocation" />
|
||||
|
||||
<import type="com.johan.evmap.api.Chargepoint" />
|
||||
<import type="com.johan.evmap.api.goingelectric.Chargepoint" />
|
||||
|
||||
<import type="com.johan.evmap.api.ChargeLocationStatus" />
|
||||
<import type="com.johan.evmap.api.availability.ChargeLocationStatus" />
|
||||
|
||||
<import type="com.johan.evmap.adapter.DataBindingAdaptersKt" />
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.johan.evmap
|
||||
|
||||
import com.johan.evmap.api.*
|
||||
import com.johan.evmap.api.availability.availabilityDetectors
|
||||
import com.johan.evmap.api.goingelectric.ChargeLocation
|
||||
import com.johan.evmap.api.goingelectric.GoingElectricApi
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
|
||||
Reference in New Issue
Block a user