Model class abstract TUI
Abstract interface for TUI application models.
The Model represents the state of a TUI application and defines the core functions of the Elm Architecture:
- init - Returns an optional command to run on startup
- update - Handles messages and returns new state + optional command
- view - Renders the current state as a string
The TUI runtime follows The Elm Architecture (TEA) pattern, which separates state, logic, and presentation:
- Model: The state of your application. It should be immutable.
- Update: A pure function that takes a Msg and the current Model, and returns a new Model and an optional Cmd.
- View: A pure function that takes the Model and returns a String (or a View object for advanced metadata) representing the UI.
┌─────────────────────────────────────────────────────┐
│ Program │
│ │
│ ┌───────┐ ┌────────┐ ┌──────┐ │
│ │ Model │────▶│ update │────▶│ view │ │
│ └───────┘ └────────┘ └──────┘ │
│ ▲ │ │ │
│ │ │ ▼ │
│ │ ┌────────┐ ┌────────┐ │
│ └─────────│ Cmd │ │ Screen │ │
│ └────────┘ └────────┘ │
│ │ │
│ ▼ │
│ ┌────────┐ │
│ │ Msg │◀──── User Input │
│ └────────┘ │
└─────────────────────────────────────────────────────┘
Example: Counter
class CounterModel implements Model {
final int count;
CounterModel([this.count = 0]);
@override
Cmd? init() => null; // No initialization needed
@override
(Model, Cmd?) update(Msg msg) {
return switch (msg) {
KeyMsg(key: Key(type: KeyType.up)) =>
(CounterModel(count + 1), null),
KeyMsg(key: Key(type: KeyType.down)) =>
(CounterModel(count - 1), null),
KeyMsg(key: Key(type: KeyType.runes, runes: [0x71])) => // 'q'
(this, Cmd.quit()),
_ => (this, null),
};
}
@override
String view() => '''
Counter: $count
Press ↑/↓ to change, q to quit
''';
}
Example: Async Data Loading
class DataModel implements Model {
final bool loading;
final List<String> items;
final String? error;
DataModel({this.loading = false, this.items = const [], this.error});
@override
Cmd? init() => Cmd.perform(
() => fetchItems(),
onSuccess: (items) => ItemsLoadedMsg(items),
onError: (e, _) => ErrorMsg(e.toString()),
);
@override
(Model, Cmd?) update(Msg msg) {
return switch (msg) {
ItemsLoadedMsg(:final items) =>
(DataModel(items: items), null),
ErrorMsg(:final message) =>
(DataModel(error: message), null),
KeyMsg(key: Key(type: KeyType.runes, runes: [0x72])) => // 'r' to refresh
(DataModel(loading: true), init()),
_ => (this, null),
};
}
@override
String view() {
if (loading) return 'Loading...';
if (error != null) return 'Error: $error\n\nPress r to retry';
return items.map((i) => '• $i').join('\n');
}
}
- Implementers
Constructors
- Model()
-
const
Properties
- hashCode → int
-
The hash code for this object.
no setterinherited
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
init(
) → Cmd? - Returns an optional command to execute on program startup.
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toString(
) → String -
A string representation of this object.
inherited
-
update(
Msg msg) → (Model, Cmd?) - Handles a message and returns the new model state and optional command.
-
view(
) → Object - Renders the current model state for display.
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited