I'm using the BLOC pattern to get the events and build my listview. I'm also using animation to appears each list. When I go to the child class, ItemEffect, I can't refresh parent class using BLOC method. In another word, when I go to ItemEffect class, the "await visitBloc.getVisits(contactId: contact.id);" in onItemClick function, couldn't refresh the parent class stream builder. I think something in animation stream builder, in ItemEffect class, cause losing the control of visit.bloc stream. I'm new in flutter and can't self this problem alone, can anyone help me, please?
class CustomerVisitsScreen extends StatefulWidget {
Contact contact;
int visitNumber =
10000; // If we set 0 as inital set, the image appears after another one
CustomerVisitsScreen(this.contact);
@override
_CustomerVisitsScreenState createState() => _CustomerVisitsScreenState();
}
class _CustomerVisitsScreenState extends State<CustomerVisitsScreen>
with SingleTickerProviderStateMixin {
VisitBloc visitBloc;
final ContactBloc contactBloc = ContactBloc();
final ListBloc listBloc = new ListBloc();
@override
void initState() {
super.initState();
//---
visitBloc = VisitBloc(contactId: widget.contact.id);
//---
WidgetsBinding.instance.addPostFrameCallback((_) {
getCategoryColorList();
countVisits(widget.contact.id);
});
}
@override
void dispose() {
listBloc.dispose();
visitBloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: Container(
decoration: BoxDecoration(
image: widget.visitNumber == 0
? DecorationImage(
image: AssetImage("assets/Image/Add.png"),
fit: BoxFit.none,
)
: DecorationImage(
image: AssetImage("assets/Image/Background.png"),
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.15),
BlendMode.dstATop),
)),
child: Column(
children: [
AppBar_SeaShape(context),
SizedBox(
height: 10,
),
Expanded(
child: getVisitsWidget(),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => onAddFactor(context, widget.contact),
child: Icon(Icons.add),
)));
}
Widget getVisitsWidget() {
return StreamBuilder(
stream: visitBloc.visits,
initialData: <Visit>[],
builder: (BuildContext context, AsyncSnapshot<List<Visit>> snapshot) {
return visitListView(snapshot.data);
},
);
}
ListView visitListView(List<Visit> list) {
listBloc.startAnimation(list.length, Duration(milliseconds: 50));
return ListView.builder(
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
final item = list[index];
int _colorCat = getListColor(list[index]);
return Dismissible(
//--- Date and Time is combined as a key to generate uniqe KEY
key: Key((item.visitDate + item.visitTime)),
confirmDismiss: (DismissDirection direction) async {
return await showDialog(
context: context,
builder: (BuildContext context) {
return MyAlertDialog();
},
);
},
onDismissed: (DismissDirection direction) {
deleteVisit(item);
},
child: ItemEffect(context, list[index], index, widget.contact,
Duration(milliseconds: 200), _colorCat),
);
});
}
}
class ItemEffect extends StatefulWidget {
final BuildContext context;
final Visit visit;
final int position;
final Contact contact;
final Duration duration;
final int color;
ItemEffect(this.context, this.visit, this.position, this.contact,
this.duration, this.color);
_ItemEffect createState() => new _ItemEffect();
}
class _ItemEffect extends State<ItemEffect> with TickerProviderStateMixin {
AnimationController _controller;
Animation<Offset> _offsetFloat;
final VisitBloc visitBloc = VisitBloc();
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: widget.duration,
);
_offsetFloat = Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset.zero)
.animate(_controller);
}
@override
Widget build(BuildContext context) {
return new StreamBuilder(
stream: new ListBloc().listenAnimation,
initialData: -1,
builder: (context, AsyncSnapshot<int> snapshot) {
if (snapshot.data >= widget.position && snapshot.data > -1)
_controller.forward();
return SlideTransition(
position: _offsetFloat,
child: Stack(
alignment: Alignment.topLeft,
children: [
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
color: Color(widget.color ?? 0),
child: Card(
color: Theme.of(context).cardColor,
elevation: 5.0,
shadowColor: Theme.of(context).accentColor,
margin: EdgeInsets.only(right: 15, top: 2),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text('${widget.visit.totalPrice}' ?? ""),
SizedBox(
width: 10,
),
Icon(
Icons.payments_outlined,
color: Colors.grey,
),
],
),
],
),
subtitle: Text(widget.visit.category ?? ""),
onTap: () {
onItemClick(
context,
widget.contact,
widget.visit,
);
},
),
),
),
alarmWidget(widget.visit),
],
));
});
}
void onItemClick(BuildContext context, Contact contact, Visit visit) async {
//--- Go to N ext Screen
await Navigator.push(context,
MaterialPageRoute(builder: (context) => FactorScreen(contact, visit)));
//--- Turned Back to this Screen and Should Refresh List
await visitBloc.getVisits(contactId: contact.id);
// setState(() {});
}
}