show compatible payment methods in details (#26)

This commit is contained in:
Johan von Forstner
2020-06-21 12:33:53 +02:00
parent e9ac39301d
commit 45dd40faa7
10 changed files with 101 additions and 10 deletions

View File

@@ -17,9 +17,7 @@ import com.google.android.material.chip.Chip
import net.vonforst.evmap.BR
import net.vonforst.evmap.R
import net.vonforst.evmap.api.availability.ChargepointStatus
import net.vonforst.evmap.api.goingelectric.ChargeLocation
import net.vonforst.evmap.api.goingelectric.Chargepoint
import net.vonforst.evmap.api.goingelectric.OpeningHoursDays
import net.vonforst.evmap.api.goingelectric.*
import net.vonforst.evmap.databinding.ItemFilterMultipleChoiceBinding
import net.vonforst.evmap.databinding.ItemFilterMultipleChoiceLargeBinding
import net.vonforst.evmap.databinding.ItemFilterSliderBinding
@@ -115,7 +113,11 @@ class DetailAdapter : DataBindingAdapter<DetailAdapter.Detail>() {
}
}
fun buildDetails(loc: ChargeLocation?, ctx: Context): List<DetailAdapter.Detail> {
fun buildDetails(
loc: ChargeLocation?,
chargeCards: Map<Long, ChargeCard>?,
ctx: Context
): List<DetailAdapter.Detail> {
if (loc == null) return emptyList()
return listOfNotNull(
@@ -165,6 +167,15 @@ fun buildDetails(loc: ChargeLocation?, ctx: Context): List<DetailAdapter.Detail>
loc.cost.descriptionLong ?: loc.cost.descriptionShort
)
else null,
if (loc.chargecards != null && loc.chargecards.isNotEmpty()) DetailAdapter.Detail(
R.drawable.ic_payment,
R.string.charge_cards,
ctx.resources.getQuantityString(
R.plurals.charge_cards_compatible_num,
loc.chargecards.size, loc.chargecards.size
),
formatChargeCards(loc.chargecards, chargeCards, ctx)
) else null,
DetailAdapter.Detail(
R.drawable.ic_location,
R.string.coordinates,
@@ -176,6 +187,25 @@ fun buildDetails(loc: ChargeLocation?, ctx: Context): List<DetailAdapter.Detail>
)
}
fun formatChargeCards(
chargecards: List<ChargeCardId>,
chargecardData: Map<Long, ChargeCard>?,
ctx: Context
): String {
if (chargecardData == null) return ""
val maxItems = 5
var result = chargecards
.take(maxItems)
.mapNotNull { chargecardData[it.id]?.name }
.joinToString()
if (chargecards.size > maxItems) {
result += " " + ctx.getString(R.string.and_n_others, chargecards.size - maxItems)
}
return result
}
class FavoritesAdapter(val vm: FavoritesViewModel) :
DataBindingAdapter<FavoritesViewModel.FavoritesListItem>() {

View File

@@ -75,14 +75,14 @@ internal class JsonObjectOrFalseAdapter<T> private constructor(
type: Type,
annotations: Set<Annotation>?,
moshi: Moshi
): JsonAdapter<*>? {
): JsonAdapter<Any>? {
val clazz = Types.getRawType(type)
return when (hasJsonObjectOrFalseAnnotation(
annotations
)) {
false -> null
true -> JsonObjectOrFalseAdapter(
moshi.adapter(clazz), clazz
moshi.adapter(type), clazz
)
}
}
@@ -101,6 +101,7 @@ internal class JsonObjectOrFalseAdapter<T> private constructor(
}
}
JsonReader.Token.BEGIN_OBJECT -> objectDelegate.fromJson(reader)
JsonReader.Token.BEGIN_ARRAY -> objectDelegate.fromJson(reader)
JsonReader.Token.STRING -> objectDelegate.fromJson(reader)
JsonReader.Token.NUMBER -> objectDelegate.fromJson(reader)
else ->

View File

@@ -52,7 +52,7 @@ data class ChargeLocation(
val chargepoints: List<Chargepoint>,
@JsonObjectOrFalse val network: String?,
val url: String,
@Embedded(prefix="fault_report_") @JsonObjectOrFalse @Json(name = "fault_report") val faultReport: FaultReport?,
@Embedded(prefix = "fault_report_") @JsonObjectOrFalse @Json(name = "fault_report") val faultReport: FaultReport?,
val verified: Boolean,
// only shown in details:
@JsonObjectOrFalse val operator: String?,
@@ -60,7 +60,7 @@ data class ChargeLocation(
@JsonObjectOrFalse @Json(name = "ladeweile") val amenities: String?,
@JsonObjectOrFalse @Json(name = "location_description") val locationDescription: String?,
val photos: List<ChargerPhoto>?,
//val chargecards: Boolean?
@JsonObjectOrFalse val chargecards: List<ChargeCardId>?,
@Embedded val openinghours: OpeningHours?,
@Embedded val cost: Cost?
) : ChargepointListItem(), Equatable {
@@ -279,3 +279,8 @@ data class ChargeCard(
val name: String,
val url: String
)
@JsonClass(generateAdapter = true)
data class ChargeCardId(
val id: Long
)

View File

@@ -3,6 +3,7 @@ package net.vonforst.evmap.storage
import androidx.room.TypeConverter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import net.vonforst.evmap.api.goingelectric.ChargeCardId
import net.vonforst.evmap.api.goingelectric.Chargepoint
import net.vonforst.evmap.api.goingelectric.ChargerPhoto
import java.time.Instant
@@ -18,6 +19,10 @@ class Converters {
val type = Types.newParameterizedType(List::class.java, ChargerPhoto::class.java)
moshi.adapter<List<ChargerPhoto>>(type)
}
private val chargeCardIdListAdapter by lazy {
val type = Types.newParameterizedType(List::class.java, ChargeCardId::class.java)
moshi.adapter<List<ChargeCardId>>(type)
}
private val stringSetAdapter by lazy {
val type = Types.newParameterizedType(Set::class.java, String::class.java)
moshi.adapter<Set<String>>(type)
@@ -43,6 +48,16 @@ class Converters {
return chargerPhotoListAdapter.fromJson(value)
}
@TypeConverter
fun fromChargeCardIdList(value: List<ChargeCardId>?): String {
return chargeCardIdListAdapter.toJson(value)
}
@TypeConverter
fun toChargeCardIdList(value: String): List<ChargeCardId>? {
return chargeCardIdListAdapter.fromJson(value)
}
@TypeConverter
fun fromLocalTime(value: LocalTime?): String? {
return value?.toString()

View File

@@ -61,6 +61,17 @@ class MapViewModel(application: Application, geApiKey: String) : AndroidViewMode
filtersWithValue(filters, filterValues, filtersActive)
}
val chargeCardMap: LiveData<Map<Long, ChargeCard>> by lazy {
MediatorLiveData<Map<Long, ChargeCard>>().apply {
value = null
addSource(chargeCards) {
value = chargeCards.value?.map {
it.id to it
}?.toMap()
}
}
}
val filtersCount: LiveData<Int> by lazy {
MediatorLiveData<Int>().apply {
value = 0

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="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM20,18L4,18v-6h16v6zM20,8L4,8L4,6h16v2z" />
</vector>

View File

@@ -9,6 +9,8 @@
<import type="net.vonforst.evmap.api.goingelectric.Chargepoint" />
<import type="net.vonforst.evmap.api.goingelectric.ChargeCard" />
<import type="net.vonforst.evmap.api.availability.ChargeLocationStatus" />
<import type="net.vonforst.evmap.adapter.DataBindingAdaptersKt" />
@@ -25,6 +27,10 @@
name="availability"
type="Resource&lt;ChargeLocationStatus&gt;" />
<variable
name="chargeCards"
type="java.util.Map&lt;Long, ChargeCard&gt;" />
</data>
<androidx.cardview.widget.CardView
@@ -182,7 +188,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:nestedScrollingEnabled="false"
app:data="@{DataBindingAdaptersKt.buildDetails(charger.data, context)}"
app:data="@{DataBindingAdaptersKt.buildDetails(charger.data, chargeCards, context)}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -126,7 +126,8 @@
android:id="@+id/detail_view"
layout="@layout/detail_view"
app:charger="@{vm.charger}"
app:availability="@{vm.availability}" />
app:availability="@{vm.availability}"
app:chargeCards="@{vm.chargeCardMap}" />
</androidx.core.widget.NestedScrollView>

View File

@@ -97,4 +97,10 @@
<string name="filter_open_247">24 Stunden geöffnet</string>
<string name="filter_barrierfree">Ohne Vertrag / Registrierung nutzbar</string>
<string name="filter_exclude_faults">Ladesäulen mit Störung ausschließen</string>
<string name="charge_cards">Ladetarife</string>
<string name="and_n_others">und %d weitere</string>
<plurals name="charge_cards_compatible_num">
<item quantity="one">%d kompatibler Ladetarif</item>
<item quantity="other">%d kompatible Ladetarife</item>
</plurals>
</resources>

View File

@@ -96,4 +96,10 @@
<string name="filter_open_247">Available 24/7</string>
<string name="filter_barrierfree">Usable without registration</string>
<string name="filter_exclude_faults">Exclude chargers with reported faults</string>
<string name="charge_cards">Payment methods</string>
<string name="and_n_others">and %d others</string>
<plurals name="charge_cards_compatible_num">
<item quantity="one">%d compatible payment method</item>
<item quantity="other">%d compatible payment methods</item>
</plurals>
</resources>