Collapse runtime menu tab surface state
This commit is contained in:
parent
f49e9b200b
commit
6ca7fbc64b
2 changed files with 36 additions and 89 deletions
|
|
@ -4867,7 +4867,6 @@ static void RequireRuntimeMenuTabsUseEveSurface(string root)
|
|||
"AetheriaRuntimeMenuTabsSurfaceBuilder.Compose(",
|
||||
"AetheriaRuntimeMenuTabsSurfaceBuilder.Project(",
|
||||
"new AetheriaRuntimeMenuTabProjectionOption(",
|
||||
"new AetheriaRuntimeMenuTabSurfaceEntry(",
|
||||
"private static string TabKey("
|
||||
};
|
||||
|
||||
|
|
@ -4891,32 +4890,36 @@ static void RequireRuntimeMenuTabsUseEveSurface(string root)
|
|||
"MenuPanel tab visibility must read managed typed current-docking state instead of direct docking caches or ActionGameManager observed adapters.");
|
||||
}
|
||||
|
||||
var requiredProjectionBuilderSymbols = new[]
|
||||
var requiredDocumentBuilderSymbols = new[]
|
||||
{
|
||||
"public sealed class AetheriaRuntimeMenuTabModelOption",
|
||||
"public static string NormalizeTabKey(string tabKey)",
|
||||
"public static AetheriaRuntimeSurfaceDocument Build(",
|
||||
"private static AetheriaRuntimeMenuTabsSurfaceState ComposeState(",
|
||||
"public int Order { get; }",
|
||||
".OrderBy(tab => tab.Order)",
|
||||
"new AetheriaRuntimeMenuTabSurfaceEntry(",
|
||||
"var normalizedCurrent = NormalizeTabKey(currentTabKey)",
|
||||
"var tabs = (visibleTabs ?? Array.Empty<AetheriaRuntimeMenuTabModelOption>())",
|
||||
"var selected = string.Equals(key, normalizedCurrent, StringComparison.Ordinal)",
|
||||
"string.Equals(key, normalizedCurrent, StringComparison.Ordinal)"
|
||||
};
|
||||
var missingProjectionBuilderSymbols = requiredProjectionBuilderSymbols
|
||||
var missingDocumentBuilderSymbols = requiredDocumentBuilderSymbols
|
||||
.Where(symbol => !menuTabsSurfaceBuilder.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (missingProjectionBuilderSymbols.Length > 0)
|
||||
if (missingDocumentBuilderSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Shared runtime menu tab surface builder no longer owns tab projection semantics: " +
|
||||
string.Join(", ", missingProjectionBuilderSymbols));
|
||||
"Shared runtime menu tab surface builder no longer owns tab document composition semantics: " +
|
||||
string.Join(", ", missingDocumentBuilderSymbols));
|
||||
}
|
||||
|
||||
if (menuTabsSurfaceBuilder.Contains("public static AetheriaRuntimeMenuTabsSurfaceState Compose(", StringComparison.Ordinal) ||
|
||||
menuTabsSurfaceBuilder.Contains("public static AetheriaRuntimeMenuTabsSurfaceState Project(", StringComparison.Ordinal))
|
||||
menuTabsSurfaceBuilder.Contains("public static AetheriaRuntimeMenuTabsSurfaceState Project(", StringComparison.Ordinal) ||
|
||||
menuTabsSurfaceBuilder.Contains("AetheriaRuntimeMenuTabsSurfaceState", StringComparison.Ordinal) ||
|
||||
menuTabsSurfaceBuilder.Contains("AetheriaRuntimeMenuTabSurfaceEntry", StringComparison.Ordinal) ||
|
||||
menuTabsSurfaceBuilder.Contains("ComposeState(", StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Runtime menu tab composition must stay behind Build(...); do not re-expose Compose/Project as the public tab surface path.");
|
||||
"Runtime menu tab composition must emit the typed surface document directly; do not rebuild a shadow SurfaceState/Entry projection layer.");
|
||||
}
|
||||
|
||||
var requiredDockedStoryObserverSymbols = new[]
|
||||
|
|
@ -4996,8 +4999,7 @@ static void RequireRuntimeMenuTabsUseEveSurface(string root)
|
|||
"public static class AetheriaRuntimeMenuTabsSurfaceCommands",
|
||||
"public static bool TryRead(",
|
||||
"public static AetheriaRuntimeSurfaceDocument Build(",
|
||||
"AetheriaRuntimeMenuTabsSurfaceState",
|
||||
"AetheriaRuntimeMenuTabSurfaceEntry"
|
||||
"var tabs = (visibleTabs ?? Array.Empty<AetheriaRuntimeMenuTabModelOption>())"
|
||||
};
|
||||
var missingBuilderSymbols = requiredBuilderSymbols
|
||||
.Where(symbol => !menuTabsSurfaceBuilder.Contains(symbol, StringComparison.Ordinal))
|
||||
|
|
|
|||
|
|
@ -5,37 +5,6 @@ using GameCult.Eve.Surface;
|
|||
|
||||
namespace GameCult.Aetheria.State.Verse
|
||||
{
|
||||
public sealed class AetheriaRuntimeMenuTabSurfaceEntry
|
||||
{
|
||||
public AetheriaRuntimeMenuTabSurfaceEntry(string key, string label, bool selected)
|
||||
{
|
||||
Key = key ?? "";
|
||||
Label = label ?? "";
|
||||
Selected = selected;
|
||||
}
|
||||
|
||||
public string Key { get; }
|
||||
public string Label { get; }
|
||||
public bool Selected { get; }
|
||||
}
|
||||
|
||||
public sealed class AetheriaRuntimeMenuTabsSurfaceState
|
||||
{
|
||||
public AetheriaRuntimeMenuTabsSurfaceState(
|
||||
string currentTabKey,
|
||||
IReadOnlyList<AetheriaRuntimeMenuTabSurfaceEntry> visibleTabs,
|
||||
string updatedAtUtc)
|
||||
{
|
||||
CurrentTabKey = currentTabKey ?? "";
|
||||
VisibleTabs = visibleTabs ?? Array.Empty<AetheriaRuntimeMenuTabSurfaceEntry>();
|
||||
UpdatedAtUtc = updatedAtUtc ?? "";
|
||||
}
|
||||
|
||||
public string CurrentTabKey { get; }
|
||||
public IReadOnlyList<AetheriaRuntimeMenuTabSurfaceEntry> VisibleTabs { get; }
|
||||
public string UpdatedAtUtc { get; }
|
||||
}
|
||||
|
||||
public sealed class AetheriaRuntimeMenuTabModelOption
|
||||
{
|
||||
public AetheriaRuntimeMenuTabModelOption(string key, string label, int order)
|
||||
|
|
@ -71,55 +40,36 @@ namespace GameCult.Aetheria.State.Verse
|
|||
IEnumerable<AetheriaRuntimeMenuTabModelOption> visibleTabs,
|
||||
string updatedAtUtc,
|
||||
long version = 1)
|
||||
{
|
||||
return Build(
|
||||
ComposeState(currentTabKey, visibleTabs, updatedAtUtc),
|
||||
version);
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeMenuTabsSurfaceState ComposeState(
|
||||
string currentTabKey,
|
||||
IEnumerable<AetheriaRuntimeMenuTabModelOption> visibleTabs,
|
||||
string updatedAtUtc)
|
||||
{
|
||||
var normalizedCurrent = NormalizeTabKey(currentTabKey);
|
||||
return new AetheriaRuntimeMenuTabsSurfaceState(
|
||||
normalizedCurrent,
|
||||
(visibleTabs ?? Array.Empty<AetheriaRuntimeMenuTabModelOption>())
|
||||
.Where(tab => tab != null)
|
||||
.OrderBy(tab => tab.Order)
|
||||
.ThenBy(tab => NormalizeTabKey(tab.Key), StringComparer.Ordinal)
|
||||
.Select(tab =>
|
||||
var tabs = (visibleTabs ?? Array.Empty<AetheriaRuntimeMenuTabModelOption>())
|
||||
.Where(tab => tab != null)
|
||||
.OrderBy(tab => tab.Order)
|
||||
.ThenBy(tab => NormalizeTabKey(tab.Key), StringComparer.Ordinal)
|
||||
.Select(tab =>
|
||||
{
|
||||
var key = NormalizeTabKey(tab.Key);
|
||||
var label = string.IsNullOrWhiteSpace(tab.Label) ? key : tab.Label;
|
||||
var selected = string.Equals(key, normalizedCurrent, StringComparison.Ordinal);
|
||||
return new
|
||||
{
|
||||
var key = NormalizeTabKey(tab.Key);
|
||||
return new AetheriaRuntimeMenuTabSurfaceEntry(
|
||||
key,
|
||||
string.IsNullOrWhiteSpace(tab.Label) ? key : tab.Label,
|
||||
string.Equals(key, normalizedCurrent, StringComparison.Ordinal));
|
||||
})
|
||||
.ToArray(),
|
||||
updatedAtUtc);
|
||||
}
|
||||
Key = key,
|
||||
Label = label,
|
||||
Selected = selected
|
||||
};
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
public static AetheriaRuntimeSurfaceDocument Build(
|
||||
AetheriaRuntimeMenuTabsSurfaceState state,
|
||||
long version = 1)
|
||||
{
|
||||
state ??= new AetheriaRuntimeMenuTabsSurfaceState(
|
||||
"",
|
||||
Array.Empty<AetheriaRuntimeMenuTabSurfaceEntry>(),
|
||||
"");
|
||||
|
||||
var commands = state.VisibleTabs
|
||||
var commands = tabs
|
||||
.Select(tab => new AetheriaRuntimeSurfaceCommandTemplate(
|
||||
CommandFor(tab.Key),
|
||||
LabelFor(tab),
|
||||
tab.Label,
|
||||
AetheriaRuntimeSurfaceCommandTemplate.CultMeshTransport))
|
||||
.ToArray();
|
||||
var buttons = state.VisibleTabs
|
||||
var buttons = tabs
|
||||
.Select(tab => Button(
|
||||
$"{SurfaceId}.{SafeId(tab.Key)}",
|
||||
tab.Selected ? $"{LabelFor(tab)} *" : LabelFor(tab),
|
||||
tab.Selected ? $"{tab.Label} *" : tab.Label,
|
||||
CommandFor(tab.Key)))
|
||||
.ToArray();
|
||||
|
||||
|
|
@ -128,7 +78,7 @@ namespace GameCult.Aetheria.State.Verse
|
|||
providerKind: "runtime.menu",
|
||||
title: "Runtime Menu Tabs",
|
||||
version: version,
|
||||
updatedAtUtc: state.UpdatedAtUtc,
|
||||
updatedAtUtc: updatedAtUtc ?? "",
|
||||
surface: new AetheriaRuntimeSurfaceTree(
|
||||
SurfaceId,
|
||||
Node(
|
||||
|
|
@ -137,17 +87,12 @@ namespace GameCult.Aetheria.State.Verse
|
|||
Array.Empty<(string Key, string Value)>(),
|
||||
Text(
|
||||
$"{SurfaceId}.current",
|
||||
$"Current: {state.CurrentTabKey}"),
|
||||
$"Current: {normalizedCurrent}"),
|
||||
ButtonRow($"{SurfaceId}.tabs", buttons)),
|
||||
Array.Empty<AetheriaRuntimeSurfaceStyleToken>()),
|
||||
commands: commands);
|
||||
}
|
||||
|
||||
private static string LabelFor(AetheriaRuntimeMenuTabSurfaceEntry tab)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(tab.Label) ? tab.Key : tab.Label;
|
||||
}
|
||||
|
||||
private static string SafeId(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
|
|
|
|||
Loading…
Reference in a new issue