From c6395feaa311053fd14feb8f96715eebfe193fcc Mon Sep 17 00:00:00 2001 From: johan12345 Date: Sun, 17 Dec 2023 22:23:58 +0100 Subject: [PATCH] Add details about voltage and amperage of chargers shown in connector details dialog (not supported by GoingElectric) fixes #151 --- .../evmap/adapter/DataBindingAdapters.kt | 3 +- .../api/openchargemap/OpenChargeMapModel.kt | 4 +- .../evmap/fragment/ConnectorDetailsDialog.kt | 49 +++++--- .../vonforst/evmap/fragment/MapFragment.kt | 20 ++- .../net/vonforst/evmap/model/ChargersModel.kt | 32 +++-- app/src/main/res/drawable/circle.xml | 11 ++ .../res/layout/dialog_connector_details.xml | 15 +-- .../dialog_connector_details_header.xml | 115 ++++++++++++++++++ .../layout/dialog_connector_details_item.xml | 39 ++---- .../dialog_connector_details_preview.xml | 18 +++ 10 files changed, 232 insertions(+), 74 deletions(-) create mode 100644 app/src/main/res/drawable/circle.xml create mode 100644 app/src/main/res/layout/dialog_connector_details_header.xml create mode 100644 app/src/main/res/layout/dialog_connector_details_preview.xml diff --git a/app/src/main/java/net/vonforst/evmap/adapter/DataBindingAdapters.kt b/app/src/main/java/net/vonforst/evmap/adapter/DataBindingAdapters.kt index 1a2885c1..c0b016a3 100644 --- a/app/src/main/java/net/vonforst/evmap/adapter/DataBindingAdapters.kt +++ b/app/src/main/java/net/vonforst/evmap/adapter/DataBindingAdapters.kt @@ -97,7 +97,6 @@ class ConnectorAdapter : DataBindingAdapter() { data class ConnectorDetails( - val chargepoint: Chargepoint, val status: ChargepointStatus?, val evseId: String?, val label: String?, @@ -108,7 +107,7 @@ class ConnectorDetailsAdapter : DataBindingAdapter() { val viewPool = RecyclerView.RecycledViewPool() diff --git a/app/src/main/java/net/vonforst/evmap/api/openchargemap/OpenChargeMapModel.kt b/app/src/main/java/net/vonforst/evmap/api/openchargemap/OpenChargeMapModel.kt index 7a8623b5..c7687b49 100644 --- a/app/src/main/java/net/vonforst/evmap/api/openchargemap/OpenChargeMapModel.kt +++ b/app/src/main/java/net/vonforst/evmap/api/openchargemap/OpenChargeMapModel.kt @@ -159,7 +159,9 @@ data class OCMConnection( fun convert(refData: OCMReferenceData) = Chargepoint( convertConnectionTypeFromOCM(connectionTypeId, refData), power, - quantity ?: 1 + quantity ?: 1, + voltage?.toDouble(), + amps?.toDouble() ) companion object { diff --git a/app/src/main/java/net/vonforst/evmap/fragment/ConnectorDetailsDialog.kt b/app/src/main/java/net/vonforst/evmap/fragment/ConnectorDetailsDialog.kt index 319f2009..c11e8195 100644 --- a/app/src/main/java/net/vonforst/evmap/fragment/ConnectorDetailsDialog.kt +++ b/app/src/main/java/net/vonforst/evmap/fragment/ConnectorDetailsDialog.kt @@ -5,12 +5,19 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.os.BundleCompat +import androidx.databinding.DataBindingUtil +import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.LinearLayoutManager +import net.vonforst.evmap.R +import net.vonforst.evmap.adapter.ConnectorAdapter import net.vonforst.evmap.adapter.ConnectorDetailsAdapter +import net.vonforst.evmap.adapter.SingleViewAdapter import net.vonforst.evmap.api.availability.ChargeLocationStatus import net.vonforst.evmap.api.availability.ChargepointStatus import net.vonforst.evmap.databinding.DialogConnectorDetailsBinding +import net.vonforst.evmap.databinding.DialogConnectorDetailsHeaderBinding import net.vonforst.evmap.databinding.DialogDataSourceSelectBinding +import net.vonforst.evmap.databinding.FragmentChargepriceHeaderBinding import net.vonforst.evmap.model.Chargepoint import net.vonforst.evmap.model.FILTERS_DISABLED import net.vonforst.evmap.storage.PreferenceDataSource @@ -23,7 +30,7 @@ class ConnectorDetailsDialog : MaterialDialogFragment() { companion object { fun getInstance( chargepoint: Chargepoint, - status: List, + status: List?, evseIds: List? = null, labels: List? = null, lastChange: List? = null @@ -31,7 +38,7 @@ class ConnectorDetailsDialog : MaterialDialogFragment() { val dialog = ConnectorDetailsDialog() dialog.arguments = Bundle().apply { putParcelable("chargepoint", chargepoint) - putParcelableArrayList("status", ArrayList(status)) + putParcelableArrayList("status", status?.let { ArrayList(status) }) putStringArrayList("evseIds", evseIds?.let { ArrayList(it) }) putStringArrayList("labels", labels?.let { ArrayList(it) }) putSerializable("lastChange", lastChange?.let { ArrayList(it) }) @@ -62,25 +69,39 @@ class ConnectorDetailsDialog : MaterialDialogFragment() { val labels = args.getStringArrayList("labels") val lastChange = args.getSerializable("lastChange") as ArrayList? - val items = List(chargepoint.count) { i -> - ConnectorDetailsAdapter.ConnectorDetails( - chargepoint, - status?.get(i), - evseIds?.get(i), - labels?.get(i), - lastChange?.get(i) - ) - }.sortedBy { it.evseId ?: it.label } + val items = if (status != null) { + List(chargepoint.count) { i -> + ConnectorDetailsAdapter.ConnectorDetails( + status.get(i), + evseIds?.get(i), + labels?.get(i), + lastChange?.get(i) + ) + }.sortedBy { it.evseId ?: it.label } + } else emptyList() binding.list.apply { - adapter = ConnectorDetailsAdapter().apply { - submitList(items) - } itemAnimator = null layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) } + val headerBinding = DataBindingUtil.inflate( + LayoutInflater.from(context), + R.layout.dialog_connector_details_header, binding.list, false + ) + if (items.isEmpty()) headerBinding.divider.visibility = View.GONE + + val joinedAdapter = ConcatAdapter( + SingleViewAdapter(headerBinding.root), + ConnectorDetailsAdapter().apply { + submitList(items) + } + ) + + binding.list.adapter = joinedAdapter + headerBinding.item = ConnectorAdapter.ChargepointWithAvailability(chargepoint, status) + binding.btnClose.setOnClickListener { dismiss() } diff --git a/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt b/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt index be74c085..70e016e7 100644 --- a/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt +++ b/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt @@ -816,18 +816,14 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac binding.detailView.connectors.apply { adapter = ConnectorAdapter().apply { onClickListener = { item -> - vm.availability.value?.data?.let { - item.status?.let { status -> - val dialog = ConnectorDetailsDialog.getInstance( - item.chargepoint, - status, - it.evseIds?.get(item.chargepoint), - it.labels?.get(item.chargepoint), - it.lastChange?.get(item.chargepoint), - ) - dialog.show(parentFragmentManager, null) - } - } + val dialog = ConnectorDetailsDialog.getInstance( + item.chargepoint, + item.status, + vm.availability.value?.data?.evseIds?.get(item.chargepoint), + vm.availability.value?.data?.labels?.get(item.chargepoint), + vm.availability.value?.data?.lastChange?.get(item.chargepoint), + ) + dialog.show(parentFragmentManager, null) } } itemAnimator = null diff --git a/app/src/main/java/net/vonforst/evmap/model/ChargersModel.kt b/app/src/main/java/net/vonforst/evmap/model/ChargersModel.kt index fa696c5d..03ee2c17 100644 --- a/app/src/main/java/net/vonforst/evmap/model/ChargersModel.kt +++ b/app/src/main/java/net/vonforst/evmap/model/ChargersModel.kt @@ -18,7 +18,7 @@ import java.time.LocalDate import java.time.LocalTime import java.time.format.DateTimeFormatter import java.time.format.FormatStyle -import java.util.* +import kotlin.math.abs sealed class ChargepointListItem @@ -127,10 +127,13 @@ data class ChargeLocation( get() { val variants = chargepoints.distinctBy { it.power to it.type } return variants.map { variant -> - val count = chargepoints + val filtered = chargepoints .filter { it.type == variant.type && it.power == variant.power } - .sumOf { it.count } - Chargepoint(variant.type, variant.power, count) + val count = filtered.sumOf { it.count } + Chargepoint(variant.type, variant.power, count, + filtered.map { it.voltage }.distinct().singleOrNull(), + filtered.map { it.current }.distinct().singleOrNull() + ) } } @@ -390,24 +393,29 @@ data class Address( @Parcelize @JsonClass(generateAdapter = true) data class Chargepoint( - // The chargepoint type (use one of the constants in the companion object) + // The connector type (use one of the constants in the companion object if applicable) val type: String, // Power in kW (or null if unknown) val power: Double?, // How many instances of this plug/socket are available? val count: Int, + // Max current in A (or null if unknown) + val current: Double? = null, + // Max voltage in V (or null if unknown). + // note that for DC chargers: current * voltage may be larger than power + // (each of the three can be separately limited) + val voltage: Double? = null ) : Equatable, Parcelable { fun hasKnownPower(): Boolean = power != null + fun hasKnownVoltageAndCurrent(): Boolean = voltage != null && current != null /** * If chargepoint power is defined, format it into a string. * Otherwise, return null. */ fun formatPower(): String? { - if (power == null) { - return null - } - val powerFmt = if (power - power.toInt() == 0.0) { + if (power == null) return null + val powerFmt = if (abs(power - power.toInt()) < 0.1) { "%.0f".format(power) } else { "%.1f".format(power) @@ -415,6 +423,12 @@ data class Chargepoint( return "$powerFmt kW" } + fun formatVoltageAndCurrent(): String? { + if (current == null || voltage == null) return null + + return "%.0f V · %.0f A".format(voltage, current) + } + companion object { const val TYPE_1 = "Type 1" const val TYPE_2_UNKNOWN = "Type 2 (either plug or socket)" diff --git a/app/src/main/res/drawable/circle.xml b/app/src/main/res/drawable/circle.xml new file mode 100644 index 00000000..934530ef --- /dev/null +++ b/app/src/main/res/drawable/circle.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_connector_details.xml b/app/src/main/res/layout/dialog_connector_details.xml index ccc35d5c..4490be67 100644 --- a/app/src/main/res/layout/dialog_connector_details.xml +++ b/app/src/main/res/layout/dialog_connector_details.xml @@ -1,28 +1,29 @@ + android:layout_height="wrap_content"> + tools:itemCount="1" + tools:listitem="@layout/dialog_connector_details_preview" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_connector_details_item.xml b/app/src/main/res/layout/dialog_connector_details_item.xml index 460d326d..cd9efe58 100644 --- a/app/src/main/res/layout/dialog_connector_details_item.xml +++ b/app/src/main/res/layout/dialog_connector_details_item.xml @@ -8,6 +8,7 @@ + - - + app:srcCompat="@drawable/circle" + tools:tint="@color/available" /> + + + + + + + + + + + + + + \ No newline at end of file