Created
October 23, 2023 11:17
-
-
Save sunderee/5710cd1e71cf39ae2a8871beae3541e3 to your computer and use it in GitHub Desktop.
Base state that can be used in Flutter apps using BLoC (inspired by Riverpod).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:equatable/equatable.dart'; | |
import 'package:meta/meta.dart'; | |
sealed class BaseState<T> extends Equatable { | |
bool get isInitial; | |
bool get isLoading; | |
bool get isSuccessful; | |
bool get hasFailed; | |
T? get data; | |
Exception? get exception; | |
const BaseState._(); | |
const factory BaseState.initial() = InitialState<T>; | |
const factory BaseState.loading() = LoadingState<T>; | |
const factory BaseState.successful(T data) = SuccessfulState<T>; | |
const factory BaseState.failed(Exception exception) = FailedState<T>; | |
} | |
typedef OnInitialOrLoading<R> = R Function(); | |
typedef OnData<T, R> = R Function(T data); | |
typedef OnException<R> = R Function(Exception exception); | |
extension BaseStateExt<T> on BaseState<T> { | |
T get _safeData { | |
if (isSuccessful && data != null) { | |
return data as T; | |
} | |
throw StateError('Cannot have null data.'); | |
} | |
R when<R>({ | |
required OnInitialOrLoading<R> onInitial, | |
required OnInitialOrLoading<R> onLoading, | |
required OnData<T, R> onData, | |
required OnException<R> onException, | |
}) { | |
if (isInitial && | |
!isLoading && | |
!isSuccessful && | |
!hasFailed && | |
data == null && | |
exception == null) { | |
return onInitial(); | |
} | |
if (isLoading) { | |
return onLoading(); | |
} | |
if (hasFailed || exception != null) { | |
return onException(exception!); | |
} | |
return onData(_safeData); | |
} | |
} | |
@immutable | |
final class InitialState<T> extends BaseState<T> { | |
@override | |
bool get isInitial => true; | |
@override | |
bool get isLoading => false; | |
@override | |
bool get isSuccessful => false; | |
@override | |
bool get hasFailed => false; | |
@override | |
final T? data; | |
@override | |
final Exception? exception; | |
const InitialState() | |
: data = null, | |
exception = null, | |
super._(); | |
@override | |
List<Object?> get props => [ | |
isLoading, | |
isSuccessful, | |
hasFailed, | |
data, | |
exception, | |
]; | |
} | |
@immutable | |
final class LoadingState<T> extends BaseState<T> { | |
@override | |
bool get isInitial => false; | |
@override | |
bool get isLoading => true; | |
@override | |
bool get isSuccessful => false; | |
@override | |
bool get hasFailed => false; | |
@override | |
final T? data; | |
@override | |
final Exception? exception; | |
const LoadingState() | |
: data = null, | |
exception = null, | |
super._(); | |
@override | |
List<Object?> get props => [ | |
isLoading, | |
isSuccessful, | |
hasFailed, | |
data, | |
exception, | |
]; | |
} | |
@immutable | |
final class SuccessfulState<T> extends BaseState<T> { | |
@override | |
bool get isInitial => false; | |
@override | |
bool get isLoading => false; | |
@override | |
bool get isSuccessful => true; | |
@override | |
bool get hasFailed => false; | |
@override | |
final T data; | |
@override | |
final Exception? exception; | |
const SuccessfulState(this.data) | |
: exception = null, | |
super._(); | |
@override | |
List<Object?> get props => [ | |
isLoading, | |
isSuccessful, | |
hasFailed, | |
data, | |
exception, | |
]; | |
} | |
@immutable | |
final class FailedState<T> extends BaseState<T> { | |
@override | |
bool get isInitial => false; | |
@override | |
bool get isLoading => false; | |
@override | |
bool get isSuccessful => false; | |
@override | |
bool get hasFailed => true; | |
@override | |
final T? data; | |
@override | |
final Exception exception; | |
const FailedState(this.exception) | |
: data = null, | |
super._(); | |
@override | |
List<Object?> get props => [ | |
isLoading, | |
isSuccessful, | |
hasFailed, | |
data, | |
exception, | |
]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment