0 purchases
eblox
EbloX #
An easy Flutter state management library.It is similar to Bloc, but it uses a lot of annotations and separates business logic from UI through the concepts of Action and State.
Simpler, more reliable, easier to test !
Example #
An example of a common counter.
Add dependency:
dependencies:
eblox:
eblox_annotation:
dev_dependencies:
build_runner:
eblox_generator:
copied to clipboard
New counter_view_model.dart
import 'package:eblox/eblox.dart';
import 'package:eblox_annotation/eblox_annotation.dart';
import 'package:flutter/cupertino.dart';
part 'counter_view_model.g.dart';
@blox
class CounterVModel with Blox{
@StateX(name:'CounterState')
int _counter = 0;
@ActionX(bind: 'CounterState')
void _add() async{
_counter ++;
}
@ActionX(bind: 'CounterState')
void _sub(){
_counter--;
}
@override
void dispose() {
super.dispose();
debugPrint('CounterVModel dispose...');
}
}
copied to clipboard
Execute flutter pub run build_runner watch --delete-conflicting-outputs command will generate the counter_view_model.g.dart file in the current directory.
It will automatically generate Action and State for us. Next, write the UI and use these Actions.
import 'package:eblox/blox.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'blox/counter_view_model.dart';
class CounterPage extends StatelessWidget {
const CounterPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child:BloxBuilder<CounterVModel,CounterState>(
inject:(injection)=> injection.inject(CounterVModel()),
builder: (count) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("$count"),
ElevatedButton(
onPressed: () {
$$<CounterVModel>(AddAction());
},
child: const Text("+"),
),
ElevatedButton(
onPressed: () {
$$<CounterVModel>(SubAction());
},
child: const Text("-"),
),
],
),
);
}),
),
);
}
}
copied to clipboard
So easy!
Usage #
Create a class and mix in Blox where we can write our business logic. It is similar to ViewModel in MVVM. But note that we have to use the @blox annotation on this class. There is also a case, if we want to be able to access the state generated by the @StateX annotation externally, we should also mix in _$className, such as class CounterVModel with Blox,_$CounterVModel,and then use $<CounterVModel >().counter` accesses the state. refer to example.
@StateX is used to decorate the state we need, it will automatically generate a State class with a specified name for packaging the modified data:
// **************************************************************************
// BloxStateGenerator
// **************************************************************************
class CounterState<T> extends BloxSingleState<T> {
CounterState(data) : super(data);
}
copied to clipboard
If you do not specify a name, the state class will be generated according to the default rules. E.g:
@StateX()
Color _color = Colors.white;
copied to clipboard
Will generate ColorState.
@ActionX is used to generate the Action class, and the name can also be specified. The bind is used to specify which State class to associate this Action with. In addition, it also associates the decorated method with the generated Action, and this method is called when the Action is sent.
An @AsyncX annotation is also currently provided to decorate asynchronous state:
part 'search_view_model.g.dart';
@blox
class SearchVModel with Blox{
@AsyncX(name: 'SongListState')
SongListModel _songModel = SongListModel();
@bindAsync
@ActionX(bind: 'SongListState')
BloxAsyncTask<SongListModel> _search(String name){
return (){
return SearchService.search(name);
};
}
}
copied to clipboard
@ActionX decorated method can also declare parameters, the generated class will automatically include:
// **************************************************************************
// BloxActionGenerator
// **************************************************************************
class SearchAction extends BloxAction {
SearchAction(String name) : super.argsByPosition([name]);
}
copied to clipboard
To associate an Action method with an asynchronous state, you need to add another annotation @bindAsync. The method annotated by @bindAsync must return the type BloxAsyncTask<T>, and the generic T is the data we need to load asynchronously type.
In the UI, you can use BloxView to handle asynchronous states:
class SearchPage extends StatelessWidget {
SearchPage({Key? key}) : super(key: key);
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Song search'),),
body: SafeArea(
child: Column(
children: [
TextField(
controller: _controller,
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
suffix: IconButton(
icon: const Icon(Icons.search_rounded),
onPressed: (){
if(_controller.text.isNotEmpty) {
$$<SearchVModel>(SearchAction(_controller.text));
}
},
)),
),
Flexible(
child: BloxView<SearchVModel, SongListState<SongListModel>>(
create: () => SearchVModel(),
onLoading: () => const Center(child: CircularProgressIndicator()),
onEmpty: ()=> const Center(child: Text("Empty")),
builder: (state) {
return ListView.builder(
itemCount: state.data.songs.length,
itemBuilder: (ctx, i) {
return Container(
alignment: Alignment.center,
height: 40,
child: Text(state.data.songs[i],style: const TextStyle(color: Colors.blueGrey,fontSize: 20),),
);
});
},
)),
],
),
),
);
}
}
copied to clipboard
BloxView provides onLoading, onEmpty, onError,builder to handle the UI display during and after loading.
Note that if you want onEmpty to be valid, then your custom data type should mixin BloxData:
class SongListModel with BloxData{
SongListModel({UnmodifiableListView<String>? songs}){
if(songs !=null) this.songs = songs;
}
UnmodifiableListView<String> songs = UnmodifiableListView([]);
@override
bool get isEmpty => songs.isEmpty;
}
copied to clipboard
Please check here for detailed examples.
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.