View Source Owl.Spinner (Owl v0.4.0)

A spinner widget.

Simply run any long-running task using run/2:

Owl.Spinner.run(
  fn -> Process.sleep(5_000) end,
  labels: [ok: "Done", error: "Failed", processing: "Please wait..."]
)

Multiple spinners can be run simultaneously:

long_running_tasks =
  Enum.map([9000, 8000, 4000, 6000], fn delay ->
    fn -> Process.sleep(delay) end
  end)

long_running_tasks
|> Task.async_stream(&Owl.Spinner.run/1, timeout: :infinity)
|> Stream.run()

Multiline frames are supported as well:

Owl.Spinner.run(fn -> Process.sleep(5_000) end,
  frames: [
    processing: [
      "╔════╤╤╤╤════╗\n║    │││ \\\n║    │││  O  ║\n║    OOO     ║",
      "╔════╤╤╤╤════╗\n║    ││││    ║\n║    ││││    ║\n║    OOOO    ║",
      "╔════╤╤╤╤════╗\n║   / │││    ║\n║  O  │││    ║\n║     OOO    ║",
      "╔════╤╤╤╤════╗\n║    ││││    ║\n║    ││││    ║\n║    OOOO    ║"
    ]
  ]
)

where-can-i-get-alternative-frames

Where can I get alternative frames?

Link to this section Summary

Functions

Runs a spinner during execution of process_function and returns its result.

Starts a new spinner.

Stops the spinner.

Updates a label of the running spinner.

Link to this section Types

Link to this section Functions

Link to this function

run(process_function, opts \\ [])

View Source
@spec run(process_function :: (() -> :ok | :error | {:ok, value} | {:error, reason}),
  refresh_every: non_neg_integer(),
  frames: [ok: frame(), error: frame(), processing: [frame()]],
  labels: [
    ok: label() | (nil | value -> label() | nil) | nil,
    error: label() | (nil | reason -> label()) | nil,
    processing: label() | nil
  ]
) :: :ok | :error | {:ok, value} | {:error, reason}
when value: any(), reason: any()

Runs a spinner during execution of process_function and returns its result.

The spinner is started, and automatically stopped after the function returns, regardless if there was an error when executing the function. It is a wrapper around start/1 and stop/1. The only downside of run/2 is that it is not possible to update a label while process_function is executing.

If function returns :ok or {:ok, value} then spinner will be stopped with :ok resolution.

If function returns :error or {:error, reason} then spinner will be stopped with :error resolution.

options

Options

  • :refresh_every - period of changing frames. Defaults to 100.
  • :frames - allows to set frames for different states of spinner:
    • :processing - list of frames which are rendered until spinner is stopped. Defaults to ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"].
    • :ok - frame that is rendered when spinner is stopped with :ok resolution. Defaults to Owl.Data.tag("✔", :green).
    • :error - frame that is rendered when spinner is stopped with :error resolution. Defaults to Owl.Data.tag("✖", :red).
  • :labels - allows to set labels for different states of spinner:
    • :processing - label that is rendered during processing. Cannot be changed during execution of process_function. Defaults to nil.
    • :ok - label that is rendered when spinner is stopped with :ok resolution. A function with arity 1 can be passed in order to format a label based on result of process_function. Defaults to nil.
    • :error - label that is rendered when spinner is stopped with :error resolution. A function with arity 1 can be passed in order to format a label based on result of process_function. Defaults to nil.

examples

Examples

Owl.Spinner.run(fn -> Process.sleep(5_000) end)
=> :ok

Owl.Spinner.run(fn -> Process.sleep(5_000) end,
  frames: [
    # an ASCII fish going back and forth
    processing: [
      ">))'>",
      "    >))'>",
      "        >))'>",
      "    <'((<",
      "<'((<"
    ]
  ]
)
=> :ok

Owl.Spinner.run(
  fn ->
    Process.sleep(5_000)
    {:error, :oops}
  end,
  labels: [
    error: fn reason -> "Failed: #{inspect(reason)}" end,
    processing: "Processing..."
  ]
)
=> {:error, :oops}
@spec start(
  id: id(),
  frames: [ok: frame(), error: frame(), processing: [frame()]],
  labels: [ok: label() | nil, error: label() | nil, processing: label() | nil],
  refresh_every: non_neg_integer()
) :: DynamicSupervisor.on_start_child()

Starts a new spinner.

Must be stopped manually by calling stop/1.

options

Options

  • :id - an id of the spinner. Required.
  • :refresh_every - period of changing frames. Defaults to 100.
  • :frames - allows to set frames for different states of spinner:
    • :processing - list of frames which are rendered until spinner is stopped. Defaults to ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"].
    • :ok - frame that is rendered when spinner is stopped with :ok resolution. Defaults to Owl.Data.tag("✔", :green).
    • :error - frame that is rendered when spinner is stopped with :error resolution. Defaults to Owl.Data.tag("✖", :red).
  • :labels - allows to set labels for different states of spinner:
    • :processing - label that is rendered during processing. Can be changed with update_label/1. Defaults to nil.
    • :ok - label that is rendered when spinner is stopped with :ok resolution. Defaults to nil.
    • :error - label that is rendered when spinner is stopped with :error resolution. Defaults to nil.

example

Example

Owl.Spinner.start(id: :my_spinner)
Process.sleep(1000)
Owl.Spinner.stop(id: :my_spinner, resolution: :ok)
@spec stop(id: id(), resolution: :ok | :error, label: label()) :: :ok

Stops the spinner.

options

Options

  • :id - an id of the spinner. Required.
  • :resolution - an atom :ok or :error. Determines frame and label for final rendering. Required.
  • :label - a label for final rendering. If not set, then values that are set on spinner start will be used.

example

Example

Owl.Spinner.stop(id: :my_spinner, resolution: :ok)
@spec update_label(id: id(), label: label()) :: :ok

Updates a label of the running spinner.

Overrides a value that is set for :processing state on start.

options

Options

  • :id - an id of the spinner. Required.
  • :label - a new value of the label. Required.

example

Example

Owl.Spinner.start(id: :my_spinner)
Owl.Spinner.update_label(id: :my_spinner, label: "Downloading files...")
Process.sleep(1000)
Owl.Spinner.update_label(id: :my_spinner, label: "Checking signatures...")
Process.sleep(1000)
Owl.Spinner.stop(id: :my_spinner, resolution: :ok, label: "Done")