diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.ConfiguracionAvanzada.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.ConfiguracionAvanzada.cs new file mode 100644 index 0000000..a3b5df0 --- /dev/null +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.ConfiguracionAvanzada.cs @@ -0,0 +1,156 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.RegularExpressions; +using RutasDBUS.Modelos.Historial; + +namespace RutasDBUS.Components.Pages; + +public partial class PlanificadorRutas +{ + private ConfiguracionHistorialRuta? _configuracionAvanzadaAplicada; + private readonly List<(string Campo, string Antes, string Despues)> _cambiosConfiguracionSinGuardar = new(); + private bool _editandoConfiguracionAvanzada; + private bool _forzarPersistenciaConfiguracion; + private bool _mostrarConfirmacionCerrarConfiguracion; + + private static readonly HashSet PropiedadesFueraConfiguracionAvanzada = new(StringComparer.Ordinal) + { + nameof(ConfiguracionHistorialRuta.MostrarParadas), + nameof(ConfiguracionHistorialRuta.UsarColorRealLineaEnItinerarios), + nameof(ConfiguracionHistorialRuta.CriterioPrioritarioRuta), + nameof(ConfiguracionHistorialRuta.PreferenciaEtiquetaRuta) + }; + + private void ToggleConfigPanel() + { + if (!_mostrarConfigAvanzada) + { + _configuracionAvanzadaAplicada = CrearConfiguracionLocal().Clonar(); + _editandoConfiguracionAvanzada = true; + _cambiosConfiguracionSinGuardar.Clear(); + _mostrarConfirmacionCerrarConfiguracion = false; + _mostrarConfigAvanzada = true; + return; + } + + SolicitarCierreConfiguracionAvanzada(); + } + + private bool SolicitarCierreConfiguracionAvanzada() + { + ActualizarCambiosConfiguracionSinGuardar(); + if (_cambiosConfiguracionSinGuardar.Count > 0) + { + _mostrarConfirmacionCerrarConfiguracion = true; + return false; + } + + CerrarConfiguracionAvanzada(); + return true; + } + + private void ActualizarCambiosConfiguracionSinGuardar() + { + _cambiosConfiguracionSinGuardar.Clear(); + if (_configuracionAvanzadaAplicada is null) + return; + + var actual = CrearConfiguracionLocal(); + foreach (var propiedad in typeof(ConfiguracionHistorialRuta).GetProperties()) + { + if (propiedad.Name.StartsWith("Version", StringComparison.Ordinal) || + PropiedadesFueraConfiguracionAvanzada.Contains(propiedad.Name)) + { + continue; + } + + var valorAntes = propiedad.GetValue(_configuracionAvanzadaAplicada); + var valorDespues = propiedad.GetValue(actual); + if (JsonSerializer.Serialize(valorAntes) == JsonSerializer.Serialize(valorDespues)) + continue; + + var nombre = Regex.Replace(propiedad.Name, "([a-z0-9])([A-Z])", "$1 $2"); + _cambiosConfiguracionSinGuardar.Add(( + nombre, + FormatearValorConfiguracion(valorAntes), + FormatearValorConfiguracion(valorDespues))); + } + } + + private static string FormatearValorConfiguracion(object? valor) + => valor switch + { + null => "-", + bool booleano => booleano ? "Sí" : "No", + IEnumerable numeros => numeros.Any() ? string.Join(", ", numeros) : "Ninguno", + IFormattable formateable => formateable.ToString(null, CultureInfo.InvariantCulture), + _ => valor.ToString() ?? "-" + }; + + private void CancelarCierreConfiguracionAvanzada() + { + _mostrarConfirmacionCerrarConfiguracion = false; + _cambiosConfiguracionSinGuardar.Clear(); + } + + private async Task DescartarCambiosConfiguracionAvanzadaAsync() + { + if (_configuracionAvanzadaAplicada is not null) + { + var actual = CrearConfiguracionLocal(); + var restaurada = _configuracionAvanzadaAplicada.Clonar(); + + restaurada.MostrarParadas = actual.MostrarParadas; + restaurada.UsarColorRealLineaEnItinerarios = actual.UsarColorRealLineaEnItinerarios; + restaurada.CriterioPrioritarioRuta = actual.CriterioPrioritarioRuta; + restaurada.PreferenciaEtiquetaRuta = actual.PreferenciaEtiquetaRuta; + AplicarConfiguracionLocal(restaurada); + + if (_usarHoraSimulada) + StopClock(); + else + StartClock(); + + await RefrescarHoraUIAsync(); + await PersistirConfiguracionConfirmadaAsync(); + } + + CerrarConfiguracionAvanzada(); + StateHasChanged(); + } + + private void CerrarConfiguracionAvanzada() + { + _mostrarConfirmacionCerrarConfiguracion = false; + _mostrarConfiguracionPendientesRuta = false; + _selectorColorPendienteRuta = null; + _cambiosConfiguracionSinGuardar.Clear(); + _configuracionAvanzadaAplicada = null; + _editandoConfiguracionAvanzada = false; + _mostrarConfigAvanzada = false; + } + + private async Task PersistirConfiguracionConfirmadaAsync() + { + var forzarAnterior = _forzarPersistenciaConfiguracion; + _forzarPersistenciaConfiguracion = true; + try + { + await PersistirConfiguracionAsync(); + } + finally + { + _forzarPersistenciaConfiguracion = forzarAnterior; + } + } + + private void MarcarConfiguracionAvanzadaComoGuardada() + { + if (!_editandoConfiguracionAvanzada) + return; + + _configuracionAvanzadaAplicada = CrearConfiguracionLocal().Clonar(); + _cambiosConfiguracionSinGuardar.Clear(); + _mostrarConfirmacionCerrarConfiguracion = false; + } +} diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs index b630923..366471c 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs @@ -39,10 +39,6 @@ public partial class PlanificadorRutas : ComponentBase private const string DashArrayPiePunteado = "1 7"; private bool _mostrarConfigAvanzada = false; - /// - /// Alterna la configuracion panel. - /// - private void ToggleConfigPanel() => _mostrarConfigAvanzada = !_mostrarConfigAvanzada; private int _nivelBrilloMapa = 0; @@ -332,7 +328,7 @@ public partial class PlanificadorRutas : ComponentBase { new RealTimeMap.BasemapLayer { - url = "https://osm.tecnosis.net/osm_tiles/{z}/{x}/{y}.png", + url = "http://192.168.41.12/osm_tiles/{z}/{x}/{y}.png", attribution = "© OpenStreetMap", title = "", detectRetina = true diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs index 499bb68..d258a1b 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs @@ -150,7 +150,8 @@ public partial class PlanificadorRutas _mostrarInformacionDerivacionHistorial = false; _historialLocalCargando = false; StopRefrescoHistorialCompartido(); - await RestaurarConfiguracionTemporalHistorialAsync(); + // Cerrar el panel no debe separar la configuracion visible de la ruta calculada. + // La configuracion previa solo se recupera al elegir expresamente "Actual". return; } @@ -1572,25 +1573,13 @@ public partial class PlanificadorRutas { ModoConfiguracionHistorial.Guardada => CrearConfiguracionGuardadaHistorial(item), ModoConfiguracionHistorial.Predeterminada => - CrearConfiguracionPredeterminadaParaHistorial(item), + CrearConfiguracionPredeterminadaParaHistorial(), _ => null }; if (configuracionHistorial is not null) - { AplicarConfiguracionLocal(configuracionHistorial); - // El factor cargado desde un historial ya se conservaba al cerrar el panel. - if (_modoConfiguracionHistorial == ModoConfiguracionHistorial.Guardada && - _configuracionTemporalPreviaHistorial is not null) - { - _configuracionTemporalPreviaHistorial.FactorEquilibradoAndarBus = - _factorEquilibradoAndarBus; - _configuracionTemporalPreviaHistorial.VersionFactorEquilibrado = - VersionPersistenciaFactorEquilibrado; - } - } - _busFilteredCache.Clear(); SincronizarSegundosPorParadaConHorarios(); @@ -1654,29 +1643,8 @@ public partial class PlanificadorRutas return configuracion; } - private ConfiguracionHistorialRuta CrearConfiguracionPredeterminadaParaHistorial( - RegistroHistorialRuta item) - { - var predeterminada = CrearConfiguracionPredeterminadaHistorial(); - var guardada = CrearConfiguracionGuardadaHistorial(item); - predeterminada.UsarHoraSimulada = guardada.UsarHoraSimulada; - - if (guardada.UsarHoraSimulada) - { - predeterminada.FechaSimulada = guardada.FechaSimulada; - predeterminada.HoraSimulada = guardada.HoraSimulada; - } - else - { - var ahora = DateTime.Now; - predeterminada.FechaSimulada = DateOnly.FromDateTime(ahora) - .ToString("yyyy-MM-dd", CultureInfo.InvariantCulture); - predeterminada.HoraSimulada = TimeOnly.FromDateTime(ahora) - .ToString("HH:mm:ss", CultureInfo.InvariantCulture); - } - - return predeterminada; - } + private ConfiguracionHistorialRuta CrearConfiguracionPredeterminadaParaHistorial() + => CrearConfiguracionPredeterminadaHistorial(); private void CapturarConfiguracionTemporalAntesDeHistorial() { @@ -1687,37 +1655,6 @@ public partial class PlanificadorRutas _configuracionParametrosActualesHistorial = CrearConfiguracionLocal(); } - private async Task RestaurarConfiguracionTemporalHistorialAsync() - { - var configuracionPrevia = _configuracionTemporalPreviaHistorial; - _configuracionTemporalPreviaHistorial = null; - _configuracionParametrosActualesHistorial = null; - - if (configuracionPrevia is null) - return; - - var mostrarParadasAntes = _mostrarParadas; - AplicarConfiguracionLocal(configuracionPrevia); - - if (_mapa is not null && mostrarParadasAntes != _mostrarParadas) - { - if (_mostrarParadas) - await DibujarParadasAsync(); - else - await OcultarParadasAsync(); - - await SincronizarMarcadoresOrigenDestinoJsAsync(); - } - - StopClock(); - if (_usarHoraSimulada) - await RefrescarHoraUIAsync(); - else - StartClock(); - - await PersistirConfiguracionAsync(); - } - private RegistroHistorialRuta? ConstruirRegistroHistorialActual() { if (_coordenadasOrigen is null || _coordenadasDestino is null) diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs index 2bd81ac..dc38d11 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs @@ -1506,7 +1506,7 @@ public partial class PlanificadorRutas : ComponentBase private bool _elevPopupMinimizado = false; - private const string _versionApp = "(v-20260916a)"; + private const string _versionApp = "(v-20260917a)"; private double? _paradaElevIdee; diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Persistencia.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Persistencia.cs index 25cffe1..ed6cb8c 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Persistencia.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Persistencia.cs @@ -54,7 +54,8 @@ public partial class PlanificadorRutas /// private async Task PersistirConfiguracionAsync() { - if (!_configuracionLocalCargada) + if (!_configuracionLocalCargada || + (_editandoConfiguracionAvanzada && !_forzarPersistenciaConfiguracion)) return; try @@ -454,7 +455,8 @@ public partial class PlanificadorRutas SincronizarTextosPenalizacionPie(); SincronizarSegundosPorParadaConHorarios(); await RefrescarHoraUIAsync(); - await PersistirConfiguracionAsync(); + await PersistirConfiguracionConfirmadaAsync(); + MarcarConfiguracionAvanzadaComoGuardada(); await PersistirModoConfiguracionHistorialAsync(); StateHasChanged(); } @@ -476,7 +478,8 @@ public partial class PlanificadorRutas SincronizarTextosPenalizacionPie(); SincronizarSegundosPorParadaConHorarios(); await RefrescarHoraUIAsync(); - await PersistirConfiguracionAsync(); + await PersistirConfiguracionConfirmadaAsync(); + MarcarConfiguracionAvanzadaComoGuardada(); await PersistirModoConfiguracionHistorialAsync(); StateHasChanged(); } diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs index c64d5a5..69021ec 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs @@ -1302,8 +1302,14 @@ public partial class PlanificadorRutas : ComponentBase /// private async Task RecalcularConParametros() { - if (_coordenadasOrigen is null || _coordenadasDestino is null) return; - await PersistirConfiguracionAsync(); + await PersistirConfiguracionConfirmadaAsync(); + MarcarConfiguracionAvanzadaComoGuardada(); + + if (_coordenadasOrigen is null || _coordenadasDestino is null) + { + StateHasChanged(); + return; + } if (_mapa is not null) { diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.RestriccionesCaminata.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.RestriccionesCaminata.cs index f635bfc..fcd34bf 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.RestriccionesCaminata.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.RestriccionesCaminata.cs @@ -96,7 +96,9 @@ public partial class PlanificadorRutas private async Task AbrirHerramientaZonasAsync() { - _mostrarConfigAvanzada = false; + if (_mostrarConfigAvanzada && !SolicitarCierreConfiguracionAvanzada()) + return; + _mostrarHerramientaZonas = true; await ActualizarEditorExclusionCaminataAsync(); } diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.ValoresFabrica.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.ValoresFabrica.cs index 5339e1e..b0b3a08 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.ValoresFabrica.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.ValoresFabrica.cs @@ -15,21 +15,12 @@ public partial class PlanificadorRutas private bool _guardandoFabrica; private ConfiguracionHistorialRuta CrearConfiguracionPredeterminadaHistorial() - { - var config = _configuracionFabrica?.Clonar() ?? CrearConfiguracionBaseHistorial(); - var ahora = DateTime.Now; - config.FechaSimulada = ahora.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture); - config.HoraSimulada = ahora.ToString("HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture); - return config; - } + => _configuracionFabrica?.Clonar() ?? CrearConfiguracionBaseHistorial(); private void AplicarValoresFabricaConservandoSeleccion() { var actual = CrearConfiguracionLocal(); var predeterminada = CrearConfiguracionPredeterminadaHistorial(); - predeterminada.UsarHoraSimulada = actual.UsarHoraSimulada; - predeterminada.FechaSimulada = actual.FechaSimulada; - predeterminada.HoraSimulada = actual.HoraSimulada; predeterminada.CriterioPrioritarioRuta = actual.CriterioPrioritarioRuta; predeterminada.PreferenciaEtiquetaRuta = actual.PreferenciaEtiquetaRuta; AplicarConfiguracionLocal(predeterminada); diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.razor b/RutasDBUS/Components/Pages/PlanificadorRutas.razor index b8e17a1..9dc1b3a 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.razor +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.razor @@ -1968,7 +1968,7 @@
} +@if (_mostrarConfirmacionCerrarConfiguracion) +{ +
+ +
+} + @if (_fabricaPendiente is not null || _mensajeFabrica is not null) {
diff --git a/RutasDBUS/Servicios/Planificacion/PlanificadorRutasServicio.cs b/RutasDBUS/Servicios/Planificacion/PlanificadorRutasServicio.cs index 2951d47..c5de3dd 100644 --- a/RutasDBUS/Servicios/Planificacion/PlanificadorRutasServicio.cs +++ b/RutasDBUS/Servicios/Planificacion/PlanificadorRutasServicio.cs @@ -125,8 +125,20 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas } var alternativasSoloPie = await CrearAlternativasSoloPieAsync(origenLatLon, destinoLatLon, parametros); - var candidatasOrigen = await SeleccionarCandidatasAsync(indiceTransito, origenLatLon[0], origenLatLon[1], parametros, ct); - var candidatasDestino = await SeleccionarCandidatasAsync(indiceTransito, destinoLatLon[0], destinoLatLon[1], parametros, ct); + var seleccionOrigen = await SeleccionarCandidatasAsync( + indiceTransito, + origenLatLon[0], + origenLatLon[1], + parametros, + ct); + var seleccionDestino = await SeleccionarCandidatasAsync( + indiceTransito, + destinoLatLon[0], + destinoLatLon[1], + parametros, + ct); + var candidatasOrigen = seleccionOrigen.Principales; + var candidatasDestino = seleccionDestino.Principales; if (candidatasOrigen.Count == 0 || candidatasDestino.Count == 0) { @@ -167,8 +179,8 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas { var directasRobustas = BuscarDirectasRobustasConHorario( indiceTransito, - candidatasOrigen, - candidatasDestino, + seleccionOrigen.Amplias, + seleccionDestino.Amplias, instanteSalida, parametros); var continuidadesCirculares = BuscarContinuidadesCircularesConHorario( @@ -2017,7 +2029,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas /// /// Selecciona las paradas cercanas mas prometedoras. /// - private async Task> SeleccionarCandidatasAsync( + private async Task<(List Principales, List Amplias)> SeleccionarCandidatasAsync( IndiceTransitoDbus indiceTransito, double latitud, double longitud, @@ -2064,7 +2076,11 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas if (!validarExclusionesV2 && (!parametros.UsarOsrmParaRanking || parametros.ActivarRangoLineas || parametros.ActivarRangoItinerarios)) - return SeleccionarCandidatasConCoberturaPatrones(candidatas, maximo, indiceTransito, parametros); + { + return ( + SeleccionarCandidatasConCoberturaPatrones(candidatas, maximo, indiceTransito, parametros), + candidatas); + } var semaforo = new SemaphoreSlim(4, 4); var tareas = candidatas.Select(async candidata => @@ -2113,7 +2129,9 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas .ThenBy(x => x.DistanciaEuclidea) .ToList(); - return SeleccionarCandidatasConCoberturaPatrones(candidatasOrdenadas, maximo, indiceTransito, parametros); + return ( + SeleccionarCandidatasConCoberturaPatrones(candidatasOrdenadas, maximo, indiceTransito, parametros), + candidatasOrdenadas); } /// diff --git a/RutasDBUS/wwwroot/app.css b/RutasDBUS/wwwroot/app.css index 239e347..df7943e 100644 --- a/RutasDBUS/wwwroot/app.css +++ b/RutasDBUS/wwwroot/app.css @@ -1413,9 +1413,12 @@ html, body { .btn-ghost.inspector-walk-eye { display: inline-flex; padding: 2px 5px; min-height: 0; vertical-align: middle; margin-left: 5px; } .inspector-walk-eye[aria-pressed="true"] { color: #22d3ee; border-color: #22d3ee; } -.fabrica-confirmacion { width: min(560px, calc(100vw - 24px)); max-height: calc(100dvh - 32px); overflow-y: auto; } -.fabrica-cambios { max-height: 45dvh; overflow-y: auto; font-size: .8rem; overflow-wrap: anywhere; } -.fabrica-cambios > div { padding: 5px 0; border-bottom: 1px solid #374151; } +.fabrica-confirmacion, +.config-unsaved-confirmation { width: min(560px, calc(100vw - 24px)); max-height: calc(100dvh - 32px); overflow-y: auto; } +.fabrica-cambios, +.config-unsaved-changes { max-height: 45dvh; overflow-y: auto; font-size: .8rem; overflow-wrap: anywhere; } +.fabrica-cambios > div, +.config-unsaved-changes > div { padding: 5px 0; border-bottom: 1px solid #374151; } .route-score-detail-line { display: inline-flex; @@ -2196,6 +2199,14 @@ html, body { white-space: nowrap; } +.config-actions-row .btn-ghost:first-child { + flex-grow: 1.45; +} + +.config-actions-row .btn-ghost:last-child { + flex-grow: .85; +} + .custom-modal-backdrop { position: fixed; inset: 0; diff --git a/RutasDBUS/wwwroot/service-worker.js b/RutasDBUS/wwwroot/service-worker.js index dd5376b..7646903 100644 --- a/RutasDBUS/wwwroot/service-worker.js +++ b/RutasDBUS/wwwroot/service-worker.js @@ -1,5 +1,5 @@ const TILE_CACHE = 'tile-cache-v1'; -const TILE_PREFIX = 'https://osm.tecnosis.net/osm_tiles/'; +const TILE_PREFIX = 'http://192.168.41.12/osm_tiles/'; self.addEventListener('install', event => { self.skipWaiting(); diff --git a/tests/RutasDBUS.RegressionTests/Program.cs b/tests/RutasDBUS.RegressionTests/Program.cs index 6c24cf1..2049e28 100644 --- a/tests/RutasDBUS.RegressionTests/Program.cs +++ b/tests/RutasDBUS.RegressionTests/Program.cs @@ -20,6 +20,30 @@ var baseMethod = typeof(PlanificadorRutas).GetMethod("CrearConfiguracionBaseHist var defaults = (ConfiguracionHistorialRuta)baseMethod.Invoke(null, null)!; Check(defaults.PesoTransbordoRankingMinutos == 6, "Penalizacion inicial de 6 minutos"); +var panelSinCambios = new PlanificadorRutas(); +var alternarPanel = typeof(PlanificadorRutas).GetMethod( + "ToggleConfigPanel", + BindingFlags.Instance | BindingFlags.NonPublic)!; +var solicitarCierre = typeof(PlanificadorRutas).GetMethod( + "SolicitarCierreConfiguracionAvanzada", + BindingFlags.Instance | BindingFlags.NonPublic)!; +alternarPanel.Invoke(panelSinCambios, null); +Check( + solicitarCierre.Invoke(panelSinCambios, null) is true, + "Configuracion avanzada sin cambios se cierra directamente"); + +var panelConCambios = new PlanificadorRutas(); +alternarPanel.Invoke(panelConCambios, null); +typeof(PlanificadorRutas) + .GetField("_velocidadPieKmH", BindingFlags.Instance | BindingFlags.NonPublic)! + .SetValue(panelConCambios, 4.2); +Check( + solicitarCierre.Invoke(panelConCambios, null) is false && + (bool)typeof(PlanificadorRutas) + .GetField("_mostrarConfirmacionCerrarConfiguracion", BindingFlags.Instance | BindingFlags.NonPublic)! + .GetValue(panelConCambios)!, + "Configuracion avanzada avisa antes de descartar cambios"); + var folder = Path.Combine(Path.GetTempPath(), "rutasdbus-regression-" + Guid.NewGuid().ToString("N")); IConfiguration Config() => new ConfigurationBuilder().AddInMemoryCollection(new Dictionary { @@ -37,7 +61,29 @@ try await File.WriteAllTextAsync(file, JsonSerializer.Serialize(defaults)); var loaded = await Service().CargarAsync(); Check(loaded?.PesoTransbordoRankingMinutos == 9, "Valores compartidos entre instancias"); - Check(loaded is { FechaSimulada: null, HoraSimulada: null }, "Los valores de fabrica no fijan la fecha y hora"); + Check(loaded is { FechaSimulada: null, HoraSimulada: null }, "Valores antiguos sin fecha y hora siguen siendo validos"); + + var guardadaConFecha = defaults.Clonar(); + guardadaConFecha.FechaSimulada = "2026-09-16"; + guardadaConFecha.HoraSimulada = "13:40:00"; + Check(await Service().GuardarAsync(guardadaConFecha), "Los valores de fabrica permiten guardar fecha y hora"); + var cargadaConFecha = await Service().CargarAsync(); + Check( + cargadaConFecha is { FechaSimulada: "2026-09-16", HoraSimulada: "13:40:00" }, + "Los valores de fabrica recuperan la fecha y hora guardadas"); + + var pagina = new PlanificadorRutas(); + typeof(PlanificadorRutas) + .GetField("_configuracionFabrica", BindingFlags.Instance | BindingFlags.NonPublic)! + .SetValue(pagina, cargadaConFecha); + var crearPredeterminada = typeof(PlanificadorRutas).GetMethod( + "CrearConfiguracionPredeterminadaHistorial", + BindingFlags.Instance | BindingFlags.NonPublic)!; + var predeterminada = (ConfiguracionHistorialRuta)crearPredeterminada.Invoke(pagina, null)!; + Check( + predeterminada is { FechaSimulada: "2026-09-16", HoraSimulada: "13:40:00" }, + "Restaurar conserva la fecha y hora de los valores de fabrica"); + File.WriteAllText(file, "{incompleto"); Check(await Service().CargarAsync() is null, "JSON danado permite usar valores base"); } @@ -183,32 +229,50 @@ var page = new PlanificadorRutas(); var flags = BindingFlags.Instance | BindingFlags.NonPublic; var fabricaHistorial = (ConfiguracionHistorialRuta)baseMethod.Invoke(null, null)!; fabricaHistorial.FactorEquilibradoAndarBus = 6; +fabricaHistorial.UsarHoraSimulada = true; +fabricaHistorial.FechaSimulada = "2026-09-16"; +fabricaHistorial.HoraSimulada = "13:40:00"; typeof(PlanificadorRutas).GetField("_configuracionFabrica", flags)!.SetValue(page, fabricaHistorial); var crearPredeterminadaHistorial = typeof(PlanificadorRutas).GetMethod( "CrearConfiguracionPredeterminadaParaHistorial", flags)!; +var crearGuardadaHistorial = typeof(PlanificadorRutas).GetMethod( + "CrearConfiguracionGuardadaHistorial", flags)!; var configuracionGuardada = fabricaHistorial.Clonar(); configuracionGuardada.UsarHoraSimulada = true; configuracionGuardada.FechaSimulada = "2026-04-08"; configuracionGuardada.HoraSimulada = "08:46:17"; configuracionGuardada.FactorEquilibradoAndarBus = 99; var registroConHora = new RegistroHistorialRuta { Configuracion = configuracionGuardada }; -var predeterminadaConHora = (ConfiguracionHistorialRuta)crearPredeterminadaHistorial.Invoke( +var predeterminadaHistorial = (ConfiguracionHistorialRuta)crearPredeterminadaHistorial.Invoke(page, null)!; +Check(predeterminadaHistorial.UsarHoraSimulada && + predeterminadaHistorial.FechaSimulada == "2026-09-16" && + predeterminadaHistorial.HoraSimulada == "13:40:00" && + predeterminadaHistorial.FactorEquilibradoAndarBus == 6, + "Predeterminada usa tambien la fecha y hora de fabrica"); +var guardada = (ConfiguracionHistorialRuta)crearGuardadaHistorial.Invoke( page, new object[] { registroConHora })!; -Check(predeterminadaConHora.UsarHoraSimulada && - predeterminadaConHora.FechaSimulada == "2026-04-08" && - predeterminadaConHora.HoraSimulada == "08:46:17" && - predeterminadaConHora.FactorEquilibradoAndarBus == 6, - "Predeterminada conserva solo la fecha y hora simuladas del historial"); -configuracionGuardada.UsarHoraSimulada = false; -configuracionGuardada.FechaSimulada = "2020-01-01"; -configuracionGuardada.HoraSimulada = "01:02:03"; -var predeterminadaSinHora = (ConfiguracionHistorialRuta)crearPredeterminadaHistorial.Invoke( - page, new object[] { registroConHora })!; -Check(!predeterminadaSinHora.UsarHoraSimulada && - predeterminadaSinHora.FechaSimulada == DateOnly.FromDateTime(DateTime.Now) - .ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture) && - predeterminadaSinHora.HoraSimulada != "01:02:03", - "Predeterminada usa la hora actual cuando el historial no tenia simulacion"); +Check(guardada.UsarHoraSimulada && + guardada.FechaSimulada == "2026-04-08" && + guardada.HoraSimulada == "08:46:17" && + guardada.FactorEquilibradoAndarBus == 99, + "Guardada conserva la fecha, hora y parametros del historial"); +var paginaCierreHistorial = new PlanificadorRutas(); +typeof(PlanificadorRutas).GetField("_mostrarHistorialRutas", flags)! + .SetValue(paginaCierreHistorial, true); +typeof(PlanificadorRutas).GetField("_factorEquilibradoAndarBus", flags)! + .SetValue(paginaCierreHistorial, 99.0); +var configuracionAnteriorHistorial = fabricaHistorial.Clonar(); +configuracionAnteriorHistorial.FactorEquilibradoAndarBus = 6; +typeof(PlanificadorRutas).GetField("_configuracionTemporalPreviaHistorial", flags)! + .SetValue(paginaCierreHistorial, configuracionAnteriorHistorial); +var alternarHistorial = typeof(PlanificadorRutas).GetMethod("ToggleHistorialPanel", flags)!; +await (Task)alternarHistorial.Invoke(paginaCierreHistorial, null)!; +Check( + !(bool)typeof(PlanificadorRutas).GetField("_mostrarHistorialRutas", flags)! + .GetValue(paginaCierreHistorial)! && + (double)typeof(PlanificadorRutas).GetField("_factorEquilibradoAndarBus", flags)! + .GetValue(paginaCierreHistorial)! == 99.0, + "Cerrar el historial conserva la configuracion de la ruta visible"); typeof(PlanificadorRutas).GetField("_factorEquilibradoAndarBus", flags)!.SetValue(page, 6.0); typeof(PlanificadorRutas).GetField("_factorPenalizacionDistanciaPie", flags)!.SetValue(page, 1.8); typeof(PlanificadorRutas).GetField("_parametroPenalizacionDistanciaPieMetros", flags)!.SetValue(page, 200.0);