From cbed41e637ea36b5207aae4fcf1bccb91eaff2c8 Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Sat, 5 Dec 2020 10:52:51 +0100 Subject: [PATCH] Add support for different spinners --- examples/Columns/Program.cs | 28 +- examples/Columns/User.cs | 89 + resources/scripts/Generate-Spinners.ps1 | 22 + .../Commands/ColorGeneratorCommand.cs | 19 +- .../Commands/EmojiGeneratorCommand.cs | 14 +- .../Generator/Commands/GeneratorSettings.cs | 10 + .../Commands/SpinnerGeneratorCommand.cs | 47 + .../scripts/Generator/Data/spinners.json | 1368 ++++++++++++ .../Generator/Data/spinners_default.json | 30 + resources/scripts/Generator/Generator.csproj | 6 + resources/scripts/Generator/Models/Spinner.cs | 31 + resources/scripts/Generator/Program.cs | 1 + .../Templates/Color.Generated.template | 1 + .../ProgressSpinner.Generated.template | 45 + .../Progress/Columns/SpinnerColumn.cs | 40 +- src/Spectre.Console/Progress/Progress.cs | 8 +- .../Progress/ProgressSpinner.Generated.cs | 1870 +++++++++++++++++ .../Progress/ProgressSpinner.cs | 27 + .../Renderers/InteractiveProgressRenderer.cs | 6 +- .../Rendering/LiveRenderable.cs | 1 - 20 files changed, 3618 insertions(+), 45 deletions(-) create mode 100644 examples/Columns/User.cs create mode 100644 resources/scripts/Generate-Spinners.ps1 create mode 100644 resources/scripts/Generator/Commands/GeneratorSettings.cs create mode 100644 resources/scripts/Generator/Commands/SpinnerGeneratorCommand.cs create mode 100644 resources/scripts/Generator/Data/spinners.json create mode 100644 resources/scripts/Generator/Data/spinners_default.json create mode 100644 resources/scripts/Generator/Models/Spinner.cs create mode 100644 resources/scripts/Generator/Templates/ProgressSpinner.Generated.template create mode 100644 src/Spectre.Console/Progress/ProgressSpinner.Generated.cs create mode 100644 src/Spectre.Console/Progress/ProgressSpinner.cs diff --git a/examples/Columns/Program.cs b/examples/Columns/Program.cs index 3a7e1e4..c7e90b5 100644 --- a/examples/Columns/Program.cs +++ b/examples/Columns/Program.cs @@ -1,39 +1,31 @@ using System.Collections.Generic; -using System.Net.Http; -using System.Threading.Tasks; -using Newtonsoft.Json.Linq; using Spectre.Console; namespace ColumnsExample { public static class Program { - public static async Task Main() + public static void Main() { - // Download some random users - using var client = new HttpClient(); - dynamic users = JObject.Parse( - await client.GetStringAsync("https://randomuser.me/api/?results=15")); - - // Create a card for each user var cards = new List(); - foreach(var user in users.results) + foreach(var user in User.LoadUsers()) { - cards.Add(new Panel(GetCardContent(user)) - .Header($"{user.location.country}") - .RoundedBorder().Expand()); + cards.Add( + new Panel(GetCardContent(user)) + .Header($"{user.Country}") + .RoundedBorder().Expand()); } // Render all cards in columns AnsiConsole.Render(new Columns(cards)); } - private static string GetCardContent(dynamic user) + private static string GetCardContent(User user) { - var name = $"{user.name.first} {user.name.last}"; - var country = $"{user.location.city}"; + var name = $"{user.FirstName} {user.LastName}"; + var city = $"{user.City}"; - return $"[b]{name}[/]\n[yellow]{country}[/]"; + return $"[b]{name}[/]\n[yellow]{city}[/]"; } } } diff --git a/examples/Columns/User.cs b/examples/Columns/User.cs new file mode 100644 index 0000000..4125dcc --- /dev/null +++ b/examples/Columns/User.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; + +namespace ColumnsExample +{ + public sealed class User + { + public string FirstName { get; set; } + public string LastName { get; set; } + public string City { get; set; } + public string Country { get; set; } + + public static List LoadUsers() + { + return new List + { + new User + { + FirstName = "Andrea", + LastName = "Johansen", + City = "Hornbæk", + Country = "Denmark", + }, + new User + { + FirstName = "Brandon", + LastName = "Cole", + City = "Washington", + Country = "United States", + }, + new User + { + FirstName = "Patrik", + LastName = "Svensson", + City = "Stockholm", + Country = "Sweden", + }, + new User + { + FirstName = "Freya", + LastName = "Thompson", + City = "Rotorua", + Country = "New Zealand", + }, + new User + { + FirstName = "طاها", + LastName = "رضایی", + City = "اهواز", + Country = "Iran", + }, + new User + { + FirstName = "Yara", + LastName = "Simon", + City = "Develier", + Country = "Switzerland", + }, + new User + { + FirstName = "Giray", + LastName = "Erbay", + City = "Karabük", + Country = "Turkey", + }, + new User + { + FirstName = "Miodrag", + LastName = "Schaffer", + City = "Möckern", + Country = "Germany", + }, + new User + { + FirstName = "Carmela", + LastName = "Lo Castro", + City = "Firenze", + Country = "Italy", + }, + new User + { + FirstName = "Roberto", + LastName = "Sims", + City = "Mallow", + Country = "Ireland", + }, + }; + } + } +} diff --git a/resources/scripts/Generate-Spinners.ps1 b/resources/scripts/Generate-Spinners.ps1 new file mode 100644 index 0000000..8e08fdf --- /dev/null +++ b/resources/scripts/Generate-Spinners.ps1 @@ -0,0 +1,22 @@ +########################################################## +# Script that generates progress spinners. +########################################################## + +$Output = Join-Path $PSScriptRoot "Temp" +$Source = Join-Path $PSScriptRoot "/../../src/Spectre.Console" + +if(!(Test-Path $Output -PathType Container)) { + New-Item -ItemType Directory -Path $Output | Out-Null +} + +# Generate the files +Push-Location Generator +&dotnet run -- spinners "$Output" --input $Output +if(!$?) { + Pop-Location + Throw "An error occured when generating code." +} +Pop-Location + +# Copy the files to the correct location +Copy-Item (Join-Path "$Output" "ProgressSpinner.Generated.cs") -Destination "$Source/Progress/ProgressSpinner.Generated.cs" diff --git a/resources/scripts/Generator/Commands/ColorGeneratorCommand.cs b/resources/scripts/Generator/Commands/ColorGeneratorCommand.cs index 9255982..0634b8f 100644 --- a/resources/scripts/Generator/Commands/ColorGeneratorCommand.cs +++ b/resources/scripts/Generator/Commands/ColorGeneratorCommand.cs @@ -7,7 +7,7 @@ using Spectre.IO; namespace Generator.Commands { - public sealed class ColorGeneratorCommand : Command + public sealed class ColorGeneratorCommand : Command { private readonly IFileSystem _fileSystem; @@ -16,7 +16,13 @@ namespace Generator.Commands _fileSystem = new FileSystem(); } - public override int Execute(CommandContext context, GeneratorCommandSettings settings) + public sealed class Settings : GeneratorSettings + { + [CommandOption("-i|--input ")] + public string Input { get; set; } + } + + public override int Execute(CommandContext context, Settings settings) { var templates = new FilePath[] { @@ -50,13 +56,4 @@ namespace Generator.Commands return 0; } } - - public sealed class GeneratorCommandSettings : CommandSettings - { - [CommandArgument(0, "")] - public string Output { get; set; } - - [CommandOption("-i|--input ")] - public string Input { get; set; } - } } diff --git a/resources/scripts/Generator/Commands/EmojiGeneratorCommand.cs b/resources/scripts/Generator/Commands/EmojiGeneratorCommand.cs index 0451dbf..0b05811 100644 --- a/resources/scripts/Generator/Commands/EmojiGeneratorCommand.cs +++ b/resources/scripts/Generator/Commands/EmojiGeneratorCommand.cs @@ -15,7 +15,7 @@ using SpectreEnvironment = Spectre.IO.Environment; namespace Generator.Commands { - public sealed class EmojiGeneratorCommand : AsyncCommand + public sealed class EmojiGeneratorCommand : AsyncCommand { private readonly IFileSystem _fileSystem; private readonly IEnvironment _environment; @@ -24,9 +24,15 @@ namespace Generator.Commands private readonly Dictionary _templates = new Dictionary { { "Templates/Emoji.Generated.template", "Emoji.Generated.cs" }, - { "Templates/Emoji.Json.template", "emojis.json" }, + { "Templates/Emoji.Json.template", "emojis.json" }, // For documentation }; + public sealed class Settings : GeneratorSettings + { + [CommandOption("-i|--input ")] + public string Input { get; set; } + } + public EmojiGeneratorCommand() { _fileSystem = new FileSystem(); @@ -34,7 +40,7 @@ namespace Generator.Commands _parser = new HtmlParser(); } - public override async Task ExecuteAsync(CommandContext context, GeneratorCommandSettings settings) + public override async Task ExecuteAsync(CommandContext context, Settings settings) { var output = new DirectoryPath(settings.Output); if (!_fileSystem.Directory.Exists(settings.Output)) @@ -60,7 +66,7 @@ namespace Generator.Commands return 0; } - private async Task FetchEmojis(GeneratorCommandSettings settings) + private async Task FetchEmojis(Settings settings) { var input = string.IsNullOrEmpty(settings.Input) ? _environment.WorkingDirectory diff --git a/resources/scripts/Generator/Commands/GeneratorSettings.cs b/resources/scripts/Generator/Commands/GeneratorSettings.cs new file mode 100644 index 0000000..b5a77c6 --- /dev/null +++ b/resources/scripts/Generator/Commands/GeneratorSettings.cs @@ -0,0 +1,10 @@ +using Spectre.Cli; + +namespace Generator.Commands +{ + public class GeneratorSettings : CommandSettings + { + [CommandArgument(0, "")] + public string Output { get; set; } + } +} diff --git a/resources/scripts/Generator/Commands/SpinnerGeneratorCommand.cs b/resources/scripts/Generator/Commands/SpinnerGeneratorCommand.cs new file mode 100644 index 0000000..1fb03eb --- /dev/null +++ b/resources/scripts/Generator/Commands/SpinnerGeneratorCommand.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Generator.Models; +using Scriban; +using Spectre.Cli; +using Spectre.IO; + +namespace Generator.Commands +{ + public sealed class SpinnerGeneratorCommand : Command + { + private readonly IFileSystem _fileSystem; + + public SpinnerGeneratorCommand() + { + _fileSystem = new FileSystem(); + } + + public override int Execute(CommandContext context, GeneratorSettings settings) + { + // Read the spinner model. + var spinners = new List(); + spinners.AddRange(Spinner.Parse(File.ReadAllText("Data/spinners.json"))); + spinners.AddRange(Spinner.Parse(File.ReadAllText("Data/spinners_default.json"))); + + var output = new DirectoryPath(settings.Output); + if (!_fileSystem.Directory.Exists(settings.Output)) + { + _fileSystem.Directory.Create(settings.Output); + } + + // Parse the Scriban template. + var templatePath = new FilePath("Templates/ProgressSpinner.Generated.template"); + var template = Template.Parse(File.ReadAllText(templatePath.FullPath)); + + // Render the template with the model. + var result = template.Render(new { Spinners = spinners }); + + // Write output to file + var file = output.CombineWithFilePath(templatePath.GetFilename().ChangeExtension(".cs")); + File.WriteAllText(file.FullPath, result); + + return 0; + } + } +} diff --git a/resources/scripts/Generator/Data/spinners.json b/resources/scripts/Generator/Data/spinners.json new file mode 100644 index 0000000..2cbcc35 --- /dev/null +++ b/resources/scripts/Generator/Data/spinners.json @@ -0,0 +1,1368 @@ +{ + "dots": { + "interval": 80, + "unicode": true, + "frames": [ + "⠋", + "⠙", + "⠹", + "⠸", + "⠼", + "⠴", + "⠦", + "⠧", + "⠇", + "⠏" + ] + }, + "dots2": { + "interval": 80, + "unicode": true, + "frames": [ + "⣾", + "⣽", + "⣻", + "⢿", + "⡿", + "⣟", + "⣯", + "⣷" + ] + }, + "dots3": { + "interval": 80, + "unicode": true, + "frames": [ + "⠋", + "⠙", + "⠚", + "⠞", + "⠖", + "⠦", + "⠴", + "⠲", + "⠳", + "⠓" + ] + }, + "dots4": { + "interval": 80, + "unicode": true, + "frames": [ + "⠄", + "⠆", + "⠇", + "⠋", + "⠙", + "⠸", + "⠰", + "⠠", + "⠰", + "⠸", + "⠙", + "⠋", + "⠇", + "⠆" + ] + }, + "dots5": { + "interval": 80, + "unicode": true, + "frames": [ + "⠋", + "⠙", + "⠚", + "⠒", + "⠂", + "⠂", + "⠒", + "⠲", + "⠴", + "⠦", + "⠖", + "⠒", + "⠐", + "⠐", + "⠒", + "⠓", + "⠋" + ] + }, + "dots6": { + "interval": 80, + "unicode": true, + "frames": [ + "⠁", + "⠉", + "⠙", + "⠚", + "⠒", + "⠂", + "⠂", + "⠒", + "⠲", + "⠴", + "⠤", + "⠄", + "⠄", + "⠤", + "⠴", + "⠲", + "⠒", + "⠂", + "⠂", + "⠒", + "⠚", + "⠙", + "⠉", + "⠁" + ] + }, + "dots7": { + "interval": 80, + "unicode": true, + "frames": [ + "⠈", + "⠉", + "⠋", + "⠓", + "⠒", + "⠐", + "⠐", + "⠒", + "⠖", + "⠦", + "⠤", + "⠠", + "⠠", + "⠤", + "⠦", + "⠖", + "⠒", + "⠐", + "⠐", + "⠒", + "⠓", + "⠋", + "⠉", + "⠈" + ] + }, + "dots8": { + "interval": 80, + "unicode": true, + "frames": [ + "⠁", + "⠁", + "⠉", + "⠙", + "⠚", + "⠒", + "⠂", + "⠂", + "⠒", + "⠲", + "⠴", + "⠤", + "⠄", + "⠄", + "⠤", + "⠠", + "⠠", + "⠤", + "⠦", + "⠖", + "⠒", + "⠐", + "⠐", + "⠒", + "⠓", + "⠋", + "⠉", + "⠈", + "⠈" + ] + }, + "dots9": { + "interval": 80, + "unicode": true, + "frames": [ + "⢹", + "⢺", + "⢼", + "⣸", + "⣇", + "⡧", + "⡗", + "⡏" + ] + }, + "dots10": { + "interval": 80, + "unicode": true, + "frames": [ + "⢄", + "⢂", + "⢁", + "⡁", + "⡈", + "⡐", + "⡠" + ] + }, + "dots11": { + "interval": 100, + "unicode": true, + "frames": [ + "⠁", + "⠂", + "⠄", + "⡀", + "⢀", + "⠠", + "⠐", + "⠈" + ] + }, + "dots12": { + "interval": 80, + "unicode": true, + "frames": [ + "⢀⠀", + "⡀⠀", + "⠄⠀", + "⢂⠀", + "⡂⠀", + "⠅⠀", + "⢃⠀", + "⡃⠀", + "⠍⠀", + "⢋⠀", + "⡋⠀", + "⠍⠁", + "⢋⠁", + "⡋⠁", + "⠍⠉", + "⠋⠉", + "⠋⠉", + "⠉⠙", + "⠉⠙", + "⠉⠩", + "⠈⢙", + "⠈⡙", + "⢈⠩", + "⡀⢙", + "⠄⡙", + "⢂⠩", + "⡂⢘", + "⠅⡘", + "⢃⠨", + "⡃⢐", + "⠍⡐", + "⢋⠠", + "⡋⢀", + "⠍⡁", + "⢋⠁", + "⡋⠁", + "⠍⠉", + "⠋⠉", + "⠋⠉", + "⠉⠙", + "⠉⠙", + "⠉⠩", + "⠈⢙", + "⠈⡙", + "⠈⠩", + "⠀⢙", + "⠀⡙", + "⠀⠩", + "⠀⢘", + "⠀⡘", + "⠀⠨", + "⠀⢐", + "⠀⡐", + "⠀⠠", + "⠀⢀", + "⠀⡀" + ] + }, + "dots8Bit": { + "interval": 80, + "unicode": true, + "frames": [ + "⠀", + "⠁", + "⠂", + "⠃", + "⠄", + "⠅", + "⠆", + "⠇", + "⡀", + "⡁", + "⡂", + "⡃", + "⡄", + "⡅", + "⡆", + "⡇", + "⠈", + "⠉", + "⠊", + "⠋", + "⠌", + "⠍", + "⠎", + "⠏", + "⡈", + "⡉", + "⡊", + "⡋", + "⡌", + "⡍", + "⡎", + "⡏", + "⠐", + "⠑", + "⠒", + "⠓", + "⠔", + "⠕", + "⠖", + "⠗", + "⡐", + "⡑", + "⡒", + "⡓", + "⡔", + "⡕", + "⡖", + "⡗", + "⠘", + "⠙", + "⠚", + "⠛", + "⠜", + "⠝", + "⠞", + "⠟", + "⡘", + "⡙", + "⡚", + "⡛", + "⡜", + "⡝", + "⡞", + "⡟", + "⠠", + "⠡", + "⠢", + "⠣", + "⠤", + "⠥", + "⠦", + "⠧", + "⡠", + "⡡", + "⡢", + "⡣", + "⡤", + "⡥", + "⡦", + "⡧", + "⠨", + "⠩", + "⠪", + "⠫", + "⠬", + "⠭", + "⠮", + "⠯", + "⡨", + "⡩", + "⡪", + "⡫", + "⡬", + "⡭", + "⡮", + "⡯", + "⠰", + "⠱", + "⠲", + "⠳", + "⠴", + "⠵", + "⠶", + "⠷", + "⡰", + "⡱", + "⡲", + "⡳", + "⡴", + "⡵", + "⡶", + "⡷", + "⠸", + "⠹", + "⠺", + "⠻", + "⠼", + "⠽", + "⠾", + "⠿", + "⡸", + "⡹", + "⡺", + "⡻", + "⡼", + "⡽", + "⡾", + "⡿", + "⢀", + "⢁", + "⢂", + "⢃", + "⢄", + "⢅", + "⢆", + "⢇", + "⣀", + "⣁", + "⣂", + "⣃", + "⣄", + "⣅", + "⣆", + "⣇", + "⢈", + "⢉", + "⢊", + "⢋", + "⢌", + "⢍", + "⢎", + "⢏", + "⣈", + "⣉", + "⣊", + "⣋", + "⣌", + "⣍", + "⣎", + "⣏", + "⢐", + "⢑", + "⢒", + "⢓", + "⢔", + "⢕", + "⢖", + "⢗", + "⣐", + "⣑", + "⣒", + "⣓", + "⣔", + "⣕", + "⣖", + "⣗", + "⢘", + "⢙", + "⢚", + "⢛", + "⢜", + "⢝", + "⢞", + "⢟", + "⣘", + "⣙", + "⣚", + "⣛", + "⣜", + "⣝", + "⣞", + "⣟", + "⢠", + "⢡", + "⢢", + "⢣", + "⢤", + "⢥", + "⢦", + "⢧", + "⣠", + "⣡", + "⣢", + "⣣", + "⣤", + "⣥", + "⣦", + "⣧", + "⢨", + "⢩", + "⢪", + "⢫", + "⢬", + "⢭", + "⢮", + "⢯", + "⣨", + "⣩", + "⣪", + "⣫", + "⣬", + "⣭", + "⣮", + "⣯", + "⢰", + "⢱", + "⢲", + "⢳", + "⢴", + "⢵", + "⢶", + "⢷", + "⣰", + "⣱", + "⣲", + "⣳", + "⣴", + "⣵", + "⣶", + "⣷", + "⢸", + "⢹", + "⢺", + "⢻", + "⢼", + "⢽", + "⢾", + "⢿", + "⣸", + "⣹", + "⣺", + "⣻", + "⣼", + "⣽", + "⣾", + "⣿" + ] + }, + "line": { + "interval": 130, + "unicode": false, + "frames": [ + "-", + "\\", + "|", + "/" + ] + }, + "line2": { + "interval": 100, + "unicode": false, + "frames": [ + "⠂", + "-", + "–", + "—", + "–", + "-" + ] + }, + "pipe": { + "interval": 100, + "unicode": false, + "frames": [ + "┤", + "┘", + "┴", + "└", + "├", + "┌", + "┬", + "┐" + ] + }, + "simpleDots": { + "interval": 400, + "unicode": false, + "frames": [ + ". ", + ".. ", + "...", + " " + ] + }, + "simpleDotsScrolling": { + "interval": 200, + "unicode": false, + "frames": [ + ". ", + ".. ", + "...", + " ..", + " .", + " " + ] + }, + "star": { + "interval": 70, + "unicode": true, + "frames": [ + "✶", + "✸", + "✹", + "✺", + "✹", + "✷" + ] + }, + "star2": { + "interval": 80, + "unicode": false, + "frames": [ + "+", + "x", + "*" + ] + }, + "flip": { + "interval": 70, + "unicode": false, + "frames": [ + "_", + "_", + "_", + "-", + "`", + "`", + "'", + "´", + "-", + "_", + "_", + "_" + ] + }, + "hamburger": { + "interval": 100, + "unicode": true, + "frames": [ + "☱", + "☲", + "☴" + ] + }, + "growVertical": { + "interval": 120, + "unicode": true, + "frames": [ + "▁", + "▃", + "▄", + "▅", + "▆", + "▇", + "▆", + "▅", + "▄", + "▃" + ] + }, + "growHorizontal": { + "interval": 120, + "unicode": true, + "frames": [ + "▏", + "▎", + "▍", + "▌", + "▋", + "▊", + "▉", + "▊", + "▋", + "▌", + "▍", + "▎" + ] + }, + "balloon": { + "interval": 140, + "unicode": false, + "frames": [ + " ", + ".", + "o", + "O", + "@", + "*", + " " + ] + }, + "balloon2": { + "interval": 120, + "unicode": false, + "frames": [ + ".", + "o", + "O", + "°", + "O", + "o", + "." + ] + }, + "noise": { + "interval": 100, + "unicode": true, + "frames": [ + "▓", + "▒", + "░" + ] + }, + "bounce": { + "interval": 120, + "unicode": true, + "frames": [ + "⠁", + "⠂", + "⠄", + "⠂" + ] + }, + "boxBounce": { + "interval": 120, + "unicode": true, + "frames": [ + "▖", + "▘", + "▝", + "▗" + ] + }, + "boxBounce2": { + "interval": 100, + "unicode": true, + "frames": [ + "▌", + "▀", + "▐", + "▄" + ] + }, + "triangle": { + "interval": 50, + "unicode": true, + "frames": [ + "◢", + "◣", + "◤", + "◥" + ] + }, + "arc": { + "interval": 100, + "unicode": true, + "frames": [ + "◜", + "◠", + "◝", + "◞", + "◡", + "◟" + ] + }, + "circle": { + "interval": 120, + "unicode": true, + "frames": [ + "◡", + "⊙", + "◠" + ] + }, + "squareCorners": { + "interval": 180, + "unicode": true, + "frames": [ + "◰", + "◳", + "◲", + "◱" + ] + }, + "circleQuarters": { + "interval": 120, + "unicode": true, + "frames": [ + "◴", + "◷", + "◶", + "◵" + ] + }, + "circleHalves": { + "interval": 50, + "unicode": true, + "frames": [ + "◐", + "◓", + "◑", + "◒" + ] + }, + "squish": { + "interval": 100, + "unicode": true, + "frames": [ + "╫", + "╪" + ] + }, + "toggle": { + "interval": 250, + "unicode": true, + "frames": [ + "⊶", + "⊷" + ] + }, + "toggle2": { + "interval": 80, + "unicode": true, + "frames": [ + "▫", + "▪" + ] + }, + "toggle3": { + "interval": 120, + "unicode": true, + "frames": [ + "□", + "■" + ] + }, + "toggle4": { + "interval": 100, + "unicode": true, + "frames": [ + "■", + "□", + "▪", + "▫" + ] + }, + "toggle5": { + "interval": 100, + "unicode": true, + "frames": [ + "▮", + "▯" + ] + }, + "toggle6": { + "interval": 300, + "unicode": true, + "frames": [ + "ဝ", + "၀" + ] + }, + "toggle7": { + "interval": 80, + "unicode": true, + "frames": [ + "⦾", + "⦿" + ] + }, + "toggle8": { + "interval": 100, + "unicode": true, + "frames": [ + "◍", + "◌" + ] + }, + "toggle9": { + "interval": 100, + "unicode": true, + "frames": [ + "◉", + "◎" + ] + }, + "toggle10": { + "interval": 100, + "unicode": true, + "frames": [ + "㊂", + "㊀", + "㊁" + ] + }, + "toggle11": { + "interval": 50, + "unicode": true, + "frames": [ + "⧇", + "⧆" + ] + }, + "toggle12": { + "interval": 120, + "unicode": true, + "frames": [ + "☗", + "☖" + ] + }, + "toggle13": { + "interval": 80, + "unicode": false, + "frames": [ + "=", + "*", + "-" + ] + }, + "arrow": { + "interval": 100, + "unicode": true, + "frames": [ + "←", + "↖", + "↑", + "↗", + "→", + "↘", + "↓", + "↙" + ] + }, + "arrow2": { + "interval": 80, + "unicode": true, + "frames": [ + "⬆️ ", + "↗️ ", + "➡️ ", + "↘️ ", + "⬇️ ", + "↙️ ", + "⬅️ ", + "↖️ " + ] + }, + "arrow3": { + "interval": 120, + "unicode": true, + "frames": [ + "▹▹▹▹▹", + "▸▹▹▹▹", + "▹▸▹▹▹", + "▹▹▸▹▹", + "▹▹▹▸▹", + "▹▹▹▹▸" + ] + }, + "bouncingBar": { + "interval": 80, + "unicode": true, + "frames": [ + "[ ]", + "[= ]", + "[== ]", + "[=== ]", + "[ ===]", + "[ ==]", + "[ =]", + "[ ]", + "[ =]", + "[ ==]", + "[ ===]", + "[====]", + "[=== ]", + "[== ]", + "[= ]" + ] + }, + "bouncingBall": { + "interval": 80, + "unicode": true, + "frames": [ + "( ● )", + "( ● )", + "( ● )", + "( ● )", + "( ●)", + "( ● )", + "( ● )", + "( ● )", + "( ● )", + "(● )" + ] + }, + "smiley": { + "interval": 200, + "unicode": true, + "frames": [ + "😄 ", + "😝 " + ] + }, + "monkey": { + "interval": 300, + "unicode": true, + "frames": [ + "🙈 ", + "🙈 ", + "🙉 ", + "🙊 " + ] + }, + "hearts": { + "interval": 100, + "unicode": true, + "frames": [ + "💛 ", + "💙 ", + "💜 ", + "💚 ", + "❤️ " + ] + }, + "clock": { + "interval": 100, + "unicode": true, + "frames": [ + "🕛 ", + "🕐 ", + "🕑 ", + "🕒 ", + "🕓 ", + "🕔 ", + "🕕 ", + "🕖 ", + "🕗 ", + "🕘 ", + "🕙 ", + "🕚 " + ] + }, + "earth": { + "interval": 180, + "unicode": true, + "frames": [ + "🌍 ", + "🌎 ", + "🌏 " + ] + }, + "material": { + "interval": 17, + "unicode": true, + "frames": [ + "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "███████▁▁▁▁▁▁▁▁▁▁▁▁▁", + "████████▁▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "██████████▁▁▁▁▁▁▁▁▁▁", + "███████████▁▁▁▁▁▁▁▁▁", + "█████████████▁▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁▁██████████████▁▁▁▁", + "▁▁▁██████████████▁▁▁", + "▁▁▁▁█████████████▁▁▁", + "▁▁▁▁██████████████▁▁", + "▁▁▁▁██████████████▁▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁▁██████████████", + "▁▁▁▁▁▁██████████████", + "▁▁▁▁▁▁▁█████████████", + "▁▁▁▁▁▁▁█████████████", + "▁▁▁▁▁▁▁▁████████████", + "▁▁▁▁▁▁▁▁████████████", + "▁▁▁▁▁▁▁▁▁███████████", + "▁▁▁▁▁▁▁▁▁███████████", + "▁▁▁▁▁▁▁▁▁▁██████████", + "▁▁▁▁▁▁▁▁▁▁██████████", + "▁▁▁▁▁▁▁▁▁▁▁▁████████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "████████▁▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "███████████▁▁▁▁▁▁▁▁▁", + "████████████▁▁▁▁▁▁▁▁", + "████████████▁▁▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁▁▁█████████████▁▁▁▁", + "▁▁▁▁▁████████████▁▁▁", + "▁▁▁▁▁████████████▁▁▁", + "▁▁▁▁▁▁███████████▁▁▁", + "▁▁▁▁▁▁▁▁█████████▁▁▁", + "▁▁▁▁▁▁▁▁█████████▁▁▁", + "▁▁▁▁▁▁▁▁▁█████████▁▁", + "▁▁▁▁▁▁▁▁▁█████████▁▁", + "▁▁▁▁▁▁▁▁▁▁█████████▁", + "▁▁▁▁▁▁▁▁▁▁▁████████▁", + "▁▁▁▁▁▁▁▁▁▁▁████████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁███████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁███████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁" + ] + }, + "moon": { + "interval": 80, + "unicode": true, + "frames": [ + "🌑 ", + "🌒 ", + "🌓 ", + "🌔 ", + "🌕 ", + "🌖 ", + "🌗 ", + "🌘 " + ] + }, + "runner": { + "interval": 140, + "unicode": true, + "frames": [ + "🚶 ", + "🏃 " + ] + }, + "pong": { + "interval": 80, + "unicode": true, + "frames": [ + "▐⠂ ▌", + "▐⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂▌", + "▐ ⠠▌", + "▐ ⡀▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐⠠ ▌" + ] + }, + "shark": { + "interval": 120, + "unicode": true, + "frames": [ + "▐|\\____________▌", + "▐_|\\___________▌", + "▐__|\\__________▌", + "▐___|\\_________▌", + "▐____|\\________▌", + "▐_____|\\_______▌", + "▐______|\\______▌", + "▐_______|\\_____▌", + "▐________|\\____▌", + "▐_________|\\___▌", + "▐__________|\\__▌", + "▐___________|\\_▌", + "▐____________|\\▌", + "▐____________/|▌", + "▐___________/|_▌", + "▐__________/|__▌", + "▐_________/|___▌", + "▐________/|____▌", + "▐_______/|_____▌", + "▐______/|______▌", + "▐_____/|_______▌", + "▐____/|________▌", + "▐___/|_________▌", + "▐__/|__________▌", + "▐_/|___________▌", + "▐/|____________▌" + ] + }, + "dqpb": { + "interval": 100, + "unicode": false, + "frames": [ + "d", + "q", + "p", + "b" + ] + }, + "weather": { + "interval": 100, + "unicode": true, + "frames": [ + "☀️ ", + "☀️ ", + "☀️ ", + "🌤 ", + "⛅️ ", + "🌥 ", + "☁️ ", + "🌧 ", + "🌨 ", + "🌧 ", + "🌨 ", + "🌧 ", + "🌨 ", + "⛈ ", + "🌨 ", + "🌧 ", + "🌨 ", + "☁️ ", + "🌥 ", + "⛅️ ", + "🌤 ", + "☀️ ", + "☀️ " + ] + }, + "christmas": { + "interval": 400, + "unicode": true, + "frames": [ + "🌲", + "🎄" + ] + }, + "grenade": { + "interval": 80, + "unicode": true, + "frames": [ + "، ", + "′ ", + " ´ ", + " ‾ ", + " ⸌", + " ⸊", + " |", + " ⁎", + " ⁕", + " ෴ ", + " ⁓", + " ", + " ", + " " + ] + }, + "point": { + "interval": 125, + "unicode": true, + "frames": [ + "∙∙∙", + "●∙∙", + "∙●∙", + "∙∙●", + "∙∙∙" + ] + }, + "layer": { + "interval": 150, + "unicode": true, + "frames": [ + "-", + "=", + "≡" + ] + }, + "betaWave": { + "interval": 80, + "unicode": true, + "frames": [ + "ρββββββ", + "βρβββββ", + "ββρββββ", + "βββρβββ", + "ββββρββ", + "βββββρβ", + "ββββββρ" + ] + }, + "aesthetic": { + "interval": 80, + "unicode": true, + "frames": [ + "▰▱▱▱▱▱▱", + "▰▰▱▱▱▱▱", + "▰▰▰▱▱▱▱", + "▰▰▰▰▱▱▱", + "▰▰▰▰▰▱▱", + "▰▰▰▰▰▰▱", + "▰▰▰▰▰▰▰", + "▰▱▱▱▱▱▱" + ] + } +} \ No newline at end of file diff --git a/resources/scripts/Generator/Data/spinners_default.json b/resources/scripts/Generator/Data/spinners_default.json new file mode 100644 index 0000000..e003021 --- /dev/null +++ b/resources/scripts/Generator/Data/spinners_default.json @@ -0,0 +1,30 @@ +{ + "Default": { + "interval": 100, + "unicode": true, + "frames": [ + "⣷", + "⣯", + "⣟", + "⡿", + "⢿", + "⣻", + "⣽", + "⣾" + ] + }, + "Ascii": { + "interval": 100, + "unicode": true, + "frames": [ + "-", + "\\", + "|", + "/", + "-", + "\\", + "|", + "/" + ] + } +} \ No newline at end of file diff --git a/resources/scripts/Generator/Generator.csproj b/resources/scripts/Generator/Generator.csproj index eef5405..c20e1b6 100644 --- a/resources/scripts/Generator/Generator.csproj +++ b/resources/scripts/Generator/Generator.csproj @@ -15,6 +15,9 @@ Always + + Always + Always @@ -24,6 +27,9 @@ Always + + Always + Always diff --git a/resources/scripts/Generator/Models/Spinner.cs b/resources/scripts/Generator/Models/Spinner.cs new file mode 100644 index 0000000..78f406d --- /dev/null +++ b/resources/scripts/Generator/Models/Spinner.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Linq; +using Humanizer; +using Newtonsoft.Json; + +namespace Generator.Models +{ + public sealed class Spinner + { + public string Name { get; set; } + public string NormalizedName { get; set; } + public int Interval { get; set; } + public bool Unicode { get; set; } + public List Frames { get; set; } + + public static IEnumerable Parse(string json) + { + var data = JsonConvert.DeserializeObject>(json); + foreach (var item in data) + { + item.Value.Name = item.Key; + item.Value.NormalizedName = item.Value.Name.Pascalize(); + + var frames = item.Value.Frames; + item.Value.Frames = frames.Select(f => f.Replace("\\", "\\\\")).ToList(); + } + + return data.Values; + } + } +} diff --git a/resources/scripts/Generator/Program.cs b/resources/scripts/Generator/Program.cs index 0bf6ece..29c4177 100644 --- a/resources/scripts/Generator/Program.cs +++ b/resources/scripts/Generator/Program.cs @@ -12,6 +12,7 @@ namespace Generator { config.AddCommand("colors"); config.AddCommand("emoji"); + config.AddCommand("spinners"); }); return app.Run(args); diff --git a/resources/scripts/Generator/Templates/Color.Generated.template b/resources/scripts/Generator/Templates/Color.Generated.template index 7f3d18f..aaf51da 100644 --- a/resources/scripts/Generator/Templates/Color.Generated.template +++ b/resources/scripts/Generator/Templates/Color.Generated.template @@ -2,6 +2,7 @@ // // This code was generated by a tool. // Generated {{ date.now | date.to_string `%F %R` }} +// Generated from https://github.com/sindresorhus/cli-spinners/blob/master/spinners.json // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/resources/scripts/Generator/Templates/ProgressSpinner.Generated.template b/resources/scripts/Generator/Templates/ProgressSpinner.Generated.template new file mode 100644 index 0000000..340199d --- /dev/null +++ b/resources/scripts/Generator/Templates/ProgressSpinner.Generated.template @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Generated {{ date.now | date.to_string `%F %R` }} +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; + +namespace Spectre.Console +{ + public abstract partial class ProgressSpinner + { + {{~ for spinner in spinners ~}} + private sealed class {{ spinner.normalized_name }}Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds({{ spinner.interval }}); + public override bool IsUnicode => {{ spinner.unicode }}; + public override IReadOnlyList Frames => new List + { + {{~ for frame in spinner.frames ~}} + "{{ frame }}", + {{~ end ~}} + }; + } + {{~ end ~}} + + /// + /// Contains all predefined spinners. + /// + public static class Known + { + {{~ for spinner in spinners ~}} + /// + /// Gets the "{{ spinner.name }}" spinner. + /// + public static ProgressSpinner {{ spinner.normalized_name }} { get; } = new {{ spinner.normalized_name }}Spinner(); + {{~ end ~}} + } + } +} diff --git a/src/Spectre.Console/Progress/Columns/SpinnerColumn.cs b/src/Spectre.Console/Progress/Columns/SpinnerColumn.cs index f7f51d1..ab265b0 100644 --- a/src/Spectre.Console/Progress/Columns/SpinnerColumn.cs +++ b/src/Spectre.Console/Progress/Columns/SpinnerColumn.cs @@ -1,4 +1,6 @@ using System; +using System.Linq; +using Spectre.Console.Internal; using Spectre.Console.Rendering; namespace Spectre.Console @@ -11,8 +13,8 @@ namespace Spectre.Console private const string ACCUMULATED = "SPINNER_ACCUMULATED"; private const string INDEX = "SPINNER_INDEX"; - private readonly string _ansiSequence = "⣷⣯⣟⡿⢿⣻⣽⣾"; - private readonly string _asciiSequence = "-\\|/-\\|/"; + private readonly ProgressSpinner _spinner; + private int? _maxLength; /// protected internal override int? ColumnWidth => 1; @@ -25,26 +27,48 @@ namespace Spectre.Console /// public Style Style { get; set; } = new Style(foreground: Color.Yellow); + /// + /// Initializes a new instance of the class. + /// + public SpinnerColumn() + : this(ProgressSpinner.Known.Default) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The spinner to use. + public SpinnerColumn(ProgressSpinner spinner) + { + _spinner = spinner ?? throw new ArgumentNullException(nameof(spinner)); + } + /// public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime) { + var useAscii = (context.LegacyConsole || !context.Unicode) && _spinner.IsUnicode; + var spinner = useAscii ? ProgressSpinner.Known.Ascii : _spinner; + if (!task.IsStarted || task.IsFinished) { - return new Markup(" "); + if (_maxLength == null) + { + _maxLength = _spinner.Frames.Max(frame => Cell.GetCellLength(context, frame)); + } + + return new Markup(new string(' ', _maxLength.Value)); } var accumulated = task.State.Update(ACCUMULATED, acc => acc + deltaTime.TotalMilliseconds); - if (accumulated >= 100) + if (accumulated >= _spinner.Interval.TotalMilliseconds) { task.State.Update(ACCUMULATED, _ => 0); task.State.Update(INDEX, index => index + 1); } - var useAscii = context.LegacyConsole || !context.Unicode; - var sequence = useAscii ? _asciiSequence : _ansiSequence; - var index = task.State.Get(INDEX); - return new Markup(sequence[index % sequence.Length].ToString(), Style ?? Style.Plain); + return new Markup(spinner.Frames[index % spinner.Frames.Count], Style ?? Style.Plain); } } } diff --git a/src/Spectre.Console/Progress/Progress.cs b/src/Spectre.Console/Progress/Progress.cs index 8fde020..27e5c2b 100644 --- a/src/Spectre.Console/Progress/Progress.cs +++ b/src/Spectre.Console/Progress/Progress.cs @@ -26,6 +26,12 @@ namespace Spectre.Console /// public bool AutoClear { get; set; } + /// + /// Gets or sets the refresh rate if AutoRefresh is enabled. + /// Defaults to 10 times/second. + /// + public TimeSpan RefreshRate { get; set; } = TimeSpan.FromMilliseconds(100); + internal List Columns { get; } /// @@ -110,7 +116,7 @@ namespace Spectre.Console if (interactive) { var columns = new List(Columns); - return new InteractiveProgressRenderer(_console, columns); + return new InteractiveProgressRenderer(_console, columns, RefreshRate); } else { diff --git a/src/Spectre.Console/Progress/ProgressSpinner.Generated.cs b/src/Spectre.Console/Progress/ProgressSpinner.Generated.cs new file mode 100644 index 0000000..13cc828 --- /dev/null +++ b/src/Spectre.Console/Progress/ProgressSpinner.Generated.cs @@ -0,0 +1,1870 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Generated 2020-12-05 10:31 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; + +namespace Spectre.Console +{ + public abstract partial class ProgressSpinner + { + private sealed class DotsSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⠋", + "⠙", + "⠹", + "⠸", + "⠼", + "⠴", + "⠦", + "⠧", + "⠇", + "⠏", + }; + } + private sealed class Dots2Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⣾", + "⣽", + "⣻", + "⢿", + "⡿", + "⣟", + "⣯", + "⣷", + }; + } + private sealed class Dots3Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⠋", + "⠙", + "⠚", + "⠞", + "⠖", + "⠦", + "⠴", + "⠲", + "⠳", + "⠓", + }; + } + private sealed class Dots4Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⠄", + "⠆", + "⠇", + "⠋", + "⠙", + "⠸", + "⠰", + "⠠", + "⠰", + "⠸", + "⠙", + "⠋", + "⠇", + "⠆", + }; + } + private sealed class Dots5Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⠋", + "⠙", + "⠚", + "⠒", + "⠂", + "⠂", + "⠒", + "⠲", + "⠴", + "⠦", + "⠖", + "⠒", + "⠐", + "⠐", + "⠒", + "⠓", + "⠋", + }; + } + private sealed class Dots6Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⠁", + "⠉", + "⠙", + "⠚", + "⠒", + "⠂", + "⠂", + "⠒", + "⠲", + "⠴", + "⠤", + "⠄", + "⠄", + "⠤", + "⠴", + "⠲", + "⠒", + "⠂", + "⠂", + "⠒", + "⠚", + "⠙", + "⠉", + "⠁", + }; + } + private sealed class Dots7Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⠈", + "⠉", + "⠋", + "⠓", + "⠒", + "⠐", + "⠐", + "⠒", + "⠖", + "⠦", + "⠤", + "⠠", + "⠠", + "⠤", + "⠦", + "⠖", + "⠒", + "⠐", + "⠐", + "⠒", + "⠓", + "⠋", + "⠉", + "⠈", + }; + } + private sealed class Dots8Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⠁", + "⠁", + "⠉", + "⠙", + "⠚", + "⠒", + "⠂", + "⠂", + "⠒", + "⠲", + "⠴", + "⠤", + "⠄", + "⠄", + "⠤", + "⠠", + "⠠", + "⠤", + "⠦", + "⠖", + "⠒", + "⠐", + "⠐", + "⠒", + "⠓", + "⠋", + "⠉", + "⠈", + "⠈", + }; + } + private sealed class Dots9Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⢹", + "⢺", + "⢼", + "⣸", + "⣇", + "⡧", + "⡗", + "⡏", + }; + } + private sealed class Dots10Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⢄", + "⢂", + "⢁", + "⡁", + "⡈", + "⡐", + "⡠", + }; + } + private sealed class Dots11Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⠁", + "⠂", + "⠄", + "⡀", + "⢀", + "⠠", + "⠐", + "⠈", + }; + } + private sealed class Dots12Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⢀⠀", + "⡀⠀", + "⠄⠀", + "⢂⠀", + "⡂⠀", + "⠅⠀", + "⢃⠀", + "⡃⠀", + "⠍⠀", + "⢋⠀", + "⡋⠀", + "⠍⠁", + "⢋⠁", + "⡋⠁", + "⠍⠉", + "⠋⠉", + "⠋⠉", + "⠉⠙", + "⠉⠙", + "⠉⠩", + "⠈⢙", + "⠈⡙", + "⢈⠩", + "⡀⢙", + "⠄⡙", + "⢂⠩", + "⡂⢘", + "⠅⡘", + "⢃⠨", + "⡃⢐", + "⠍⡐", + "⢋⠠", + "⡋⢀", + "⠍⡁", + "⢋⠁", + "⡋⠁", + "⠍⠉", + "⠋⠉", + "⠋⠉", + "⠉⠙", + "⠉⠙", + "⠉⠩", + "⠈⢙", + "⠈⡙", + "⠈⠩", + "⠀⢙", + "⠀⡙", + "⠀⠩", + "⠀⢘", + "⠀⡘", + "⠀⠨", + "⠀⢐", + "⠀⡐", + "⠀⠠", + "⠀⢀", + "⠀⡀", + }; + } + private sealed class Dots8BitSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⠀", + "⠁", + "⠂", + "⠃", + "⠄", + "⠅", + "⠆", + "⠇", + "⡀", + "⡁", + "⡂", + "⡃", + "⡄", + "⡅", + "⡆", + "⡇", + "⠈", + "⠉", + "⠊", + "⠋", + "⠌", + "⠍", + "⠎", + "⠏", + "⡈", + "⡉", + "⡊", + "⡋", + "⡌", + "⡍", + "⡎", + "⡏", + "⠐", + "⠑", + "⠒", + "⠓", + "⠔", + "⠕", + "⠖", + "⠗", + "⡐", + "⡑", + "⡒", + "⡓", + "⡔", + "⡕", + "⡖", + "⡗", + "⠘", + "⠙", + "⠚", + "⠛", + "⠜", + "⠝", + "⠞", + "⠟", + "⡘", + "⡙", + "⡚", + "⡛", + "⡜", + "⡝", + "⡞", + "⡟", + "⠠", + "⠡", + "⠢", + "⠣", + "⠤", + "⠥", + "⠦", + "⠧", + "⡠", + "⡡", + "⡢", + "⡣", + "⡤", + "⡥", + "⡦", + "⡧", + "⠨", + "⠩", + "⠪", + "⠫", + "⠬", + "⠭", + "⠮", + "⠯", + "⡨", + "⡩", + "⡪", + "⡫", + "⡬", + "⡭", + "⡮", + "⡯", + "⠰", + "⠱", + "⠲", + "⠳", + "⠴", + "⠵", + "⠶", + "⠷", + "⡰", + "⡱", + "⡲", + "⡳", + "⡴", + "⡵", + "⡶", + "⡷", + "⠸", + "⠹", + "⠺", + "⠻", + "⠼", + "⠽", + "⠾", + "⠿", + "⡸", + "⡹", + "⡺", + "⡻", + "⡼", + "⡽", + "⡾", + "⡿", + "⢀", + "⢁", + "⢂", + "⢃", + "⢄", + "⢅", + "⢆", + "⢇", + "⣀", + "⣁", + "⣂", + "⣃", + "⣄", + "⣅", + "⣆", + "⣇", + "⢈", + "⢉", + "⢊", + "⢋", + "⢌", + "⢍", + "⢎", + "⢏", + "⣈", + "⣉", + "⣊", + "⣋", + "⣌", + "⣍", + "⣎", + "⣏", + "⢐", + "⢑", + "⢒", + "⢓", + "⢔", + "⢕", + "⢖", + "⢗", + "⣐", + "⣑", + "⣒", + "⣓", + "⣔", + "⣕", + "⣖", + "⣗", + "⢘", + "⢙", + "⢚", + "⢛", + "⢜", + "⢝", + "⢞", + "⢟", + "⣘", + "⣙", + "⣚", + "⣛", + "⣜", + "⣝", + "⣞", + "⣟", + "⢠", + "⢡", + "⢢", + "⢣", + "⢤", + "⢥", + "⢦", + "⢧", + "⣠", + "⣡", + "⣢", + "⣣", + "⣤", + "⣥", + "⣦", + "⣧", + "⢨", + "⢩", + "⢪", + "⢫", + "⢬", + "⢭", + "⢮", + "⢯", + "⣨", + "⣩", + "⣪", + "⣫", + "⣬", + "⣭", + "⣮", + "⣯", + "⢰", + "⢱", + "⢲", + "⢳", + "⢴", + "⢵", + "⢶", + "⢷", + "⣰", + "⣱", + "⣲", + "⣳", + "⣴", + "⣵", + "⣶", + "⣷", + "⢸", + "⢹", + "⢺", + "⢻", + "⢼", + "⢽", + "⢾", + "⢿", + "⣸", + "⣹", + "⣺", + "⣻", + "⣼", + "⣽", + "⣾", + "⣿", + }; + } + private sealed class LineSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(130); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + "-", + "\\", + "|", + "/", + }; + } + private sealed class Line2Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + "⠂", + "-", + "–", + "—", + "–", + "-", + }; + } + private sealed class PipeSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + "┤", + "┘", + "┴", + "└", + "├", + "┌", + "┬", + "┐", + }; + } + private sealed class SimpleDotsSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(400); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + ". ", + ".. ", + "...", + " ", + }; + } + private sealed class SimpleDotsScrollingSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(200); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + ". ", + ".. ", + "...", + " ..", + " .", + " ", + }; + } + private sealed class StarSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(70); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "✶", + "✸", + "✹", + "✺", + "✹", + "✷", + }; + } + private sealed class Star2Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + "+", + "x", + "*", + }; + } + private sealed class FlipSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(70); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + "_", + "_", + "_", + "-", + "`", + "`", + "'", + "´", + "-", + "_", + "_", + "_", + }; + } + private sealed class HamburgerSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "☱", + "☲", + "☴", + }; + } + private sealed class GrowVerticalSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▁", + "▃", + "▄", + "▅", + "▆", + "▇", + "▆", + "▅", + "▄", + "▃", + }; + } + private sealed class GrowHorizontalSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▏", + "▎", + "▍", + "▌", + "▋", + "▊", + "▉", + "▊", + "▋", + "▌", + "▍", + "▎", + }; + } + private sealed class BalloonSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(140); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + " ", + ".", + "o", + "O", + "@", + "*", + " ", + }; + } + private sealed class Balloon2Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + ".", + "o", + "O", + "°", + "O", + "o", + ".", + }; + } + private sealed class NoiseSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▓", + "▒", + "░", + }; + } + private sealed class BounceSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⠁", + "⠂", + "⠄", + "⠂", + }; + } + private sealed class BoxBounceSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▖", + "▘", + "▝", + "▗", + }; + } + private sealed class BoxBounce2Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▌", + "▀", + "▐", + "▄", + }; + } + private sealed class TriangleSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(50); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "◢", + "◣", + "◤", + "◥", + }; + } + private sealed class ArcSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "◜", + "◠", + "◝", + "◞", + "◡", + "◟", + }; + } + private sealed class CircleSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "◡", + "⊙", + "◠", + }; + } + private sealed class SquareCornersSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(180); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "◰", + "◳", + "◲", + "◱", + }; + } + private sealed class CircleQuartersSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "◴", + "◷", + "◶", + "◵", + }; + } + private sealed class CircleHalvesSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(50); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "◐", + "◓", + "◑", + "◒", + }; + } + private sealed class SquishSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "╫", + "╪", + }; + } + private sealed class ToggleSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(250); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⊶", + "⊷", + }; + } + private sealed class Toggle2Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▫", + "▪", + }; + } + private sealed class Toggle3Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "□", + "■", + }; + } + private sealed class Toggle4Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "■", + "□", + "▪", + "▫", + }; + } + private sealed class Toggle5Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▮", + "▯", + }; + } + private sealed class Toggle6Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(300); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "ဝ", + "၀", + }; + } + private sealed class Toggle7Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⦾", + "⦿", + }; + } + private sealed class Toggle8Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "◍", + "◌", + }; + } + private sealed class Toggle9Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "◉", + "◎", + }; + } + private sealed class Toggle10Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "㊂", + "㊀", + "㊁", + }; + } + private sealed class Toggle11Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(50); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⧇", + "⧆", + }; + } + private sealed class Toggle12Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "☗", + "☖", + }; + } + private sealed class Toggle13Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + "=", + "*", + "-", + }; + } + private sealed class ArrowSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "←", + "↖", + "↑", + "↗", + "→", + "↘", + "↓", + "↙", + }; + } + private sealed class Arrow2Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⬆️ ", + "↗️ ", + "➡️ ", + "↘️ ", + "⬇️ ", + "↙️ ", + "⬅️ ", + "↖️ ", + }; + } + private sealed class Arrow3Spinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▹▹▹▹▹", + "▸▹▹▹▹", + "▹▸▹▹▹", + "▹▹▸▹▹", + "▹▹▹▸▹", + "▹▹▹▹▸", + }; + } + private sealed class BouncingBarSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "[ ]", + "[= ]", + "[== ]", + "[=== ]", + "[ ===]", + "[ ==]", + "[ =]", + "[ ]", + "[ =]", + "[ ==]", + "[ ===]", + "[====]", + "[=== ]", + "[== ]", + "[= ]", + }; + } + private sealed class BouncingBallSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "( ● )", + "( ● )", + "( ● )", + "( ● )", + "( ●)", + "( ● )", + "( ● )", + "( ● )", + "( ● )", + "(● )", + }; + } + private sealed class SmileySpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(200); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "😄 ", + "😝 ", + }; + } + private sealed class MonkeySpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(300); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "🙈 ", + "🙈 ", + "🙉 ", + "🙊 ", + }; + } + private sealed class HeartsSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "💛 ", + "💙 ", + "💜 ", + "💚 ", + "❤️ ", + }; + } + private sealed class ClockSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "🕛 ", + "🕐 ", + "🕑 ", + "🕒 ", + "🕓 ", + "🕔 ", + "🕕 ", + "🕖 ", + "🕗 ", + "🕘 ", + "🕙 ", + "🕚 ", + }; + } + private sealed class EarthSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(180); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "🌍 ", + "🌎 ", + "🌏 ", + }; + } + private sealed class MaterialSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(17); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "███████▁▁▁▁▁▁▁▁▁▁▁▁▁", + "████████▁▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "██████████▁▁▁▁▁▁▁▁▁▁", + "███████████▁▁▁▁▁▁▁▁▁", + "█████████████▁▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁▁██████████████▁▁▁▁", + "▁▁▁██████████████▁▁▁", + "▁▁▁▁█████████████▁▁▁", + "▁▁▁▁██████████████▁▁", + "▁▁▁▁██████████████▁▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁▁██████████████", + "▁▁▁▁▁▁██████████████", + "▁▁▁▁▁▁▁█████████████", + "▁▁▁▁▁▁▁█████████████", + "▁▁▁▁▁▁▁▁████████████", + "▁▁▁▁▁▁▁▁████████████", + "▁▁▁▁▁▁▁▁▁███████████", + "▁▁▁▁▁▁▁▁▁███████████", + "▁▁▁▁▁▁▁▁▁▁██████████", + "▁▁▁▁▁▁▁▁▁▁██████████", + "▁▁▁▁▁▁▁▁▁▁▁▁████████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "████████▁▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "███████████▁▁▁▁▁▁▁▁▁", + "████████████▁▁▁▁▁▁▁▁", + "████████████▁▁▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁▁▁█████████████▁▁▁▁", + "▁▁▁▁▁████████████▁▁▁", + "▁▁▁▁▁████████████▁▁▁", + "▁▁▁▁▁▁███████████▁▁▁", + "▁▁▁▁▁▁▁▁█████████▁▁▁", + "▁▁▁▁▁▁▁▁█████████▁▁▁", + "▁▁▁▁▁▁▁▁▁█████████▁▁", + "▁▁▁▁▁▁▁▁▁█████████▁▁", + "▁▁▁▁▁▁▁▁▁▁█████████▁", + "▁▁▁▁▁▁▁▁▁▁▁████████▁", + "▁▁▁▁▁▁▁▁▁▁▁████████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁███████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁███████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + }; + } + private sealed class MoonSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "🌑 ", + "🌒 ", + "🌓 ", + "🌔 ", + "🌕 ", + "🌖 ", + "🌗 ", + "🌘 ", + }; + } + private sealed class RunnerSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(140); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "🚶 ", + "🏃 ", + }; + } + private sealed class PongSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▐⠂ ▌", + "▐⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂▌", + "▐ ⠠▌", + "▐ ⡀▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐⠠ ▌", + }; + } + private sealed class SharkSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(120); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▐|\\____________▌", + "▐_|\\___________▌", + "▐__|\\__________▌", + "▐___|\\_________▌", + "▐____|\\________▌", + "▐_____|\\_______▌", + "▐______|\\______▌", + "▐_______|\\_____▌", + "▐________|\\____▌", + "▐_________|\\___▌", + "▐__________|\\__▌", + "▐___________|\\_▌", + "▐____________|\\▌", + "▐____________/|▌", + "▐___________/|_▌", + "▐__________/|__▌", + "▐_________/|___▌", + "▐________/|____▌", + "▐_______/|_____▌", + "▐______/|______▌", + "▐_____/|_______▌", + "▐____/|________▌", + "▐___/|_________▌", + "▐__/|__________▌", + "▐_/|___________▌", + "▐/|____________▌", + }; + } + private sealed class DqpbSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => false; + public override IReadOnlyList Frames => new List + { + "d", + "q", + "p", + "b", + }; + } + private sealed class WeatherSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "☀️ ", + "☀️ ", + "☀️ ", + "🌤 ", + "⛅️ ", + "🌥 ", + "☁️ ", + "🌧 ", + "🌨 ", + "🌧 ", + "🌨 ", + "🌧 ", + "🌨 ", + "⛈ ", + "🌨 ", + "🌧 ", + "🌨 ", + "☁️ ", + "🌥 ", + "⛅️ ", + "🌤 ", + "☀️ ", + "☀️ ", + }; + } + private sealed class ChristmasSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(400); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "🌲", + "🎄", + }; + } + private sealed class GrenadeSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "، ", + "′ ", + " ´ ", + " ‾ ", + " ⸌", + " ⸊", + " |", + " ⁎", + " ⁕", + " ෴ ", + " ⁓", + " ", + " ", + " ", + }; + } + private sealed class PointSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(125); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "∙∙∙", + "●∙∙", + "∙●∙", + "∙∙●", + "∙∙∙", + }; + } + private sealed class LayerSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(150); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "-", + "=", + "≡", + }; + } + private sealed class BetaWaveSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "ρββββββ", + "βρβββββ", + "ββρββββ", + "βββρβββ", + "ββββρββ", + "βββββρβ", + "ββββββρ", + }; + } + private sealed class AestheticSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "▰▱▱▱▱▱▱", + "▰▰▱▱▱▱▱", + "▰▰▰▱▱▱▱", + "▰▰▰▰▱▱▱", + "▰▰▰▰▰▱▱", + "▰▰▰▰▰▰▱", + "▰▰▰▰▰▰▰", + "▰▱▱▱▱▱▱", + }; + } + private sealed class DefaultSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "⣷", + "⣯", + "⣟", + "⡿", + "⢿", + "⣻", + "⣽", + "⣾", + }; + } + private sealed class AsciiSpinner : ProgressSpinner + { + public override TimeSpan Interval => TimeSpan.FromMilliseconds(80); + public override bool IsUnicode => true; + public override IReadOnlyList Frames => new List + { + "-", + "\\", + "|", + "/", + "-", + "\\", + "|", + "/", + }; + } + + /// + /// Contains all predefined spinners. + /// + public static class Known + { + /// + /// Gets the "dots" spinner. + /// + public static ProgressSpinner Dots { get; } = new DotsSpinner(); + /// + /// Gets the "dots2" spinner. + /// + public static ProgressSpinner Dots2 { get; } = new Dots2Spinner(); + /// + /// Gets the "dots3" spinner. + /// + public static ProgressSpinner Dots3 { get; } = new Dots3Spinner(); + /// + /// Gets the "dots4" spinner. + /// + public static ProgressSpinner Dots4 { get; } = new Dots4Spinner(); + /// + /// Gets the "dots5" spinner. + /// + public static ProgressSpinner Dots5 { get; } = new Dots5Spinner(); + /// + /// Gets the "dots6" spinner. + /// + public static ProgressSpinner Dots6 { get; } = new Dots6Spinner(); + /// + /// Gets the "dots7" spinner. + /// + public static ProgressSpinner Dots7 { get; } = new Dots7Spinner(); + /// + /// Gets the "dots8" spinner. + /// + public static ProgressSpinner Dots8 { get; } = new Dots8Spinner(); + /// + /// Gets the "dots9" spinner. + /// + public static ProgressSpinner Dots9 { get; } = new Dots9Spinner(); + /// + /// Gets the "dots10" spinner. + /// + public static ProgressSpinner Dots10 { get; } = new Dots10Spinner(); + /// + /// Gets the "dots11" spinner. + /// + public static ProgressSpinner Dots11 { get; } = new Dots11Spinner(); + /// + /// Gets the "dots12" spinner. + /// + public static ProgressSpinner Dots12 { get; } = new Dots12Spinner(); + /// + /// Gets the "dots8Bit" spinner. + /// + public static ProgressSpinner Dots8Bit { get; } = new Dots8BitSpinner(); + /// + /// Gets the "line" spinner. + /// + public static ProgressSpinner Line { get; } = new LineSpinner(); + /// + /// Gets the "line2" spinner. + /// + public static ProgressSpinner Line2 { get; } = new Line2Spinner(); + /// + /// Gets the "pipe" spinner. + /// + public static ProgressSpinner Pipe { get; } = new PipeSpinner(); + /// + /// Gets the "simpleDots" spinner. + /// + public static ProgressSpinner SimpleDots { get; } = new SimpleDotsSpinner(); + /// + /// Gets the "simpleDotsScrolling" spinner. + /// + public static ProgressSpinner SimpleDotsScrolling { get; } = new SimpleDotsScrollingSpinner(); + /// + /// Gets the "star" spinner. + /// + public static ProgressSpinner Star { get; } = new StarSpinner(); + /// + /// Gets the "star2" spinner. + /// + public static ProgressSpinner Star2 { get; } = new Star2Spinner(); + /// + /// Gets the "flip" spinner. + /// + public static ProgressSpinner Flip { get; } = new FlipSpinner(); + /// + /// Gets the "hamburger" spinner. + /// + public static ProgressSpinner Hamburger { get; } = new HamburgerSpinner(); + /// + /// Gets the "growVertical" spinner. + /// + public static ProgressSpinner GrowVertical { get; } = new GrowVerticalSpinner(); + /// + /// Gets the "growHorizontal" spinner. + /// + public static ProgressSpinner GrowHorizontal { get; } = new GrowHorizontalSpinner(); + /// + /// Gets the "balloon" spinner. + /// + public static ProgressSpinner Balloon { get; } = new BalloonSpinner(); + /// + /// Gets the "balloon2" spinner. + /// + public static ProgressSpinner Balloon2 { get; } = new Balloon2Spinner(); + /// + /// Gets the "noise" spinner. + /// + public static ProgressSpinner Noise { get; } = new NoiseSpinner(); + /// + /// Gets the "bounce" spinner. + /// + public static ProgressSpinner Bounce { get; } = new BounceSpinner(); + /// + /// Gets the "boxBounce" spinner. + /// + public static ProgressSpinner BoxBounce { get; } = new BoxBounceSpinner(); + /// + /// Gets the "boxBounce2" spinner. + /// + public static ProgressSpinner BoxBounce2 { get; } = new BoxBounce2Spinner(); + /// + /// Gets the "triangle" spinner. + /// + public static ProgressSpinner Triangle { get; } = new TriangleSpinner(); + /// + /// Gets the "arc" spinner. + /// + public static ProgressSpinner Arc { get; } = new ArcSpinner(); + /// + /// Gets the "circle" spinner. + /// + public static ProgressSpinner Circle { get; } = new CircleSpinner(); + /// + /// Gets the "squareCorners" spinner. + /// + public static ProgressSpinner SquareCorners { get; } = new SquareCornersSpinner(); + /// + /// Gets the "circleQuarters" spinner. + /// + public static ProgressSpinner CircleQuarters { get; } = new CircleQuartersSpinner(); + /// + /// Gets the "circleHalves" spinner. + /// + public static ProgressSpinner CircleHalves { get; } = new CircleHalvesSpinner(); + /// + /// Gets the "squish" spinner. + /// + public static ProgressSpinner Squish { get; } = new SquishSpinner(); + /// + /// Gets the "toggle" spinner. + /// + public static ProgressSpinner Toggle { get; } = new ToggleSpinner(); + /// + /// Gets the "toggle2" spinner. + /// + public static ProgressSpinner Toggle2 { get; } = new Toggle2Spinner(); + /// + /// Gets the "toggle3" spinner. + /// + public static ProgressSpinner Toggle3 { get; } = new Toggle3Spinner(); + /// + /// Gets the "toggle4" spinner. + /// + public static ProgressSpinner Toggle4 { get; } = new Toggle4Spinner(); + /// + /// Gets the "toggle5" spinner. + /// + public static ProgressSpinner Toggle5 { get; } = new Toggle5Spinner(); + /// + /// Gets the "toggle6" spinner. + /// + public static ProgressSpinner Toggle6 { get; } = new Toggle6Spinner(); + /// + /// Gets the "toggle7" spinner. + /// + public static ProgressSpinner Toggle7 { get; } = new Toggle7Spinner(); + /// + /// Gets the "toggle8" spinner. + /// + public static ProgressSpinner Toggle8 { get; } = new Toggle8Spinner(); + /// + /// Gets the "toggle9" spinner. + /// + public static ProgressSpinner Toggle9 { get; } = new Toggle9Spinner(); + /// + /// Gets the "toggle10" spinner. + /// + public static ProgressSpinner Toggle10 { get; } = new Toggle10Spinner(); + /// + /// Gets the "toggle11" spinner. + /// + public static ProgressSpinner Toggle11 { get; } = new Toggle11Spinner(); + /// + /// Gets the "toggle12" spinner. + /// + public static ProgressSpinner Toggle12 { get; } = new Toggle12Spinner(); + /// + /// Gets the "toggle13" spinner. + /// + public static ProgressSpinner Toggle13 { get; } = new Toggle13Spinner(); + /// + /// Gets the "arrow" spinner. + /// + public static ProgressSpinner Arrow { get; } = new ArrowSpinner(); + /// + /// Gets the "arrow2" spinner. + /// + public static ProgressSpinner Arrow2 { get; } = new Arrow2Spinner(); + /// + /// Gets the "arrow3" spinner. + /// + public static ProgressSpinner Arrow3 { get; } = new Arrow3Spinner(); + /// + /// Gets the "bouncingBar" spinner. + /// + public static ProgressSpinner BouncingBar { get; } = new BouncingBarSpinner(); + /// + /// Gets the "bouncingBall" spinner. + /// + public static ProgressSpinner BouncingBall { get; } = new BouncingBallSpinner(); + /// + /// Gets the "smiley" spinner. + /// + public static ProgressSpinner Smiley { get; } = new SmileySpinner(); + /// + /// Gets the "monkey" spinner. + /// + public static ProgressSpinner Monkey { get; } = new MonkeySpinner(); + /// + /// Gets the "hearts" spinner. + /// + public static ProgressSpinner Hearts { get; } = new HeartsSpinner(); + /// + /// Gets the "clock" spinner. + /// + public static ProgressSpinner Clock { get; } = new ClockSpinner(); + /// + /// Gets the "earth" spinner. + /// + public static ProgressSpinner Earth { get; } = new EarthSpinner(); + /// + /// Gets the "material" spinner. + /// + public static ProgressSpinner Material { get; } = new MaterialSpinner(); + /// + /// Gets the "moon" spinner. + /// + public static ProgressSpinner Moon { get; } = new MoonSpinner(); + /// + /// Gets the "runner" spinner. + /// + public static ProgressSpinner Runner { get; } = new RunnerSpinner(); + /// + /// Gets the "pong" spinner. + /// + public static ProgressSpinner Pong { get; } = new PongSpinner(); + /// + /// Gets the "shark" spinner. + /// + public static ProgressSpinner Shark { get; } = new SharkSpinner(); + /// + /// Gets the "dqpb" spinner. + /// + public static ProgressSpinner Dqpb { get; } = new DqpbSpinner(); + /// + /// Gets the "weather" spinner. + /// + public static ProgressSpinner Weather { get; } = new WeatherSpinner(); + /// + /// Gets the "christmas" spinner. + /// + public static ProgressSpinner Christmas { get; } = new ChristmasSpinner(); + /// + /// Gets the "grenade" spinner. + /// + public static ProgressSpinner Grenade { get; } = new GrenadeSpinner(); + /// + /// Gets the "point" spinner. + /// + public static ProgressSpinner Point { get; } = new PointSpinner(); + /// + /// Gets the "layer" spinner. + /// + public static ProgressSpinner Layer { get; } = new LayerSpinner(); + /// + /// Gets the "betaWave" spinner. + /// + public static ProgressSpinner BetaWave { get; } = new BetaWaveSpinner(); + /// + /// Gets the "aesthetic" spinner. + /// + public static ProgressSpinner Aesthetic { get; } = new AestheticSpinner(); + /// + /// Gets the "Default" spinner. + /// + public static ProgressSpinner Default { get; } = new DefaultSpinner(); + /// + /// Gets the "Ascii" spinner. + /// + public static ProgressSpinner Ascii { get; } = new AsciiSpinner(); + } + } +} diff --git a/src/Spectre.Console/Progress/ProgressSpinner.cs b/src/Spectre.Console/Progress/ProgressSpinner.cs new file mode 100644 index 0000000..e231216 --- /dev/null +++ b/src/Spectre.Console/Progress/ProgressSpinner.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace Spectre.Console +{ + /// + /// Represents a spinner used in a . + /// + public abstract partial class ProgressSpinner + { + /// + /// Gets the update interval for the spinner. + /// + public abstract TimeSpan Interval { get; } + + /// + /// Gets a value indicating whether or not the spinner + /// uses Unicode characters. + /// + public abstract bool IsUnicode { get; } + + /// + /// Gets the spinner frames. + /// + public abstract IReadOnlyList Frames { get; } + } +} diff --git a/src/Spectre.Console/Progress/Renderers/InteractiveProgressRenderer.cs b/src/Spectre.Console/Progress/Renderers/InteractiveProgressRenderer.cs index ffafd63..85c0f1c 100644 --- a/src/Spectre.Console/Progress/Renderers/InteractiveProgressRenderer.cs +++ b/src/Spectre.Console/Progress/Renderers/InteractiveProgressRenderer.cs @@ -15,9 +15,9 @@ namespace Spectre.Console.Internal private readonly Stopwatch _stopwatch; private TimeSpan _lastUpdate; - public override TimeSpan RefreshRate => TimeSpan.FromMilliseconds(100); + public override TimeSpan RefreshRate { get; } - public InteractiveProgressRenderer(IAnsiConsole console, List columns) + public InteractiveProgressRenderer(IAnsiConsole console, List columns, TimeSpan refreshRate) { _console = console ?? throw new ArgumentNullException(nameof(console)); _columns = columns ?? throw new ArgumentNullException(nameof(columns)); @@ -25,6 +25,8 @@ namespace Spectre.Console.Internal _lock = new object(); _stopwatch = new Stopwatch(); _lastUpdate = TimeSpan.Zero; + + RefreshRate = refreshRate; } public override void Started() diff --git a/src/Spectre.Console/Rendering/LiveRenderable.cs b/src/Spectre.Console/Rendering/LiveRenderable.cs index fad49f8..340f03b 100644 --- a/src/Spectre.Console/Rendering/LiveRenderable.cs +++ b/src/Spectre.Console/Rendering/LiveRenderable.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Linq; using Spectre.Console.Internal; -using Spectre.Console.Rendering; namespace Spectre.Console.Rendering {