mirror of
https://github.com/ev-map/EVMap.git
synced 2026-04-19 13:48:02 -04:00
Merge pull request #157 from johan12345/db-restructure
Database restructuring in preparation for new features
This commit is contained in:
@@ -268,12 +268,13 @@ class MapScreen(ctx: CarContext, val session: EVMapSession, val favorites: Boole
|
||||
try {
|
||||
// load chargers
|
||||
if (favorites) {
|
||||
chargers = db.chargeLocationsDao().getAllChargeLocationsAsync().sortedBy {
|
||||
distanceBetween(
|
||||
location.latitude, location.longitude,
|
||||
it.coordinates.lat, it.coordinates.lng
|
||||
)
|
||||
}
|
||||
chargers =
|
||||
db.favoritesDao().getAllFavoritesAsync().map { it.charger }.sortedBy {
|
||||
distanceBetween(
|
||||
location.latitude, location.longitude,
|
||||
it.coordinates.lat, it.coordinates.lng
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val response = api.getChargepointsRadius(
|
||||
referenceData,
|
||||
|
||||
@@ -14,7 +14,7 @@ class FavoritesAdapter(val onDelete: (FavoritesViewModel.FavoritesListItem) -> U
|
||||
|
||||
override fun getItemViewType(position: Int): Int = R.layout.item_favorite
|
||||
|
||||
override fun getItemId(position: Int): Long = getItem(position).charger.id
|
||||
override fun getItemId(position: Int): Long = getItem(position).fav.favorite.favoriteId
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun bind(
|
||||
|
||||
@@ -326,7 +326,7 @@ class GoingElectricApiWrapper(
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}.map { it.convert(apikey) }
|
||||
}.map { it.convert(apikey, false) }
|
||||
|
||||
// apply clustering
|
||||
val useClustering = zoom < 13
|
||||
@@ -350,7 +350,7 @@ class GoingElectricApiWrapper(
|
||||
return if (response.isSuccessful && response.body()!!.status == "ok" && response.body()!!.chargelocations.size == 1) {
|
||||
Resource.success(
|
||||
(response.body()!!.chargelocations[0] as GEChargeLocation).convert(
|
||||
apikey
|
||||
apikey, true
|
||||
)
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -29,7 +29,7 @@ data class GEChargeCardList(
|
||||
)
|
||||
|
||||
sealed class GEChargepointListItem {
|
||||
abstract fun convert(apikey: String): ChargepointListItem
|
||||
abstract fun convert(apikey: String, isDetailed: Boolean): ChargepointListItem
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
@@ -54,7 +54,7 @@ data class GEChargeLocation(
|
||||
val openinghours: GEOpeningHours?,
|
||||
val cost: GECost?
|
||||
) : GEChargepointListItem() {
|
||||
override fun convert(apikey: String) = ChargeLocation(
|
||||
override fun convert(apikey: String, isDetailed: Boolean) = ChargeLocation(
|
||||
id,
|
||||
"goingelectric",
|
||||
name,
|
||||
@@ -76,7 +76,9 @@ data class GEChargeLocation(
|
||||
openinghours?.convert(),
|
||||
cost?.convert(),
|
||||
null,
|
||||
ChargepriceData(address.country, network, chargepoints.map { it.type })
|
||||
ChargepriceData(address.country, network, chargepoints.map { it.type }),
|
||||
Instant.now(),
|
||||
isDetailed
|
||||
)
|
||||
}
|
||||
|
||||
@@ -161,7 +163,7 @@ data class GEChargeLocationCluster(
|
||||
val clusterCount: Int,
|
||||
val coordinates: GECoordinate
|
||||
) : GEChargepointListItem() {
|
||||
override fun convert(apikey: String) =
|
||||
override fun convert(apikey: String, isDetailed: Boolean) =
|
||||
ChargeLocationCluster(clusterCount, coordinates.convert())
|
||||
}
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ class OpenChargeMapApiWrapper(
|
||||
.filter { it.power == null || it.power >= (minPower ?: 0.0) }
|
||||
.filter { if (connectorsVal != null && !connectorsVal.all) it.connectionTypeId in connectorsVal.values.map { it.toLong() } else true }
|
||||
.sumOf { it.quantity ?: 1 } >= (minConnectors ?: 0)
|
||||
}.map { it.convert(referenceData) }.distinct() as List<ChargepointListItem>
|
||||
}.map { it.convert(referenceData, false) }.distinct() as List<ChargepointListItem>
|
||||
|
||||
// apply clustering
|
||||
val useClustering = zoom < 13
|
||||
@@ -256,7 +256,7 @@ class OpenChargeMapApiWrapper(
|
||||
try {
|
||||
val response = api.getChargepointDetail(id)
|
||||
if (response.isSuccessful && response.body()?.size == 1) {
|
||||
return Resource.success(response.body()!![0].convert(referenceData))
|
||||
return Resource.success(response.body()!![0].convert(referenceData, true))
|
||||
} else {
|
||||
return Resource.error(response.message(), null)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.squareup.moshi.JsonClass
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import net.vonforst.evmap.max
|
||||
import net.vonforst.evmap.model.*
|
||||
import java.time.Instant
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
// Unknown, Currently Available, Currently In Use, Operational
|
||||
@@ -44,7 +45,7 @@ data class OCMChargepoint(
|
||||
@Json(name = "UserComments") val userComments: List<OCMUserComment>?,
|
||||
@Json(name = "DateLastStatusUpdate") val lastStatusUpdateDate: ZonedDateTime?
|
||||
) {
|
||||
fun convert(refData: OCMReferenceData) = ChargeLocation(
|
||||
fun convert(refData: OCMReferenceData, isDetailed: Boolean) = ChargeLocation(
|
||||
id,
|
||||
"openchargemap",
|
||||
addressInfo.title,
|
||||
@@ -69,7 +70,9 @@ data class OCMChargepoint(
|
||||
ChargepriceData(
|
||||
addressInfo.countryISOCode(refData),
|
||||
operatorId?.toString(),
|
||||
connections.map { "${it.connectionTypeId},${it.currentTypeId}" })
|
||||
connections.map { "${it.connectionTypeId},${it.currentTypeId}" }),
|
||||
Instant.now(),
|
||||
isDetailed
|
||||
)
|
||||
|
||||
private fun convertFaultReport(): FaultReport? {
|
||||
|
||||
@@ -28,7 +28,8 @@ import net.vonforst.evmap.adapter.DataBindingAdapter
|
||||
import net.vonforst.evmap.adapter.FavoritesAdapter
|
||||
import net.vonforst.evmap.databinding.FragmentFavoritesBinding
|
||||
import net.vonforst.evmap.databinding.ItemFavoriteBinding
|
||||
import net.vonforst.evmap.model.ChargeLocation
|
||||
import net.vonforst.evmap.model.Favorite
|
||||
import net.vonforst.evmap.model.FavoriteWithDetail
|
||||
import net.vonforst.evmap.utils.checkAnyLocationPermission
|
||||
import net.vonforst.evmap.viewmodel.FavoritesViewModel
|
||||
import net.vonforst.evmap.viewmodel.viewModelFactory
|
||||
@@ -36,7 +37,7 @@ import net.vonforst.evmap.viewmodel.viewModelFactory
|
||||
class FavoritesFragment : Fragment(), LostApiClient.ConnectionCallbacks {
|
||||
private lateinit var binding: FragmentFavoritesBinding
|
||||
private var locationClient: LostApiClient? = null
|
||||
private var toDelete: ChargeLocation? = null
|
||||
private var toDelete: Favorite? = null
|
||||
private var deleteSnackbar: Snackbar? = null
|
||||
private lateinit var adapter: FavoritesAdapter
|
||||
|
||||
@@ -84,7 +85,7 @@ class FavoritesFragment : Fragment(), LostApiClient.ConnectionCallbacks {
|
||||
)
|
||||
|
||||
adapter = FavoritesAdapter(onDelete = {
|
||||
delete(it.charger)
|
||||
delete(it.fav)
|
||||
}).apply {
|
||||
onClickListener = {
|
||||
findNavController().navigate(
|
||||
@@ -132,18 +133,20 @@ class FavoritesFragment : Fragment(), LostApiClient.ConnectionCallbacks {
|
||||
}
|
||||
}
|
||||
|
||||
fun delete(fav: ChargeLocation) {
|
||||
val position = vm.listData.value?.indexOfFirst { it.charger == fav } ?: return
|
||||
fun delete(fav: FavoriteWithDetail) {
|
||||
val position =
|
||||
vm.listData.value?.indexOfFirst { it.fav.favorite.favoriteId == fav.favorite.favoriteId }
|
||||
?: return
|
||||
// if there is already a profile to delete, delete it now
|
||||
actuallyDelete()
|
||||
deleteSnackbar?.dismiss()
|
||||
|
||||
toDelete = fav
|
||||
toDelete = fav.favorite
|
||||
|
||||
view?.let {
|
||||
val snackbar = Snackbar.make(
|
||||
it,
|
||||
getString(R.string.deleted_filterprofile, fav.name),
|
||||
getString(R.string.deleted_filterprofile, fav.charger.name),
|
||||
Snackbar.LENGTH_LONG
|
||||
).setAction(R.string.undo) {
|
||||
toDelete = null
|
||||
@@ -182,7 +185,7 @@ class FavoritesFragment : Fragment(), LostApiClient.ConnectionCallbacks {
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
val fav = vm.favorites.value?.find { it.id == viewHolder.itemId }
|
||||
val fav = vm.favorites.value?.find { it.favorite.favoriteId == viewHolder.itemId }
|
||||
fav?.let { delete(it) }
|
||||
}
|
||||
|
||||
|
||||
@@ -499,9 +499,9 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
private fun toggleFavorite() {
|
||||
val favs = vm.favorites.value ?: return
|
||||
val charger = vm.chargerSparse.value ?: return
|
||||
val isFav = favs.find { it.id == charger.id } != null
|
||||
if (isFav) {
|
||||
vm.deleteFavorite(charger)
|
||||
val fav = favs.find { it.charger.id == charger.id }
|
||||
if (fav != null) {
|
||||
vm.deleteFavorite(fav.favorite)
|
||||
} else {
|
||||
vm.insertFavorite(charger)
|
||||
}
|
||||
@@ -511,7 +511,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
highlight = true,
|
||||
fault = charger.faultReport != null,
|
||||
multi = charger.isMulti(vm.filteredConnectors.value),
|
||||
fav = !isFav
|
||||
fav = fav == null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -642,7 +642,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
highlight = false,
|
||||
fault = c.faultReport != null,
|
||||
multi = c.isMulti(vm.filteredConnectors.value),
|
||||
fav = c.id in vm.favorites.value?.map { it.id } ?: emptyList()
|
||||
fav = c.id in vm.favorites.value?.map { it.charger.id } ?: emptyList()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -657,7 +657,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
highlight = true,
|
||||
fault = charger.faultReport != null,
|
||||
multi = charger.isMulti(vm.filteredConnectors.value),
|
||||
fav = charger.id in vm.favorites.value?.map { it.id } ?: emptyList()
|
||||
fav = charger.id in vm.favorites.value?.map { it.charger.id } ?: emptyList()
|
||||
)
|
||||
)
|
||||
animator.animateMarkerBounce(marker)
|
||||
@@ -671,7 +671,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
highlight = false,
|
||||
fault = c.faultReport != null,
|
||||
multi = c.isMulti(vm.filteredConnectors.value),
|
||||
fav = c.id in vm.favorites.value?.map { it.id } ?: emptyList()
|
||||
fav = c.id in vm.favorites.value?.map { it.charger.id } ?: emptyList()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -681,7 +681,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
private fun updateFavoriteToggle() {
|
||||
val favs = vm.favorites.value ?: return
|
||||
val charger = vm.chargerSparse.value ?: return
|
||||
if (favs.find { it.id == charger.id } != null) {
|
||||
if (favs.find { it.charger.id == charger.id } != null) {
|
||||
favToggle.setIcon(R.drawable.ic_fav)
|
||||
} else {
|
||||
favToggle.setIcon(R.drawable.ic_fav_no)
|
||||
@@ -1023,7 +1023,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
highlight = charger == vm.chargerSparse.value,
|
||||
fault = charger.faultReport != null,
|
||||
multi = charger.isMulti(vm.filteredConnectors.value),
|
||||
fav = charger.id in vm.favorites.value?.map { it.id } ?: emptyList()
|
||||
fav = charger.id in vm.favorites.value?.map { it.charger.id } ?: emptyList()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1041,7 +1041,8 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
val highlight = charger == vm.chargerSparse.value
|
||||
val fault = charger.faultReport != null
|
||||
val multi = charger.isMulti(vm.filteredConnectors.value)
|
||||
val fav = charger.id in vm.favorites.value?.map { it.id } ?: emptyList()
|
||||
val fav =
|
||||
charger.id in vm.favorites.value?.map { it.charger.id } ?: emptyList()
|
||||
animator.animateMarkerDisappear(marker, tint, highlight, fault, multi, fav)
|
||||
} else {
|
||||
animator.deleteMarker(marker)
|
||||
@@ -1057,7 +1058,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
|
||||
val highlight = charger == vm.chargerSparse.value
|
||||
val fault = charger.faultReport != null
|
||||
val multi = charger.isMulti(vm.filteredConnectors.value)
|
||||
val fav = charger.id in vm.favorites.value?.map { it.id } ?: emptyList()
|
||||
val fav = charger.id in vm.favorites.value?.map { it.charger.id } ?: emptyList()
|
||||
val marker = map.addMarker(
|
||||
MarkerOptions()
|
||||
.position(LatLng(charger.coordinates.lat, charger.coordinates.lng))
|
||||
|
||||
@@ -24,6 +24,14 @@ import kotlin.math.floor
|
||||
|
||||
sealed class ChargepointListItem
|
||||
|
||||
|
||||
/**
|
||||
* A whole charging site (potentially with multiple chargepoints).
|
||||
*
|
||||
* @param timeRetrieved Time when this information was retrieved from the data source
|
||||
* @param isDetailed Whether this data includes all available details (for many data sources,
|
||||
* API calls that return a list may only give a compact representation)
|
||||
*/
|
||||
@Entity(primaryKeys = ["id", "dataSource"])
|
||||
@Parcelize
|
||||
data class ChargeLocation(
|
||||
@@ -49,7 +57,9 @@ data class ChargeLocation(
|
||||
@Embedded val openinghours: OpeningHours?,
|
||||
@Embedded val cost: Cost?,
|
||||
val license: String?,
|
||||
@Embedded(prefix = "chargeprice") val chargepriceData: ChargepriceData?
|
||||
@Embedded(prefix = "chargeprice") val chargepriceData: ChargepriceData?,
|
||||
val timeRetrieved: Instant,
|
||||
val isDetailed: Boolean
|
||||
) : ChargepointListItem(), Equatable, Parcelable {
|
||||
/**
|
||||
* maximum power available from this charger.
|
||||
|
||||
28
app/src/main/java/net/vonforst/evmap/model/FavoritesModel.kt
Normal file
28
app/src/main/java/net/vonforst/evmap/model/FavoritesModel.kt
Normal file
@@ -0,0 +1,28 @@
|
||||
package net.vonforst.evmap.model
|
||||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = ChargeLocation::class,
|
||||
parentColumns = arrayOf("id", "dataSource"),
|
||||
childColumns = arrayOf("chargerId", "chargerDataSource"),
|
||||
onDelete = ForeignKey.RESTRICT,
|
||||
)
|
||||
]
|
||||
)
|
||||
data class Favorite(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val favoriteId: Long = 0,
|
||||
val chargerId: Long,
|
||||
val chargerDataSource: String
|
||||
)
|
||||
|
||||
data class FavoriteWithDetail(
|
||||
@Embedded() val favorite: Favorite,
|
||||
@Embedded val charger: ChargeLocation
|
||||
)
|
||||
@@ -20,6 +20,7 @@ import net.vonforst.evmap.model.*
|
||||
@Database(
|
||||
entities = [
|
||||
ChargeLocation::class,
|
||||
Favorite::class,
|
||||
BooleanFilterValue::class,
|
||||
MultipleChoiceFilterValue::class,
|
||||
SliderFilterValue::class,
|
||||
@@ -31,11 +32,12 @@ import net.vonforst.evmap.model.*
|
||||
OCMConnectionType::class,
|
||||
OCMCountry::class,
|
||||
OCMOperator::class
|
||||
], version = 14
|
||||
], version = 16
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun chargeLocationsDao(): ChargeLocationsDao
|
||||
abstract fun favoritesDao(): FavoritesDao
|
||||
abstract fun filterValueDao(): FilterValueDao
|
||||
abstract fun filterProfileDao(): FilterProfileDao
|
||||
abstract fun recentAutocompletePlaceDao(): RecentAutocompletePlaceDao
|
||||
@@ -53,7 +55,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
.addMigrations(
|
||||
MIGRATION_2, MIGRATION_3, MIGRATION_4, MIGRATION_5, MIGRATION_6,
|
||||
MIGRATION_7, MIGRATION_8, MIGRATION_9, MIGRATION_10, MIGRATION_11,
|
||||
MIGRATION_12, MIGRATION_13, MIGRATION_14
|
||||
MIGRATION_12, MIGRATION_13, MIGRATION_14, MIGRATION_15, MIGRATION_16
|
||||
)
|
||||
.addCallback(object : Callback() {
|
||||
override fun onCreate(db: SupportSQLiteDatabase) {
|
||||
@@ -312,5 +314,37 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val MIGRATION_15 = object : Migration(14, 15) {
|
||||
@SuppressLint("Range")
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
try {
|
||||
db.beginTransaction()
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS `Favorite` (`favoriteId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `chargerId` INTEGER NOT NULL, `chargerDataSource` TEXT NOT NULL, FOREIGN KEY(`chargerId`, `chargerDataSource`) REFERENCES `ChargeLocation`(`id`, `dataSource`) ON UPDATE NO ACTION ON DELETE RESTRICT )");
|
||||
|
||||
val cursor = db.query("SELECT * FROM `ChargeLocation`")
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getLong(cursor.getColumnIndex("id"))
|
||||
val dataSource = cursor.getString(cursor.getColumnIndex("dataSource"))
|
||||
val values = ContentValues().apply {
|
||||
put("chargerId", id)
|
||||
put("chargerDataSource", dataSource)
|
||||
}
|
||||
db.insert("favorite", SQLiteDatabase.CONFLICT_ROLLBACK, values)
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful()
|
||||
} finally {
|
||||
db.endTransaction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val MIGRATION_16 = object : Migration(15, 16) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL("ALTER TABLE `ChargeLocation` ADD `timeRetrieved` INTEGER NOT NULL DEFAULT 0")
|
||||
db.execSQL("ALTER TABLE `ChargeLocation` ADD `isDetailed` INTEGER NOT NULL DEFAULT 0")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
app/src/main/java/net/vonforst/evmap/storage/FavoritesDao.kt
Normal file
29
app/src/main/java/net/vonforst/evmap/storage/FavoritesDao.kt
Normal file
@@ -0,0 +1,29 @@
|
||||
package net.vonforst.evmap.storage
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import net.vonforst.evmap.model.Favorite
|
||||
import net.vonforst.evmap.model.FavoriteWithDetail
|
||||
|
||||
@Dao
|
||||
interface FavoritesDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insert(vararg favorites: Favorite)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(vararg favorites: Favorite)
|
||||
|
||||
@Query("SELECT * FROM favorite LEFT JOIN chargelocation ON favorite.chargerDataSource = chargelocation.dataSource AND favorite.chargerId = chargelocation.id")
|
||||
fun getAllFavorites(): LiveData<List<FavoriteWithDetail>>
|
||||
|
||||
@Query("SELECT * FROM favorite LEFT JOIN chargelocation ON favorite.chargerDataSource = chargelocation.dataSource AND favorite.chargerId = chargelocation.id")
|
||||
suspend fun getAllFavoritesAsync(): List<FavoriteWithDetail>
|
||||
|
||||
@Query("SELECT * FROM favorite LEFT JOIN chargelocation ON favorite.chargerDataSource = chargelocation.dataSource AND favorite.chargerId = chargelocation.id WHERE lat >= :lat1 AND lat <= :lat2 AND lng >= :lng1 AND lng <= :lng2")
|
||||
suspend fun getFavoritesInBoundsAsync(
|
||||
lat1: Double,
|
||||
lat2: Double,
|
||||
lng1: Double,
|
||||
lng2: Double
|
||||
): List<FavoriteWithDetail>
|
||||
}
|
||||
@@ -11,6 +11,8 @@ import net.vonforst.evmap.api.availability.ChargeLocationStatus
|
||||
import net.vonforst.evmap.api.availability.ChargepointStatus
|
||||
import net.vonforst.evmap.api.availability.getAvailability
|
||||
import net.vonforst.evmap.model.ChargeLocation
|
||||
import net.vonforst.evmap.model.Favorite
|
||||
import net.vonforst.evmap.model.FavoriteWithDetail
|
||||
import net.vonforst.evmap.storage.AppDatabase
|
||||
import net.vonforst.evmap.utils.distanceBetween
|
||||
|
||||
@@ -18,8 +20,8 @@ class FavoritesViewModel(application: Application, geApiKey: String) :
|
||||
AndroidViewModel(application) {
|
||||
private var db = AppDatabase.getInstance(application)
|
||||
|
||||
val favorites: LiveData<List<ChargeLocation>> by lazy {
|
||||
db.chargeLocationsDao().getAllChargeLocations()
|
||||
val favorites: LiveData<List<FavoriteWithDetail>> by lazy {
|
||||
db.favoritesDao().getAllFavorites()
|
||||
}
|
||||
|
||||
val location: MutableLiveData<LatLng> by lazy {
|
||||
@@ -28,8 +30,9 @@ class FavoritesViewModel(application: Application, geApiKey: String) :
|
||||
|
||||
val availability: MediatorLiveData<Map<Long, Resource<ChargeLocationStatus>>> by lazy {
|
||||
MediatorLiveData<Map<Long, Resource<ChargeLocationStatus>>>().apply {
|
||||
addSource(favorites) { chargers ->
|
||||
if (chargers != null) {
|
||||
addSource(favorites) { favorites ->
|
||||
if (favorites != null) {
|
||||
val chargers = favorites.map { it.charger }
|
||||
viewModelScope.launch {
|
||||
val data = hashMapOf<Long, Resource<ChargeLocationStatus>>()
|
||||
chargers.forEach { charger ->
|
||||
@@ -54,9 +57,10 @@ class FavoritesViewModel(application: Application, geApiKey: String) :
|
||||
val listData: MediatorLiveData<List<FavoritesListItem>> by lazy {
|
||||
MediatorLiveData<List<FavoritesListItem>>().apply {
|
||||
val callback = { _: Any ->
|
||||
listData.value = favorites.value?.map { charger ->
|
||||
listData.value = favorites.value?.map { favorite ->
|
||||
val charger = favorite.charger
|
||||
FavoritesListItem(
|
||||
charger,
|
||||
favorite,
|
||||
totalAvailable(charger.id),
|
||||
charger.chargepoints.sumBy { it.count },
|
||||
location.value.let { loc ->
|
||||
@@ -78,11 +82,14 @@ class FavoritesViewModel(application: Application, geApiKey: String) :
|
||||
}
|
||||
|
||||
data class FavoritesListItem(
|
||||
val charger: ChargeLocation,
|
||||
val fav: FavoriteWithDetail,
|
||||
val available: Resource<List<ChargepointStatus>>,
|
||||
val total: Int,
|
||||
val distance: Double?
|
||||
) : Equatable
|
||||
) : Equatable {
|
||||
val charger
|
||||
get() = fav.charger
|
||||
}
|
||||
|
||||
private fun totalAvailable(id: Long): Resource<List<ChargepointStatus>> {
|
||||
val availability = availability.value?.get(id) ?: return Resource.error(null, null)
|
||||
@@ -97,12 +104,14 @@ class FavoritesViewModel(application: Application, geApiKey: String) :
|
||||
fun insertFavorite(charger: ChargeLocation) {
|
||||
viewModelScope.launch {
|
||||
db.chargeLocationsDao().insert(charger)
|
||||
db.favoritesDao()
|
||||
.insert(Favorite(chargerId = charger.id, chargerDataSource = charger.dataSource))
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteFavorite(charger: ChargeLocation) {
|
||||
fun deleteFavorite(fav: Favorite) {
|
||||
viewModelScope.launch {
|
||||
db.chargeLocationsDao().delete(charger)
|
||||
db.favoritesDao().delete(fav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,8 +222,8 @@ class MapViewModel(application: Application, private val state: SavedStateHandle
|
||||
}
|
||||
}
|
||||
|
||||
val favorites: LiveData<List<ChargeLocation>> by lazy {
|
||||
db.chargeLocationsDao().getAllChargeLocations()
|
||||
val favorites: LiveData<List<FavoriteWithDetail>> by lazy {
|
||||
db.favoritesDao().getAllFavorites()
|
||||
}
|
||||
|
||||
val searchResult: MutableLiveData<PlaceWithBounds> by lazy {
|
||||
@@ -279,12 +279,14 @@ class MapViewModel(application: Application, private val state: SavedStateHandle
|
||||
fun insertFavorite(charger: ChargeLocation) {
|
||||
viewModelScope.launch {
|
||||
db.chargeLocationsDao().insert(charger)
|
||||
db.favoritesDao()
|
||||
.insert(Favorite(chargerId = charger.id, chargerDataSource = charger.dataSource))
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteFavorite(charger: ChargeLocation) {
|
||||
fun deleteFavorite(favorite: Favorite) {
|
||||
viewModelScope.launch {
|
||||
db.chargeLocationsDao().delete(charger)
|
||||
db.favoritesDao().delete(favorite)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,12 +312,12 @@ class MapViewModel(application: Application, private val state: SavedStateHandle
|
||||
if (filterStatus.value == FILTERS_FAVORITES) {
|
||||
// load favorites from local DB
|
||||
val b = mapPosition.bounds
|
||||
var chargers = db.chargeLocationsDao().getChargeLocationsInBoundsAsync(
|
||||
var chargers = db.favoritesDao().getFavoritesInBoundsAsync(
|
||||
b.southwest.latitude,
|
||||
b.northeast.latitude,
|
||||
b.southwest.longitude,
|
||||
b.northeast.longitude
|
||||
) as List<ChargepointListItem>
|
||||
).map { it.charger } as List<ChargepointListItem>
|
||||
|
||||
val clusterDistance = getClusterDistance(mapPosition.zoom)
|
||||
clusterDistance?.let {
|
||||
|
||||
Reference in New Issue
Block a user