# This is an example of how to use commands to perform expensive work in the # background and receive the results via `update/2`. # # Usage: # elixir examples/snippets/advanced/commands.exs defmodule CommandsExample do use Raxol.Core.Runtime.Application import Raxol.View.Elements alias Raxol.Core.Commands.Command alias Raxol.Core.Events.Event require Raxol.Core.Runtime.Log @impl true def init(_context) do Raxol.Core.Runtime.Log.debug("CommandsExample: init/1") {:ok, %{commands: %{}, next_id: 0, executed_commands: []}} end @impl true def update(message, %{commands: commands, next_id: id} = model) do Raxol.Core.Runtime.Log.debug("CommandsExample: update/2 received message: \#{inspect(message)}") case message do %Event{type: :key, data: %{key: :char, char: "t"}} -> Raxol.Core.Runtime.Log.info("CommandsExample: Starting command \#{id}") new_model = %{ model | commands: Map.put(commands, id, {:processing, nil}), next_id: id + 1 } command = Command.new(&process/0, {:finished, id}) {:ok, new_model, [command]} {:command_result, {:finished, id}, result} -> Raxol.Core.Runtime.Log.info("CommandsExample: Command \#{id} finished with result: \#{result}") new_commands = Map.put(commands, id, {:finished, result}) new_executed = [{id, result} | model.executed_commands] trimmed_executed = Enum.take(new_executed, 10) new_model = %{model | commands: new_commands, executed_commands: trimmed_executed} {:ok, new_model, []} %Event{type: :key, data: %{key: :char, char: "q"}} -> {:ok, model, [Command.new(:quit)]} %Event{type: :key, data: %{key: :char, char: "c", ctrl: true}} -> {:ok, model, [Command.new(:quit)]} _ -> {:ok, model, []} end end defp process do Raxol.Core.Runtime.Log.debug("CommandsExample: process/0 running...") result = Enum.random(1..10_000) Raxol.Core.Runtime.Log.debug("CommandsExample: process/0 finished with \#{result}") result end @impl true def view(%{commands: commands, executed_commands: executed_commands} = model) do Raxol.Core.Runtime.Log.debug("CommandsExample: view/1") active_commands_data = for {id, {status, result}} <- commands, status == :processing, do: %{id: id, status: status, result: result || "N/A"} finished_commands_data = for {id, {_status, result}} <- commands, not nil(result), do: %{id: id, result: result} view do column style: %{gap: 1} do box(title: "Press 't' repeatedly to start asynchronous commands (q/Ctrl+C to Quit)", style: [[:border, :single], [:padding, 1]]) do table( id: :active_commands, data: active_commands_data ++ finished_commands_data, columns: [ %{header: "ID", key: :id, width: 10}, %{header: "Status", key: :status, width: 15}, %{header: "Result", key: :result, width: 15} ], style: [[:height, 8], [:width, :fill]] ) end box(title: "Recently Executed Commands (Last 10)", style: [[:border, :single], [:padding, 1]]) do executed_data = Enum.map(executed_commands, fn {id, result} -> %{id: id, result: result} end) table( id: :executed_commands, data: executed_data, columns: [ %{header: "Command ID", key: :id, width: 15}, %{header: "Result", key: :result, width: 15} ], style: [[:height, 12], [:width, :fill]] ) end end end end end Raxol.Core.Runtime.Log.info("CommandsExample: Starting Raxol...") {:ok, _pid} = Raxol.start_link(CommandsExample, []) Raxol.Core.Runtime.Log.info("CommandsExample: Raxol started. Running...")