0 purchases
custom bloc
A simple custom stream builder library based on BLOC pattern. Uses stream underneath.
Features #
This allows easy adding of data from network and disposing of bloc
How To Use Custom Bloc #
class Example extends StatefulWidget {
const Example({Key? key}) : super(key: key);
@override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
final counterBloc = CounterBloc();
@override
void dispose() {
super.dispose();
counterBloc.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: CustomStreamBuilder<int, String>(
stream: counterBloc.behaviorSubject,
dataBuilder: (context, data) {
return ListView.separated(
itemCount: 1,
scrollDirection: Axis.horizontal,
padding:
const EdgeInsets.symmetric(horizontal: 4, vertical: 24),
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'index: $index: data: $data',
style: const TextStyle(fontSize: 34),
),
],
));
},
separatorBuilder: (context, index) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: VerticalDivider(),
);
},
);
},
loadingBuilder: (context) => const Center(
child: CircularProgressIndicator(),
),
errorBuilder: (context, error) => Text(
error,
style: const TextStyle(),
),
),
),
const SizedBox(
height: 34,
),
Row(
children: [
TextButton(
onPressed: () {
counterBloc.fetchCurrent(false);
},
child: const Text(
'Add Value',
style: TextStyle(),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
counterBloc.resetData();
},
child: const Text(
'Set to no data',
style: TextStyle(),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
counterBloc.fetchCurrent(true);
},
child: const Text(
'Add Error',
style: TextStyle(),
)),
],
),
const SizedBox(
height: 34,
)
],
),
),
);
}
}
class CounterBloc with BaseBloc<int, String> {
int value = 0;
CounterBloc() {
fetchCurrent(false);
}
fetchCurrent(bool addError) async {
setAsLoading();
if (!addError) {
await Future.delayed(const Duration(seconds: 2));
value++;
addToModel(value);
} else {
value = 0;
addToError('Could not fetch data');
}
}
resetData() {
value = 0;
setAsNoContent();
}
invalidate() {
invalidateBaseBloc();
}
dispose() {
disposeBaseBloc();
}
}
class Example2 extends StatefulWidget {
const Example2({Key? key}) : super(key: key);
@override
State<Example2> createState() => _Example2State();
}
class _Example2State extends State<Example2> {
final counterBloc = CounterBloc();
final newCounterBloc = CounterBloc2();
@override
void dispose() {
super.dispose();
counterBloc.dispose();
newCounterBloc.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: CustomStreamBuilder.twoSubject(
streams: [
counterBloc.behaviorSubject,
newCounterBloc.behaviorSubject
],
dataBuilder2: (context, data, secondData) {
var counterBlocData = data.model as int?;
var counterBlocState = data.itemState;
var counterBlocDataError = data.error as String?;
var newCounterBlocData = secondData.model as double?;
var newCounterBlocState = secondData.itemState;
var newCounterBlocError = secondData.error as String?;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (counterBlocState == ItemState.loading)
const Center(
child: CircularProgressIndicator(),
)
else if (counterBlocState == ItemState.hasError)
Text(
'counterBlocData error: $counterBlocDataError',
style: const TextStyle(fontSize: 34),
)
else if (counterBlocState == ItemState.noContent)
const SizedBox()
else
Text(
'counterBlocData: $counterBlocData',
style: const TextStyle(fontSize: 34),
),
const SizedBox(
height: 34,
),
if (newCounterBlocState == ItemState.loading)
const Center(
child: CircularProgressIndicator(),
)
else if (newCounterBlocState == ItemState.hasError)
Text(
'newCounterBlocError error: $newCounterBlocError',
style: const TextStyle(fontSize: 34),
)
else if (newCounterBlocState == ItemState.noContent)
const SizedBox()
else
Text(
'newCounterBlocData: $newCounterBlocData',
style: const TextStyle(fontSize: 34),
),
],
));
},
loadingBuilder: (context) => const Center(
child: CircularProgressIndicator(),
),
errorBuilder: (context, error) => Text(
error,
style: const TextStyle(),
),
),
),
const SizedBox(
height: 34,
),
Wrap(
children: [
TextButton(
onPressed: () {
counterBloc.fetchCurrent(false);
},
child: const Text(
'Add Value to stream 1',
style: TextStyle(),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
counterBloc.resetData();
},
child: const Text(
'Set to no data stream 1',
style: TextStyle(),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
counterBloc.fetchCurrent(true);
},
child: const Text(
'Add Error to stream 1',
style: TextStyle(),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
newCounterBloc.fetchCurrent(false);
},
child: const Text(
'Add Value to stream 2',
style: TextStyle(color: Colors.red),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
newCounterBloc.resetData();
},
child: const Text(
'Set to no data stream 2',
style: TextStyle(color: Colors.red),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
newCounterBloc.fetchCurrent(true);
},
child: const Text(
'Add Error to stream 2',
style: TextStyle(color: Colors.red),
)),
],
),
const SizedBox(
height: 34,
)
],
),
),
);
}
}
class CounterBloc2 with BaseBloc<double, String> {
double value = 0;
CounterBloc2() {
fetchCurrent(false);
}
fetchCurrent(bool addError) async {
setAsLoading();
if (!addError) {
await Future.delayed(const Duration(seconds: 2));
value += 0.5;
addToModel(value);
} else {
value = 0;
addToError('Could not fetch data');
}
}
resetData() {
value = 0;
setAsNoContent();
}
invalidate() {
invalidateBaseBloc();
}
dispose() {
disposeBaseBloc();
}
}
class ExampleMulti extends StatefulWidget {
const ExampleMulti({Key? key}) : super(key: key);
@override
State<ExampleMulti> createState() => _ExampleMultiState();
}
class _ExampleMultiState extends State<ExampleMulti> {
final counterBloc = CounterBloc();
final newCounterBloc = CounterBloc2();
@override
void dispose() {
super.dispose();
counterBloc.dispose();
newCounterBloc.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: CustomStreamBuilder.multiSubject(
streams: [
counterBloc.behaviorSubject,
newCounterBloc.behaviorSubject
],
itemBuilderMulti: (context, data) {
var counterBlocData = data.first.model as int?;
var counterBlocState = data.first.itemState;
var counterBlocDataError = data.first.error as String?;
var newCounterBlocData = data.elementAt(1).model as double?;
var newCounterBlocState = data.elementAt(1).itemState;
var newCounterBlocError = data.elementAt(1).error as String?;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (counterBlocState == ItemState.loading)
const Center(
child: CircularProgressIndicator(),
)
else if (counterBlocState == ItemState.hasError)
Text(
'counterBlocData error: $counterBlocDataError',
style: const TextStyle(fontSize: 34),
)
else if (counterBlocState == ItemState.noContent)
const SizedBox()
else
Text(
'counterBlocData: $counterBlocData',
style: const TextStyle(fontSize: 34),
),
const SizedBox(
height: 34,
),
if (newCounterBlocState == ItemState.loading)
const Center(
child: CircularProgressIndicator(),
)
else if (newCounterBlocState == ItemState.hasError)
Text(
'newCounterBlocError error: $newCounterBlocError',
style: const TextStyle(fontSize: 34),
)
else if (newCounterBlocState == ItemState.noContent)
const SizedBox()
else
Text(
'newCounterBlocData: $newCounterBlocData',
style: const TextStyle(fontSize: 34),
),
],
));
},
),
),
const SizedBox(
height: 34,
),
Wrap(
children: [
TextButton(
onPressed: () {
counterBloc.fetchCurrent(false);
},
child: const Text(
'Add Value to stream 1',
style: TextStyle(),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
counterBloc.resetData();
},
child: const Text(
'Set to no data stream 1',
style: TextStyle(),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
counterBloc.fetchCurrent(true);
},
child: const Text(
'Add Error to stream 1',
style: TextStyle(),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
newCounterBloc.fetchCurrent(false);
},
child: const Text(
'Add Value to stream 2',
style: TextStyle(color: Colors.red),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
newCounterBloc.resetData();
},
child: const Text(
'Set to no data stream 2',
style: TextStyle(color: Colors.red),
)),
const SizedBox(
width: 34,
),
TextButton(
onPressed: () {
newCounterBloc.fetchCurrent(true);
},
child: const Text(
'Add Error to stream 2',
style: TextStyle(color: Colors.red),
)),
],
),
const SizedBox(
height: 34,
)
],
),
),
);
}
}
copied to clipboard
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.