Generic navigation stack for UI routes. Maintains a list of enum-typed routes, supports Go, Push, Pop, PopTo, Reset, Clear, and exposes current route, depth, revision and change event.
namespace Sunless.Libraries.UI;
using System;
using System.Collections.Generic;
using System.Linq;
public static class NavStack<TRoute> where TRoute : struct, Enum
{
static readonly List<TRoute> _stack = new();
static int _revision;
public static event Action OnChanged;
public static TRoute Current => _stack.Count > 0 ? _stack[^1] : default;
public static int Revision => _revision;
public static int Depth => _stack.Count;
public static bool CanPop => _stack.Count > 1;
public static IReadOnlyList<TRoute> Stack => _stack;
public static void Go(TRoute route)
{
if (_stack.Count > 0 && EqualityComparer<TRoute>.Default.Equals(_stack[^1], route)) return;
if (_stack.Count == 0) _stack.Add(route);
else _stack[^1] = route;
Bump();
}
public static void Push(TRoute route)
{
if (_stack.Count > 0 && EqualityComparer<TRoute>.Default.Equals(_stack[^1], route)) return;
_stack.Add(route);
Bump();
}
public static bool Pop()
{
if (_stack.Count <= 1) return false;
_stack.RemoveAt(_stack.Count - 1);
Bump();
return true;
}
public static void PopTo(TRoute route)
{
var idx = _stack.LastIndexOf(route);
if (idx < 0) return;
while (_stack.Count - 1 > idx) _stack.RemoveAt(_stack.Count - 1);
Bump();
}
public static void Reset(TRoute route)
{
_stack.Clear();
_stack.Add(route);
Bump();
}
public static void Clear()
{
_stack.Clear();
Bump();
}
public static bool IsAt(TRoute route) =>
_stack.Count > 0 && EqualityComparer<TRoute>.Default.Equals(_stack[^1], route);
public static bool Contains(TRoute route) => _stack.Contains(route);
static void Bump()
{
_revision++;
try { OnChanged?.Invoke(); }
catch (Exception e) { Log.Warning($"[NavStack<{typeof(TRoute).Name}>] OnChanged threw: {e.Message}"); }
}
}