examples/05-Progress.ps1

# 05 - Progress: run work in small steps and show progress. The window only stays responsive between
# messages, so long work is split into steps: the page asks for the next step, PowerShell does one and answers.
if (-not (Get-Command Show-NativeWebView -ErrorAction Ignore)) { Import-Module NativeWebView -ErrorAction Stop }

$Files = @(Get-ChildItem -Path $PSHOME -File -Recurse -ErrorAction Ignore | Select-Object -First 60)
$State = @{ Index = 0; Bytes = [long] 0 }

$Html = @'
<!doctype html>
<html><head><style>
  body { font-family: Verdana, 'Segoe UI', Arial, sans-serif; font-size: 13px; color: #454545; padding: 24px; background: #F9F9F9; }
  h3 { color: #154363; }
  .bar { height: 18px; background: #e4e4e4; border-radius: 9px; overflow: hidden; }
  .fill { height: 100%; width: 0; background: linear-gradient(90deg, #095495, #a2bfd6); transition: width .2s; }
  button { margin-top: 16px; padding: 8px 18px; background: #095495; color: white; border: 0; border-radius: 4px; font: inherit; }
  button:hover { background: #154363; }
</style></head>
<body>
  <h3 id="title">Measuring files...</h3>
  <div class="bar"><div class="fill" id="fill"></div></div>
  <p id="text"></p>
  <button id="close" hidden>Close</button>
  <script>
    kHost.on(function (m) {
      if (m.action !== "progress") { return; }
      document.getElementById("fill").style.width = m.percent + "%";
      document.getElementById("text").textContent = m.text;
      if (m.done) { document.getElementById("title").textContent = "Done"; document.getElementById("close").hidden = false; }
      else { kHost.send({ action: "next" }); }
    });
    document.getElementById("close").onclick = function () { kHost.send({ action: "close" }); };
    kHost.send({ action: "next" });
  </script>
</body></html>
'@


Show-NativeWebView -Html $Html -Title "Progress" -Width 460 -Height 260 -OnMessage {
    param($Message, $Window)
    $Data = $Message | ConvertFrom-Json
    if ($Data.action -eq "close") { $Window.Close(); return }
    if ($State.Index -lt $Files.Count) {
        $State.Bytes += $Files[$State.Index].Length      # one step of "work"
        $State.Index++
    }
    [int] $Percent = if ($Files.Count -eq 0) { 100 } else { [int] (100 * $State.Index / $Files.Count) }
    $Window.Send("progress", @{ percent = $Percent; done = ($State.Index -ge $Files.Count)
        text = ([string] $State.Index + " of " + $Files.Count + " files, " + [math]::Round($State.Bytes / 1MB, 1) + " MB") })
}.GetNewClosure()