0 purchases
stream loader
stream_loader #
A Flutter plugin for loading content asynchronously with Dart Stream and RxDart.
RxDart loader bloc.
Reactive loader bloc.
Simple reactive state management container.
Author: Petrus Nguyễn Thái Học #
Getting Started #
In your flutter project, add the dependency to your pubspec.yaml
dependencies:
...
stream_loader: <latest_version>
copied to clipboard
Examples #
stream_loader/example
stream_loader_demo
Usage #
1. Model and api
abstract class Comment implements Built<Comment, CommentBuilder> { ... }
class Api {
Stream<BuiltList<Comment>> getComments() { ... }
Stream<Comment> getCommentBy({@required int id}) { ... }
}
final api = Api();
copied to clipboard
2. Create LoaderWidget load comments from api
import 'package:stream_loader/stream_loader.dart';
LoaderWidget<BuiltList<Comment>>(
blocProvider: () => LoaderBloc(
loaderFunction: api.getComments,
refresherFunction: api.getComments,
initialContent: <Comment>[].build(),
logger: print,
),
messageHandler: (context, message, bloc) {
message.fold(
onFetchFailure: (error, stackTrace) => context.snackBar('Fetch error'),
onFetchSuccess: (_) {},
onRefreshSuccess: (data) => context.snackBar('Refresh success'),
onRefreshFailure: (error, stackTrace) => context.snackBar('Refresh error'),
);
},
builder: (context, state, bloc) {
if (state.error != null) {
return ErrorWidget(error: state.error);
}
if (state.isLoading) {
return LoadingWidget();
}
return RefreshIndicator(
onRefresh: bloc.refresh,
child: CommentsListWidget(comments: state.content),
);
}
);
copied to clipboard
3. Create LoaderWidget load comment detail from api
import 'package:stream_loader/stream_loader.dart';
final Comment comment;
final loadDetail = () => api.getCommentBy(id: comment.id);
LoaderWidget<Comment>(
blocProvider: () => LoaderBloc(
loaderFunction: loadDetail,
refresherFunction: loadDetail,
initialContent: comment,
logger: print,
),
messageHandler: (context, message, bloc) {
message.fold(
onFetchFailure: (_, __) {},
onFetchSuccess: (_) {},
onRefreshFailure: (_, __) {},
onRefreshSuccess: (_) => context.snackBar('Refresh success'),
);
},
builder: (context, state, bloc) {
return RefreshIndicator(
onRefresh: bloc.refresh,
child: CommentDetailWidget(comment: state.content),
);
},
);
copied to clipboard
Note: Can use LoaderBloc without LoaderWidget easily
class _CommentsState extends State<Comments> {
LoaderBloc<BuiltList<Comment>> bloc;
@override
void didChangeDependencies() {
super.didChangeDependencies();
bloc ??= LoaderBloc(
loaderFunction: api.getComments,
refresherFunction: api.getComments,
initialContent: <Comment>[].build(),
logger: print,
)..fetch();
}
@override
void dispose() {
bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return StreamBuilder<LoaderState<BuiltList<Comment>>>(
stream: bloc.state$,
initialData: bloc.state$.value, // <- required because bloc.state$ does not replay the latest value
builder: (context, snapshot) {
final state = snapshot.data;
if (state.error != null) {
return ErrorWidget(error: state.error);
}
if (state.isLoading) {
return LoadingWidget();
}
return RefreshIndicator(
onRefresh: bloc.refresh,
child: CommentsListWidget(comments: state.content),
);
}
);
}
}
copied to clipboard
Change flatten behavior of loaderFunction and refresherFunction. #
Default behavior of loaderFunction is FlattenStrategy.latest (uses switchMap).
Default behavior of refreshFlatMapPolicy is FlattenStrategy.first, (uses exhaustMap).
To change them, passing your value to LoaderBloc constructor
LoaderBloc(
...,
loaderFlattenStrategy: FlattenStrategy.concat, // asyncExpand
refreshFlattenStrategy: FlattenStrategy.latest, // switchMap
);
copied to clipboard
License #
MIT License
Copyright (c) 2020-2022 Petrus Nguyễn Thái Học
copied to clipboard
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.