/// Minimal async state container so screens can pattern-match over /// loading / data / error instead of juggling three nullable fields. sealed class AsyncValue { const AsyncValue(); const factory AsyncValue.loading() = AsyncLoading; const factory AsyncValue.data(T value) = AsyncData; const factory AsyncValue.error(String message) = AsyncError; T? get valueOrNull => this is AsyncData ? (this as AsyncData).value : null; bool get isLoading => this is AsyncLoading; R map({ required R Function() loading, required R Function(T value) data, required R Function(String message) error, }) { return switch (this) { AsyncLoading() => loading(), AsyncData(value: final v) => data(v), AsyncError(message: final m) => error(m), }; } } final class AsyncLoading extends AsyncValue { const AsyncLoading(); } final class AsyncData extends AsyncValue { const AsyncData(this.value); final T value; } final class AsyncError extends AsyncValue { const AsyncError(this.message); final String message; }