From d52ec0c63f47cbcf7b91389a7f2f75dfdae0dac3 Mon Sep 17 00:00:00 2001 From: johan12345 Date: Wed, 5 Oct 2022 21:28:51 +0200 Subject: [PATCH] improve heuristics in Chargeprice code fixes #238 --- .../vonforst/evmap/auto/ChargepriceScreen.kt | 8 +++ .../evmap/auto/ChargerDetailScreen.kt | 25 +++++---- .../evmap/api/chargeprice/ChargepriceApi.kt | 51 +++++++++++++++---- .../evmap/viewmodel/ChargepriceViewModel.kt | 6 +++ app/src/main/res/layout/detail_view.xml | 2 +- 5 files changed, 67 insertions(+), 25 deletions(-) diff --git a/app/src/google/java/net/vonforst/evmap/auto/ChargepriceScreen.kt b/app/src/google/java/net/vonforst/evmap/auto/ChargepriceScreen.kt index cce6d4ea..5e9b1327 100644 --- a/app/src/google/java/net/vonforst/evmap/auto/ChargepriceScreen.kt +++ b/app/src/google/java/net/vonforst/evmap/auto/ChargepriceScreen.kt @@ -201,6 +201,14 @@ class ChargepriceScreen(ctx: CarContext, val charger: ChargeLocation) : Screen(c try { val car = determineVehicle(manufacturer, modelName) val cpStation = ChargepriceStation.fromEvmap(charger, car.compatibleEvmapConnectors) + + if (cpStation.chargePoints.isEmpty()) { + errorMessage = + carContext.getString(R.string.chargeprice_no_compatible_connectors) + invalidate() + return@launch + } + val result = api.getChargePrices( ChargepriceRequest( dataAdapter = dataAdapter, diff --git a/app/src/google/java/net/vonforst/evmap/auto/ChargerDetailScreen.kt b/app/src/google/java/net/vonforst/evmap/auto/ChargerDetailScreen.kt index 88dfde68..4b3a2643 100644 --- a/app/src/google/java/net/vonforst/evmap/auto/ChargerDetailScreen.kt +++ b/app/src/google/java/net/vonforst/evmap/auto/ChargerDetailScreen.kt @@ -104,24 +104,23 @@ class ChargerDetailScreen(ctx: CarContext, val chargerSparse: ChargeLocation) : navigateToCharger(charger) } .build()) - charger.chargepriceData?.country?.let { country -> - if (ChargepriceApi.isCountrySupported(country, charger.dataSource)) { - addAction(Action.Builder() - .setIcon( - CarIcon.Builder( - IconCompat.createWithResource( - carContext, - R.drawable.ic_chargeprice - ) - ).build() - ) - .setTitle(carContext.getString(R.string.auto_prices)) + if (ChargepriceApi.isChargerSupported(charger)) { + addAction( + Action.Builder() + .setIcon( + CarIcon.Builder( + IconCompat.createWithResource( + carContext, + R.drawable.ic_chargeprice + ) + ).build() + ) + .setTitle(carContext.getString(R.string.auto_prices)) .setOnClickListener { screenManager.push(ChargepriceScreen(carContext, charger)) } .build()) } - } } ?: setLoading(true) }.build() ).apply { diff --git a/app/src/main/java/net/vonforst/evmap/api/chargeprice/ChargepriceApi.kt b/app/src/main/java/net/vonforst/evmap/api/chargeprice/ChargepriceApi.kt index 7ceeab84..2b9af65e 100644 --- a/app/src/main/java/net/vonforst/evmap/api/chargeprice/ChargepriceApi.kt +++ b/app/src/main/java/net/vonforst/evmap/api/chargeprice/ChargepriceApi.kt @@ -112,18 +112,47 @@ interface ChargepriceApi { else -> throw IllegalArgumentException() } + /** + * Checks if a charger is supported by Chargeprice. + * + * This function just applies some heuristics on the charger's data without making API + * calls. If it returns true, that is not a guarantee that Chargeprice will have information + * on this charger. But if it is false, it is pretty unlikely that Chargeprice will have + * useful data, so we do not show the price comparison button in this case. + */ @JvmStatic - fun isCountrySupported(country: String, dataSource: String): Boolean = when (dataSource) { - "goingelectric" -> country in listOf( - // list of countries according to Chargeprice.app, 2021/08/24 - "Deutschland", - "Österreich", - "Schweiz", - "Frankreich", - "Belgien", - "Niederlande", - "Luxemburg", - "Dänemark", + fun isChargerSupported(charger: ChargeLocation): Boolean { + val dataSourceSupported = charger.dataSource in listOf("goingelectric", "openchargemap") + val countrySupported = + charger.chargepriceData?.country?.let { isCountrySupported(it, charger.dataSource) } + ?: false + val networkSupported = charger.chargepriceData?.network?.let { + if (charger.dataSource == "openchargemap") { + it !in listOf( + "1", // unknown operator + "44", // private residence/individual + "45" // business owner at location + ) + } else { + true + } + } ?: false + val powerAvailable = charger.chargepoints.all { it.hasKnownPower() } + return dataSourceSupported && countrySupported && networkSupported && powerAvailable + } + + private fun isCountrySupported(country: String, dataSource: String): Boolean = + when (dataSource) { + "goingelectric" -> country in listOf( + // list of countries according to Chargeprice.app, 2021/08/24 + "Deutschland", + "Österreich", + "Schweiz", + "Frankreich", + "Belgien", + "Niederlande", + "Luxemburg", + "Dänemark", "Norwegen", "Schweden", "Slowenien", diff --git a/app/src/main/java/net/vonforst/evmap/viewmodel/ChargepriceViewModel.kt b/app/src/main/java/net/vonforst/evmap/viewmodel/ChargepriceViewModel.kt index d7df19ac..18437e74 100644 --- a/app/src/main/java/net/vonforst/evmap/viewmodel/ChargepriceViewModel.kt +++ b/app/src/main/java/net/vonforst/evmap/viewmodel/ChargepriceViewModel.kt @@ -243,6 +243,12 @@ class ChargepriceViewModel( } val cpStation = ChargepriceStation.fromEvmap(charger, compatibleConnectors) + if (cpStation.chargePoints.isEmpty()) { + // no compatible connectors + chargePrices.value = Resource.success(emptyList()) + chargePriceMeta.value = Resource.success(ChargepriceMeta(emptyList())) + return + } loadPricesJob?.cancel() loadPricesJob = viewModelScope.launch { diff --git a/app/src/main/res/layout/detail_view.xml b/app/src/main/res/layout/detail_view.xml index 1e95a6ad..75889b49 100644 --- a/app/src/main/res/layout/detail_view.xml +++ b/app/src/main/res/layout/detail_view.xml @@ -321,7 +321,7 @@ android:layout_marginTop="8dp" android:text="@string/go_to_chargeprice" android:transitionName="@string/shared_element_chargeprice" - app:goneUnless="@{charger.data != null && charger.data.chargepriceData != null && charger.data.chargepriceData.country != null && ChargepriceApi.isCountrySupported(charger.data.chargepriceData.country, charger.data.dataSource)}" + app:goneUnless="@{charger.data != null && ChargepriceApi.isChargerSupported(charger.data)}" app:icon="@drawable/ic_chargeprice" app:layout_constraintEnd_toStartOf="@+id/guideline2" app:layout_constraintStart_toStartOf="@+id/guideline"