Gasolinera app
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package com.example.prueba
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.location.Geocoder
|
||||
@@ -28,7 +27,6 @@ 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.compose.ui.unit.sp
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.example.prueba.data.GasStationInfo
|
||||
import com.example.prueba.data.GasStationRepository
|
||||
@@ -74,7 +72,6 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
|
||||
var destinationQuery by remember { mutableStateOf("") }
|
||||
var isRouteActive by remember { mutableStateOf(false) }
|
||||
var isReserveFilterActive by remember { mutableStateOf(false) }
|
||||
var destinationLocation by remember { mutableStateOf<android.location.Location?>(null) }
|
||||
|
||||
var hasPermission by remember {
|
||||
@@ -96,6 +93,7 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val geocoder = Geocoder(context, Locale.getDefault())
|
||||
@Suppress("DEPRECATION")
|
||||
val addresses = geocoder.getFromLocation(location.latitude, location.longitude, 1)
|
||||
if (!addresses.isNullOrEmpty()) {
|
||||
val address = addresses[0]
|
||||
@@ -107,29 +105,14 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(hasPermission, destinationLocation, selectedTab, isReserveFilterActive) {
|
||||
// Registro del rastreador de GPS (Se ejecuta solo al inicio o si cambia el permiso)
|
||||
LaunchedEffect(hasPermission) {
|
||||
if (hasPermission) {
|
||||
val loc = lastLocation ?: LocationStorage.getLastLocation(context)
|
||||
loc?.let {
|
||||
// Primero recta para rapidez
|
||||
stations = repository.getCheapestAndNearest(
|
||||
userLocation = it,
|
||||
maxDistanceKm = if (isReserveFilterActive) 40.0 else null,
|
||||
destinationLocation = if (isRouteActive) destinationLocation else null,
|
||||
getRealDistances = false
|
||||
)
|
||||
// Luego real para precisión
|
||||
scope.launch {
|
||||
stations = repository.getCheapestAndNearest(
|
||||
userLocation = it,
|
||||
maxDistanceKm = if (isReserveFilterActive) 40.0 else null,
|
||||
destinationLocation = if (isRouteActive) destinationLocation else null,
|
||||
getRealDistances = true
|
||||
)
|
||||
}
|
||||
}
|
||||
if (selectedTab == 0) isLoading = true
|
||||
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
|
||||
|
||||
// Cargar ubicación inicial guardada para no empezar de cero
|
||||
LocationStorage.getLastLocation(context)?.let { lastLocation = it }
|
||||
|
||||
val locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 15000)
|
||||
.setMinUpdateDistanceMeters(500f)
|
||||
.build()
|
||||
@@ -139,24 +122,10 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
val location = result.lastLocation ?: return
|
||||
lastLocation = location
|
||||
LocationStorage.saveLocation(context, location)
|
||||
if (selectedTab == 0) {
|
||||
scope.launch {
|
||||
updateAddress(location)
|
||||
stations = repository.getCheapestAndNearest(
|
||||
userLocation = location,
|
||||
maxDistanceKm = if (isReserveFilterActive) 40.0 else null,
|
||||
destinationLocation = if (isRouteActive) destinationLocation else null,
|
||||
getRealDistances = true
|
||||
)
|
||||
isLoading = false
|
||||
}
|
||||
} else {
|
||||
isLoading = false
|
||||
}
|
||||
scope.launch { updateAddress(location) }
|
||||
}
|
||||
}
|
||||
|
||||
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
|
||||
try {
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, android.os.Looper.getMainLooper())
|
||||
@@ -167,6 +136,36 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
}
|
||||
}
|
||||
|
||||
// Actualizador de la lista de gasolineras (Reacciona al movimiento del GPS)
|
||||
LaunchedEffect(hasPermission, destinationLocation, selectedTab, isRouteActive, lastLocation) {
|
||||
if (hasPermission) {
|
||||
val loc = lastLocation ?: LocationStorage.getLastLocation(context)
|
||||
|
||||
loc?.let {
|
||||
if (selectedTab == 0) {
|
||||
// 1. Carga ultra-rápida (recta)
|
||||
stations = repository.getCheapestAndNearest(
|
||||
userLocation = it,
|
||||
destinationLocation = if (isRouteActive) destinationLocation else null,
|
||||
getRealDistances = false
|
||||
)
|
||||
|
||||
// 2. Carga de precisión (carretera)
|
||||
val realStations = repository.getCheapestAndNearest(
|
||||
userLocation = it,
|
||||
destinationLocation = if (isRouteActive) destinationLocation else null,
|
||||
getRealDistances = true
|
||||
)
|
||||
if (realStations.isNotEmpty()) {
|
||||
stations = realStations
|
||||
}
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
if (selectedTab == 0 && stations.isEmpty()) isLoading = true
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
topBar = {
|
||||
@@ -187,6 +186,7 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val geocoder = Geocoder(context, Locale.getDefault())
|
||||
@Suppress("DEPRECATION")
|
||||
val results = geocoder.getFromLocationName(destinationQuery, 1)
|
||||
if (!results.isNullOrEmpty()) {
|
||||
destinationLocation = android.location.Location("").apply {
|
||||
@@ -257,8 +257,8 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
scope.launch {
|
||||
stations = repository.getCheapestAndNearest(
|
||||
userLocation = loc, forceRefresh = true,
|
||||
maxDistanceKm = if (isReserveFilterActive) 40.0 else null,
|
||||
destinationLocation = if (isRouteActive) destinationLocation else null
|
||||
destinationLocation = if (isRouteActive) destinationLocation else null,
|
||||
getRealDistances = true
|
||||
)
|
||||
isRefreshing = false
|
||||
}
|
||||
@@ -269,7 +269,7 @@ fun GasStationApp(repository: GasStationRepository) {
|
||||
if (isLoading && stations.isEmpty()) {
|
||||
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
|
||||
} else if (stations.isEmpty()) {
|
||||
Text(if (isReserveFilterActive) "No hay nada a menos de 40km" else "Sin resultados", modifier = Modifier.align(Alignment.Center))
|
||||
Text("Sin resultados", modifier = Modifier.align(Alignment.Center))
|
||||
} else {
|
||||
GasStationList(stations = stations, onLogClick = { showFuelDialog = it })
|
||||
}
|
||||
@@ -454,10 +454,15 @@ fun GasStationItem(station: GasStationInfo, onClick: () -> Unit, onLogClick: ()
|
||||
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), shape = MaterialTheme.shapes.small) {
|
||||
Icon(Icons.Default.Add, null, modifier = Modifier.size(16.dp))
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text("Registrar")
|
||||
FilledTonalIconButton(
|
||||
onClick = onLogClick,
|
||||
modifier = Modifier.size(40.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
contentDescription = "Registrar repostaje",
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ class MainScreen(carContext: CarContext) : Screen(carContext) {
|
||||
private var gasStations: List<GasStationInfo> = emptyList()
|
||||
private var currentAddress: String? = null
|
||||
private var isLoading = true
|
||||
private var isReserveFilterActive = false
|
||||
private val repository = GasStationRepository()
|
||||
|
||||
init {
|
||||
@@ -54,17 +53,13 @@ class MainScreen(carContext: CarContext) : Screen(carContext) {
|
||||
LocationStorage.getLastLocation(carContext)?.let { lastLoc ->
|
||||
lifecycleScope.launch {
|
||||
updateAddress(lastLoc)
|
||||
// Primero recta
|
||||
gasStations = repository.getCheapestAndNearest(
|
||||
userLocation = lastLoc,
|
||||
maxDistanceKm = if (isReserveFilterActive) 40.0 else null,
|
||||
getRealDistances = false
|
||||
)
|
||||
invalidate()
|
||||
// Luego real
|
||||
gasStations = repository.getCheapestAndNearest(
|
||||
userLocation = lastLoc,
|
||||
maxDistanceKm = if (isReserveFilterActive) 40.0 else null,
|
||||
getRealDistances = true
|
||||
)
|
||||
invalidate()
|
||||
@@ -85,12 +80,15 @@ class MainScreen(carContext: CarContext) : Screen(carContext) {
|
||||
gasStations = repository.getCheapestAndNearest(
|
||||
userLocation = location,
|
||||
forceRefresh = forceRefresh,
|
||||
maxDistanceKm = if (isReserveFilterActive) 40.0 else null,
|
||||
getRealDistances = true
|
||||
)
|
||||
isLoading = false
|
||||
invalidate()
|
||||
}
|
||||
if (forceRefresh) {
|
||||
fusedLocationClient.removeLocationUpdates(this)
|
||||
fetchLocationAndGasStations(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,13 +98,12 @@ class MainScreen(carContext: CarContext) : Screen(carContext) {
|
||||
override fun onGetTemplate(): Template {
|
||||
val listBuilder = ItemList.Builder()
|
||||
|
||||
val reserveAction = Action.Builder()
|
||||
.setTitle(if (isReserveFilterActive) "Todo" else "Reserva")
|
||||
val refreshAction = Action.Builder()
|
||||
.setTitle("Refrescar")
|
||||
.setOnClickListener {
|
||||
isReserveFilterActive = !isReserveFilterActive
|
||||
isLoading = true
|
||||
invalidate()
|
||||
fetchLocationAndGasStations(forceRefresh = false)
|
||||
fetchLocationAndGasStations(forceRefresh = true)
|
||||
}
|
||||
.build()
|
||||
|
||||
@@ -119,7 +116,7 @@ class MainScreen(carContext: CarContext) : Screen(carContext) {
|
||||
|
||||
if (gasStations.isEmpty()) {
|
||||
return MessageTemplate.Builder("Sin resultados")
|
||||
.setHeader(Header.Builder().setTitle("Gasolineras").addEndHeaderAction(reserveAction).build())
|
||||
.setHeader(Header.Builder().setTitle("Gasolineras").addEndHeaderAction(refreshAction).build())
|
||||
.addAction(Action.Builder().setTitle("Reintentar").setOnClickListener {
|
||||
isLoading = true
|
||||
invalidate()
|
||||
@@ -180,7 +177,7 @@ class MainScreen(carContext: CarContext) : Screen(carContext) {
|
||||
.setHeader(
|
||||
Header.Builder()
|
||||
.setTitle(currentAddress ?: "Gasolineras Diésel")
|
||||
.addEndHeaderAction(reserveAction)
|
||||
.addEndHeaderAction(refreshAction)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
|
||||
@@ -25,7 +25,6 @@ class GasStationRepository {
|
||||
suspend fun getCheapestAndNearest(
|
||||
userLocation: Location,
|
||||
forceRefresh: Boolean = false,
|
||||
maxDistanceKm: Double? = null,
|
||||
destinationLocation: Location? = null,
|
||||
getRealDistances: Boolean = false
|
||||
): List<GasStationInfo> {
|
||||
@@ -75,7 +74,7 @@ class GasStationRepository {
|
||||
} ?: emptyList()
|
||||
|
||||
// Radio máximo: 30km si es local, 400km si hay destino (ruta larga)
|
||||
val finalMaxDist = maxDistanceKm ?: if (destinationLocation == null) 30.0 else 400.0
|
||||
val finalMaxDist = if (destinationLocation == null) 30.0 else 400.0
|
||||
|
||||
val filtered = allStations.filter { (it.distance / 1000.0) <= finalMaxDist }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user