mirror of
https://github.com/ev-map/EVMap.git
synced 2026-04-19 21:58:09 -04:00
@@ -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'
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
@@ -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) {
|
||||
|
||||
10
app/src/main/res/drawable/ic_refresh.xml
Normal file
10
app/src/main/res/drawable/ic_refresh.xml
Normal 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>
|
||||
@@ -137,7 +137,7 @@
|
||||
android:textColor="@android:color/white"
|
||||
app:backgroundTintAvailability="@{BindingAdaptersKt.flatten(filteredAvailability.data.status.values())}"
|
||||
app:invisibleUnlessAnimated="@{filteredAvailability.data != null && !expanded}"
|
||||
app:invisibleUnless="@{filteredAvailability.data != null}"
|
||||
app:invisibleUnless="@{filteredAvailability.data != null && !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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user