using Spry; using Inversion; /** * ProgressDemo - A progress bar demo for the Continuations documentation * * Demonstrates: * - spry-continuation attribute for SSE * - spry-dynamic for updatable sections * - continuation() method for real-time updates * - ContinuationContext API */ public class ProgressDemo : Component { public int percent { get; set; default = 0; } public string status { get; set; default = "Ready"; } public bool is_running { get; set; default = false; } public override string markup { get { return """
0% Ready
"""; }} public override async void prepare() throws Error { this["status-text"].text_content = status; this["percent-text"].text_content = @"$percent%"; if (is_running) { this["start-btn"].set_attribute("disabled", "disabled"); this["start-btn"].text_content = "Running..."; } else { this["start-btn"].remove_attribute("disabled"); this["start-btn"].text_content = percent >= 100 ? "Complete!" : "Start Task"; } } public async override void handle_action(string action) throws Error { switch (action) { case "Start": if (!is_running && percent < 100) { is_running = true; status = "Starting..."; } break; case "Reset": percent = 0; status = "Ready"; is_running = false; break; } } public async override void continuation(ContinuationContext ctx) throws Error { if (!is_running) return; for (int i = percent; i <= 100; i += 5) { percent = i; if (i < 30) { status = @"Processing... $i%"; } else if (i < 60) { status = @"Building... $i%"; } else if (i < 90) { status = @"Finalizing... $i%"; } else { status = @"Almost done... $i%"; } // Send updates via SSE to the dynamic sections yield ctx.send_dynamic("progress-bar"); yield ctx.send_dynamic("status"); // Simulate work Timeout.add(200, () => { continuation.callback(); return false; }); yield; } percent = 100; status = "Complete!"; is_running = false; yield ctx.send_dynamic("progress-bar"); yield ctx.send_dynamic("status"); } }