mirror of
https://github.com/ev-map/EVMap.git
synced 2025-12-27 00:57:45 -05:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1be519b1ee | ||
|
|
01737f21d2 | ||
|
|
17ce9f420b | ||
|
|
6eb90498eb | ||
|
|
074e0bf904 | ||
|
|
41ac223e97 | ||
|
|
f7196bcce0 | ||
|
|
4f6092e5dc | ||
|
|
dfd42e1ffd | ||
|
|
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 186
|
||||
versionName "1.6.3"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
resConfigs supportedLocales.split(',')
|
||||
@@ -246,10 +246,7 @@ dependencies {
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
implementation "androidx.room:room-ktx:$room_version"
|
||||
implementation('com.github.anboralabs:spatia-room:0.2.6') {
|
||||
exclude group: 'com.github.dalgarins', module: 'android-spatialite'
|
||||
}
|
||||
implementation 'com.github.ev-map:android-spatialite:654dca2365'
|
||||
implementation 'com.github.anboralabs:spatia-room:0.2.7'
|
||||
|
||||
// billing library
|
||||
def billing_version = "6.0.0"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -281,7 +281,7 @@ interface TeslaGraphQlApi {
|
||||
val siteDynamic: SiteDynamic,
|
||||
val siteStatic: SiteStatic,
|
||||
val pricing: Pricing,
|
||||
val congestionPriceHistogram: CongestionPriceHistogram,
|
||||
val congestionPriceHistogram: CongestionPriceHistogram?,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
@@ -574,12 +574,13 @@ class TeslaAvailabilityDetector(
|
||||
i += connector.count
|
||||
}
|
||||
|
||||
val indexOfMidnight =
|
||||
details.congestionPriceHistogram.dataAttributes.indexOfFirst { it.label == "12AM" }
|
||||
val congestionHistogram = indexOfMidnight.takeIf { it >= 0 }?.let { index ->
|
||||
val data = details.congestionPriceHistogram.data.toMutableList()
|
||||
Collections.rotate(data, -index)
|
||||
data
|
||||
val congestionHistogram = details.congestionPriceHistogram?.let { cph ->
|
||||
val indexOfMidnight = cph.dataAttributes.indexOfFirst { it.label == "12AM" }
|
||||
indexOfMidnight.takeIf { it >= 0 }?.let { index ->
|
||||
val data = cph.data.toMutableList()
|
||||
Collections.rotate(data, -index)
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
return ChargeLocationStatus(
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.vonforst.evmap.api.goingelectric
|
||||
|
||||
import android.content.Context
|
||||
import android.database.DatabaseUtils
|
||||
import com.car2go.maps.model.LatLng
|
||||
import com.car2go.maps.model.LatLngBounds
|
||||
import com.squareup.moshi.Moshi
|
||||
@@ -217,7 +218,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 +309,26 @@ 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")
|
||||
val networks = filters?.getMultipleChoiceValue("networks")
|
||||
val chargecards = filters?.getMultipleChoiceValue("chargecards")
|
||||
|
||||
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 +337,40 @@ 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
|
||||
&& (networks == null || networks.all || it.network !in networks.values)
|
||||
&& (chargecards == null || chargecards.all)
|
||||
) {
|
||||
/* barrierfree, networks and chargecards are combined with OR - so we can only
|
||||
* be sure that the charger is barrierFree if the other filters are not active
|
||||
* or the charger does not match the other filters */
|
||||
inferred = inferred.copy(barrierFree = true)
|
||||
}
|
||||
inferred
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}.map { it.convert(apikey, false) }
|
||||
}
|
||||
|
||||
@@ -487,9 +530,6 @@ class GoingElectricApiWrapper(
|
||||
if (filters.getBooleanValue("open_247") == true) {
|
||||
result.append(" AND twentyfourSeven IS 1")
|
||||
}
|
||||
if (filters.getBooleanValue("barrierfree") == true) {
|
||||
result.append(" AND barrierFree IS 1")
|
||||
}
|
||||
if (filters.getBooleanValue("exclude_faults") == true) {
|
||||
result.append(" AND fault_report_description IS NULL AND fault_report_created IS NULL")
|
||||
}
|
||||
@@ -505,31 +545,46 @@ class GoingElectricApiWrapper(
|
||||
val connectorsList = if (connectors.values.size == 0) {
|
||||
""
|
||||
} else {
|
||||
"'" + connectors.values.joinToString("', '") { GEChargepoint.convertTypeFromGE(it) } + "'"
|
||||
connectors.values.joinToString(",") {
|
||||
DatabaseUtils.sqlEscapeString(
|
||||
GEChargepoint.convertTypeFromGE(
|
||||
it
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
result.append(" AND json_extract(cp.value, '$.type') IN (${connectorsList})")
|
||||
requiresChargepointQuery = true
|
||||
}
|
||||
|
||||
// networks, chargecards and barrierFree filters are combined with OR in the GE API
|
||||
val networks = filters.getMultipleChoiceValue("networks")
|
||||
if (networks != null && !networks.all) {
|
||||
val networksList = if (networks.values.size == 0) {
|
||||
""
|
||||
} else {
|
||||
"'" + networks.values.joinToString("', '") + "'"
|
||||
}
|
||||
result.append(" AND network IN (${networksList})")
|
||||
}
|
||||
|
||||
val chargecards = filters.getMultipleChoiceValue("chargecards")
|
||||
if (chargecards != null && !chargecards.all) {
|
||||
val chargecardsList = if (chargecards.values.size == 0) {
|
||||
""
|
||||
} else {
|
||||
chargecards.values.joinToString(",")
|
||||
val barrierFree = filters.getBooleanValue("barrierfree")
|
||||
|
||||
if ((networks != null && !networks.all) || barrierFree == true || (chargecards != null && !chargecards.all)) {
|
||||
val queries = mutableListOf<String>()
|
||||
if (networks != null && !networks.all) {
|
||||
val networksList = if (networks.values.size == 0) {
|
||||
""
|
||||
} else {
|
||||
networks.values.joinToString(",") { DatabaseUtils.sqlEscapeString(it) }
|
||||
}
|
||||
queries.add("network IN (${networksList})")
|
||||
}
|
||||
result.append(" AND json_extract(cc.value, '$.id') IN (${chargecardsList})")
|
||||
requiresChargeCardQuery = true
|
||||
if (barrierFree == true) {
|
||||
queries.add("barrierFree IS 1")
|
||||
}
|
||||
if (chargecards != null && !chargecards.all) {
|
||||
val chargecardsList = if (chargecards.values.size == 0) {
|
||||
""
|
||||
} else {
|
||||
chargecards.values.joinToString(",")
|
||||
}
|
||||
queries.add("json_extract(cc.value, '$.id') IN (${chargecardsList})")
|
||||
requiresChargeCardQuery = true
|
||||
}
|
||||
result.append(" AND (${queries.joinToString(" OR ")})")
|
||||
}
|
||||
|
||||
val categories = filters.getMultipleChoiceValue("categories")
|
||||
@@ -546,5 +601,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())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.vonforst.evmap.api.openchargemap
|
||||
|
||||
import android.content.Context
|
||||
import android.database.DatabaseUtils
|
||||
import com.car2go.maps.model.LatLng
|
||||
import com.car2go.maps.model.LatLngBounds
|
||||
import com.squareup.moshi.Moshi
|
||||
@@ -347,12 +348,14 @@ class OpenChargeMapApiWrapper(
|
||||
val connectorsList = if (connectors.values.size == 0) {
|
||||
""
|
||||
} else {
|
||||
"'" + connectors.values.joinToString("', '") {
|
||||
OCMConnection.convertConnectionTypeFromOCM(
|
||||
it.toLong(),
|
||||
refData
|
||||
connectors.values.joinToString(",") {
|
||||
DatabaseUtils.sqlEscapeString(
|
||||
OCMConnection.convertConnectionTypeFromOCM(
|
||||
it.toLong(),
|
||||
refData
|
||||
)
|
||||
)
|
||||
} + "'"
|
||||
}
|
||||
}
|
||||
result.append(" AND json_extract(cp.value, '$.type') IN (${connectorsList})")
|
||||
requiresChargepointQuery = true
|
||||
@@ -363,9 +366,9 @@ class OpenChargeMapApiWrapper(
|
||||
val networksList = if (operators.values.size == 0) {
|
||||
""
|
||||
} else {
|
||||
"'" + operators.values.joinToString("', '") { opId ->
|
||||
refData.operators.find { it.id == opId.toLong() }?.title.orEmpty()
|
||||
} + "'"
|
||||
operators.values.joinToString(",") { opId ->
|
||||
DatabaseUtils.sqlEscapeString(refData.operators.find { it.id == opId.toLong() }?.title.orEmpty())
|
||||
}
|
||||
}
|
||||
result.append(" AND network IN (${networksList})")
|
||||
}
|
||||
@@ -379,4 +382,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()
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<string name="fault_report_date">Com problemas (atualizado: %s)</string>
|
||||
<string name="filter_chargecards">Formas de pagamento</string>
|
||||
<string name="pref_language">Língua da app</string>
|
||||
<string name="all_selected">Todos selecionados</string>
|
||||
<string name="all_selected">Todas selecionadas</string>
|
||||
<string name="edit">editar</string>
|
||||
<string name="pref_darkmode">Modo escuro</string>
|
||||
<string name="connection_error">Não foi possível carregar a lista de carregadores</string>
|
||||
@@ -97,7 +97,7 @@
|
||||
<string name="save_as_profile">Guardar como perfil</string>
|
||||
<string name="filterprofiles_empty_state">Não existem filtros guardados</string>
|
||||
<string name="welcome_2">Cada cor corresponde a potência máxima do carregador</string>
|
||||
<string name="welcome_to_evmap">Bem-vindo ao EVMap</string>
|
||||
<string name="welcome_to_evmap">Bem-vindo(a) ao EVMap</string>
|
||||
<string name="pref_darkmode_always_off">Sempre desligado</string>
|
||||
<string name="welcome_2_title">Escolha a potência</string>
|
||||
<string name="navigate">Navegar</string>
|
||||
@@ -302,7 +302,7 @@
|
||||
<string name="charger_website">Website</string>
|
||||
<string name="realtime_data_login_needed">Conta Tesla necessária para informação em tempo real</string>
|
||||
<string name="charge_price_minute_format">%2$s%1$.2f/min</string>
|
||||
<string name="pref_tesla_account_disabled">Faça o login para ver os dados em tempo real dos Superchargers da Tesla. Não é necessário possuir um veículo da Tesla</string>
|
||||
<string name="pref_tesla_account_disabled">Faça o login para ver informação em tempo real sobre os Tesla Superchargers. Não é necessário possuir um veículo Tesla</string>
|
||||
<string name="login">Login</string>
|
||||
<string name="login_error">Falha no login</string>
|
||||
<string name="pricing_up_to">até %s</string>
|
||||
@@ -324,4 +324,10 @@
|
||||
<string name="pref_map_scale_meters">metros</string>
|
||||
<string name="pref_map_scale_miles">milhas</string>
|
||||
<string name="pref_map_scale">Barra de escala do mapa</string>
|
||||
<string name="data_retrieved_at">Informação atualizada %s</string>
|
||||
<string name="settings_cache_count">Tamanho da cache</string>
|
||||
<string name="settings_cache_clear">Limpar cache</string>
|
||||
<string name="settings_cache_count_summary">%d carregadores na base de dados, %.1f MB</string>
|
||||
<string name="settings_caching">Caching (base de dados local)</string>
|
||||
<string name="settings_cache_clear_summary">Elimina todos os carregadores guardados na base de dados local, com a exceção dos seus favoritos</string>
|
||||
</resources>
|
||||
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
|
||||
2
fastlane/metadata/android/de-DE/changelogs/184.txt
Normal file
2
fastlane/metadata/android/de-DE/changelogs/184.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Fehler behoben:
|
||||
- Abstürze im Zusammenspiel mit bestimmten Filtern behoben
|
||||
3
fastlane/metadata/android/de-DE/changelogs/186.txt
Normal file
3
fastlane/metadata/android/de-DE/changelogs/186.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Fehler behoben:
|
||||
- Fehler im Caching-Algorithmus im Zusammenspiel mit bestimmten Filtern behoben
|
||||
- Abstürze 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
|
||||
2
fastlane/metadata/android/en-US/changelogs/184.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/184.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Bugfixes:
|
||||
- Fixed crashes when some filters are active
|
||||
3
fastlane/metadata/android/en-US/changelogs/186.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/186.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Bugfixes:
|
||||
- Fixed error in caching algorithm when some filters are active
|
||||
- Fixed crashes
|
||||
Reference in New Issue
Block a user