mirror of
https://github.com/ev-map/EVMap.git
synced 2026-04-23 15:47:08 -04:00
add favorites view
This commit is contained in:
@@ -13,6 +13,7 @@ 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.viewmodel.FavoritesViewModel
|
||||
|
||||
interface Equatable {
|
||||
override fun equals(other: Any?): Boolean;
|
||||
@@ -29,15 +30,15 @@ abstract class DataBindingAdapter<T : Equatable>() :
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder<T>, position: Int) =
|
||||
holder.bind(getItem(position))
|
||||
bind(holder, getItem(position))
|
||||
|
||||
class ViewHolder<T>(private val binding: ViewDataBinding) :
|
||||
class ViewHolder<T>(val binding: ViewDataBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
}
|
||||
|
||||
fun bind(item: T) {
|
||||
binding.setVariable(BR.item, item)
|
||||
binding.executePendingBindings()
|
||||
}
|
||||
open fun bind(holder: ViewHolder<T>, item: T) {
|
||||
holder.binding.setVariable(BR.item, item)
|
||||
holder.binding.executePendingBindings()
|
||||
}
|
||||
|
||||
class DiffCallback<T : Equatable> : DiffUtil.ItemCallback<T>() {
|
||||
@@ -112,3 +113,13 @@ fun buildDetails(loc: ChargeLocation?, ctx: Context): List<DetailAdapter.Detail>
|
||||
else null
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class FavoritesAdapter(val vm: FavoritesViewModel) : DataBindingAdapter<ChargeLocation>() {
|
||||
override fun getItemViewType(position: Int): Int = R.layout.item_favorite
|
||||
|
||||
override fun bind(holder: ViewHolder<ChargeLocation>, item: ChargeLocation) {
|
||||
holder.binding.setVariable(BR.vm, vm)
|
||||
super.bind(holder, item)
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ data class ChargeLocation(
|
||||
//val chargecards: Boolean?
|
||||
@Embedded val openinghours: OpeningHours?,
|
||||
@Embedded val cost: Cost?
|
||||
) : ChargepointListItem() {
|
||||
) : ChargepointListItem(), Equatable {
|
||||
val maxPower: Double
|
||||
get() {
|
||||
return chargepoints.map { it.power }.max() ?: 0.0
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package net.vonforst.evmap.fragment
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.gms.location.FusedLocationProviderClient
|
||||
import com.google.android.gms.location.LocationServices
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
import net.vonforst.evmap.MapsActivity
|
||||
import net.vonforst.evmap.R
|
||||
import net.vonforst.evmap.adapter.FavoritesAdapter
|
||||
import net.vonforst.evmap.databinding.FragmentFavoritesBinding
|
||||
import net.vonforst.evmap.viewmodel.FavoritesViewModel
|
||||
import net.vonforst.evmap.viewmodel.viewModelFactory
|
||||
|
||||
class FavoritesFragment : Fragment() {
|
||||
private lateinit var binding: FragmentFavoritesBinding
|
||||
private lateinit var fusedLocationClient: FusedLocationProviderClient
|
||||
|
||||
private val vm: FavoritesViewModel by viewModels(factoryProducer = {
|
||||
viewModelFactory {
|
||||
FavoritesViewModel(
|
||||
requireActivity().application,
|
||||
getString(R.string.goingelectric_key)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = DataBindingUtil.inflate(
|
||||
inflater,
|
||||
R.layout.fragment_favorites, container, false
|
||||
)
|
||||
binding.lifecycleOwner = this
|
||||
binding.vm = vm
|
||||
|
||||
fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireContext())
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val toolbar = view.findViewById(R.id.toolbar) as Toolbar
|
||||
|
||||
val navController = findNavController()
|
||||
toolbar.setupWithNavController(
|
||||
navController,
|
||||
(requireActivity() as MapsActivity).appBarConfiguration
|
||||
)
|
||||
|
||||
binding.favsList.apply {
|
||||
adapter = FavoritesAdapter(vm)
|
||||
layoutManager =
|
||||
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
addItemDecoration(
|
||||
DividerItemDecoration(
|
||||
context, LinearLayoutManager.VERTICAL
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
vm.favorites.observe(viewLifecycleOwner, Observer {
|
||||
print(it.toString())
|
||||
})
|
||||
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
requireContext(),
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
|
||||
vm.location.value = LatLng(location.latitude, location.longitude)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
private lateinit var clusterIconGenerator: ClusterIconGenerator
|
||||
private lateinit var chargerIconGenerator: ChargerIconGenerator
|
||||
private lateinit var animator: MarkerAnimator
|
||||
private lateinit var favToggle: MenuItem
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
@@ -115,6 +116,9 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
bottomSheetBehavior = BottomSheetBehaviorGoogleMapsLike.from(binding.bottomSheet)
|
||||
detailAppBarBehavior = MergedAppBarLayoutBehavior.from(binding.detailAppBar)
|
||||
|
||||
binding.detailAppBar.toolbar.inflateMenu(R.menu.detail)
|
||||
favToggle = binding.detailAppBar.toolbar.menu.findItem(R.id.menu_fav)
|
||||
|
||||
setupObservers()
|
||||
setupClickListeners()
|
||||
setupAdapters()
|
||||
@@ -173,6 +177,25 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
binding.detailAppBar.toolbar.setNavigationOnClickListener {
|
||||
bottomSheetBehavior.state = BottomSheetBehaviorGoogleMapsLike.STATE_COLLAPSED
|
||||
}
|
||||
binding.detailAppBar.toolbar.setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.menu_fav -> {
|
||||
toggleFavorite()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleFavorite() {
|
||||
val favs = vm.favorites.value ?: return
|
||||
val charger = vm.chargerSparse.value ?: return
|
||||
if (favs.find { it.id == charger.id } != null) {
|
||||
vm.deleteFavorite(charger)
|
||||
} else {
|
||||
vm.insertFavorite(charger)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupObservers() {
|
||||
@@ -193,6 +216,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
}
|
||||
binding.fabDirections.show()
|
||||
detailAppBarBehavior.setToolbarTitle(it.name)
|
||||
updateFavoriteToggle()
|
||||
} else {
|
||||
bottomSheetBehavior.state = BottomSheetBehaviorGoogleMapsLike.STATE_HIDDEN
|
||||
}
|
||||
@@ -201,6 +225,19 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
val chargepoints = it.data
|
||||
if (chargepoints != null) updateMap(chargepoints)
|
||||
})
|
||||
vm.favorites.observe(viewLifecycleOwner, Observer {
|
||||
updateFavoriteToggle()
|
||||
})
|
||||
}
|
||||
|
||||
private fun updateFavoriteToggle() {
|
||||
val favs = vm.favorites.value ?: return
|
||||
val charger = vm.chargerSparse.value ?: return
|
||||
if (favs.find { it.id == charger.id } != null) {
|
||||
favToggle.setIcon(R.drawable.ic_fav)
|
||||
} else {
|
||||
favToggle.setIcon(R.drawable.ic_fav_no)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupAdapters() {
|
||||
@@ -340,8 +377,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
return ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
private fun updateMap(chargepoints: List<ChargepointListItem>) {
|
||||
|
||||
@@ -7,10 +7,10 @@ import net.vonforst.evmap.api.goingelectric.ChargeLocation
|
||||
@Dao
|
||||
interface ChargeLocationsDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insert(vararg locations: ChargeLocation)
|
||||
suspend fun insert(vararg locations: ChargeLocation)
|
||||
|
||||
@Delete
|
||||
fun delete(vararg locations: ChargeLocation)
|
||||
suspend fun delete(vararg locations: ChargeLocation)
|
||||
|
||||
@Query("SELECT * FROM chargelocation")
|
||||
fun getAllChargeLocations(): LiveData<List<ChargeLocation>>
|
||||
|
||||
@@ -19,23 +19,23 @@ class Converters {
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromChargepointList(value: List<Chargepoint>): String {
|
||||
fun fromChargepointList(value: List<Chargepoint>?): String {
|
||||
return chargepointListAdapter.toJson(value)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toChargepointList(value: String): List<Chargepoint> {
|
||||
return chargepointListAdapter.fromJson(value)!!
|
||||
fun toChargepointList(value: String): List<Chargepoint>? {
|
||||
return chargepointListAdapter.fromJson(value)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromChargerPhotoList(value: List<ChargerPhoto>): String {
|
||||
fun fromChargerPhotoList(value: List<ChargerPhoto>?): String {
|
||||
return chargerPhotoListAdapter.toJson(value)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toChargerPhotoList(value: String): List<ChargerPhoto> {
|
||||
return chargerPhotoListAdapter.fromJson(value)!!
|
||||
fun toChargerPhotoList(value: String): List<ChargerPhoto>? {
|
||||
return chargerPhotoListAdapter.fromJson(value)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package net.vonforst.evmap.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
import kotlinx.coroutines.launch
|
||||
import net.vonforst.evmap.api.goingelectric.ChargeLocation
|
||||
import net.vonforst.evmap.api.goingelectric.GoingElectricApi
|
||||
import net.vonforst.evmap.storage.AppDatabase
|
||||
|
||||
class FavoritesViewModel(application: Application, geApiKey: String) :
|
||||
AndroidViewModel(application) {
|
||||
private var api = GoingElectricApi.create(geApiKey)
|
||||
private var db = AppDatabase.getInstance(application)
|
||||
|
||||
val favorites: LiveData<List<ChargeLocation>> by lazy {
|
||||
db.chargeLocationsDao().getAllChargeLocations()
|
||||
}
|
||||
|
||||
val location: MutableLiveData<LatLng> by lazy {
|
||||
MutableLiveData<LatLng>()
|
||||
}
|
||||
|
||||
/*val availability: MediatorLiveData<Map<Long, Resource<ChargeLocationStatus>>> by lazy {
|
||||
MediatorLiveData<Map<Long, Resource<ChargeLocationStatus>>>().apply {
|
||||
addSource(favorites) { chargers ->
|
||||
if (chargers != null) {
|
||||
viewModelScope.launch {
|
||||
chargers.map {
|
||||
availability.value = Resource.loading(null)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
fun insertFavorite(charger: ChargeLocation) {
|
||||
viewModelScope.launch {
|
||||
db.chargeLocationsDao().insert(charger)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteFavorite(charger: ChargeLocation) {
|
||||
viewModelScope.launch {
|
||||
db.chargeLocationsDao().delete(charger)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,11 +91,15 @@ class MapViewModel(application: Application, geApiKey: String) : AndroidViewMode
|
||||
}
|
||||
|
||||
fun insertFavorite(charger: ChargeLocation) {
|
||||
db.chargeLocationsDao().insert(charger)
|
||||
viewModelScope.launch {
|
||||
db.chargeLocationsDao().insert(charger)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteFavorite(charger: ChargeLocation) {
|
||||
db.chargeLocationsDao().delete(charger)
|
||||
viewModelScope.launch {
|
||||
db.chargeLocationsDao().delete(charger)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadChargepoints(mapPosition: MapPosition) {
|
||||
|
||||
Reference in New Issue
Block a user