diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs index 0bd9ff4..f9bac43 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs @@ -1799,9 +1799,12 @@ public partial class PlanificadorRutas : ComponentBase /// private string FormatearEtiquetaAlternativaTarjeta(AlternativaRuta alternativa, int indice) { - return !string.IsNullOrWhiteSpace(alternativa.Etiqueta) - ? alternativa.Etiqueta - : $"Opcion {indice + 1}"; + if (alternativa.EsSoloAPie) + return !string.IsNullOrWhiteSpace(alternativa.Etiqueta) + ? alternativa.Etiqueta + : "Solo a pie"; + + return $"Opción {indice + 1}"; } diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Geocodificacion.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Geocodificacion.cs index cfe6bf9..23dc06d 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Geocodificacion.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Geocodificacion.cs @@ -33,6 +33,7 @@ public partial class PlanificadorRutas private SugerenciaBusquedaMapa? _ubicacionOrigenSeleccionada; private SugerenciaBusquedaMapa? _ubicacionDestinoSeleccionada; private int _versionSugerenciasBusqueda; + private int _versionIntercambioBuscador; private CancellationTokenSource? _ctsSugerenciasBusqueda; private IReadOnlyList SugerenciasOrigenVisibles => diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs index 49f6f43..913e2ff 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs @@ -535,6 +535,10 @@ public partial class PlanificadorRutas : ComponentBase return; var myToken = Interlocked.Increment(ref _paradaPopupToken); + _ctsParadaPopup?.Cancel(); + _ctsParadaPopup?.Dispose(); + _ctsParadaPopup = new CancellationTokenSource(); + var cancellationToken = _ctsParadaPopup.Token; _paradaClicada = null; _paradaElevIdee = null; @@ -554,59 +558,148 @@ public partial class PlanificadorRutas : ComponentBase _paradaClicada = paradaDetectada; StateHasChanged(); + try + { + await JS.InvokeVoidAsync( + "rt.setSelectedStopMarker", + paradaDetectada.Latitud, + paradaDetectada.Longitud); + } + catch { } + + _ = CompletarPopupParadaAsync(paradaDetectada, punto, clave, myToken, cancellationToken); + } + + private async Task CompletarPopupParadaAsync( + Parada paradaDetectada, + (double Latitud, double Longitud) punto, + string clave, + int token, + CancellationToken cancellationToken) + { + var tareaElevacion = CompletarElevacionPopupParadaAsync( + paradaDetectada, punto, clave, token, cancellationToken); + var tareaHorarios = CompletarHorariosPopupParadaAsync( + paradaDetectada, token, cancellationToken); + + try + { + await Task.WhenAll(tareaElevacion, tareaHorarios); + } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + } + catch + { + // Una carga auxiliar no debe bloquear ni cerrar el popup de la parada. + } + } + + private async Task CompletarElevacionPopupParadaAsync( + Parada paradaDetectada, + (double Latitud, double Longitud) punto, + string clave, + int token, + CancellationToken cancellationToken) + { + try { if (!_elevIdeeCache.ContainsKey(clave)) { await ObtenerElevacionesIdeePorLoteAsync( new List<(double lat, double lon)> { punto }, - CancellationToken.None); + cancellationToken); } + if (!EsPopupParadaVigente(paradaDetectada, token, cancellationToken)) + return; + _paradaElevIdee = _elevIdeeCache.TryGetValue(clave, out var idee) ? idee : null; } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + return; + } catch { + if (!EsPopupParadaVigente(paradaDetectada, token, cancellationToken)) + return; _paradaElevIdee = null; } - - if (myToken != _paradaPopupToken) return; - StateHasChanged(); - - // ========================== - // HORARIOS (ZIP) -> usando tu AhoraLocal() (real o simulada) - // ========================== - if (_usarHorariosTeoricos) + + if (EsPopupParadaVigente(paradaDetectada, token, cancellationToken)) + await InvokeAsync(StateHasChanged); + } + + private async Task CompletarHorariosPopupParadaAsync( + Parada paradaDetectada, + int token, + CancellationToken cancellationToken) + { + if (!_usarHorariosTeoricos) + return; + + await EnsureHorariosLoadedAsync(); + if (!EsPopupParadaVigente(paradaDetectada, token, cancellationToken)) + return; + + if (_horariosOk) { - await EnsureHorariosLoadedAsync(); - - if (_horariosOk) + try { - try - { - var now = AhoraLocal(); - var fecha = DateOnly.FromDateTime(now); - var hora = TimeOnly.FromDateTime(now); - - // tu parada usa Codigo (ej "34" o "P-34"). El servicio normaliza. - var deps = Horarios.GetNextDeparturesByCodigo( - paradaDetectada.Codigo, - fecha, - hora, - take: null, - includePast: true); - - _nextDeps = ConstruirListaHorariosConActual(deps, hora); - _scrollHorariosPendiente = true; - } - catch (Exception ex) - { - _horariosOk = false; - _horariosError = "Error leyendo horarios: " + ex.Message; - } + var now = AhoraLocal(); + var fecha = DateOnly.FromDateTime(now); + var hora = TimeOnly.FromDateTime(now); + + var deps = Horarios.GetNextDeparturesByCodigo( + paradaDetectada.Codigo, + fecha, + hora, + take: null, + includePast: true); + + if (!EsPopupParadaVigente(paradaDetectada, token, cancellationToken)) + return; + + _nextDeps = ConstruirListaHorariosConActual(deps, hora); + _scrollHorariosPendiente = true; + } + catch (Exception ex) + { + if (!EsPopupParadaVigente(paradaDetectada, token, cancellationToken)) + return; + _horariosOk = false; + _horariosError = "Error leyendo horarios: " + ex.Message; } } - + + if (EsPopupParadaVigente(paradaDetectada, token, cancellationToken)) + await InvokeAsync(StateHasChanged); + } + + private bool EsPopupParadaVigente( + Parada parada, + int token, + CancellationToken cancellationToken) + => !cancellationToken.IsCancellationRequested && + token == Volatile.Read(ref _paradaPopupToken) && + string.Equals(_paradaClicada?.Codigo, parada.Codigo, StringComparison.OrdinalIgnoreCase); + + private async Task CerrarPopupParadaAsync() + { + Interlocked.Increment(ref _paradaPopupToken); + _ctsParadaPopup?.Cancel(); + _ctsParadaPopup?.Dispose(); + _ctsParadaPopup = null; + _paradaClicada = null; + _paradaElevIdee = null; + _paradaElevLocal5 = null; + _paradaElevLocal2 = null; + _paradaElevLocal1 = null; + _nextDeps.Clear(); + _scrollHorariosPendiente = false; + try { await JS.InvokeVoidAsync("rt.clearSelectedStopMarker"); } catch { } StateHasChanged(); } @@ -1294,6 +1387,7 @@ public partial class PlanificadorRutas : ComponentBase private int _paradaPopupToken = 0; + private CancellationTokenSource? _ctsParadaPopup; /// @@ -1400,7 +1494,7 @@ public partial class PlanificadorRutas : ComponentBase private bool _elevPopupMinimizado = false; - private const string _versionApp = "(v-20260910b)"; + private const string _versionApp = "(v-20260914a)"; private double? _paradaElevIdee; @@ -1419,8 +1513,8 @@ public partial class PlanificadorRutas : ComponentBase private async Task CerrarPopupsAsync() { _itinerarioClicado = null; - - _paradaClicada = null; + + await CerrarPopupParadaAsync(); await CerrarInspectorAsync(); if (_tramoElevDetalle is not null) diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs index 1aee165..86f7e13 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs @@ -1445,12 +1445,20 @@ public partial class PlanificadorRutas : ComponentBase /// private async Task IntercambiarOrigenDestino() { + _ctsSugerenciasBusqueda?.Cancel(); + _ctsSugerenciasBusqueda?.Dispose(); + _ctsSugerenciasBusqueda = null; + _versionSugerenciasBusqueda++; (_coordenadasOrigen, _coordenadasDestino) = (_coordenadasDestino, _coordenadasOrigen); (_textoBusquedaOrigen, _textoBusquedaDestino) = (_textoBusquedaDestino, _textoBusquedaOrigen); (_ubicacionOrigenSeleccionada, _ubicacionDestinoSeleccionada) = (_ubicacionDestinoSeleccionada, _ubicacionOrigenSeleccionada); _sugerenciasBusquedaOrigen.Clear(); _sugerenciasBusquedaDestino.Clear(); _campoBusquedaActivo = null; + _versionIntercambioBuscador++; + + StateHasChanged(); + await Task.Yield(); await ClearRoutesJsAsync(); await CerrarTodasLasPreviewsAsync(); @@ -1916,6 +1924,7 @@ public partial class PlanificadorRutas : ComponentBase _panelRutasMovilContraido = _mostrarBuscadorMapa; await CerrarTodasLasPreviewsAsync(); + await CerrarPopupParadaAsync(); _ctsCalculo?.Cancel(); _ctsCalculo = new CancellationTokenSource(); diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.RestriccionesCaminata.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.RestriccionesCaminata.cs index a2dece7..f635bfc 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.RestriccionesCaminata.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.RestriccionesCaminata.cs @@ -21,6 +21,8 @@ public partial class PlanificadorRutas private bool _recalculandoZonas; private string? _errorZonas; private const string ClaveZonasLocal = "rutasdbus.zonas.v1"; + private const int MaximoExclusionesCaminata = 25; + private const int MaximoVerticesPorExclusion = 50; private bool _zonasCargadas; private bool _nuevaExclusionEsPunto; @@ -35,9 +37,9 @@ public partial class PlanificadorRutas if (!string.IsNullOrWhiteSpace(json)) { var zonas = JsonSerializer.Deserialize>(json) ?? new(); - foreach (var zona in zonas.Take(10)) + foreach (var zona in zonas.Take(MaximoExclusionesCaminata)) { - if (zona is null || zona.Vertices is null || zona.Vertices.Count > 50 || + if (zona is null || zona.Vertices is null || zona.Vertices.Count > MaximoVerticesPorExclusion || zona.Vertices.Any(p => p is null || p.Length != 2 || !CoordenadaExclusionValida(p[0], p[1]))) continue; if (zona.EsPunto && zona.Vertices.Count > 1) continue; @@ -59,7 +61,7 @@ public partial class PlanificadorRutas try { var resultado = await JS.InvokeAsync("rt.saveLocalValueResult", ClaveZonasLocal, - JsonSerializer.Serialize(_zonasExclusionCaminata)); + JsonSerializer.Serialize(_zonasExclusionCaminata.Take(MaximoExclusionesCaminata))); if (!resultado.GetProperty("ok").GetBoolean()) _errorZonas = "No se pudieron guardar las zonas en este navegador."; } @@ -120,7 +122,8 @@ public partial class PlanificadorRutas private async Task IniciarDibujoExclusionCaminataAsync() { - if (!_zonasCargadas || _recalculandoZonas || _modoDibujoExclusionCaminata || _zonasExclusionCaminata.Count >= 10) return; + if (!_zonasCargadas || _recalculandoZonas || _modoDibujoExclusionCaminata || + _zonasExclusionCaminata.Count >= MaximoExclusionesCaminata) return; var zona = new ZonaExclusionCaminata { EsPunto = _nuevaExclusionEsPunto }; _zonasExclusionCaminata.Add(zona); _zonaExclusionSeleccionada = zona.Id; @@ -211,7 +214,7 @@ public partial class PlanificadorRutas { if (!_modoDibujoExclusionCaminata || _recalculandoZonas || !CoordenadaExclusionValida(latitud, longitud)) return; var zona = ZonaExclusionSeleccionada!; - if (zona.Vertices.Count >= 50) return; + if (zona.Vertices.Count >= MaximoVerticesPorExclusion) return; zona.Vertices.Add(new[] { latitud, longitud }); if (zona.EsPunto) zona.Cerrada = true; await ActualizarEditorExclusionCaminataAsync(); diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.TiempoYHorarios.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.TiempoYHorarios.cs index 9106093..8a111a6 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.TiempoYHorarios.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.TiempoYHorarios.cs @@ -427,6 +427,10 @@ public partial class PlanificadorRutas : ComponentBase /// public void Dispose() { + _ctsParadaPopup?.Cancel(); + _ctsParadaPopup?.Dispose(); + _ctsSugerenciasBusqueda?.Cancel(); + _ctsSugerenciasBusqueda?.Dispose(); _clockCts?.Cancel(); _clockTimer?.Dispose(); _clockCts?.Dispose(); diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.ValoresFabrica.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.ValoresFabrica.cs index 3d3fdbf..ebda092 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.ValoresFabrica.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.ValoresFabrica.cs @@ -27,10 +27,6 @@ public partial class PlanificadorRutas { var actual = CrearConfiguracionLocal(); var predeterminada = CrearConfiguracionPredeterminadaHistorial(); - predeterminada.ActivarRangoLineas = actual.ActivarRangoLineas; - predeterminada.LineaMin = actual.LineaMin; - predeterminada.LineaMax = actual.LineaMax; - predeterminada.LineasPermitidas = actual.LineasPermitidas; predeterminada.UsarHoraSimulada = actual.UsarHoraSimulada; predeterminada.FechaSimulada = actual.FechaSimulada; predeterminada.HoraSimulada = actual.HoraSimulada; diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.razor b/RutasDBUS/Components/Pages/PlanificadorRutas.razor index 12e62fb..87e57b9 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.razor +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.razor @@ -148,6 +148,7 @@
-
@@ -1530,7 +1532,7 @@ aria-pressed="@_nuevaExclusionEsPunto" disabled="@_recalculandoZonas" @onclick="() => SeleccionarTipoExclusionCaminata(true)">Punto - }