Gasolinera app
This commit is contained in:
@@ -12,6 +12,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -23,18 +24,20 @@ import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.example.prueba.data.GasStationInfo
|
||||
import com.example.prueba.data.GasStationRepository
|
||||
import com.example.prueba.data.PriceCategory
|
||||
import com.example.prueba.ui.theme.PruebaTheme
|
||||
import com.example.prueba.utils.FavoriteStorage
|
||||
import com.example.prueba.utils.FuelRecord
|
||||
import com.example.prueba.utils.FuelStorage
|
||||
import com.example.prueba.utils.LocationStorage
|
||||
import com.google.android.gms.location.*
|
||||
import com.google.android.gms.tasks.CancellationTokenSource
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -68,6 +71,8 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
var isLoading by remember { mutableStateOf(false) }
|
||||
var isRefreshing by remember { mutableStateOf(false) }
|
||||
var selectedTab by remember { mutableIntStateOf(0) }
|
||||
var searchQuery by remember { mutableStateOf("") }
|
||||
var isSearchActive by remember { mutableStateOf(false) }
|
||||
|
||||
var hasPermission by remember {
|
||||
mutableStateOf(
|
||||
@@ -104,17 +109,21 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(hasPermission) {
|
||||
LaunchedEffect(hasPermission, searchQuery, selectedTab) {
|
||||
if (hasPermission) {
|
||||
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
|
||||
LocationStorage.getLastLocation(context)?.let { lastLoc ->
|
||||
scope.launch {
|
||||
updateAddress(lastLoc)
|
||||
stations = repository.getCheapestAndNearest(context, lastLoc)
|
||||
}
|
||||
val loc = lastLocation ?: LocationStorage.getLastLocation(context)
|
||||
|
||||
loc?.let {
|
||||
stations = repository.getCheapestAndNearest(
|
||||
context = context,
|
||||
userLocation = it,
|
||||
municipalityQuery = if (selectedTab == 0) searchQuery.ifBlank { null } else null,
|
||||
onlyFavorites = (selectedTab == 1)
|
||||
)
|
||||
}
|
||||
|
||||
isLoading = true
|
||||
if (selectedTab != 2) isLoading = true
|
||||
val locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 10000)
|
||||
.setMinUpdateDistanceMeters(500f)
|
||||
.build()
|
||||
@@ -124,9 +133,13 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
val location = result.lastLocation ?: return
|
||||
lastLocation = location
|
||||
LocationStorage.saveLocation(context, location)
|
||||
scope.launch {
|
||||
updateAddress(location)
|
||||
stations = repository.getCheapestAndNearest(context, location)
|
||||
if (searchQuery.isBlank()) {
|
||||
scope.launch {
|
||||
updateAddress(location)
|
||||
stations = repository.getCheapestAndNearest(context, location)
|
||||
isLoading = false
|
||||
}
|
||||
} else {
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
@@ -145,25 +158,56 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
topBar = {
|
||||
CenterAlignedTopAppBar(
|
||||
title = {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text("Gasolineras Baratas", style = MaterialTheme.typography.titleSmall)
|
||||
Text(
|
||||
text = currentAddress,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
maxLines = 1
|
||||
)
|
||||
Column {
|
||||
CenterAlignedTopAppBar(
|
||||
title = {
|
||||
if (isSearchActive) {
|
||||
TextField(
|
||||
value = searchQuery,
|
||||
onValueChange = { searchQuery = it },
|
||||
placeholder = { Text("Buscar municipio...") },
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
|
||||
singleLine = true,
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = Color.Transparent,
|
||||
unfocusedContainerColor = Color.Transparent
|
||||
),
|
||||
trailingIcon = {
|
||||
IconButton(onClick = {
|
||||
searchQuery = ""
|
||||
isSearchActive = false
|
||||
}) {
|
||||
Icon(Icons.Default.Close, contentDescription = "Cerrar")
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text("Gasolineras Diésel", style = MaterialTheme.typography.titleSmall)
|
||||
Text(
|
||||
text = currentAddress,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
if (!isSearchActive && selectedTab != 2) {
|
||||
IconButton(onClick = { isSearchActive = true }) {
|
||||
Icon(Icons.Default.Search, contentDescription = "Buscar")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
NavigationBar {
|
||||
NavigationBarItem(
|
||||
icon = { Icon(Icons.Default.Place, "Gasolineras") },
|
||||
label = { Text("Gasolineras") },
|
||||
label = { Text("Diésel") },
|
||||
selected = selectedTab == 0,
|
||||
onClick = { selectedTab = 0 }
|
||||
)
|
||||
@@ -203,7 +247,7 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
lastLocation?.let { loc ->
|
||||
isRefreshing = true
|
||||
scope.launch {
|
||||
stations = repository.getCheapestAndNearest(context, loc, forceRefresh = true)
|
||||
stations = repository.getCheapestAndNearest(context, loc, forceRefresh = true, municipalityQuery = if(searchQuery.isNotBlank()) searchQuery else null)
|
||||
isRefreshing = false
|
||||
}
|
||||
}
|
||||
@@ -223,22 +267,23 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
repository = repository,
|
||||
lastLocation = lastLocation,
|
||||
onLogClick = { showFuelDialog = it },
|
||||
onUpdateStations = { stations = it }
|
||||
onUpdateStations = { stations = it },
|
||||
searchQuery = searchQuery
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val favoriteStations = stations.filter { it.isFavorite }
|
||||
if (favoriteStations.isEmpty()) {
|
||||
if (stations.isEmpty()) {
|
||||
Text("No tienes gasolineras favoritas marcadas", modifier = Modifier.align(Alignment.Center))
|
||||
} else {
|
||||
GasStationList(
|
||||
stations = favoriteStations,
|
||||
stations = stations,
|
||||
context = context,
|
||||
scope = scope,
|
||||
repository = repository,
|
||||
lastLocation = lastLocation,
|
||||
onLogClick = { showFuelDialog = it },
|
||||
onUpdateStations = { stations = it }
|
||||
onUpdateStations = { stations = it },
|
||||
searchQuery = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -262,7 +307,6 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
showFuelDialog?.let { station ->
|
||||
FuelLogDialog(
|
||||
stationName = station.name,
|
||||
pricePerLiter = station.price,
|
||||
onDismiss = { showFuelDialog = null },
|
||||
onConfirm = { liters, total ->
|
||||
val record = FuelRecord(
|
||||
@@ -284,7 +328,6 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
editRecordDialog?.let { record ->
|
||||
FuelLogDialog(
|
||||
stationName = record.stationName,
|
||||
pricePerLiter = record.pricePerLiter,
|
||||
initialLiters = record.liters.toString(),
|
||||
initialTotal = record.totalPrice.toString(),
|
||||
onDismiss = { editRecordDialog = null },
|
||||
@@ -311,7 +354,8 @@ fun GasStationList(
|
||||
repository: GasStationRepository,
|
||||
lastLocation: android.location.Location?,
|
||||
onLogClick: (GasStationInfo) -> Unit,
|
||||
onUpdateStations: (List<GasStationInfo>) -> Unit
|
||||
onUpdateStations: (List<GasStationInfo>) -> Unit,
|
||||
searchQuery: String
|
||||
) {
|
||||
LazyColumn(contentPadding = PaddingValues(vertical = 8.dp)) {
|
||||
items(stations) { station ->
|
||||
@@ -325,9 +369,10 @@ fun GasStationList(
|
||||
onLogClick = { onLogClick(station) },
|
||||
onFavoriteClick = {
|
||||
FavoriteStorage.toggleFavorite(context, station.id)
|
||||
lastLocation?.let { loc ->
|
||||
val loc = lastLocation ?: LocationStorage.getLastLocation(context)
|
||||
loc?.let {
|
||||
scope.launch {
|
||||
onUpdateStations(repository.getCheapestAndNearest(context, loc))
|
||||
onUpdateStations(repository.getCheapestAndNearest(context, it, municipalityQuery = if(searchQuery.isNotBlank()) searchQuery else null))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -386,7 +431,6 @@ fun FuelHistoryScreen(records: List<FuelRecord>, onDelete: (FuelRecord) -> Unit,
|
||||
@Composable
|
||||
fun FuelLogDialog(
|
||||
stationName: String,
|
||||
pricePerLiter: Double,
|
||||
initialLiters: String = "",
|
||||
initialTotal: String = "",
|
||||
onDismiss: () -> Unit,
|
||||
@@ -431,6 +475,21 @@ fun FuelLogDialog(
|
||||
|
||||
@Composable
|
||||
fun GasStationItem(station: GasStationInfo, onClick: () -> Unit, onLogClick: () -> Unit, onFavoriteClick: () -> Unit) {
|
||||
val priceColor = when (station.priceCategory) {
|
||||
PriceCategory.CHEAP -> Color(0xFF2E7D32)
|
||||
PriceCategory.NORMAL -> MaterialTheme.colorScheme.primary
|
||||
PriceCategory.EXPENSIVE -> Color(0xFFC62828)
|
||||
}
|
||||
|
||||
val brandColor = when {
|
||||
station.name.contains("REPSOL", ignoreCase = true) -> Color(0xFFE30613)
|
||||
station.name.contains("CEPSA", ignoreCase = true) -> Color(0xFFEC0000)
|
||||
station.name.contains("BP", ignoreCase = true) -> Color(0xFF00A94F)
|
||||
station.name.contains("GALP", ignoreCase = true) -> Color(0xFFFF6B00)
|
||||
station.name.contains("SHELL", ignoreCase = true) -> Color(0xFFFFD500)
|
||||
else -> MaterialTheme.colorScheme.surfaceVariant
|
||||
}
|
||||
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -446,6 +505,11 @@ fun GasStationItem(station: GasStationInfo, onClick: () -> Unit, onLogClick: ()
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Surface(
|
||||
color = brandColor,
|
||||
modifier = Modifier.size(12.dp).padding(end = 8.dp),
|
||||
shape = androidx.compose.foundation.shape.CircleShape
|
||||
) {}
|
||||
Text(
|
||||
text = "${station.name} - ${station.municipality}",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
@@ -471,9 +535,9 @@ fun GasStationItem(station: GasStationInfo, onClick: () -> Unit, onLogClick: ()
|
||||
shape = MaterialTheme.shapes.medium
|
||||
) {
|
||||
Text(
|
||||
text = "${String.format(Locale.getDefault(), "%.1f", station.distance / 1000)} km",
|
||||
text = "${String.format(Locale.getDefault(), "%.1f", station.distance / 1000)} km (recta)",
|
||||
modifier = Modifier.padding(horizontal = 10.dp, vertical = 6.dp),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSecondaryContainer
|
||||
)
|
||||
}
|
||||
@@ -482,14 +546,24 @@ fun GasStationItem(station: GasStationInfo, onClick: () -> Unit, onLogClick: ()
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
verticalAlignment = Alignment.Bottom
|
||||
) {
|
||||
Text(
|
||||
text = "${station.price} €/L",
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold
|
||||
)
|
||||
Column {
|
||||
Text(
|
||||
text = "Diésel A: ${station.price} €/L",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = priceColor,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
station.pricePremium?.let { premium ->
|
||||
Text(
|
||||
text = "Premium: $premium €/L",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
Button(
|
||||
onClick = onLogClick,
|
||||
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp),
|
||||
|
||||
@@ -147,68 +147,74 @@ class MainScreen(carContext: CarContext) : Screen(carContext) {
|
||||
|
||||
for (station in gasStations) {
|
||||
val distanceStr = String.format(Locale.getDefault(), "%.1f km", station.distance / 1000)
|
||||
listBuilder.addItem(
|
||||
Row.Builder()
|
||||
.setTitle("${station.name} - ${station.municipality}")
|
||||
.addText("${station.price} €/L • $distanceStr")
|
||||
.addText(station.address)
|
||||
.setOnClickListener {
|
||||
val pane = Pane.Builder()
|
||||
.addRow(Row.Builder().setTitle("Precio").addText("${station.price} €/L").build())
|
||||
.addRow(Row.Builder().setTitle("Distancia").addText(distanceStr).build())
|
||||
.addAction(
|
||||
Action.Builder()
|
||||
.setTitle(if (station.isFavorite) "Quitar Favorito" else "Añadir Favorito")
|
||||
.setOnClickListener {
|
||||
FavoriteStorage.toggleFavorite(carContext, station.id)
|
||||
screenManager.pop()
|
||||
fetchLocationAndGasStations(forceRefresh = false)
|
||||
}
|
||||
.build()
|
||||
)
|
||||
.addAction(
|
||||
Action.Builder()
|
||||
.setTitle("Ir ahora")
|
||||
.setOnClickListener {
|
||||
val uri = Uri.parse("geo:${station.latitude},${station.longitude}?q=${station.latitude},${station.longitude}")
|
||||
val intent = Intent(CarContext.ACTION_NAVIGATE, uri)
|
||||
carContext.startCarApp(intent)
|
||||
}
|
||||
.build()
|
||||
)
|
||||
.addAction(
|
||||
Action.Builder()
|
||||
.setTitle("Registrar Repostaje")
|
||||
.setOnClickListener {
|
||||
// Guardar record simplificado desde el coche
|
||||
val record = FuelRecord(
|
||||
date = System.currentTimeMillis(),
|
||||
stationName = station.name,
|
||||
address = station.address,
|
||||
municipality = station.municipality,
|
||||
liters = 0.0, // Se editará en el móvil después
|
||||
totalPrice = 0.0,
|
||||
pricePerLiter = station.price
|
||||
)
|
||||
FuelStorage.saveRecord(carContext, record)
|
||||
screenManager.pop()
|
||||
}
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
|
||||
screenManager.push(
|
||||
object : Screen(carContext) {
|
||||
override fun onGetTemplate(): Template {
|
||||
return PaneTemplate.Builder(pane)
|
||||
.setHeader(Header.Builder().setTitle(station.name).setStartHeaderAction(Action.BACK).build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
)
|
||||
val rowBuilder = Row.Builder()
|
||||
.setTitle("${station.name} - ${station.municipality}")
|
||||
.addText("A: ${station.price} €/L" + (station.pricePremium?.let { " • P: $it €/L" } ?: ""))
|
||||
.addText("$distanceStr (recta) • ${station.address}")
|
||||
.setOnClickListener {
|
||||
val paneBuilder = Pane.Builder()
|
||||
.addRow(Row.Builder().setTitle("Diésel A").addText("${station.price} €/L").build())
|
||||
|
||||
station.pricePremium?.let {
|
||||
paneBuilder.addRow(Row.Builder().setTitle("Diésel Premium").addText("$it €/L").build())
|
||||
}
|
||||
.build()
|
||||
)
|
||||
|
||||
val pane = paneBuilder
|
||||
.addRow(Row.Builder().setTitle("Ubicación").addText("${station.municipality}\n${station.address}").build())
|
||||
.addRow(Row.Builder().setTitle("Distancia").addText("$distanceStr (en línea recta)").build())
|
||||
.addAction(
|
||||
Action.Builder()
|
||||
.setTitle(if (station.isFavorite) "Quitar Favorito" else "Añadir Favorito")
|
||||
.setOnClickListener {
|
||||
FavoriteStorage.toggleFavorite(carContext, station.id)
|
||||
screenManager.pop()
|
||||
fetchLocationAndGasStations(forceRefresh = false)
|
||||
}
|
||||
.build()
|
||||
)
|
||||
.addAction(
|
||||
Action.Builder()
|
||||
.setTitle("Ir ahora")
|
||||
.setOnClickListener {
|
||||
val uri = Uri.parse("geo:${station.latitude},${station.longitude}?q=${station.latitude},${station.longitude}")
|
||||
val intent = Intent(CarContext.ACTION_NAVIGATE, uri)
|
||||
carContext.startCarApp(intent)
|
||||
}
|
||||
.build()
|
||||
)
|
||||
.addAction(
|
||||
Action.Builder()
|
||||
.setTitle("Registrar")
|
||||
.setOnClickListener {
|
||||
val record = FuelRecord(
|
||||
date = System.currentTimeMillis(),
|
||||
stationName = station.name,
|
||||
address = station.address,
|
||||
municipality = station.municipality,
|
||||
liters = 0.0,
|
||||
totalPrice = 0.0,
|
||||
pricePerLiter = station.price
|
||||
)
|
||||
FuelStorage.saveRecord(carContext, record)
|
||||
screenManager.pop()
|
||||
}
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
|
||||
screenManager.push(
|
||||
object : Screen(carContext) {
|
||||
override fun onGetTemplate(): Template {
|
||||
return PaneTemplate.Builder(pane)
|
||||
.setHeader(Header.Builder().setTitle(station.name).setStartHeaderAction(Action.BACK).build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
listBuilder.addItem(rowBuilder.build())
|
||||
}
|
||||
|
||||
return ListTemplate.Builder()
|
||||
|
||||
@@ -15,7 +15,13 @@ class GasStationRepository {
|
||||
.build()
|
||||
.create(GasolineraApi::class.java)
|
||||
|
||||
suspend fun getCheapestAndNearest(context: Context, userLocation: Location, forceRefresh: Boolean = false): List<GasStationInfo> {
|
||||
suspend fun getCheapestAndNearest(
|
||||
context: Context,
|
||||
userLocation: Location,
|
||||
forceRefresh: Boolean = false,
|
||||
municipalityQuery: String? = null,
|
||||
onlyFavorites: Boolean = false
|
||||
): List<GasStationInfo> {
|
||||
return try {
|
||||
if (cachedResponse == null || forceRefresh) {
|
||||
cachedResponse = api.getGasolineras()
|
||||
@@ -23,47 +29,76 @@ class GasStationRepository {
|
||||
|
||||
val favorites = FavoriteStorage.getFavoriteIds(context)
|
||||
|
||||
cachedResponse?.listaEESS?.mapNotNull {
|
||||
val allStations = cachedResponse?.listaEESS?.mapNotNull {
|
||||
val lat = it.latitud.replace(",", ".").toDoubleOrNull()
|
||||
val lon = it.longitud.replace(",", ".").toDoubleOrNull()
|
||||
val price = it.precioDiesel.replace(",", ".").toDoubleOrNull() ?: it.precioGasolina95.replace(",", ".").toDoubleOrNull()
|
||||
|
||||
if (lat != null && lon != null && price != null) {
|
||||
val stationLoc = Location("").apply {
|
||||
latitude = lat
|
||||
longitude = lon
|
||||
}
|
||||
val distance = userLocation.distanceTo(stationLoc)
|
||||
GasStationInfo(
|
||||
id = it.id,
|
||||
name = it.rotulo,
|
||||
address = it.direccion,
|
||||
municipality = it.municipio,
|
||||
price = price,
|
||||
distance = distance,
|
||||
latitude = lat,
|
||||
longitude = lon,
|
||||
isFavorite = favorites.contains(it.id)
|
||||
)
|
||||
if (lat != null && lon != null) {
|
||||
val dieselPrice = it.precioDiesel.replace(",", ".").toDoubleOrNull()
|
||||
val premiumPrice = it.precioDieselPremium.replace(",", ".").toDoubleOrNull()
|
||||
|
||||
if (dieselPrice != null || premiumPrice != null) {
|
||||
val stationLoc = Location("").apply {
|
||||
latitude = lat
|
||||
longitude = lon
|
||||
}
|
||||
val distance = userLocation.distanceTo(stationLoc)
|
||||
GasStationInfo(
|
||||
id = it.id,
|
||||
name = it.rotulo,
|
||||
address = it.direccion,
|
||||
municipality = it.municipio,
|
||||
price = dieselPrice ?: 0.0,
|
||||
pricePremium = premiumPrice,
|
||||
distance = distance,
|
||||
latitude = lat,
|
||||
longitude = lon,
|
||||
isFavorite = favorites.contains(it.id)
|
||||
)
|
||||
} else null
|
||||
} else null
|
||||
}?.sortedBy { it.distance }
|
||||
?.take(50)
|
||||
?.sortedWith(compareByDescending<GasStationInfo> { it.isFavorite }.thenBy { it.price })
|
||||
?.take(10) ?: emptyList()
|
||||
} ?: emptyList()
|
||||
|
||||
val filteredStations = when {
|
||||
onlyFavorites -> allStations.filter { it.isFavorite }
|
||||
.sortedBy { it.distance }
|
||||
!municipalityQuery.isNullOrBlank() -> allStations.filter { it.municipality.contains(municipalityQuery, ignoreCase = true) }
|
||||
.sortedBy { it.distance }
|
||||
else -> allStations.sortedBy { it.distance }.take(50)
|
||||
}
|
||||
|
||||
if (filteredStations.isEmpty()) return emptyList()
|
||||
|
||||
val minPrice = filteredStations.minOf { it.price }
|
||||
val avgPrice = filteredStations.map { it.price }.average()
|
||||
|
||||
filteredStations.map { station ->
|
||||
val category = when {
|
||||
station.price <= minPrice * 1.01 -> PriceCategory.CHEAP
|
||||
station.price <= avgPrice -> PriceCategory.NORMAL
|
||||
else -> PriceCategory.EXPENSIVE
|
||||
}
|
||||
station.copy(priceCategory = category)
|
||||
}.sortedWith(compareByDescending<GasStationInfo> { it.isFavorite }.thenBy { it.price })
|
||||
.take(if (onlyFavorites) 50 else 15)
|
||||
} catch (e: Exception) {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class PriceCategory { CHEAP, NORMAL, EXPENSIVE }
|
||||
|
||||
data class GasStationInfo(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val address: String,
|
||||
val municipality: String,
|
||||
val price: Double,
|
||||
val pricePremium: Double? = null,
|
||||
val distance: Float,
|
||||
val latitude: Double,
|
||||
val longitude: Double,
|
||||
val isFavorite: Boolean = false
|
||||
val isFavorite: Boolean = false,
|
||||
val priceCategory: PriceCategory = PriceCategory.NORMAL
|
||||
)
|
||||
|
||||
@@ -19,6 +19,8 @@ data class Gasolinera(
|
||||
val municipio: String,
|
||||
@SerializedName("Precio Gasoleo A")
|
||||
val precioDiesel: String,
|
||||
@SerializedName("Precio Gasoleo Premium")
|
||||
val precioDieselPremium: String,
|
||||
@SerializedName("Precio Gasolina 95 E5")
|
||||
val precioGasolina95: String,
|
||||
@SerializedName("Latitud")
|
||||
|
||||
Reference in New Issue
Block a user