mirror of
https://github.com/ev-map/EVMap.git
synced 2026-05-19 12:26:20 -04:00
OSM: adjustments for AA/AAOS app
This commit is contained in:
@@ -62,6 +62,7 @@ import net.vonforst.evmap.storage.ChargeLocationsRepository
|
||||
import net.vonforst.evmap.storage.PreferenceDataSource
|
||||
import net.vonforst.evmap.ui.ChargerIconGenerator
|
||||
import net.vonforst.evmap.ui.getMarkerTint
|
||||
import net.vonforst.evmap.utils.formatDMS
|
||||
import net.vonforst.evmap.viewmodel.Status
|
||||
import net.vonforst.evmap.viewmodel.awaitFinished
|
||||
import java.time.ZoneId
|
||||
@@ -258,7 +259,7 @@ class ChargerDetailScreen(
|
||||
|
||||
// Row 1: address + chargepoints
|
||||
rows.add(Row.Builder().apply {
|
||||
setTitle(charger.address.toString())
|
||||
setTitle(charger.address?.toString() ?: charger.coordinates.formatDMS())
|
||||
|
||||
if (photo == null) {
|
||||
// show just the icon
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.location.Location
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.car.app.AppManager
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.CarToast
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.annotations.ExperimentalCarApi
|
||||
import androidx.car.app.annotations.RequiresCarApi
|
||||
@@ -30,6 +31,8 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.car2go.maps.AnyMap
|
||||
import com.car2go.maps.OnMapReadyCallback
|
||||
@@ -56,6 +59,8 @@ import net.vonforst.evmap.storage.ChargeLocationsRepository
|
||||
import net.vonforst.evmap.storage.PreferenceDataSource
|
||||
import net.vonforst.evmap.ui.MarkerManager
|
||||
import net.vonforst.evmap.utils.distanceBetween
|
||||
import net.vonforst.evmap.utils.headingDiff
|
||||
import net.vonforst.evmap.viewmodel.Resource
|
||||
import net.vonforst.evmap.viewmodel.Status
|
||||
import net.vonforst.evmap.viewmodel.await
|
||||
import net.vonforst.evmap.viewmodel.awaitFinished
|
||||
@@ -67,6 +72,9 @@ import java.time.Instant
|
||||
import java.time.ZonedDateTime
|
||||
import kotlin.collections.set
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.time.DurationUnit
|
||||
import kotlin.time.TimeSource
|
||||
|
||||
/**
|
||||
* Main map screen showing either nearby chargers or favorites.
|
||||
@@ -425,12 +433,15 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
|
||||
}
|
||||
this@MapScreen.chargers = chargers
|
||||
} else {
|
||||
val response = repo.getChargepoints(
|
||||
val responseLiveData = repo.getChargepoints(
|
||||
map.projection.visibleRegion.latLngBounds,
|
||||
map.cameraPosition.zoom,
|
||||
filtersWithValue,
|
||||
false
|
||||
).awaitFinished()
|
||||
)
|
||||
val observer = setupProgressToasts(responseLiveData)
|
||||
val response = responseLiveData.awaitFinished()
|
||||
responseLiveData.removeObserver(observer)
|
||||
if (response.status == Status.ERROR || response.data == null) {
|
||||
loadingError = true
|
||||
this@MapScreen.chargers = null
|
||||
@@ -454,6 +465,31 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupProgressToasts(
|
||||
responseLiveData: LiveData<Resource<List<ChargepointListItem>>>
|
||||
): Observer<Resource<List<ChargepointListItem>>> {
|
||||
var lastTime = TimeSource.Monotonic.markNow()
|
||||
val observer =
|
||||
Observer<Resource<List<ChargepointListItem>>> { value ->
|
||||
if (value.progress != null && lastTime.elapsedNow().toDouble(
|
||||
DurationUnit.SECONDS
|
||||
) > 2
|
||||
) {
|
||||
CarToast.makeText(
|
||||
carContext,
|
||||
carContext.getString(
|
||||
R.string.downloading_chargers_percent,
|
||||
value.progress * 100
|
||||
),
|
||||
CarToast.LENGTH_SHORT
|
||||
).show()
|
||||
lastTime = TimeSource.Monotonic.markNow()
|
||||
}
|
||||
}
|
||||
responseLiveData.observe(this@MapScreen, observer)
|
||||
return observer
|
||||
}
|
||||
|
||||
private fun onEnergyLevelUpdated(energyLevel: EnergyLevel) {
|
||||
val isUpdate = this.energyLevel == null
|
||||
this.energyLevel = energyLevel
|
||||
|
||||
@@ -30,6 +30,8 @@ import androidx.car.app.model.Toggle
|
||||
import androidx.core.content.IntentCompat
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -157,7 +159,7 @@ class SettingsScreen(ctx: CarContext, val session: EVMapSession) : Screen(ctx) {
|
||||
}
|
||||
|
||||
@ExperimentalCarApi
|
||||
class DataSettingsScreen(ctx: CarContext, val session: EVMapSession) : Screen(ctx) {
|
||||
class DataSettingsScreen(ctx: CarContext, val session: EVMapSession) : Screen(ctx), DefaultLifecycleObserver {
|
||||
val prefs = PreferenceDataSource(ctx)
|
||||
val encryptedPrefs = EncryptedPreferenceDataStore(ctx)
|
||||
val db = AppDatabase.getInstance(ctx)
|
||||
@@ -175,11 +177,15 @@ class DataSettingsScreen(ctx: CarContext, val session: EVMapSession) : Screen(ct
|
||||
|
||||
var teslaLoggingIn = false
|
||||
|
||||
init {
|
||||
lifecycle.addObserver(this)
|
||||
}
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
return ListTemplate.Builder().apply {
|
||||
setTitle(carContext.getString(R.string.settings_data_sources))
|
||||
setHeaderAction(Action.BACK)
|
||||
setSingleList(ItemList.Builder().apply {
|
||||
addSectionedList(SectionedItemList.create(ItemList.Builder().apply {
|
||||
addItem(Row.Builder().apply {
|
||||
setTitle(carContext.getString(R.string.pref_data_source))
|
||||
setBrowsable(true)
|
||||
@@ -195,6 +201,41 @@ class DataSettingsScreen(ctx: CarContext, val session: EVMapSession) : Screen(ct
|
||||
)
|
||||
}
|
||||
}.build())
|
||||
/*addItem(
|
||||
Row.Builder()
|
||||
.setTitle(carContext.getString(R.string.pref_prediction_enabled))
|
||||
.addText(carContext.getString(R.string.pref_prediction_enabled_summary))
|
||||
.setToggle(Toggle.Builder {
|
||||
prefs.predictionEnabled = it
|
||||
}.setChecked(prefs.predictionEnabled).build())
|
||||
.build()
|
||||
)*/
|
||||
addItem(Row.Builder().apply {
|
||||
setTitle(carContext.getString(R.string.pref_tesla_account))
|
||||
addText(
|
||||
if (encryptedPrefs.teslaRefreshToken != null) {
|
||||
carContext.getString(
|
||||
R.string.pref_tesla_account_enabled,
|
||||
encryptedPrefs.teslaEmail
|
||||
)
|
||||
} else if (teslaLoggingIn) {
|
||||
carContext.getString(R.string.logging_in)
|
||||
} else {
|
||||
carContext.getString(R.string.pref_tesla_account_disabled)
|
||||
}
|
||||
)
|
||||
if (encryptedPrefs.teslaRefreshToken != null) {
|
||||
setOnClickListener {
|
||||
teslaLogout()
|
||||
}
|
||||
} else {
|
||||
setOnClickListener(ParkedOnlyOnClickListener.create {
|
||||
teslaLogin()
|
||||
})
|
||||
}
|
||||
}.build())
|
||||
}.build(), carContext.getString(R.string.settings_charger_data)))
|
||||
addSectionedList(SectionedItemList.create(ItemList.Builder().apply {
|
||||
addItem(Row.Builder().apply {
|
||||
setTitle(carContext.getString(R.string.pref_search_provider))
|
||||
setBrowsable(true)
|
||||
@@ -243,43 +284,54 @@ class DataSettingsScreen(ctx: CarContext, val session: EVMapSession) : Screen(ct
|
||||
}
|
||||
}
|
||||
}.build())
|
||||
/*addItem(
|
||||
Row.Builder()
|
||||
.setTitle(carContext.getString(R.string.pref_prediction_enabled))
|
||||
.addText(carContext.getString(R.string.pref_prediction_enabled_summary))
|
||||
.setToggle(Toggle.Builder {
|
||||
prefs.predictionEnabled = it
|
||||
}.setChecked(prefs.predictionEnabled).build())
|
||||
.build()
|
||||
)*/
|
||||
}.build(), carContext.getString(R.string.settings_map)))
|
||||
addSectionedList(SectionedItemList.create(ItemList.Builder().apply {
|
||||
addItem(Row.Builder().apply {
|
||||
setTitle(carContext.getString(R.string.pref_tesla_account))
|
||||
addText(
|
||||
if (encryptedPrefs.teslaRefreshToken != null) {
|
||||
carContext.getString(
|
||||
R.string.pref_tesla_account_enabled,
|
||||
encryptedPrefs.teslaEmail
|
||||
setTitle(carContext.getString(R.string.settings_cache_count))
|
||||
cacheCount?.let { count ->
|
||||
cacheSize?.let { size ->
|
||||
val sizeMb = size.toFloat() / 1024 / 1024
|
||||
addText(
|
||||
carContext.getString(
|
||||
R.string.settings_cache_count_summary,
|
||||
count,
|
||||
sizeMb
|
||||
)
|
||||
)
|
||||
} else if (teslaLoggingIn) {
|
||||
carContext.getString(R.string.logging_in)
|
||||
} else {
|
||||
carContext.getString(R.string.pref_tesla_account_disabled)
|
||||
}
|
||||
)
|
||||
if (encryptedPrefs.teslaRefreshToken != null) {
|
||||
setOnClickListener {
|
||||
teslaLogout()
|
||||
}
|
||||
} else {
|
||||
setOnClickListener(ParkedOnlyOnClickListener.create {
|
||||
teslaLogin()
|
||||
})
|
||||
}
|
||||
}.build())
|
||||
}.build())
|
||||
addItem(Row.Builder().apply {
|
||||
setTitle(carContext.getString(R.string.settings_cache_clear))
|
||||
addText(carContext.getString(R.string.settings_cache_clear_summary))
|
||||
setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
db.savedRegionDao().deleteAll()
|
||||
db.chargeLocationsDao().deleteAllIfNotFavorite()
|
||||
loadCacheSize()
|
||||
}
|
||||
}
|
||||
}.build())
|
||||
}.build(), carContext.getString(R.string.settings_caching)))
|
||||
}.build()
|
||||
}
|
||||
|
||||
var cacheCount: Long? = null
|
||||
var cacheSize: Long? = null
|
||||
|
||||
private suspend fun loadCacheSize() {
|
||||
cacheCount = db.chargeLocationsDao().getCountAsync()
|
||||
cacheSize = db.chargeLocationsDao().getSize()
|
||||
invalidate()
|
||||
}
|
||||
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
super.onStart(owner)
|
||||
lifecycleScope.launch {
|
||||
loadCacheSize()
|
||||
}
|
||||
}
|
||||
|
||||
private fun teslaLogin() {
|
||||
val codeVerifier = TeslaAuthenticationApi.generateCodeVerifier()
|
||||
val codeChallenge = TeslaAuthenticationApi.generateCodeChallenge(codeVerifier)
|
||||
@@ -399,7 +451,8 @@ class ChooseDataSourceScreen(
|
||||
val descriptions = when (type) {
|
||||
Type.CHARGER_DATA_SOURCE -> listOf(
|
||||
carContext.getString(R.string.data_source_goingelectric_desc),
|
||||
carContext.getString(R.string.data_source_openchargemap_desc)
|
||||
carContext.getString(R.string.data_source_openchargemap_desc),
|
||||
carContext.getString(R.string.data_source_openstreetmap_desc)
|
||||
)
|
||||
Type.SEARCH_PROVIDER -> null
|
||||
Type.MAP_PROVIDER -> null
|
||||
|
||||
@@ -102,6 +102,9 @@ abstract class ChargeLocationsDao {
|
||||
@Query("SELECT COUNT(*) FROM chargelocation")
|
||||
abstract fun getCount(): LiveData<Long>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM chargelocation")
|
||||
abstract suspend fun getCountAsync(): Long
|
||||
|
||||
@SkipQueryVerification
|
||||
@Query("SELECT SUM(pgsize) FROM dbstat WHERE name == \"ChargeLocation\"")
|
||||
abstract suspend fun getSize(): Long
|
||||
|
||||
@@ -364,6 +364,7 @@
|
||||
<string name="referral_tesla">Tesla</string>
|
||||
<string name="generic_connection_error">Daten konnten nicht geladen werden</string>
|
||||
<string name="copied">In Zwischenablage kopiert</string>
|
||||
<string name="downloading_chargers_percent">Lade Ladestations-Datenbank herunter… %.0f%%</string>
|
||||
<string name="status_available">Verfügbar</string>
|
||||
<string name="status_occupied">Besetzt</string>
|
||||
<string name="status_charging">Lädt</string>
|
||||
|
||||
@@ -364,6 +364,7 @@
|
||||
<string name="referral_tesla">Tesla</string>
|
||||
<string name="generic_connection_error">Could not load data</string>
|
||||
<string name="copied">Copied to clipboard</string>
|
||||
<string name="downloading_chargers_percent">Downloading charger database… %.0f%%</string>
|
||||
<string name="status_available">Available</string>
|
||||
<string name="status_occupied">Occupied</string>
|
||||
<string name="status_charging">Charging</string>
|
||||
|
||||
Reference in New Issue
Block a user