cambios del dia 02/08
This commit is contained in:
@@ -54,6 +54,7 @@ public partial class PlanificadorRutas : ComponentBase, IDisposable
|
||||
try { await JS.InvokeVoidAsync("rt.initMobileMapControls"); } catch (Exception ex) { Console.WriteLine("rt.initMobileMapControls: " + ex); }
|
||||
try { await JS.InvokeVoidAsync("rt.initDraggablePopups"); } catch (Exception ex) { Console.WriteLine("rt.initDraggablePopups: " + ex); }
|
||||
await CargarConfiguracionLocalAsync();
|
||||
await CargarPreferenciaParametrosActualesHistorialAsync();
|
||||
await AsegurarHistorialLocalCargadoAsync();
|
||||
await CargarHistorialCompartidoAsync();
|
||||
await CargarModelosHorariosAsync();
|
||||
@@ -215,8 +216,6 @@ public partial class PlanificadorRutas : ComponentBase, IDisposable
|
||||
return;
|
||||
}
|
||||
|
||||
QuitarSalidasParadaActivasPorClaves(claves);
|
||||
|
||||
foreach (var clave in claves)
|
||||
{
|
||||
if (!_itPreviewIdsPorClave.TryGetValue(clave, out var ids) || ids.Count == 0)
|
||||
@@ -255,7 +254,6 @@ public partial class PlanificadorRutas : ComponentBase, IDisposable
|
||||
|
||||
_itPreviewActivos.Clear();
|
||||
_itPreviewIdsPorClave.Clear();
|
||||
_salidasParadaItinerariosActivas.Clear();
|
||||
LimpiarParadasItinerarioVisibles();
|
||||
|
||||
_previewLineasActivas.Clear(); // <- esto ya lo usas para los "full_..."
|
||||
|
||||
@@ -55,8 +55,10 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
private const double UmbralPendienteSubidaRutaPorDefecto = 2.0;
|
||||
private const double UmbralPendienteSubidaMediaRutaPorDefecto = 5.0;
|
||||
private const double UmbralPendienteSubidaFuerteRutaPorDefecto = 10.0;
|
||||
private const string ColorPendienteSubidaSuaveRutaPorDefecto = "#ec4899";
|
||||
private const string ColorPendienteSubidaMediaRutaPorDefecto = "#2563eb";
|
||||
private const string ColorPendienteBajadaRutaPorDefecto = "#9ebdff";
|
||||
private const string ColorPendienteLlanoRutaPorDefecto = "#166534";
|
||||
private const string ColorPendienteSubidaSuaveRutaPorDefecto = "#dc2626";
|
||||
private const string ColorPendienteSubidaMediaRutaPorDefecto = "#7c3aed";
|
||||
private const string ColorPendienteSubidaFuerteRutaPorDefecto = "#000000";
|
||||
private const double UmbralPendienteBajadaRutaPorDefecto = 5.0;
|
||||
private const double UmbralAlturaAlertaPendienteRutaMetrosPorDefecto = 6.0;
|
||||
@@ -375,6 +377,8 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
private double _umbralPendienteSubidaRuta = UmbralPendienteSubidaRutaPorDefecto;
|
||||
private double _umbralPendienteSubidaMediaRuta = UmbralPendienteSubidaMediaRutaPorDefecto;
|
||||
private double _umbralPendienteSubidaFuerteRuta = UmbralPendienteSubidaFuerteRutaPorDefecto;
|
||||
private string _colorPendienteBajadaRuta = ColorPendienteBajadaRutaPorDefecto;
|
||||
private string _colorPendienteLlanoRuta = ColorPendienteLlanoRutaPorDefecto;
|
||||
private string _colorPendienteSubidaSuaveRuta = ColorPendienteSubidaSuaveRutaPorDefecto;
|
||||
private string _colorPendienteSubidaMediaRuta = ColorPendienteSubidaMediaRutaPorDefecto;
|
||||
private string _colorPendienteSubidaFuerteRuta = ColorPendienteSubidaFuerteRutaPorDefecto;
|
||||
|
||||
@@ -12,6 +12,8 @@ public partial class PlanificadorRutas
|
||||
{
|
||||
private const string ClaveHistorialLocal = "rutasdbus.planificador.routeHistory.v1";
|
||||
private const string ClaveRespaldoHistorialLocal = "rutasdbus.planificador.routeHistory.recovery.v1";
|
||||
private const string ClavePreferenciaParametrosActualesHistorial =
|
||||
"rutasdbus.planificador.history.useCurrentConfig.v1";
|
||||
private const int MaxItemsHistorialLocal = 25;
|
||||
private const int MaxBytesHistorialLocal = 24 * 1024;
|
||||
private const int IntervaloRefrescoHistorialCompartidoSegundos = 3;
|
||||
@@ -875,6 +877,7 @@ public partial class PlanificadorRutas
|
||||
_configuracionParametrosActualesHistorial = CrearConfiguracionLocal();
|
||||
|
||||
_usarParametrosActualesHistorial = usarParametrosActuales;
|
||||
await PersistirPreferenciaParametrosActualesHistorialAsync();
|
||||
|
||||
if (usarParametrosActuales && _configuracionParametrosActualesHistorial is not null)
|
||||
AplicarConfiguracionLocal(_configuracionParametrosActualesHistorial);
|
||||
@@ -903,6 +906,35 @@ public partial class PlanificadorRutas
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CargarPreferenciaParametrosActualesHistorialAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var valor = await JS.InvokeAsync<string?>(
|
||||
"rt.loadLocalValue",
|
||||
ClavePreferenciaParametrosActualesHistorial);
|
||||
if (bool.TryParse(valor, out var usarConfiguracionActual))
|
||||
_usarParametrosActualesHistorial = usarConfiguracionActual;
|
||||
}
|
||||
catch (JSException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PersistirPreferenciaParametrosActualesHistorialAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await JS.InvokeVoidAsync(
|
||||
"rt.saveLocalValue",
|
||||
ClavePreferenciaParametrosActualesHistorial,
|
||||
_usarParametrosActualesHistorial.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
catch (JSException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private bool PrepararDerivacionHistorialParaRecalculo()
|
||||
{
|
||||
var procedeDeHistorial = _tipoReferenciaHistorial != TipoReferenciaHistorial.Ninguna &&
|
||||
@@ -1488,7 +1520,6 @@ public partial class PlanificadorRutas
|
||||
var configuracionPrevia = _configuracionTemporalPreviaHistorial;
|
||||
_configuracionTemporalPreviaHistorial = null;
|
||||
_configuracionParametrosActualesHistorial = null;
|
||||
_usarParametrosActualesHistorial = true;
|
||||
|
||||
if (configuracionPrevia is null)
|
||||
return;
|
||||
|
||||
@@ -296,8 +296,84 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
/// <summary>
|
||||
/// Alterna desde el popup de parada el itinerario asociado a una salida.
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, string> _salidasParadaItinerariosActivas =
|
||||
new(StringComparer.OrdinalIgnoreCase);
|
||||
private bool _procesandoTodosItinerariosParada;
|
||||
private bool _ocultandoTodosItinerariosParada;
|
||||
|
||||
private bool TodosItinerariosParadaPintados
|
||||
{
|
||||
get
|
||||
{
|
||||
var itinerarios = ObtenerItinerariosUnicosParada();
|
||||
return itinerarios.Count > 0 && itinerarios.All(EstaItinerarioPintado);
|
||||
}
|
||||
}
|
||||
|
||||
private string TextoBotonTodosItinerariosParada => _procesandoTodosItinerariosParada
|
||||
? (_ocultandoTodosItinerariosParada ? "Ocultando..." : "Pintando...")
|
||||
: (TodosItinerariosParadaPintados ? "Ocultar todos" : "Ver todos");
|
||||
|
||||
private List<ElementoItinerario> ObtenerItinerariosUnicosParada()
|
||||
{
|
||||
var clavesUnicas = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var itinerariosUnicos = new List<ElementoItinerario>();
|
||||
|
||||
foreach (var salida in NextDepsOrdenados.ToList())
|
||||
{
|
||||
var itinerario = ObtenerItinerarioSalidaParada(salida);
|
||||
if (itinerario is null || itinerario.Variantes.Count == 0)
|
||||
continue;
|
||||
|
||||
var clave = ItClave(itinerario.Variantes[0]);
|
||||
if (clavesUnicas.Add(clave))
|
||||
itinerariosUnicos.Add(itinerario);
|
||||
}
|
||||
|
||||
return itinerariosUnicos;
|
||||
}
|
||||
|
||||
private async Task ToggleTodosItinerariosParadaAsync()
|
||||
{
|
||||
if (_procesandoTodosItinerariosParada)
|
||||
return;
|
||||
|
||||
var itinerariosUnicos = ObtenerItinerariosUnicosParada();
|
||||
if (itinerariosUnicos.Count == 0)
|
||||
return;
|
||||
|
||||
var ocultarTodos = itinerariosUnicos.All(EstaItinerarioPintado);
|
||||
_procesandoTodosItinerariosParada = true;
|
||||
_ocultandoTodosItinerariosParada = ocultarTodos;
|
||||
StateHasChanged();
|
||||
|
||||
try
|
||||
{
|
||||
if (ocultarTodos)
|
||||
{
|
||||
foreach (var itinerario in itinerariosUnicos)
|
||||
await QuitarItItemAsync(itinerario);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var coordenadas = new List<double[]>();
|
||||
foreach (var itinerario in itinerariosUnicos)
|
||||
{
|
||||
if (!EstaItinerarioPintado(itinerario))
|
||||
await PintarItItemAsync(itinerario);
|
||||
|
||||
coordenadas.AddRange(ConstruirCoordenadasItinerario(itinerario));
|
||||
}
|
||||
|
||||
if (coordenadas.Count > 0)
|
||||
await FitRoutesJsAsync(coordenadas);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_procesandoTodosItinerariosParada = false;
|
||||
_ocultandoTodosItinerariosParada = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ToggleItinerarioSalidaParadaAsync(ProximaSalidaVm salida)
|
||||
{
|
||||
@@ -305,28 +381,18 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
if (itinerario is null)
|
||||
return;
|
||||
|
||||
var salidaId = CrearIdSalidaParada(salida);
|
||||
var claveItinerario = ItClave(itinerario.Variantes[0]);
|
||||
var esSalidaActiva = _salidasParadaItinerariosActivas.TryGetValue(salidaId, out var claveActiva) &&
|
||||
string.Equals(claveActiva, claveItinerario, StringComparison.OrdinalIgnoreCase);
|
||||
var estaPintado = EstaItinerarioPintado(itinerario);
|
||||
|
||||
if (esSalidaActiva && estaPintado)
|
||||
if (estaPintado)
|
||||
{
|
||||
await QuitarItItemAsync(itinerario);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!estaPintado)
|
||||
{
|
||||
await PintarItItemAsync(itinerario);
|
||||
await FitRoutesJsAsync(ConstruirCoordenadasItinerario(itinerario));
|
||||
}
|
||||
|
||||
QuitarSalidasParadaActivasPorClaves([claveItinerario]);
|
||||
_salidasParadaItinerariosActivas[salidaId] = claveItinerario;
|
||||
}
|
||||
|
||||
if (_itItemsFiltrados.Any(x => x.Id.Equals(itinerario.Id, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
_itSeleccionadoId = itinerario.Id;
|
||||
@@ -339,31 +405,45 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
private bool EstaItinerarioSalidaParadaPintado(ProximaSalidaVm salida)
|
||||
{
|
||||
var itinerario = ObtenerItinerarioSalidaParada(salida);
|
||||
return itinerario is not null &&
|
||||
_salidasParadaItinerariosActivas.TryGetValue(CrearIdSalidaParada(salida), out var claveActiva) &&
|
||||
itinerario.Variantes.Any(variante =>
|
||||
string.Equals(claveActiva, ItClave(variante), StringComparison.OrdinalIgnoreCase)) &&
|
||||
EstaItinerarioPintado(itinerario);
|
||||
return itinerario is not null && EstaItinerarioPintado(itinerario);
|
||||
}
|
||||
|
||||
private void QuitarSalidasParadaActivasPorClaves(IEnumerable<string> claves)
|
||||
private string ObtenerTextoVisibleSalidaParada(ProximaSalidaVm salida)
|
||||
{
|
||||
var clavesAEliminar = new HashSet<string>(claves, StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var salidaId in _salidasParadaItinerariosActivas
|
||||
.Where(x => clavesAEliminar.Contains(x.Value))
|
||||
.Select(x => x.Key)
|
||||
.ToList())
|
||||
var texto = salida.LineaTxt?.Trim() ?? string.Empty;
|
||||
var separadorDestino = texto.IndexOf(" - ", StringComparison.Ordinal);
|
||||
var codigo = separadorDestino > 0 ? texto[..separadorDestino].Trim() : texto;
|
||||
|
||||
var itinerario = ObtenerItinerarioSalidaParada(salida);
|
||||
var nombreLinea = itinerario?.Variantes.FirstOrDefault()?.Linea.Nombre?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(nombreLinea) &&
|
||||
separadorDestino >= 0 &&
|
||||
separadorDestino + 3 < texto.Length)
|
||||
{
|
||||
_salidasParadaItinerariosActivas.Remove(salidaId);
|
||||
}
|
||||
nombreLinea = texto[(separadorDestino + 3)..].Trim();
|
||||
}
|
||||
|
||||
private static string CrearIdSalidaParada(ProximaSalidaVm salida)
|
||||
=> string.Join('|',
|
||||
salida.ExpId,
|
||||
salida.RutaId,
|
||||
salida.Hora,
|
||||
salida.ItinerarioClave);
|
||||
return string.IsNullOrWhiteSpace(nombreLinea)
|
||||
? codigo
|
||||
: $"{codigo} ({nombreLinea})";
|
||||
}
|
||||
|
||||
private string ObtenerNombreDestinoSalidaParada(ProximaSalidaVm salida)
|
||||
{
|
||||
var itinerario = ObtenerItinerarioSalidaParada(salida);
|
||||
if (itinerario?.Variantes.Count > 0)
|
||||
{
|
||||
var destino = ObtenerNombreDestinoItinerario(itinerario.Variantes[0]);
|
||||
if (!string.IsNullOrWhiteSpace(destino))
|
||||
return destino;
|
||||
}
|
||||
|
||||
var texto = salida.LineaTxt?.Trim() ?? string.Empty;
|
||||
var separadorDestino = texto.IndexOf(" - ", StringComparison.Ordinal);
|
||||
return separadorDestino >= 0 && separadorDestino + 3 < texto.Length
|
||||
? texto[(separadorDestino + 3)..].Trim()
|
||||
: string.Empty;
|
||||
}
|
||||
|
||||
private bool EstaItinerarioPintado(ElementoItinerario itinerario)
|
||||
=> itinerario.Variantes.Any(variante =>
|
||||
@@ -1309,7 +1389,7 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
private bool _elevPopupMinimizado = false;
|
||||
|
||||
|
||||
private const string _versionApp = "(v-20260901a)";
|
||||
private const string _versionApp = "(v-20260902d)";
|
||||
|
||||
|
||||
private double? _paradaElevIdee;
|
||||
@@ -1438,28 +1518,35 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtiene texto itinerario clicado.
|
||||
/// Obtiene el codigo y el nombre de la linea del itinerario clicado.
|
||||
/// </summary>
|
||||
private string GetTextoItinerarioClicado()
|
||||
private string GetTextoLineaItinerarioClicado(InfoVariante? vReal)
|
||||
{
|
||||
if (_itinerarioClicado is null)
|
||||
return "";
|
||||
|
||||
var vReal = GetVarianteRealClicada();
|
||||
if (vReal is null)
|
||||
return _itinerarioClicado.Text;
|
||||
|
||||
var linea = vReal.Linea?.Codigo?.ToString() ?? "?";
|
||||
var itin = vReal.CodigoItinerario;
|
||||
var sentido = NormalizarSentidoCodigo(vReal.Sentido?.Codigo); // I / V
|
||||
var nombre = vReal.Linea?.Nombre ?? "";
|
||||
var trayecto = ConstruirTextoRecorridoVariante(vReal);
|
||||
var nombre = vReal.Linea?.Nombre?.Trim() ?? "";
|
||||
var codigo = $"{linea}.{itin}-{sentido}";
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(trayecto))
|
||||
return $"{linea}.{itin}-{sentido} — {trayecto}";
|
||||
return string.IsNullOrWhiteSpace(nombre)
|
||||
? codigo
|
||||
: $"{codigo} ({nombre})";
|
||||
}
|
||||
|
||||
// ✅ Siempre devuelve el texto del sentido pinchado, no "I+V"
|
||||
return $"{linea}.{itin}-{sentido} — {nombre}";
|
||||
/// <summary>
|
||||
/// Obtiene la parada final del itinerario clicado.
|
||||
/// </summary>
|
||||
private string GetDestinoItinerarioClicado(InfoVariante? vReal)
|
||||
{
|
||||
return vReal is null
|
||||
? ""
|
||||
: ObtenerNombreDestinoItinerario(vReal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -11,7 +11,7 @@ public partial class PlanificadorRutas
|
||||
private const int VersionPersistenciaFactorPenalizacionPie = 1;
|
||||
private const int VersionPersistenciaFactorEquilibrado = 2;
|
||||
private const int VersionPersistenciaPendientes = 2;
|
||||
private const int VersionPersistenciaColoresPendientes = 1;
|
||||
private const int VersionPersistenciaColoresPendientes = 2;
|
||||
private const int VersionPersistenciaCoeficienteEsfuerzo = 1;
|
||||
private const int VersionPersistenciaFuenteElevacion = 1;
|
||||
private bool _configuracionLocalCargada = false;
|
||||
@@ -55,6 +55,8 @@ public partial class PlanificadorRutas
|
||||
public double? UmbralPendienteSubidaRuta { get; set; }
|
||||
public double? UmbralPendienteSubidaMediaRuta { get; set; }
|
||||
public double? UmbralPendienteSubidaFuerteRuta { get; set; }
|
||||
public string? ColorPendienteBajadaRuta { get; set; }
|
||||
public string? ColorPendienteLlanoRuta { get; set; }
|
||||
public string? ColorPendienteSubidaSuaveRuta { get; set; }
|
||||
public string? ColorPendienteSubidaMediaRuta { get; set; }
|
||||
public string? ColorPendienteSubidaFuerteRuta { get; set; }
|
||||
@@ -180,6 +182,8 @@ public partial class PlanificadorRutas
|
||||
UmbralPendienteSubidaRuta = _umbralPendienteSubidaRuta,
|
||||
UmbralPendienteSubidaMediaRuta = _umbralPendienteSubidaMediaRuta,
|
||||
UmbralPendienteSubidaFuerteRuta = _umbralPendienteSubidaFuerteRuta,
|
||||
ColorPendienteBajadaRuta = _colorPendienteBajadaRuta,
|
||||
ColorPendienteLlanoRuta = _colorPendienteLlanoRuta,
|
||||
ColorPendienteSubidaSuaveRuta = _colorPendienteSubidaSuaveRuta,
|
||||
ColorPendienteSubidaMediaRuta = _colorPendienteSubidaMediaRuta,
|
||||
ColorPendienteSubidaFuerteRuta = _colorPendienteSubidaFuerteRuta,
|
||||
@@ -295,6 +299,18 @@ public partial class PlanificadorRutas
|
||||
: UmbralPendienteSubidaFuerteRutaPorDefecto;
|
||||
var migrarColoresPendientes =
|
||||
(config.VersionColoresPendientes ?? 0) < VersionPersistenciaColoresPendientes;
|
||||
_colorPendienteBajadaRuta = migrarColoresPendientes
|
||||
? ColorPendienteBajadaRutaPorDefecto
|
||||
: NormalizarColorHexRuta(
|
||||
config.ColorPendienteBajadaRuta,
|
||||
ColorPendienteBajadaRutaPorDefecto);
|
||||
if (string.Equals(_colorPendienteBajadaRuta, "#2563eb", StringComparison.OrdinalIgnoreCase))
|
||||
_colorPendienteBajadaRuta = ColorPendienteBajadaRutaPorDefecto;
|
||||
_colorPendienteLlanoRuta = migrarColoresPendientes
|
||||
? ColorPendienteLlanoRutaPorDefecto
|
||||
: NormalizarColorHexRuta(
|
||||
config.ColorPendienteLlanoRuta,
|
||||
ColorPendienteLlanoRutaPorDefecto);
|
||||
_colorPendienteSubidaSuaveRuta = migrarColoresPendientes
|
||||
? ColorPendienteSubidaSuaveRutaPorDefecto
|
||||
: NormalizarColorHexRuta(
|
||||
@@ -442,6 +458,8 @@ public partial class PlanificadorRutas
|
||||
_umbralPendienteSubidaRuta = UmbralPendienteSubidaRutaPorDefecto;
|
||||
_umbralPendienteSubidaMediaRuta = UmbralPendienteSubidaMediaRutaPorDefecto;
|
||||
_umbralPendienteSubidaFuerteRuta = UmbralPendienteSubidaFuerteRutaPorDefecto;
|
||||
_colorPendienteBajadaRuta = ColorPendienteBajadaRutaPorDefecto;
|
||||
_colorPendienteLlanoRuta = ColorPendienteLlanoRutaPorDefecto;
|
||||
_colorPendienteSubidaSuaveRuta = ColorPendienteSubidaSuaveRutaPorDefecto;
|
||||
_colorPendienteSubidaMediaRuta = ColorPendienteSubidaMediaRutaPorDefecto;
|
||||
_colorPendienteSubidaFuerteRuta = ColorPendienteSubidaFuerteRutaPorDefecto;
|
||||
@@ -457,6 +475,7 @@ public partial class PlanificadorRutas
|
||||
_nivelBrilloMapa = 0;
|
||||
_usarColorRealLineaEnItinerarios = false;
|
||||
_usarOsrmParaRanking = false;
|
||||
_usarParametrosActualesHistorial = true;
|
||||
|
||||
if (_usarHoraSimulada)
|
||||
StopClock();
|
||||
@@ -466,6 +485,7 @@ public partial class PlanificadorRutas
|
||||
SincronizarSegundosPorParadaConHorarios();
|
||||
await RefrescarHoraUIAsync();
|
||||
await PersistirConfiguracionAsync();
|
||||
await PersistirPreferenciaParametrosActualesHistorialAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -500,6 +520,8 @@ public partial class PlanificadorRutas
|
||||
_umbralPendienteSubidaRuta = UmbralPendienteSubidaRutaPorDefecto;
|
||||
_umbralPendienteSubidaMediaRuta = UmbralPendienteSubidaMediaRutaPorDefecto;
|
||||
_umbralPendienteSubidaFuerteRuta = UmbralPendienteSubidaFuerteRutaPorDefecto;
|
||||
_colorPendienteBajadaRuta = ColorPendienteBajadaRutaPorDefecto;
|
||||
_colorPendienteLlanoRuta = ColorPendienteLlanoRutaPorDefecto;
|
||||
_colorPendienteSubidaSuaveRuta = ColorPendienteSubidaSuaveRutaPorDefecto;
|
||||
_colorPendienteSubidaMediaRuta = ColorPendienteSubidaMediaRutaPorDefecto;
|
||||
_colorPendienteSubidaFuerteRuta = ColorPendienteSubidaFuerteRutaPorDefecto;
|
||||
@@ -515,6 +537,7 @@ public partial class PlanificadorRutas
|
||||
_nivelBrilloMapa = 0;
|
||||
_usarColorRealLineaEnItinerarios = false;
|
||||
_usarOsrmParaRanking = false;
|
||||
_usarParametrosActualesHistorial = true;
|
||||
|
||||
if (_usarHoraSimulada)
|
||||
StopClock();
|
||||
@@ -524,6 +547,7 @@ public partial class PlanificadorRutas
|
||||
SincronizarSegundosPorParadaConHorarios();
|
||||
await RefrescarHoraUIAsync();
|
||||
await PersistirConfiguracionAsync();
|
||||
await PersistirPreferenciaParametrosActualesHistorialAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,14 +134,16 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private enum NivelColorSubidaRuta
|
||||
private enum NivelColorPendienteRuta
|
||||
{
|
||||
Suave,
|
||||
Media,
|
||||
Fuerte
|
||||
Bajada,
|
||||
Llano,
|
||||
Subida,
|
||||
SubidaMedia,
|
||||
SubidaFuerte
|
||||
}
|
||||
|
||||
private NivelColorSubidaRuta? _selectorColorPendienteRuta;
|
||||
private NivelColorPendienteRuta? _selectorColorPendienteRuta;
|
||||
|
||||
private void AbrirConfiguracionPendientesRuta()
|
||||
{
|
||||
@@ -155,29 +157,37 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
_mostrarConfiguracionPendientesRuta = false;
|
||||
}
|
||||
|
||||
private void AlternarSelectorColorPendienteRuta(NivelColorSubidaRuta nivel)
|
||||
private void AlternarSelectorColorPendienteRuta(NivelColorPendienteRuta nivel)
|
||||
=> _selectorColorPendienteRuta = _selectorColorPendienteRuta == nivel ? null : nivel;
|
||||
|
||||
private string ObtenerColorPendienteSubidaRuta(NivelColorSubidaRuta nivel)
|
||||
private string ObtenerColorPendienteRuta(NivelColorPendienteRuta nivel)
|
||||
=> nivel switch
|
||||
{
|
||||
NivelColorSubidaRuta.Media => _colorPendienteSubidaMediaRuta,
|
||||
NivelColorSubidaRuta.Fuerte => _colorPendienteSubidaFuerteRuta,
|
||||
NivelColorPendienteRuta.Bajada => _colorPendienteBajadaRuta,
|
||||
NivelColorPendienteRuta.Llano => _colorPendienteLlanoRuta,
|
||||
NivelColorPendienteRuta.SubidaMedia => _colorPendienteSubidaMediaRuta,
|
||||
NivelColorPendienteRuta.SubidaFuerte => _colorPendienteSubidaFuerteRuta,
|
||||
_ => _colorPendienteSubidaSuaveRuta
|
||||
};
|
||||
|
||||
private async Task AplicarColorPendienteSubidaRutaAsync(
|
||||
private async Task AplicarColorPendienteRutaAsync(
|
||||
string color,
|
||||
NivelColorSubidaRuta nivel)
|
||||
NivelColorPendienteRuta nivel)
|
||||
{
|
||||
var nuevo = NormalizarColorHexRuta(color, ObtenerColorPendienteSubidaRuta(nivel));
|
||||
var nuevo = NormalizarColorHexRuta(color, ObtenerColorPendienteRuta(nivel));
|
||||
|
||||
switch (nivel)
|
||||
{
|
||||
case NivelColorSubidaRuta.Media:
|
||||
case NivelColorPendienteRuta.Bajada:
|
||||
_colorPendienteBajadaRuta = nuevo;
|
||||
break;
|
||||
case NivelColorPendienteRuta.Llano:
|
||||
_colorPendienteLlanoRuta = nuevo;
|
||||
break;
|
||||
case NivelColorPendienteRuta.SubidaMedia:
|
||||
_colorPendienteSubidaMediaRuta = nuevo;
|
||||
break;
|
||||
case NivelColorSubidaRuta.Fuerte:
|
||||
case NivelColorPendienteRuta.SubidaFuerte:
|
||||
_colorPendienteSubidaFuerteRuta = nuevo;
|
||||
break;
|
||||
default:
|
||||
@@ -588,9 +598,17 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
ColorPendienteSubidaSuaveRutaPorDefecto));
|
||||
|
||||
if (pendientePorcentaje.Value <= -umbralBajada)
|
||||
return ("bajada", "#16a34a");
|
||||
return (
|
||||
"bajada",
|
||||
NormalizarColorHexRuta(
|
||||
_colorPendienteBajadaRuta,
|
||||
ColorPendienteBajadaRutaPorDefecto));
|
||||
|
||||
return ("llano", "#dc2626");
|
||||
return (
|
||||
"llano",
|
||||
NormalizarColorHexRuta(
|
||||
_colorPendienteLlanoRuta,
|
||||
ColorPendienteLlanoRutaPorDefecto));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -287,19 +287,33 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:.25rem;">
|
||||
<div style="font-weight:600;">
|
||||
var todosItinerariosParadaPintados = TodosItinerariosParadaPintados;
|
||||
<div class="stop-schedule-header">
|
||||
<div class="stop-schedule-header__title">
|
||||
Horarios (@_nextDeps.Count)
|
||||
</div>
|
||||
|
||||
<div class="stop-schedule-header__actions">
|
||||
<button type="button"
|
||||
class="btn-ghost"
|
||||
class="stop-itinerary-show-all @(todosItinerariosParadaPintados ? "is-active" : "")"
|
||||
title="@(todosItinerariosParadaPintados
|
||||
? "Ocultar los itinerarios de esta parada"
|
||||
: "Ver una vez cada itinerario de esta parada")"
|
||||
aria-pressed="@todosItinerariosParadaPintados"
|
||||
disabled="@_procesandoTodosItinerariosParada"
|
||||
@onclick="ToggleTodosItinerariosParadaAsync">
|
||||
<span aria-hidden="true">👁</span>
|
||||
<span>@TextoBotonTodosItinerariosParada</span>
|
||||
</button>
|
||||
|
||||
<button type="button"
|
||||
class="btn-ghost stop-schedule-order-button"
|
||||
title="@HorarioOrdenTooltip"
|
||||
style="padding:.1rem .45rem; min-width:auto; line-height:1.1;"
|
||||
@onclick="ToggleOrdenHorarios">
|
||||
@HorarioOrdenIcono
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (HorariosTaxibusSimuladosVisibles)
|
||||
{
|
||||
@@ -313,10 +327,18 @@
|
||||
@foreach (var x in NextDepsOrdenados)
|
||||
{
|
||||
var itinerarioPintado = EstaItinerarioSalidaParadaPintado(x);
|
||||
var textoItinerario = ObtenerTextoVisibleSalidaParada(x);
|
||||
var destinoItinerario = ObtenerNombreDestinoSalidaParada(x);
|
||||
<li id="@x.AnchorId"
|
||||
class="stop-schedule-row @(x.EsProximo ? "stop-schedule-row--next" : "")">
|
||||
<span class="stop-schedule-row__text">
|
||||
<b>@x.Hora</b> - @x.LineaTxt
|
||||
<b>@x.Hora</b> - @textoItinerario
|
||||
@if (!string.IsNullOrWhiteSpace(destinoItinerario))
|
||||
{
|
||||
<span class="stop-schedule-row__destination">
|
||||
<span aria-hidden="true">→</span> @destinoItinerario
|
||||
</span>
|
||||
}
|
||||
</span>
|
||||
<button type="button"
|
||||
class="stop-itinerary-toggle @(itinerarioPintado ? "is-active" : "")"
|
||||
@@ -345,18 +367,26 @@
|
||||
@if (_itinerarioClicado is not null)
|
||||
{
|
||||
var vReal = GetVarianteRealClicada();
|
||||
var textoLineaItinerario = GetTextoLineaItinerarioClicado(vReal);
|
||||
var destinoItinerario = GetDestinoItinerarioClicado(vReal);
|
||||
|
||||
<div class="popup-parada popup-slot popup-itinerario draggable-popup" data-drag-key="popup-itinerario">
|
||||
<div class="popup-parada-header draggable-popup-handle">
|
||||
@GetTextoItinerarioClicado()
|
||||
<div class="popup-parada-header popup-itinerario-header draggable-popup-handle">
|
||||
<span>@textoLineaItinerario</span>
|
||||
@if (!string.IsNullOrWhiteSpace(destinoItinerario))
|
||||
{
|
||||
<span class="popup-itinerario-header__destination">
|
||||
<span aria-hidden="true">→</span> @destinoItinerario
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
<div class="popup-parada-body popup-itinerario-body">
|
||||
@if (vReal is not null)
|
||||
{
|
||||
<div style="margin-top:.25rem;">
|
||||
<div><b>Paradas:</b> @(vReal.CodigosParadas?.Count ?? 0)</div>
|
||||
<div><b>Trayecto:</b> @ConstruirTextoRecorridoVariante(vReal)</div>
|
||||
<div><b>Recorrido:</b> @FormatearDistanciaVariante(vReal)</div>
|
||||
<div><b>Recorrido:</b> @ConstruirTextoRecorridoVariante(vReal)</div>
|
||||
<div><b>Longitud:</b> @FormatearDistanciaVariante(vReal)</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -1855,6 +1885,53 @@
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<div class="pendientes-config-modal__field">
|
||||
<span class="pendientes-config-modal__threshold-label">
|
||||
<button type="button"
|
||||
class="pendientes-config-modal__swatch"
|
||||
style="background-color: @_colorPendienteBajadaRuta"
|
||||
title="Cambiar color de bajada"
|
||||
aria-label="Cambiar color de bajada"
|
||||
disabled="@_pintandoElevacionesRuta"
|
||||
@onclick="() => AlternarSelectorColorPendienteRuta(NivelColorPendienteRuta.Bajada)">
|
||||
</button>
|
||||
<span>Umbral Bajada (%)</span>
|
||||
@if (_selectorColorPendienteRuta == NivelColorPendienteRuta.Bajada)
|
||||
{
|
||||
<SelectorColorSimple Color="@_colorPendienteBajadaRuta"
|
||||
Disabled="@_pintandoElevacionesRuta"
|
||||
ColorChanged="@(color => AplicarColorPendienteRutaAsync(color, NivelColorPendienteRuta.Bajada))" />
|
||||
}
|
||||
</span>
|
||||
<input type="text"
|
||||
class="config-input"
|
||||
inputmode="decimal"
|
||||
aria-label="Umbral Bajada (%)"
|
||||
value="@_umbralPendienteBajadaRuta.ToString("0.#", CultureInfo.InvariantCulture)"
|
||||
disabled="@_pintandoElevacionesRuta"
|
||||
@onchange="@(e => CambiarUmbralElevacionRutaAsync(e, false))" />
|
||||
</div>
|
||||
|
||||
<div class="pendientes-config-modal__field pendientes-config-modal__field--color-only">
|
||||
<span class="pendientes-config-modal__threshold-label">
|
||||
<button type="button"
|
||||
class="pendientes-config-modal__swatch"
|
||||
style="background-color: @_colorPendienteLlanoRuta"
|
||||
title="Cambiar color de andando normal"
|
||||
aria-label="Cambiar color de andando normal"
|
||||
disabled="@_pintandoElevacionesRuta"
|
||||
@onclick="() => AlternarSelectorColorPendienteRuta(NivelColorPendienteRuta.Llano)">
|
||||
</button>
|
||||
<span>Andando normal</span>
|
||||
@if (_selectorColorPendienteRuta == NivelColorPendienteRuta.Llano)
|
||||
{
|
||||
<SelectorColorSimple Color="@_colorPendienteLlanoRuta"
|
||||
Disabled="@_pintandoElevacionesRuta"
|
||||
ColorChanged="@(color => AplicarColorPendienteRutaAsync(color, NivelColorPendienteRuta.Llano))" />
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="pendientes-config-modal__field">
|
||||
<span class="pendientes-config-modal__threshold-label">
|
||||
<button type="button"
|
||||
@@ -1863,14 +1940,14 @@
|
||||
title="Cambiar color de subida"
|
||||
aria-label="Cambiar color de subida"
|
||||
disabled="@_pintandoElevacionesRuta"
|
||||
@onclick="() => AlternarSelectorColorPendienteRuta(NivelColorSubidaRuta.Suave)">
|
||||
@onclick="() => AlternarSelectorColorPendienteRuta(NivelColorPendienteRuta.Subida)">
|
||||
</button>
|
||||
<span>Umbral Subida (%)</span>
|
||||
@if (_selectorColorPendienteRuta == NivelColorSubidaRuta.Suave)
|
||||
@if (_selectorColorPendienteRuta == NivelColorPendienteRuta.Subida)
|
||||
{
|
||||
<SelectorColorSimple Color="@_colorPendienteSubidaSuaveRuta"
|
||||
Disabled="@_pintandoElevacionesRuta"
|
||||
ColorChanged="@(color => AplicarColorPendienteSubidaRutaAsync(color, NivelColorSubidaRuta.Suave))" />
|
||||
ColorChanged="@(color => AplicarColorPendienteRutaAsync(color, NivelColorPendienteRuta.Subida))" />
|
||||
}
|
||||
</span>
|
||||
<input type="text"
|
||||
@@ -1890,14 +1967,14 @@
|
||||
title="Cambiar color de subida media"
|
||||
aria-label="Cambiar color de subida media"
|
||||
disabled="@_pintandoElevacionesRuta"
|
||||
@onclick="() => AlternarSelectorColorPendienteRuta(NivelColorSubidaRuta.Media)">
|
||||
@onclick="() => AlternarSelectorColorPendienteRuta(NivelColorPendienteRuta.SubidaMedia)">
|
||||
</button>
|
||||
<span>Subida Media (%)</span>
|
||||
@if (_selectorColorPendienteRuta == NivelColorSubidaRuta.Media)
|
||||
@if (_selectorColorPendienteRuta == NivelColorPendienteRuta.SubidaMedia)
|
||||
{
|
||||
<SelectorColorSimple Color="@_colorPendienteSubidaMediaRuta"
|
||||
Disabled="@_pintandoElevacionesRuta"
|
||||
ColorChanged="@(color => AplicarColorPendienteSubidaRutaAsync(color, NivelColorSubidaRuta.Media))" />
|
||||
ColorChanged="@(color => AplicarColorPendienteRutaAsync(color, NivelColorPendienteRuta.SubidaMedia))" />
|
||||
}
|
||||
</span>
|
||||
<input type="text"
|
||||
@@ -1917,14 +1994,14 @@
|
||||
title="Cambiar color de subida fuerte"
|
||||
aria-label="Cambiar color de subida fuerte"
|
||||
disabled="@_pintandoElevacionesRuta"
|
||||
@onclick="() => AlternarSelectorColorPendienteRuta(NivelColorSubidaRuta.Fuerte)">
|
||||
@onclick="() => AlternarSelectorColorPendienteRuta(NivelColorPendienteRuta.SubidaFuerte)">
|
||||
</button>
|
||||
<span>Subida Fuerte (%)</span>
|
||||
@if (_selectorColorPendienteRuta == NivelColorSubidaRuta.Fuerte)
|
||||
@if (_selectorColorPendienteRuta == NivelColorPendienteRuta.SubidaFuerte)
|
||||
{
|
||||
<SelectorColorSimple Color="@_colorPendienteSubidaFuerteRuta"
|
||||
Disabled="@_pintandoElevacionesRuta"
|
||||
ColorChanged="@(color => AplicarColorPendienteSubidaRutaAsync(color, NivelColorSubidaRuta.Fuerte))" />
|
||||
ColorChanged="@(color => AplicarColorPendienteRutaAsync(color, NivelColorPendienteRuta.SubidaFuerte))" />
|
||||
}
|
||||
</span>
|
||||
<input type="text"
|
||||
@@ -1936,16 +2013,6 @@
|
||||
@onchange="@(e => CambiarUmbralColorSubidaRutaAsync(e, true))" />
|
||||
</div>
|
||||
|
||||
<label class="pendientes-config-modal__field">
|
||||
<span>Umbral Bajada (%)</span>
|
||||
<input type="text"
|
||||
class="config-input"
|
||||
inputmode="decimal"
|
||||
value="@_umbralPendienteBajadaRuta.ToString("0.#", CultureInfo.InvariantCulture)"
|
||||
disabled="@_pintandoElevacionesRuta"
|
||||
@onchange="@(e => CambiarUmbralElevacionRutaAsync(e, false))" />
|
||||
</label>
|
||||
|
||||
<label class="pendientes-config-modal__field">
|
||||
<span>Umbral Alerta (m)</span>
|
||||
<input type="text"
|
||||
|
||||
@@ -29,13 +29,13 @@
|
||||
@code {
|
||||
private static readonly (string Nombre, string Hex)[] ColoresPredefinidos =
|
||||
[
|
||||
("Verde", "#16a34a"),
|
||||
("Verde oscuro", "#166534"),
|
||||
("Amarillo", "#eab308"),
|
||||
("Naranja", "#f97316"),
|
||||
("Rojo", "#dc2626"),
|
||||
("Rosa", "#ec4899"),
|
||||
("Violeta", "#7c3aed"),
|
||||
("Azul", "#2563eb"),
|
||||
("Azul", "#9ebdff"),
|
||||
("Cian", "#0891b2"),
|
||||
("Gris", "#64748b"),
|
||||
("Negro", "#000000")
|
||||
|
||||
@@ -783,6 +783,17 @@ html, body {
|
||||
margin-bottom: .25rem;
|
||||
}
|
||||
|
||||
.popup-itinerario-header {
|
||||
padding-right: 1.8rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.popup-itinerario-header__destination {
|
||||
margin-left: .3rem;
|
||||
color: #bae6fd;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.popup-parada-body {
|
||||
font-size: .8rem;
|
||||
}
|
||||
@@ -791,6 +802,78 @@ html, body {
|
||||
margin-bottom: .15rem;
|
||||
}
|
||||
|
||||
.stop-schedule-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: .5rem;
|
||||
margin-bottom: .3rem;
|
||||
}
|
||||
|
||||
.popup-parada-body .stop-schedule-header {
|
||||
margin-bottom: .3rem;
|
||||
}
|
||||
|
||||
.stop-schedule-header__title {
|
||||
min-width: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.stop-schedule-header__actions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .3rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.popup-parada-body .stop-schedule-header__title,
|
||||
.popup-parada-body .stop-schedule-header__actions {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.stop-itinerary-show-all {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: .28rem;
|
||||
min-height: 26px;
|
||||
padding: .18rem .48rem;
|
||||
border: 1px solid rgba(56, 189, 248, .55);
|
||||
border-radius: 5px;
|
||||
color: #e0f2fe;
|
||||
background: rgba(14, 116, 144, .24);
|
||||
font-size: .72rem;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.stop-itinerary-show-all:hover,
|
||||
.stop-itinerary-show-all:focus-visible {
|
||||
border-color: #7dd3fc;
|
||||
color: #ffffff;
|
||||
background: rgba(14, 116, 144, .45);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.stop-itinerary-show-all.is-active {
|
||||
border-color: #7dd3fc;
|
||||
color: #ffffff;
|
||||
background: #0369a1;
|
||||
}
|
||||
|
||||
.stop-itinerary-show-all:disabled {
|
||||
cursor: default;
|
||||
opacity: .58;
|
||||
}
|
||||
|
||||
.stop-schedule-order-button {
|
||||
min-width: 26px;
|
||||
min-height: 26px;
|
||||
padding: .1rem .38rem;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.stop-schedule-list {
|
||||
max-height: 220px;
|
||||
overflow-y: auto;
|
||||
@@ -827,6 +910,12 @@ html, body {
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.stop-schedule-row__destination {
|
||||
margin-left: .3rem;
|
||||
color: #bae6fd;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.stop-itinerary-toggle {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
@@ -2343,6 +2432,11 @@ html, body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pendientes-config-modal__field--color-only .pendientes-config-modal__threshold-label {
|
||||
grid-column: 1 / -1;
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.pendientes-config-modal__threshold-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user