using OpenTheBox.Core; using OpenTheBox.Core.Crafting; using OpenTheBox.Core.Enums; using OpenTheBox.Data; using OpenTheBox.Localization; using Spectre.Console; using Spectre.Console.Rendering; namespace OpenTheBox.Rendering.Panels; /// /// Renders all unlocked crafting workstations: active jobs show progress, /// idle stations show a waiting indicator. /// public static class CraftingPanel { /// /// Builds a renderable panel showing all unlocked workstations and their status. /// public static IRenderable Render(GameState state, ContentRegistry? registry = null, LocalizationManager? loc = null) { var rows = new List(); // Index active jobs by workstation var jobsByStation = state.ActiveCraftingJobs .GroupBy(j => j.Workstation) .ToDictionary(g => g.Key, g => g.OrderBy(j => j.StartedAt).First()); // Show all unlocked workstations in stable order foreach (var station in state.UnlockedWorkstations.OrderBy(w => w.ToString())) { string stationName = loc?.Get($"workstation.{station}") ?? station.ToString(); if (jobsByStation.TryGetValue(station, out var job)) { string recipeName = job.RecipeId; if (registry is not null && registry.Recipes.TryGetValue(job.RecipeId, out var recipe)) recipeName = loc is not null ? loc.Get(recipe.NameKey) : recipe.NameKey; if (job.IsComplete) { string check = UnicodeSupport.IsUtf8 ? "✓" : ">"; rows.Add(new Markup($" [bold green]{check}[/] [yellow]{Markup.Escape(stationName)}[/]: {Markup.Escape(recipeName)} — [bold green]{Markup.Escape(loc?.Get("craft.done") ?? "Done")}[/]")); } else { int pct = (int)job.ProgressPercent; int barWidth = 20; int filled = barWidth * pct / 100; string bar = new string('#', filled) + new string('-', barWidth - filled); rows.Add(new Markup($" [yellow]{Markup.Escape(stationName)}[/]: {Markup.Escape(recipeName)} [[{bar}]] {pct}%")); } } else { // Idle workstation string idle = UnicodeSupport.IsUtf8 ? "⏳" : "~"; string idleText = loc?.Get("craft.idle") ?? "Waiting for ingredients"; rows.Add(new Markup($" [dim]{idle} {Markup.Escape(stationName)}: {Markup.Escape(idleText)}[/]")); } } if (rows.Count == 0) { rows.Add(new Markup($"[dim]{Markup.Escape(loc?.Get("craft.panel.empty") ?? "No workshops unlocked.")}[/]")); } return new Panel(new Rows(rows)) .Header($"[bold orange1]{Markup.Escape(loc?.Get("craft.panel.title") ?? "Workshops")}[/]") .Border(BoxBorder.Rounded); } }