Line data Source code
1 : part of 'bloc/rx_bloc_base.dart'; 2 : 3 : /// ResultErrorStream utility extension methods. 4 : extension ResultErrorStream<T> on Stream<ResultError<T>> { 5 : /// Map the ResultError to the the exception that holds 6 4 : Stream<Exception> mapToException() => map((error) => error.error); 7 : 8 : /// Map the ResultError to the the exception that holds 9 1 : Stream<ErrorWithTag> mapToErrorWithTag() => 10 3 : map((error) => ErrorWithTag.fromResult(error)); 11 : } 12 : 13 : /// ResultStream utility extension methods. 14 : extension ResultStream<T> on Stream<Result<T>> { 15 : /// Finds the [ResultSuccess] as unwraps the [ResultSuccess.data] from it. 16 : /// 17 : /// It filters the other types of [Result] such as 18 : /// [ResultError] and [ResultLoading]. 19 2 : Stream<T> whereSuccess() => 20 8 : whereType<ResultSuccess<T>>().map((data) => data.data); 21 : 22 : /// Finds the [ResultError] as unwraps the [ResultError.error] from it. 23 : /// 24 : /// It filters the other types of [Result] such as 25 : /// [ResultSuccess] and [ResultLoading]. 26 1 : Stream<Exception> whereError() => 27 4 : whereType<ResultError<T>>().map((error) => error.error); 28 : 29 : /// Returns `true` if the [Result] is [ResultLoading], 30 : /// otherwise returns `false` 31 4 : Stream<bool> isLoading() => map((data) => data is ResultLoading); 32 : 33 : /// Returns a container [] 34 4 : Stream<LoadingWithTag> isLoadingWithTag() => map((data) => LoadingWithTag( 35 1 : loading: data is ResultLoading, 36 1 : tag: data.tag, 37 : )); 38 : } 39 : 40 : /// Result utility extension methods. 41 : extension AsResultStream<T> on Stream<T> { 42 : /// Converts the [Stream] to a [Stream] of [Result] 43 : /// 44 : /// As soon as the [Stream] is being subscribed it emits 45 : /// [ResultLoading] immediately, 46 : /// as afterwards emits either [ResultError] or [ResultSuccess] 47 2 : Stream<Result<T>> asResultStream({ 48 : String tag = '', 49 : }) => 50 6 : map((data) => Result<T>.success(data, tag: tag)) 51 2 : .onErrorReturnWith( 52 4 : (error, stacktrace) => Result<T>.error( 53 2 : error is Exception ? error : Exception(error.toString()), 54 : tag: tag, 55 : ), 56 : ) 57 4 : .startWith(Result<T>.loading(tag: tag)); 58 : } 59 : 60 : /// Future asResultStream utilities 61 : extension FutureAsResultStream<T> on Future<T> { 62 : /// Converts the [Future] to a [Stream] of [Result] 63 : /// 64 : /// As soon as the [Stream] is being subscribed it emits 65 : /// [ResultLoading] immediately, 66 : /// as afterwards emits either [ResultError] or [ResultSuccess] 67 2 : Stream<Result<T>> asResultStream({String tag = ''}) => 68 4 : asStream().asResultStream(tag: tag); 69 : } 70 : 71 : /// Stream loading and error handlers 72 : extension HandleByRxBlocBase<T> on Stream<Result<T>> { 73 : /// Handle [ResultLoading] states from stream. 74 : /// 75 : /// Once the states are being handled they sink to [RxBlocBase.loadingState]. 76 : /// Converts the stream to broadcast one based on [shareReplay]. 77 : /// 78 : /// In case you need to handle error states along with the loading state, 79 : /// use [setResultStateHandler] instead. 80 1 : Stream<Result<T>> setLoadingStateHandler( 81 : RxBlocBase bloc, { 82 : bool shareReplay = true, 83 : }) => 84 1 : doOnData( 85 3 : (event) => bloc._loadingBloc.setResult( 86 : result: event, 87 : ), 88 1 : ).asSharedStream(shareReplay: shareReplay); 89 : 90 : /// Handle [ResultError] states from the stream. 91 : /// 92 : /// Once the states are being handled they sink to [RxBlocBase.errorState]. 93 : /// Converts the stream to broadcast one based on [shareReplay]. 94 : /// 95 : /// In case you need to register loading states along with the exceptions, 96 : /// use [setResultStateHandler] instead. 97 1 : Stream<Result<T>> setErrorStateHandler( 98 : RxBlocBase bloc, { 99 : bool shareReplay = true, 100 : }) => 101 2 : doOnData((event) { 102 1 : if (event is ResultError<T>) { 103 3 : bloc._resultStreamExceptionsSubject.sink.add(event); 104 : } 105 1 : }).asSharedStream(shareReplay: shareReplay); 106 : 107 : /// Handle [ResultLoading] and [ResultError] by a BLoC. 108 : /// 109 : /// Converts the stream to broadcast one based on [shareReplay]. 110 : /// 111 : /// Useful when multiple type of result streams are executed by a single Bloc, 112 : /// as all [ResultError] and [ResultLoading] states resides in a central place 113 : /// 114 : /// Once [ResultLoading] states are being handled 115 : /// they sink to [RxBlocBase.loadingState]. 116 : /// Once [ResultError] states are being handled 117 : /// they sink to [RxBlocBase.errorState]. 118 1 : Stream<Result<T>> setResultStateHandler(RxBlocBase bloc, 119 : {bool shareReplay = true}) => 120 1 : setErrorStateHandler(bloc) 121 1 : .setLoadingStateHandler(bloc) 122 1 : .asSharedStream(shareReplay: shareReplay); 123 : } 124 : 125 : /// Stream binder utilities 126 : extension Bind<T> on Stream<T> { 127 : /// Bind a stream to the given subject [subject]. 128 : /// 129 : /// Each event from the stream will be added to the subject, meaning that the 130 : /// both needs to be of the same type. 131 : /// Be aware that the binding is facilitating the subscribing, so the 132 : /// unsubscribing needs to be handled accordingly either by 133 : /// using [CompositeSubscription] or manually. 134 0 : StreamSubscription<T> bind(Subject<T> subject) => listen(subject.sink.add); 135 : } 136 : 137 : /// Stream subscription disposer 138 : extension DisposedBy<T> on StreamSubscription<T> { 139 : /// Add the stream to [compositeSubscription]. 140 : /// 141 : /// Once [compositeSubscription] is being disposed all added subscriptions 142 : /// will be disposed automatically 143 1 : StreamSubscription<T> disposedBy( 144 : CompositeSubscription compositeSubscription) => 145 1 : compositeSubscription.add(this); 146 : }