mirror of
https://github.com/ev-map/EVMap.git
synced 2025-12-29 10:07:45 -05:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
895b24d406 | ||
|
|
3dea7993f3 | ||
|
|
ca90f1b37f | ||
|
|
fe0843e653 | ||
|
|
0f42ae84de | ||
|
|
2748b0a3db |
@@ -21,8 +21,8 @@ android {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 33
|
||||
// NOTE: always increase versionCode by 2 since automotive flavor uses versionCode + 1
|
||||
versionCode 180
|
||||
versionName "1.6.0"
|
||||
versionCode 182
|
||||
versionName "1.6.1"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
resConfigs supportedLocales.split(',')
|
||||
|
||||
@@ -49,6 +49,8 @@ interface ChargepointApi<out T : ReferenceData> {
|
||||
|
||||
fun convertFiltersToSQL(filters: FilterValues, referenceData: ReferenceData): FiltersSQLQuery
|
||||
|
||||
fun filteringInSQLRequiresDetails(filters: FilterValues): Boolean
|
||||
|
||||
val name: String
|
||||
val id: String
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ internal class JsonObjectOrFalseAdapter<T> private constructor(
|
||||
false -> null // Response was false
|
||||
else -> {
|
||||
if (this.clazz == GEFaultReport::class.java) {
|
||||
GEFaultReport(null, null) as T
|
||||
GEFaultReport(null, "") as T
|
||||
} else {
|
||||
throw IllegalStateException("Non-false boolean for @JsonObjectOrFalse field")
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ class GoingElectricApiWrapper(
|
||||
}
|
||||
} while (startkey != null && startkey < 10000)
|
||||
|
||||
val result = postprocessResult(data, minPower, connectorsVal, minConnectors)
|
||||
val result = postprocessResult(data, filters)
|
||||
|
||||
return Resource.success(ChargepointList(result, startkey == null))
|
||||
}
|
||||
@@ -308,18 +308,24 @@ class GoingElectricApiWrapper(
|
||||
}
|
||||
} while (startkey != null && startkey < 10000)
|
||||
|
||||
val result = postprocessResult(data, minPower, connectorsVal, minConnectors)
|
||||
val result = postprocessResult(data, filters)
|
||||
return Resource.success(ChargepointList(result, startkey == null))
|
||||
}
|
||||
|
||||
private fun postprocessResult(
|
||||
chargers: List<GEChargepointListItem>,
|
||||
minPower: Int?,
|
||||
connectorsVal: MultipleChoiceFilterValue?,
|
||||
minConnectors: Int?
|
||||
filters: FilterValues?
|
||||
): List<ChargepointListItem> {
|
||||
// apply filters which GoingElectric does not support natively
|
||||
val minPower = filters?.getSliderValue("min_power")
|
||||
val minConnectors = filters?.getSliderValue("min_connectors")
|
||||
val connectorsVal = filters?.getMultipleChoiceValue("connectors")
|
||||
val freecharging = filters?.getBooleanValue("freecharging")
|
||||
val freeparking = filters?.getBooleanValue("freeparking")
|
||||
val open247 = filters?.getBooleanValue("open_247")
|
||||
val barrierfree = filters?.getBooleanValue("barrierfree")
|
||||
|
||||
return chargers.filter { it ->
|
||||
// apply filters which GoingElectric does not support natively
|
||||
if (it is GEChargeLocation) {
|
||||
it.chargepoints
|
||||
.filter { it.power >= (minPower ?: 0) }
|
||||
@@ -328,6 +334,34 @@ class GoingElectricApiWrapper(
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}.map {
|
||||
// infer some properties based on applied filters
|
||||
if (it is GEChargeLocation) {
|
||||
var inferred = it
|
||||
if (freecharging == true) {
|
||||
inferred = inferred.copy(
|
||||
cost = inferred.cost?.copy(freecharging = true)
|
||||
?: GECost(freecharging = true)
|
||||
)
|
||||
}
|
||||
if (freeparking == true) {
|
||||
inferred = inferred.copy(
|
||||
cost = inferred.cost?.copy(freeparking = true) ?: GECost(freeparking = true)
|
||||
)
|
||||
}
|
||||
if (open247 == true) {
|
||||
inferred = inferred.copy(
|
||||
openinghours = inferred.openinghours?.copy(twentyfourSeven = true)
|
||||
?: GEOpeningHours(twentyfourSeven = true)
|
||||
)
|
||||
}
|
||||
if (barrierfree == true) {
|
||||
inferred = inferred.copy(barrierFree = true)
|
||||
}
|
||||
inferred
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}.map { it.convert(apikey, false) }
|
||||
}
|
||||
|
||||
@@ -546,5 +580,14 @@ class GoingElectricApiWrapper(
|
||||
|
||||
return FiltersSQLQuery(result.toString(), requiresChargepointQuery, requiresChargeCardQuery)
|
||||
}
|
||||
|
||||
override fun filteringInSQLRequiresDetails(filters: FilterValues): Boolean {
|
||||
val chargecards = filters.getMultipleChoiceValue("chargecards")
|
||||
return filters.getBooleanValue("freecharging") == true
|
||||
|| filters.getBooleanValue("freeparking") == true
|
||||
|| filters.getBooleanValue("open_247") == true
|
||||
|| filters.getBooleanValue("barrierfree") == true
|
||||
|| (chargecards != null && !chargecards.all)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,10 +86,10 @@ data class GEChargeLocation(
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GECost(
|
||||
val freecharging: Boolean,
|
||||
val freeparking: Boolean,
|
||||
@JsonObjectOrFalse @Json(name = "description_short") val descriptionShort: String?,
|
||||
@JsonObjectOrFalse @Json(name = "description_long") val descriptionLong: String?
|
||||
val freecharging: Boolean = false,
|
||||
val freeparking: Boolean = false,
|
||||
@JsonObjectOrFalse @Json(name = "description_short") val descriptionShort: String? = null,
|
||||
@JsonObjectOrFalse @Json(name = "description_long") val descriptionLong: String? = null
|
||||
) {
|
||||
fun convert() = Cost(
|
||||
// In GE, freecharging = false can either mean "paid charging" or "no information
|
||||
@@ -104,8 +104,8 @@ data class GECost(
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GEOpeningHours(
|
||||
@Json(name = "24/7") val twentyfourSeven: Boolean,
|
||||
@JsonObjectOrFalse val description: String?,
|
||||
val days: GEOpeningHoursDays?
|
||||
@JsonObjectOrFalse val description: String? = null,
|
||||
val days: GEOpeningHoursDays? = null
|
||||
) {
|
||||
fun convert() = OpeningHours(twentyfourSeven, description, days?.convert())
|
||||
}
|
||||
|
||||
@@ -379,4 +379,10 @@ class OpenChargeMapApiWrapper(
|
||||
return FiltersSQLQuery(result.toString(), requiresChargepointQuery, false)
|
||||
}
|
||||
|
||||
override fun filteringInSQLRequiresDetails(filters: FilterValues): Boolean {
|
||||
val operators = filters.getMultipleChoiceValue("operators")
|
||||
return (operators != null && !operators.all)
|
||||
// TODO: it would be possible to implement this without requiring details if we extended the data structure to also save the operator ID in the DB
|
||||
}
|
||||
|
||||
}
|
||||
@@ -101,7 +101,7 @@ data class OCMChargepoint(
|
||||
connections.first { it.statusType != null && it.statusTypeId in faultStatuses }.statusType!!.title
|
||||
)
|
||||
}
|
||||
return FaultReport(null, null)
|
||||
return FaultReport(null, "")
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -161,6 +161,7 @@ class ChargeLocationsRepository(
|
||||
val filtersSerialized =
|
||||
filters?.filter { it.value != it.filter.defaultValue() }?.takeIf { it.isNotEmpty() }
|
||||
?.serialize()
|
||||
val requiresDetail = filters?.let { api.filteringInSQLRequiresDetails(it) } ?: false
|
||||
val savedRegionResult = savedRegionDao.savedRegionCovers(
|
||||
bounds.southwest.latitude,
|
||||
bounds.northeast.latitude,
|
||||
@@ -168,7 +169,8 @@ class ChargeLocationsRepository(
|
||||
bounds.northeast.longitude,
|
||||
api.id,
|
||||
cacheSoftLimitDate(api),
|
||||
filtersSerialized
|
||||
filtersSerialized,
|
||||
requiresDetail
|
||||
)
|
||||
val useClustering = shouldUseServerSideClustering(zoom)
|
||||
val apiResult = liveData {
|
||||
@@ -224,13 +226,15 @@ class ChargeLocationsRepository(
|
||||
val filtersSerialized =
|
||||
filters?.filter { it.value != it.filter.defaultValue() }?.takeIf { it.isNotEmpty() }
|
||||
?.serialize()
|
||||
val requiresDetail = filters?.let { api.filteringInSQLRequiresDetails(it) } ?: false
|
||||
val savedRegionResult = savedRegionDao.savedRegionCoversRadius(
|
||||
location.latitude,
|
||||
location.longitude,
|
||||
radiusMeters * 0.999, // to account for float rounding errors
|
||||
api.id,
|
||||
cacheSoftLimitDate(api),
|
||||
filtersSerialized
|
||||
filtersSerialized,
|
||||
requiresDetail
|
||||
)
|
||||
val useClustering = shouldUseServerSideClustering(zoom)
|
||||
val apiResult = liveData {
|
||||
|
||||
@@ -4,22 +4,20 @@ import android.annotation.SuppressLint
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import androidx.lifecycle.map
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import co.anbora.labs.spatia.builder.SpatiaBuilder
|
||||
import co.anbora.labs.spatia.builder.SpatiaRoom
|
||||
import co.anbora.labs.spatia.geometry.GeometryConverters
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.vonforst.evmap.api.goingelectric.GEChargeCard
|
||||
import net.vonforst.evmap.api.goingelectric.GEChargepoint
|
||||
import net.vonforst.evmap.api.openchargemap.OCMConnectionType
|
||||
import net.vonforst.evmap.api.openchargemap.OCMCountry
|
||||
import net.vonforst.evmap.api.openchargemap.OCMOperator
|
||||
import net.vonforst.evmap.model.*
|
||||
import net.vonforst.evmap.viewmodel.await
|
||||
|
||||
@Database(
|
||||
entities = [
|
||||
@@ -37,7 +35,7 @@ import net.vonforst.evmap.viewmodel.await
|
||||
OCMCountry::class,
|
||||
OCMOperator::class,
|
||||
SavedRegion::class
|
||||
], version = 20
|
||||
], version = 21
|
||||
)
|
||||
@TypeConverters(Converters::class, GeometryConverters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
@@ -77,7 +75,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
MIGRATION_2, MIGRATION_3, MIGRATION_4, MIGRATION_5, MIGRATION_6,
|
||||
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_17, MIGRATION_18, MIGRATION_19, MIGRATION_20, MIGRATION_21
|
||||
)
|
||||
.addCallback(object : Callback() {
|
||||
override fun onCreate(db: SupportSQLiteDatabase) {
|
||||
@@ -447,6 +445,13 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val MIGRATION_21 = object : Migration(20, 21) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
// clear cache with this update
|
||||
db.execSQL("DELETE FROM savedregion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -548,7 +548,8 @@ class MapViewModel(application: Application, private val state: SavedStateHandle
|
||||
val apiId = apiId.value
|
||||
when (apiId) {
|
||||
"goingelectric" -> {
|
||||
val chargeCardsVal = filters.getMultipleChoiceValue("chargecards")!!
|
||||
val chargeCardsVal =
|
||||
filters.getMultipleChoiceValue("chargecards") ?: return@addSource
|
||||
filteredChargeCards.value =
|
||||
if (chargeCardsVal.all) null else chargeCardsVal.values.map { it.toLong() }
|
||||
.toSet()
|
||||
|
||||
3
fastlane/metadata/android/de-DE/changelogs/182.txt
Normal file
3
fastlane/metadata/android/de-DE/changelogs/182.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Fehler behoben:
|
||||
- Abstürze behoben
|
||||
- Fehler im Caching-Algorithmus im Zusammenspiel mit bestimmten Filtern behoben
|
||||
3
fastlane/metadata/android/en-US/changelogs/182.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/182.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Bugfixes:
|
||||
- Fixed crashes
|
||||
- Fixed error in caching algorithm when some filters are active
|
||||
Reference in New Issue
Block a user