From 1fee260d1cab745480d4face4702ab655edb4d16 Mon Sep 17 00:00:00 2001 From: johan12345 Date: Sun, 9 Jul 2023 16:53:25 +0200 Subject: [PATCH] OpenStreetMap API: implement some first filters --- .../api/openstreetmap/OpenStreetMapApi.kt | 104 +++++++++++++++++- .../net/vonforst/evmap/storage/Database.kt | 12 +- 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/net/vonforst/evmap/api/openstreetmap/OpenStreetMapApi.kt b/app/src/main/java/net/vonforst/evmap/api/openstreetmap/OpenStreetMapApi.kt index 81b83b46..f046c01b 100644 --- a/app/src/main/java/net/vonforst/evmap/api/openstreetmap/OpenStreetMapApi.kt +++ b/app/src/main/java/net/vonforst/evmap/api/openstreetmap/OpenStreetMapApi.kt @@ -1,20 +1,34 @@ package net.vonforst.evmap.api.openstreetmap +import android.database.DatabaseUtils import com.car2go.maps.model.LatLng import com.car2go.maps.model.LatLngBounds import com.squareup.moshi.Moshi import net.vonforst.evmap.BuildConfig +import net.vonforst.evmap.R import net.vonforst.evmap.addDebugInterceptors import net.vonforst.evmap.api.ChargepointApi import net.vonforst.evmap.api.ChargepointList import net.vonforst.evmap.api.FiltersSQLQuery import net.vonforst.evmap.api.StringProvider +import net.vonforst.evmap.api.goingelectric.GEChargepoint +import net.vonforst.evmap.api.mapPower +import net.vonforst.evmap.api.mapPowerInverse +import net.vonforst.evmap.api.nameForPlugType import net.vonforst.evmap.api.openchargemap.ZonedDateTimeAdapter +import net.vonforst.evmap.api.powerSteps +import net.vonforst.evmap.model.BooleanFilter import net.vonforst.evmap.model.ChargeLocation +import net.vonforst.evmap.model.Chargepoint import net.vonforst.evmap.model.Filter import net.vonforst.evmap.model.FilterValue import net.vonforst.evmap.model.FilterValues +import net.vonforst.evmap.model.MultipleChoiceFilter import net.vonforst.evmap.model.ReferenceData +import net.vonforst.evmap.model.SliderFilter +import net.vonforst.evmap.model.getBooleanValue +import net.vonforst.evmap.model.getMultipleChoiceValue +import net.vonforst.evmap.model.getSliderValue import net.vonforst.evmap.viewmodel.Resource import okhttp3.OkHttpClient import retrofit2.Response @@ -99,14 +113,100 @@ class OpenStreetMapApiWrapper(baseurl: String = "https://evmap-dev.vonforst.net" referenceData: ReferenceData, sp: StringProvider ): List> { - return emptyList() + + val plugs = listOf( + Chargepoint.TYPE_1, + Chargepoint.CCS_TYPE_1, + Chargepoint.TYPE_2_SOCKET, + Chargepoint.TYPE_2_PLUG, + Chargepoint.CCS_TYPE_2, + Chargepoint.CHADEMO, + Chargepoint.SUPERCHARGER, + Chargepoint.CEE_BLAU, + Chargepoint.CEE_ROT, + Chargepoint.SCHUKO + ) + val plugMap = plugs.associateWith { plug -> + nameForPlugType(sp, plug) + } + + return listOf( + BooleanFilter(sp.getString(R.string.filter_free), "freecharging"), + BooleanFilter(sp.getString(R.string.filter_free_parking), "freeparking"), + BooleanFilter(sp.getString(R.string.filter_open_247), "open_247"), + SliderFilter( + sp.getString(R.string.filter_min_power), "min_power", + powerSteps.size - 1, + mapping = ::mapPower, + inverseMapping = ::mapPowerInverse, + unit = "kW" + ), + MultipleChoiceFilter( + sp.getString(R.string.filter_connectors), "connectors", + plugMap, + commonChoices = setOf( + Chargepoint.TYPE_1, + Chargepoint.TYPE_2_SOCKET, + Chargepoint.TYPE_2_PLUG, + Chargepoint.CCS_TYPE_1, + Chargepoint.CCS_TYPE_2, + Chargepoint.CHADEMO + ), + manyChoices = true + ), + SliderFilter( + sp.getString(R.string.filter_min_connectors), + "min_connectors", + 10, + min = 1 + ) + ) } override fun convertFiltersToSQL( filters: FilterValues, referenceData: ReferenceData ): FiltersSQLQuery { - TODO("Not yet implemented") + if (filters.isEmpty()) return FiltersSQLQuery("", false, false) + var requiresChargepointQuery = false + + val result = StringBuilder() + if (filters.getBooleanValue("freecharging") == true) { + result.append(" AND freecharging IS 1") + } + if (filters.getBooleanValue("freeparking") == true) { + result.append(" AND freeparking IS 1") + } + if (filters.getBooleanValue("open_247") == true) { + result.append(" AND twentyfourSeven IS 1") + } + + val minPower = filters.getSliderValue("min_power") + if (minPower != null && minPower > 0) { + result.append(" AND json_extract(cp.value, '$.power') >= ${minPower}") + requiresChargepointQuery = true + } + + val connectors = filters.getMultipleChoiceValue("connectors") + if (connectors != null && !connectors.all) { + val connectorsList = if (connectors.values.size == 0) { + "" + } else { + connectors.values.joinToString(",") { + DatabaseUtils.sqlEscapeString(it) + } + } + result.append(" AND json_extract(cp.value, '$.type') IN (${connectorsList})") + requiresChargepointQuery = true + } + + val minConnectors = filters.getSliderValue("min_connectors") + if (minConnectors != null && minConnectors > 1) { + result.append(" GROUP BY ChargeLocation.id HAVING COUNT(1) >= $minConnectors") + requiresChargepointQuery = true + } + + return FiltersSQLQuery(result.toString(), requiresChargepointQuery, false) } override fun filteringInSQLRequiresDetails(filters: FilterValues): Boolean { diff --git a/app/src/main/java/net/vonforst/evmap/storage/Database.kt b/app/src/main/java/net/vonforst/evmap/storage/Database.kt index 5b855c2e..988f6faa 100644 --- a/app/src/main/java/net/vonforst/evmap/storage/Database.kt +++ b/app/src/main/java/net/vonforst/evmap/storage/Database.kt @@ -34,7 +34,7 @@ import net.vonforst.evmap.model.* OCMCountry::class, OCMOperator::class, SavedRegion::class - ], version = 22 + ], version = 23 ) @TypeConverters(Converters::class, GeometryConverters::class) abstract class AppDatabase : RoomDatabase() { @@ -75,13 +75,14 @@ abstract class AppDatabase : RoomDatabase() { MIGRATION_7, MIGRATION_8, MIGRATION_9, MIGRATION_10, MIGRATION_11, MIGRATION_12, MIGRATION_13, MIGRATION_14, MIGRATION_15, MIGRATION_16, MIGRATION_17, MIGRATION_18, MIGRATION_19, MIGRATION_20, MIGRATION_21, - MIGRATION_22 + MIGRATION_22, MIGRATION_23 ) .addCallback(object : Callback() { override fun onCreate(db: SupportSQLiteDatabase) { // create default filter profile for each data source db.execSQL("INSERT INTO `FilterProfile` (`dataSource`, `name`, `id`, `order`) VALUES ('goingelectric', 'FILTERS_CUSTOM', $FILTERS_CUSTOM, 0)") db.execSQL("INSERT INTO `FilterProfile` (`dataSource`, `name`, `id`, `order`) VALUES ('openchargemap', 'FILTERS_CUSTOM', $FILTERS_CUSTOM, 0)") + db.execSQL("INSERT INTO `FilterProfile` (`dataSource`, `name`, `id`, `order`) VALUES ('openstreetmap', 'FILTERS_CUSTOM', $FILTERS_CUSTOM, 0)") // initialize spatialite columns db.query("SELECT RecoverGeometryColumn('ChargeLocation', 'coordinates', 4326, 'POINT', 'XY');") .moveToNext() @@ -459,6 +460,13 @@ abstract class AppDatabase : RoomDatabase() { db.execSQL("DELETE FROM savedregion") } } + + private val MIGRATION_23 = object : Migration(22, 23) { + override fun migrate(db: SupportSQLiteDatabase) { + // API openstreetmap added + db.execSQL("INSERT INTO `FilterProfile` (`dataSource`, `name`, `id`, `order`) VALUES ('openstreetmap', 'FILTERS_CUSTOM', $FILTERS_CUSTOM, 0)") + } + } } /**