Line data Source code
1 : library data_state; 2 : 3 : import 'package:equatable/equatable.dart'; 4 : import 'package:state_notifier/state_notifier.dart'; 5 : 6 : class DataState<T> with EquatableMixin { 7 : final T model; 8 : final bool isLoading; 9 : final DataException? exception; 10 : final StackTrace? stackTrace; 11 : 12 1 : const DataState( 13 : this.model, { 14 : this.isLoading = false, 15 : this.exception, 16 : this.stackTrace, 17 : }); 18 : 19 2 : bool get hasException => exception != null; 20 : 21 2 : bool get hasModel => model != null; 22 : 23 1 : @override 24 4 : List<Object?> get props => [model, isLoading, exception]; 25 : 26 0 : @override 27 : bool get stringify => true; 28 : } 29 : 30 : class DataException with EquatableMixin implements Exception { 31 : final Object error; 32 : final StackTrace? stackTrace; 33 : final int? statusCode; 34 : 35 1 : const DataException(this.error, {this.stackTrace, this.statusCode}); 36 : 37 1 : @override 38 4 : List<Object?> get props => [error, stackTrace, statusCode]; 39 : 40 1 : @override 41 : String toString() { 42 6 : return 'DataException: $error ${statusCode != null ? " [HTTP $statusCode]" : ""}\n${stackTrace ?? ''}'; 43 : } 44 : } 45 : 46 : class DataStateNotifier<T> extends StateNotifier<DataState<T>> { 47 1 : DataStateNotifier({ 48 : required DataState<T> data, 49 : Future<void> Function(DataStateNotifier<T>)? reload, 50 : }) : _reloadFn = reload, 51 1 : super(data); 52 : 53 : final Future<void> Function(DataStateNotifier<T>)? _reloadFn; 54 : void Function()? onDispose; 55 : 56 2 : DataState<T> get data => super.state; 57 : 58 1 : void updateWith({ 59 : Object? model = stamp, 60 : bool? isLoading, 61 : Object? exception = stamp, 62 : Object? stackTrace = stamp, 63 : }) { 64 2 : super.state = DataState<T>( 65 3 : model == stamp ? state.model : model as T, 66 2 : isLoading: isLoading ?? state.isLoading, 67 : exception: 68 3 : exception == stamp ? state.exception : exception as DataException?, 69 : stackTrace: 70 3 : stackTrace == stamp ? state.stackTrace : stackTrace as StackTrace?, 71 : ); 72 : } 73 : 74 1 : Future<void> reload() async { 75 2 : return _reloadFn?.call(this); 76 : } 77 : 78 1 : @override 79 : RemoveListener addListener( 80 : Listener<DataState<T>> listener, { 81 : bool fireImmediately = true, 82 : }) { 83 : final dispose = 84 1 : super.addListener(listener, fireImmediately: fireImmediately); 85 1 : return () { 86 1 : dispose(); 87 2 : onDispose?.call(); 88 : }; 89 : } 90 : 91 1 : @override 92 : void dispose() { 93 1 : if (mounted) { 94 1 : super.dispose(); 95 : } 96 : } 97 : } 98 : 99 : class _Stamp { 100 1 : const _Stamp(); 101 : } 102 : 103 : const stamp = _Stamp();