mirror of
https://github.com/ev-map/EVMap.git
synced 2026-04-26 00:58:06 -04:00
rework from DialogFragment into included view
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package net.vonforst.evmap.adapter
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.ViewDataBinding
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package net.vonforst.evmap.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.content.Context
|
||||
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
|
||||
@@ -13,97 +11,53 @@ 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
|
||||
import net.vonforst.evmap.ui.MaterialDialogFragment
|
||||
import java.time.Instant
|
||||
|
||||
class ConnectorDetailsDialog : MaterialDialogFragment() {
|
||||
private lateinit var binding: DialogConnectorDetailsBinding
|
||||
|
||||
companion object {
|
||||
fun getInstance(
|
||||
chargepoint: Chargepoint,
|
||||
status: List<ChargepointStatus>?,
|
||||
evseIds: List<String>? = null,
|
||||
labels: List<String?>? = null,
|
||||
lastChange: List<Instant?>? = null
|
||||
): ConnectorDetailsDialog {
|
||||
val dialog = ConnectorDetailsDialog()
|
||||
dialog.arguments = Bundle().apply {
|
||||
putParcelable("chargepoint", chargepoint)
|
||||
putParcelableArrayList("status", status?.let { ArrayList(status) })
|
||||
putStringArrayList("evseIds", evseIds?.let { ArrayList(it) })
|
||||
putStringArrayList("labels", labels?.let { ArrayList(it) })
|
||||
putSerializable("lastChange", lastChange?.let { ArrayList(it) })
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
}
|
||||
|
||||
override fun createView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = DialogConnectorDetailsBinding.inflate(inflater, container, false)
|
||||
prefs = PreferenceDataSource(requireContext())
|
||||
return binding.root
|
||||
}
|
||||
|
||||
private lateinit var prefs: PreferenceDataSource
|
||||
|
||||
override fun initView(view: View, savedInstanceState: Bundle?) {
|
||||
val args = requireArguments()
|
||||
|
||||
val chargepoint = BundleCompat.getParcelable(args, "chargepoint", Chargepoint::class.java)!!
|
||||
val status =
|
||||
BundleCompat.getParcelableArrayList(args, "status", ChargepointStatus::class.java)
|
||||
val evseIds = args.getStringArrayList("evseIds")
|
||||
val labels = args.getStringArrayList("labels")
|
||||
val lastChange = args.getSerializable("lastChange") as ArrayList<Instant>?
|
||||
|
||||
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()
|
||||
class ConnectorDetailsDialog(
|
||||
val binding: DialogConnectorDetailsBinding,
|
||||
context: Context,
|
||||
onClose: () -> Unit
|
||||
) {
|
||||
private val headerBinding: DialogConnectorDetailsHeaderBinding
|
||||
private val detailsAdapter = ConnectorDetailsAdapter()
|
||||
|
||||
init {
|
||||
binding.list.apply {
|
||||
itemAnimator = null
|
||||
layoutManager =
|
||||
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
}
|
||||
|
||||
val headerBinding = DataBindingUtil.inflate<DialogConnectorDetailsHeaderBinding>(
|
||||
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(
|
||||
binding.list.adapter = ConcatAdapter(
|
||||
SingleViewAdapter(headerBinding.root),
|
||||
ConnectorDetailsAdapter().apply {
|
||||
submitList(items)
|
||||
}
|
||||
detailsAdapter
|
||||
)
|
||||
|
||||
binding.list.adapter = joinedAdapter
|
||||
headerBinding.item = ConnectorAdapter.ChargepointWithAvailability(chargepoint, status)
|
||||
|
||||
binding.btnClose.setOnClickListener {
|
||||
dismiss()
|
||||
onClose()
|
||||
}
|
||||
}
|
||||
|
||||
fun setData(cp: Chargepoint, status: ChargeLocationStatus?) {
|
||||
val cpStatus = status?.status?.get(cp)
|
||||
val items = if (status != null) {
|
||||
List(cp.count) { i ->
|
||||
ConnectorDetailsAdapter.ConnectorDetails(
|
||||
cpStatus?.get(i),
|
||||
status.evseIds?.get(cp)?.get(i),
|
||||
status.labels?.get(cp)?.get(i),
|
||||
status.lastChange?.get(cp)?.get(i)
|
||||
)
|
||||
}.sortedBy { it.evseId ?: it.label }
|
||||
} else emptyList()
|
||||
detailsAdapter.submitList(items)
|
||||
|
||||
headerBinding.divider.visibility = if (items.isEmpty()) View.GONE else View.VISIBLE
|
||||
headerBinding.item = ConnectorAdapter.ChargepointWithAvailability(cp, cpStatus)
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.transition.MaterialArcMotion
|
||||
import com.google.android.material.transition.MaterialContainerTransform
|
||||
import com.google.android.material.transition.MaterialContainerTransform.FADE_MODE_CROSS
|
||||
import com.google.android.material.transition.MaterialFadeThrough
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.mahc.custombottomsheetbehavior.BottomSheetBehaviorGoogleMapsLike
|
||||
@@ -107,6 +108,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
private var requestingLocationUpdates = false
|
||||
private lateinit var bottomSheetBehavior: BottomSheetBehaviorGoogleMapsLike<View>
|
||||
private lateinit var detailAppBarBehavior: MergedAppBarLayoutBehavior
|
||||
private lateinit var detailsDialog: ConnectorDetailsDialog
|
||||
private lateinit var prefs: PreferenceDataSource
|
||||
private var markers: MutableBiMap<Marker, ChargeLocation> = HashBiMap()
|
||||
private var clusterMarkers: List<Marker> = emptyList()
|
||||
@@ -128,6 +130,12 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
return
|
||||
}
|
||||
|
||||
if (vm.selectedChargepoint.value != null) {
|
||||
closeConnectorDetailsDialog()
|
||||
vm.selectedChargepoint.value = null
|
||||
return
|
||||
}
|
||||
|
||||
if (binding.search.hasFocus()) {
|
||||
removeSearchFocus()
|
||||
}
|
||||
@@ -269,6 +277,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
vm.bottomSheetState.value?.let { bottomSheetBehavior.state = it }
|
||||
}
|
||||
bottomSheetBehavior.isCollapsible = bottomSheetCollapsible
|
||||
binding.detailView.connectorDetails
|
||||
|
||||
setupObservers()
|
||||
setupClickListeners()
|
||||
@@ -322,6 +331,12 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
binding.appLogo.root.visibility = View.GONE
|
||||
binding.search.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
detailsDialog =
|
||||
ConnectorDetailsDialog(binding.detailView.connectorDetails, requireContext()) {
|
||||
closeConnectorDetailsDialog()
|
||||
vm.selectedChargepoint.value = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@@ -670,6 +685,14 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
vm.mapTrafficEnabled.observe(viewLifecycleOwner) {
|
||||
map?.setTrafficEnabled(it)
|
||||
}
|
||||
vm.selectedChargepoint.observe(viewLifecycleOwner) {
|
||||
binding.detailView.connectorDetailsCard.visibility =
|
||||
if (it != null) View.VISIBLE else View.INVISIBLE
|
||||
if (it != null) {
|
||||
detailsDialog.setData(it, vm.availability.value?.data)
|
||||
}
|
||||
updateBackPressedCallback()
|
||||
}
|
||||
|
||||
updateBackPressedCallback()
|
||||
}
|
||||
@@ -714,6 +737,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
|| vm.searchResult.value != null
|
||||
|| (vm.layersMenuOpen.value ?: false)
|
||||
|| binding.search.hasFocus()
|
||||
|| vm.selectedChargepoint.value != null
|
||||
}
|
||||
|
||||
private fun unhighlightAllMarkers() {
|
||||
@@ -815,15 +839,9 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
|
||||
binding.detailView.connectors.apply {
|
||||
adapter = ConnectorAdapter().apply {
|
||||
onClickListener = { item ->
|
||||
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)
|
||||
onClickListener = {
|
||||
vm.selectedChargepoint.value = it.chargepoint
|
||||
openConnectorDetailsDialog()
|
||||
}
|
||||
}
|
||||
itemAnimator = null
|
||||
@@ -910,6 +928,44 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
}
|
||||
}
|
||||
|
||||
private fun openConnectorDetailsDialog() {
|
||||
val chargepoints = vm.chargerDetails.value?.data?.chargepointsMerged ?: return
|
||||
val chargepoint = vm.selectedChargepoint.value ?: return
|
||||
val index = chargepoints.indexOf(chargepoint).takeIf { it >= 0 } ?: return
|
||||
val vh = binding.detailView.connectors.findViewHolderForAdapterPosition(index) ?: return
|
||||
|
||||
val materialTransform = MaterialContainerTransform().apply {
|
||||
startView = vh.itemView
|
||||
endView = binding.detailView.connectorDetailsCard
|
||||
setPathMotion(MaterialArcMotion())
|
||||
duration = 250
|
||||
scrimColor = Color.TRANSPARENT
|
||||
addTarget(binding.detailView.connectorDetailsCard)
|
||||
isElevationShadowEnabled = false
|
||||
fadeMode = FADE_MODE_CROSS
|
||||
}
|
||||
TransitionManager.beginDelayedTransition(binding.root, materialTransform)
|
||||
}
|
||||
|
||||
private fun closeConnectorDetailsDialog() {
|
||||
val chargepoints = vm.chargerDetails.value?.data?.chargepointsMerged ?: return
|
||||
val chargepoint = vm.selectedChargepoint.value ?: return
|
||||
val index = chargepoints.indexOf(chargepoint).takeIf { it >= 0 } ?: return
|
||||
val vh = binding.detailView.connectors.findViewHolderForAdapterPosition(index) ?: return
|
||||
|
||||
val materialTransform = MaterialContainerTransform().apply {
|
||||
startView = binding.detailView.connectorDetailsCard
|
||||
endView = vh.itemView
|
||||
setPathMotion(MaterialArcMotion())
|
||||
duration = 200
|
||||
scrimColor = Color.TRANSPARENT
|
||||
addTarget(vh.itemView)
|
||||
isElevationShadowEnabled = false
|
||||
fadeMode = FADE_MODE_CROSS
|
||||
}
|
||||
TransitionManager.beginDelayedTransition(binding.root, materialTransform)
|
||||
}
|
||||
|
||||
private fun showPaymentMethodsDialog(charger: ChargeLocation) {
|
||||
val activity = activity ?: return
|
||||
val chargecardData = vm.chargeCardMap.value ?: return
|
||||
|
||||
@@ -139,8 +139,8 @@ fun <T> setRecyclerViewData(recyclerView: ViewPager2, items: List<T>?) {
|
||||
}
|
||||
|
||||
@BindingAdapter("connectorIcon")
|
||||
fun getConnectorItem(view: ImageView, type: String) {
|
||||
view.setImageResource(iconForPlugType(type))
|
||||
fun getConnectorItem(view: ImageView, type: String?) {
|
||||
view.setImageResource(type?.let { iconForPlugType(it) } ?: 0)
|
||||
}
|
||||
|
||||
@BindingAdapter("srcCompat")
|
||||
|
||||
@@ -16,7 +16,6 @@ import kotlinx.parcelize.Parcelize
|
||||
import net.vonforst.evmap.api.availability.AvailabilityRepository
|
||||
import net.vonforst.evmap.api.availability.ChargeLocationStatus
|
||||
import net.vonforst.evmap.api.availability.tesla.Pricing
|
||||
import net.vonforst.evmap.api.availability.tesla.TeslaChargingOwnershipGraphQlApi
|
||||
import net.vonforst.evmap.api.createApi
|
||||
import net.vonforst.evmap.api.fronyx.PredictionData
|
||||
import net.vonforst.evmap.api.fronyx.PredictionRepository
|
||||
@@ -150,7 +149,11 @@ class MapViewModel(application: Application, private val state: SavedStateHandle
|
||||
}
|
||||
|
||||
val chargerSparse: MutableLiveData<ChargeLocation?> by lazy {
|
||||
state.getLiveData("chargerSparse")
|
||||
state.getLiveData<ChargeLocation?>("chargerSparse").apply {
|
||||
observeForever {
|
||||
selectedChargepoint.value = null
|
||||
}
|
||||
}
|
||||
}
|
||||
private val triggerChargerDetailsRefresh = MutableLiveData(false)
|
||||
val chargerDetails: LiveData<Resource<ChargeLocation>> = chargerSparse.switchMap { charger ->
|
||||
@@ -167,6 +170,10 @@ class MapViewModel(application: Application, private val state: SavedStateHandle
|
||||
}
|
||||
}
|
||||
|
||||
val selectedChargepoint: MutableLiveData<Chargepoint?> by lazy {
|
||||
state.getLiveData("selectedChargepoint")
|
||||
}
|
||||
|
||||
val charger: MediatorLiveData<Resource<ChargeLocation>> by lazy {
|
||||
MediatorLiveData<Resource<ChargeLocation>>().apply {
|
||||
addSource(chargerDetails) {
|
||||
|
||||
@@ -560,6 +560,24 @@
|
||||
app:layout_constraintBottom_toBottomOf="@+id/textView13"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
||||
app:layout_constraintTop_toTopOf="@+id/textView13" />
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="?attr/materialCardViewElevatedStyle"
|
||||
android:id="@+id/connector_details_card"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
||||
app:layout_constraintTop_toTopOf="@id/connectors"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="24dp"
|
||||
android:layout_marginBottom="@dimen/detail_corner_radius_negative"
|
||||
android:paddingBottom="@dimen/detail_corner_radius"
|
||||
app:cardElevation="6dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<include
|
||||
layout="@layout/dialog_connector_details"
|
||||
android:id="@+id/connector_details" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="36dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@{UtilsKt.nameForPlugType(ChargepointApiKt.stringProvider(context), item.chargepoint.type) + " · " + item.chargepoint.formatPower()}"
|
||||
android:text="@{item != null ? UtilsKt.nameForPlugType(ChargepointApiKt.stringProvider(context), item.chargepoint.type) + " · " + item.chargepoint.formatPower() : null}"
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
||||
app:goneUnless="@{item.chargepoint.hasKnownPower()}"
|
||||
app:layout_constraintBottom_toTopOf="@id/textView8"
|
||||
|
||||
Reference in New Issue
Block a user