Add ability to refresh availability data

fixes #175
This commit is contained in:
johan12345
2022-06-12 17:22:50 +02:00
parent dc9f47df8a
commit 0ca8fb0eee
12 changed files with 88 additions and 41 deletions

View File

@@ -148,6 +148,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.browser:browser:1.4.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'com.github.johan12345:CustomBottomSheetBehavior:f69f532660'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'

View File

@@ -110,6 +110,12 @@ class FavoritesFragment : Fragment(), LostApiClient.ConnectionCallbacks {
createTouchHelper().attachToRecyclerView(binding.favsList)
locationClient!!.connect()
binding.swipeRefresh.setOnRefreshListener {
vm.reloadAvailability() {
binding.swipeRefresh.isRefreshing = false
}
}
}
override fun onConnected() {

View File

@@ -95,28 +95,10 @@ import net.vonforst.evmap.utils.checkFineLocationPermission
import net.vonforst.evmap.utils.distanceBetween
import net.vonforst.evmap.viewmodel.*
import java.io.IOException
import kotlin.collections.List
import kotlin.collections.Set
import kotlin.collections.any
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.contains
import kotlin.collections.emptyList
import kotlin.collections.filterIsInstance
import kotlin.collections.find
import kotlin.collections.forEach
import kotlin.collections.getOrNull
import kotlin.collections.isNotEmpty
import kotlin.collections.iterator
import kotlin.collections.listOf
import kotlin.collections.map
import kotlin.collections.mapNotNull
import kotlin.collections.set
import kotlin.collections.sortedBy
import kotlin.collections.sortedByDescending
import kotlin.collections.toList
import kotlin.collections.toSet
import kotlin.collections.toTypedArray
class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallback,
@@ -423,6 +405,9 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
else -> false
}
}
binding.detailView.btnRefreshLiveData.setOnClickListener {
vm.reloadAvailability()
}
}
var searchKeyListener: KeyListener? = null

View File

@@ -32,21 +32,7 @@ class FavoritesViewModel(application: Application, geApiKey: String) :
MediatorLiveData<Map<Long, Resource<ChargeLocationStatus>>>().apply {
addSource(favorites) { favorites ->
if (favorites != null) {
val chargers = favorites.map { it.charger }
viewModelScope.launch {
val data = hashMapOf<Long, Resource<ChargeLocationStatus>>()
chargers.forEach { charger ->
data[charger.id] = Resource.loading(null)
}
availability.value = data
chargers.map { charger ->
async {
data[charger.id] = getAvailability(charger)
availability.value = data
}
}.awaitAll()
}
reloadAvailability()
} else {
value = null
}
@@ -54,6 +40,27 @@ class FavoritesViewModel(application: Application, geApiKey: String) :
}
}
fun reloadAvailability(callback: (() -> Unit)? = null) {
val favorites = favorites.value ?: return
val chargers = favorites.map { it.charger }
viewModelScope.launch {
val data = hashMapOf<Long, Resource<ChargeLocationStatus>>()
chargers.forEach { charger ->
data[charger.id] = Resource.loading(null)
}
availability.value = data
chargers.map { charger ->
async {
data[charger.id] = getAvailability(charger)
availability.value = data
}
}.awaitAll()
callback?.invoke()
}
}
val listData: MediatorLiveData<List<FavoritesListItem>> by lazy {
MediatorLiveData<List<FavoritesListItem>>().apply {
val callback = { _: Any ->

View File

@@ -381,6 +381,13 @@ class MapViewModel(application: Application, private val state: SavedStateHandle
availability.value = getAvailability(charger)
}
fun reloadAvailability() {
val charger = chargerSparse.value ?: return
viewModelScope.launch {
loadAvailability(charger)
}
}
private var chargerLoadingTask: Job? = null
private fun loadChargerDetails(charger: ChargeLocation, referenceData: ReferenceData) {

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z" />
</vector>

View File

@@ -137,7 +137,7 @@
android:textColor="@android:color/white"
app:backgroundTintAvailability="@{BindingAdaptersKt.flatten(filteredAvailability.data.status.values())}"
app:invisibleUnlessAnimated="@{filteredAvailability.data != null &amp;&amp; !expanded}"
app:invisibleUnless="@{filteredAvailability.data != null}"
app:invisibleUnless="@{filteredAvailability.data != null &amp;&amp; !expanded}"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/txtName"
tools:backgroundTint="@color/available"
@@ -293,10 +293,11 @@
android:id="@+id/textView13"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:gravity="right|end"
android:text="@{availability.status == Status.SUCCESS ? @string/realtime_data_source(availability.data.source) : availability.status == Status.LOADING ? @string/realtime_data_loading : @string/realtime_data_unavailable}"
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/btnRefreshLiveData"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toBottomOf="@+id/connectors"
tools:text="Echtzeitdaten nicht verfügbar" />
@@ -376,6 +377,18 @@
app:layout_constraintBottom_toBottomOf="parent"
tools:text="The data is provided under the National Oman Open Data LicensE (NOODLE), Version 3.14, and may be used for any purpose whatsoever." />
<Button
android:id="@+id/btnRefreshLiveData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.App.Button.OutlinedButton.IconOnly.Small"
android:contentDescription="@string/refresh_live_data"
android:enabled="@{availability.status != Status.LOADING}"
app:icon="@drawable/ic_refresh"
app:layout_constraintBottom_toBottomOf="@+id/textView13"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/connectors" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

View File

@@ -33,16 +33,21 @@
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/favs_list"
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="0dp"
android:layout_height="0dp"
app:data="@{vm.listData}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar_container" />
app:layout_constraintTop_toBottomOf="@+id/toolbar_container">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/favs_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:data="@{vm.listData}" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/animation_view"

View File

@@ -115,7 +115,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="@android:color/white"
app:backgroundTintAvailability="@{item.available.data}"
app:goneUnless="@{item.available.status == Status.SUCCESS}"
app:invisibleUnless="@{item.available.status == Status.SUCCESS}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/btnDelete"
tools:backgroundTint="@color/available"

View File

@@ -258,4 +258,5 @@
<string name="pref_map_rotate_gestures_enabled">Kartenrotation erlauben</string>
<string name="pref_map_rotate_gestures_on">Karte kann mit Zweifingergeste rotiert werden</string>
<string name="pref_map_rotate_gestures_off">Karte bleibt fest nach Norden ausgerichtet</string>
<string name="refresh_live_data">Echtzeitstatus aktualisieren</string>
</resources>

View File

@@ -243,4 +243,5 @@
<string name="pref_map_rotate_gestures_enabled">Enable map rotation</string>
<string name="pref_map_rotate_gestures_on">Map can be rotated with two-finger gesture</string>
<string name="pref_map_rotate_gestures_off">Map will be fixed to north-up</string>
<string name="refresh_live_data">refresh real-time status</string>
</resources>

View File

@@ -56,4 +56,15 @@
<item name="android:minHeight">48dp</item>
</style>
<style name="Widget.App.Button.OutlinedButton.IconOnly.Small" parent="Widget.Material3.Button.OutlinedButton">
<item name="iconPadding">0dp</item>
<item name="android:insetTop">0dp</item>
<item name="android:insetBottom">0dp</item>
<item name="android:paddingLeft">7dp</item>
<item name="android:paddingRight">7dp</item>
<item name="android:minWidth">30dp</item>
<item name="android:minHeight">30dp</item>
<item name="iconTint">?android:textColorSecondary</item>
</style>
</resources>