Skip to main content

Application state

ArlecchinoState is a singleton holding what outlives a view instance:

MemberMeaning
OutputThe status line at the bottom of the frame; empty renders as a blank line
ModalThe modal currently open, or null
ModalsThe whole stack, bottom first
FilePickerA pending file picker request
PickerLastFolderThe folder the picker ended in, so the next request can resume there
NotificationsThe list behind the output row
Invalidate()Asks for a repaint without changing anything

Take it as a constructor parameter in views and commands. Deriving from it is allowed — the class is not sealed — which is the usual place to hang application state that every view reads. For state that is really data, a store of atoms is the better home.

The output line

private readonly ArlecchinoState _state;

_state.Output = $"picked: {path}";

Rendered on the last row above a rule, styled Warning when it carries text. It is drawn only while options.ShowOutputLine is on.

Notifications

Writing to Output raises a notification. The row shows the newest one for options.NotificationTimeout (5 seconds by default) and then goes quiet by itself, so a message no longer sits on screen for the rest of the session. An empty string clears the row at once.

The message outlives the row. It stays in the list for options.NotificationLifetime (10 minutes) — or until Notifications.Capacity (200) newer ones have pushed it out, so an application that reports in a loop cannot grow the list without limit.

The list is a screen of its own: Ctrl+N, or a click on the output row, opens Routes.Notifications — newest first, Information / Warning / Failure colored by role, Backspace clears it, Esc goes back.

_state.Notifications.Notify("could not reach the server", NotificationLevel.Failure);

That is the whole of it for a message that fits on a line. Work that takes a while reports its own progress and then settles into what came of it, and an application that shows its work as a stack of cards rather than one row reads Notifications.Recent instead of Current — see Diagnostics.

Both timeouts and the key that opens the screen are set in one call — see Hosting and options:

builder.Services.AddArlecchino().UseNotifications(timeout: TimeSpan.FromSeconds(3));

WithoutNotifications() leaves the row off entirely; the hints box is turned off separately with options.Hints = HintsShown.Never.

Asking for a modal

The Request* helpers cover the common cases and close the modal for you on submit or cancel:

_state.RequestText("Rename", current, validate: null, onSubmit: value => Rename(value));
_state.RequestConfirmation("Delete the profile?", () => Delete(profile));

Assigning State.Modal directly gives access to every property of a modal type, and PushModal opens one over another. Every kind is on Modals.

Invalidate

Assigning Output, a modal or the file picker asks for a repaint by itself. Anything else that changes what a view draws says so:

_state.Invalidate();

The frame loop is the full list of who already asks.

Deriving from it

public sealed class AppState : ArlecchinoState
{
public AppState(Repaint repaint, Notifications notifications) : base(repaint, notifications) { }

public string ProfileName { get; set; } = "";
}

Register the derived type in place of the base one and take AppState where you need it. Anything the framework itself writes — the output line, the modal stack — keeps working, because it is written against the base class.