FutureBuilder shows [instance] instead of actual data - flutter

I want to download a list from firestore and display as a list in flutter widget. The data is successfully downloaded (proved by the print(cp.data()).
However, the result shown is [Instance of '_JsonQueryDocumentSnapshot'] instead of the actual carpark data.
Could anyone pls help point out what the bug is.
Thanks
class DownloadDataScreen extends StatefulWidget {
#override
_DownloadDataScreen createState() => _DownloadDataScreen();
}
class _DownloadDataScreen extends State<DownloadDataScreen> {
List<DocumentSnapshot> carparkList = []; //List for storing carparks
void initState() {
super.initState();
readFromFirebase();
}
Future readFromFirebase() async {
// await FirebaseFirestore.instance
await FirebaseFirestore.instance
.collection('carpark')
.get()
.then((QuerySnapshot snapshot) {
snapshot.docs.forEach(
(DocumentSnapshot cp) {
carparkList.add(cp);
print('printing cp');
print(cp.data());
},
);
});
**return carparkList;**
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: new Text(
'Car Park',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: FutureBuilder(
future: readFromFirebase(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
const Icon(
Icons.check_circle_outline,
color: Colors.green,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Column(
children: [
Text('Result: ${snapshot.data}'),
],
),
)
];
} else if (snapshot.hasError) {
children = <Widget>[
const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = const <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
),
);
}
}

First, you don't need to call the function from the init because you already use the FutureBuilder.
Also, you don't need to cast it because when the future completes, the async snapshot already would provide you a list of DocumentSnapshot in the data and the .doc propertie.
Like this:
FutureBuilder<QuerySnapshot>(
builder:(context,snapshot){
if(snapshot.hasData){
/// here your data
snapshot.data.docs;
}
)

Related

Flutter : Auto refresh to update the data

I am developing a cart page which contains + and - buttons, on pressing it , the value in the backend changes, but it doesn't automatically change in the frontend.
Cartpage.dart
class CartUI extends StatefulWidget {
const CartUI({Key? key}) : super(key: key);
#override
State<CartUI> createState() => _CartUIState();
}
class _CartUIState extends State<CartUI> {
#override
Widget build(BuildContext context) {
final user = Provider.of<Userr?>(context, listen: false);
return Scaffold(
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(children: [
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('myOrders')
.doc(user?.uid)
.collection('items')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Lottie.asset('assets/animations/delivery.json'),
);
} else {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (BuildContext context, int index) {
final DocumentSnapshot documentSnapshot =
snapshot.data!.docs[index];
return Container(
height: 120,
width: 300,
child: Row(
children: [
Column(
children: [
SizedBox(
width: 200,
child: Text(
documentSnapshot['name'],
style: const TextStyle(
color: Colors.black87,
fontWeight: FontWeight.bold,
fontSize: 15,
),
),
),
Text(
documentSnapshot['quantity'].toString(),
style: const TextStyle(
fontSize: 15,
),
),
Text(
'Rs.${documentSnapshot['price'].toString()}',
style: const TextStyle(
color: Colors.black87,
fontSize: 15,
),
),
Row(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
const SizedBox(
width: 40,
),
ElevatedButton(
onPressed: () {
if (documentSnapshot['value'] != 0.0) {
setState(() {
String id = documentSnapshot['docid'];
final user = Provider.of<Userr?>(context, listen: false);
var postDocRef = FirebaseFirestore.instance.collection('myOrders').doc(user?.uid).collection('items').doc();
Provider.of<Calculations>(context, listen: false).updatecartdata(
context,
{
'value': documentSnapshot['value'] - 0.5,
'price': documentSnapshot['price'] - (documentSnapshot['ogprice'] / 2),
},id
);
}
);
}
if (documentSnapshot['value'] ==
0.5) {
String id =
documentSnapshot['docid'];
Provider.of<ManageData>(
context,
listen: false)
.deleteData(context, id);
}
},
child: const Text('-'),
),
const SizedBox(width: 20),
Text(documentSnapshot['value']
.toString()),
const SizedBox(width: 20),
ElevatedButton(
onPressed: () {
String id =
documentSnapshot['docid'];
final user =
Provider.of<Userr?>(context,
listen: false);
var postDocRef =
FirebaseFirestore.instance
.collection('myOrders')
.doc(user?.uid)
.collection('items')
.doc();
Provider.of<Calculations>(context, listen: false).updatecartdata(
context,
{
'value': documentSnapshot['value'] + 0.5,
'price': documentSnapshot['price'] + (documentSnapshot['ogprice'] / 2),
},id
);
},
child: const Text('+'),
),
]),
],
),
],
),
);
});
}
},
),
),
_BillDetailView(),
]),
],
),
),
);
}
}
class _BillDetailView extends StatelessWidget {
#override
Widget build(BuildContext context) {
final textStyle =
Theme
.of(context)
.textTheme
.bodyText1!
.copyWith(fontSize: 16.0);
return Container(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Bill Details',
style:
Theme
.of(context)
.textTheme
.headline6!
.copyWith(fontSize: 17.0),
),
SizedBox(
height: 5,
),
FutureBuilder(
future: Provider.of<Calculations>(context, listen: false)
.getTotalCost(context),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('Item total', style: textStyle),
Text('${snapshot.data}', style: textStyle),
],
);
} else if (snapshot.hasError) {
return Text("Error: ${snapshot.error.toString()}");
} else {
return const CircularProgressIndicator();
}
},
),
],
),
);
}
}
Calculation.dart
Future<dynamic> getTotalCost(BuildContext context) async {
final user = Provider.of<Userr?>(context, listen: false);
double totalCost = 0.0;
QuerySnapshot snapshot = await FirebaseFirestore.instance
.collection('myOrders')
.doc(user?.uid)
.collection('items')
.get();
for (var doc in snapshot.docs) {
totalCost += doc["price"];
}
print(totalCost.toString());
return totalCost.toString();
}
The value in the front end changes but last updated(Added or subtracted) value is not reflecting.After hot reload it changes, but not automatically.
How to change this code to automatically update the item total in the front end.
You need to use StreamBuilder instead of FutureBuilder to get live updates.
Changes your Calculation.dart to:
Stream<dynamic> getTotalCost(BuildContext context) async {
final user = Provider.of<Userr?>(context, listen: false);
double totalCost = 0.0;
QuerySnapshot snapshot = await FirebaseFirestore.instance
.collection('myOrders')
.doc(user?.uid)
.collection('items')
.snapshots();
for (var doc in snapshot.docs) {
totalCost += doc["price"];
}
print(totalCost.toString());
return totalCost.toString();
}
And change FutureBuilder to StreamBuilder:
StreamBuilder(
stream: Provider.of<Calculations>(context, listen: false)
.getTotalCost(context),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('Item total', style: textStyle),
Text('${snapshot.data}', style: textStyle),
],
);
} else if (snapshot.hasError) {
return Text("Error: ${snapshot.error.toString()}");
} else {
return const CircularProgressIndicator();
}
},
),

Flutter text message is not being displayed on the foreground but is visible on cloud firestore

I have been working on the chat functionality of an app. However, I have found that the message is been saved on the backend but does not display on the screen. Any help will be beneficial. I would like to know where I went wrong and see if the chat functionality can function properly. I would like for the sender of the text message to see the message and have the ability to communicate with the receiver of the message seemlessly. Below is the code snippet:
class MessageCenter extends StatefulWidget {
final String garageUid;
final String garageName;
const MessageCenter(
{super.key, required this.garageUid, required this.garageName});
#override
State<MessageCenter> createState() =>
_MessageCenterState(garageName, garageUid);
}
class _MessageCenterState extends State<MessageCenter> {
CollectionReference chats = FirebaseFirestore.instance.collection('chats');
final String garageUid;
final String garageName;
final currentUserId = FirebaseAuth.instance.currentUser!.uid;
var chatDocId;
final _textController = TextEditingController();
_MessageCenterState(this.garageUid, this.garageName);
#override
void initState() {
chats
.where('users', isEqualTo: {garageUid: null, currentUserId: null})
.limit(1)
.get()
.then(
(QuerySnapshot querySnapshot) {
if (querySnapshot.docs.isNotEmpty) {
chatDocId = querySnapshot.docs.single.id;
} else {
chats.add({
'users': {currentUserId: null, garageUid: null}
}).then((value) => {chatDocId = value});
}
},
)
.catchError((error) {});
super.initState();
}
void sendMessage(String msg) {
if (msg == '') return;
chats.doc(chatDocId).collection('messages').add({
'createdOn': FieldValue.serverTimestamp(),
'uid': currentUserId,
'msg': msg
}).then((value) {
_textController.text = '';
});
}
bool isSender(String user) {
return user == currentUserId;
}
Alignment getAlignment(user) {
if (user == currentUserId) {
return Alignment.topRight;
}
return Alignment.topLeft;
}
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('chats')
.doc(chatDocId)
.collection('messages')
.orderBy('createdOn', descending: true)
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text('Something went wrong'),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasData) {
var data;
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
previousPageTitle: "back",
middle: Text(garageUid),
trailing: CupertinoButton(
child: const Icon(CupertinoIcons.phone),
onPressed: () {},
),
),
child: SafeArea(
child: Column(
children: [
Expanded(
child: ListView(
reverse: true,
children:
snapshot.data!.docs.map((DocumentSnapshot document) {
data = document.data()!;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: ChatBubble(
clipper: ChatBubbleClipper6(
nipSize: 0,
radius: 0,
type: isSender(data['uid'].toString())
? BubbleType.sendBubble
: BubbleType.receiverBubble,
),
alignment: getAlignment(data['uid'].toString()),
margin: const EdgeInsets.only(top: 20),
backGroundColor: isSender(data['uid'].toString())
? const Color(0xFF08C187)
: const Color(0xffE7E7ED),
child: Container(
constraints: BoxConstraints(
maxWidth:
MediaQuery.of(context).size.width * 0.7,
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
data['msg'],
style: TextStyle(
color:
isSender(data['uid'].toString())
? Colors.white
: Colors.black),
maxLines: 100,
overflow: TextOverflow.ellipsis,
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
data['createdOn'] == null
? DateTime.now().toString()
: data['createdOn']
.toDate()
.toString(),
style: TextStyle(
fontSize: 10,
color:
isSender(data['uid'].toString())
? Colors.white
: Colors.black),
),
],
),
],
),
),
),
);
}).toList(),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: CupertinoTextField(
controller: _textController,
)),
CupertinoButton(
child: const Icon(Icons.send_sharp),
onPressed: () => sendMessage(_textController.text))
],
),
],
),
),
);
}
return Container();
},
);
}
}

Flutter Cubit fetching and displaying data

I'm trying to fetch data from Genshin API, code below is working, but only with delay (in GenshinCubit class), it looks weard, because I don't know how much time to set for delay. I think, there is a problem in code, cause it must not set the GenshinLoaded state before the loadedList is completed. Now, if I remove the delay, it just sets the GenshinLoaded when the list is still in work and not completed, await doesn't help. Because of that I get a white screen and need to hot reload for my list to display.
class Repository {
final String characters = 'https://api.genshin.dev/characters/';
Future<List<Character>> getCharactersList() async {
List<Character> charactersList = [];
List<String> links = [];
final response = await http.get(Uri.parse(characters));```
List<dynamic> json = jsonDecode(response.body);
json.forEach((element) {
links.add('$characters$element');
});
links.forEach((element) async {
final response2 = await http.get(Uri.parse(element));
dynamic json2 = jsonDecode(response2.body);
charactersList.add(Character.fromJson(json2));
});
return charactersList;
}
}
class GenshinCubit extends Cubit<GenshinState> {
final Repository repository;
GenshinCubit(this.repository) : super(GenshinInitial(),);
getCharacters() async {
try {
emit(GenshinLoading());
List<Character> list = await repository.getCharactersList();
await Future<void>.delayed(const Duration(milliseconds: 1000));
emit(GenshinLoaded(loadedList: list));
}catch (e) {
print(e);
emit(GenshinError());
}
}
}
class HomeScreen extends StatelessWidget {
final userRepository = Repository();
HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<GenshinCubit>(
create: (context) => GenshinCubit(userRepository)..getCharacters(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: Container(child: const CharactersScreen())),
),
);
}
}
class CharactersScreen extends StatefulWidget {
const CharactersScreen({
Key? key,
}) : super(key: key);
#override
State<CharactersScreen> createState() => _CharactersScreenState();
}
class _CharactersScreenState extends State<CharactersScreen> {
#override
Widget build(BuildContext context) {
return Column(
children: [
BlocBuilder<GenshinCubit, GenshinState>(
builder: (context, state) {
if (state is GenshinLoading) {
return Center(
child: CircularProgressIndicator(),
);
}
if (state is GenshinLoaded) {
return SafeArea(
top: false,
child: Column(
children: [
Container(
color: Colors.black,
height: MediaQuery.of(context).size.height,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: state.loadedList.length,
itemBuilder: ((context, index) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 50.0, horizontal: 50),
child: GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CharacterDetailsPage(
character: state.loadedList[index],
),
),
),
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.3),
borderRadius: const BorderRadius.all(
Radius.circular(
30,
),
)),
child: Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(
right: 30.0, bottom: 30),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
state.loadedList[index].name
.toString(),
style: TextStyle(
color: Colors.black,
fontSize: 50),
),
RatingBarIndicator(
itemPadding: EdgeInsets.zero,
rating: double.parse(
state.loadedList[index].rarity
.toString(),
),
itemCount: int.parse(
state.loadedList[index].rarity
.toString(),
),
itemBuilder: (context, index) =>
Icon(
Icons.star_rate_rounded,
color: Colors.amber,
))
],
),
),
),
),
),
);
})),
),
],
),
);
}
if (state is GenshinInitial) {
return Text('Start');
}
if (state is GenshinError) {
return Text('Error');
}
return Text('Meow');
}),
],
);
}
}
I found a solution!
I've got that problem because of forEach. How to wait for forEach to complete with asynchronous callbacks? - there is a solution.

flutter check if data exists in firestore

I've been trying to check if user selected data matches with my firestore data.
onPressed: () async{
await Navigator.of(context).push(MaterialPageRoute(builder: (context) => Checker (
from: fromSel,
to: toSel,
)));
},
and in the second page i used
StreamBuilder(
stream: Firestore.instance
.collection('Schedules')
.where('from', isEqualTo: from)
.where('to', isEqualTo: to)
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (!snapshot.hasData)
return Center(child: CircularProgressIndicator());
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index){
DocumentSnapshot power = snapshot.data.documents[index];
print(power['from']);
print(power['to']);
return Container(
height: 200,
width: MediaQuery.of(context).size.width,
child: Column(
children: [
Text(power['from']),
Text(power['to'])
],
),
);
}
);
}),
so the problem i'm getting is it's not displaying the value when i use .where('from', isEqualTo: from) but it works when i use .where('from', isEqualTo: 'Adama'). and also works with .where('from', isEqualTo: from) when i instantiate from value manually like String from = 'Adama'
can you please tell me what the problem is?
and below is my firestore structure
below is the whole code for the checker (renamed to search)
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:demo/BookingPages/budget.dart';
import 'package:demo/Lists/trip.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Search extends StatefulWidget {
final from, to, seat, adult, child, infant;
final DateTime arrive, depart;
Search(
{Key key, this.from, this.to, this.seat, this.arrive, this.depart, this.adult, this.infant, this.child})
: super(key: key);
#override
_SearchState createState() => _SearchState(from: from, to: to, seat: seat, adult: adult, child: child, infant: infant, arrive: arrive, depart: depart);
}
class _SearchState extends State<Search> {
// Stream<QuerySnapshot> comparision;
var from, to, seat, adult, child, infant;
final DateTime arrive, depart;
_SearchState(
{Key key, this.from, this.to, this.seat, this.arrive, this.depart, this.adult, this.infant, this.child});
Stream<QuerySnapshot> comparision(BuildContext context) async* {
try{
yield* Firestore.instance
.collection('Schedules')
.where('from', isEqualTo: from.toString())
.where('to', isEqualTo: to.toString())
// .where('dates', arrayContains: widget.depart.day)
.snapshots();
}catch(e){
print(e);
}
}
// #override
// void initState() {
// // TODO: implement initState
// comparision = Firestore.instance
// .collection('Schedules')
// .where('from', isEqualTo: from)
// .where('to', isEqualTo: to)
// .snapshots();
//
// super.initState();
// }
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: StreamBuilder(
stream: Firestore.instance
.collection('Schedules')
.where('from', isEqualTo: from)
.where('to', isEqualTo: to)
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (!snapshot.hasData)
return Center(child: CircularProgressIndicator());
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index){
DocumentSnapshot power = snapshot.data.documents[index];
print(power['from']);
print(power['to']);
return Container(
height: 200,
width: MediaQuery.of(context).size.width,
child: Column(
children: [
Text(power['from']),
Text(power['to'])
],
),
);
}
);
}),
)
// Expanded(
// child: StreamBuilder<QuerySnapshot>(
// stream: comparision,
// builder: (BuildContext context, AsyncSnapshot<QuerySnapshot>snapshot) {
// if (!snapshot.hasData)
// return Center(child: CircularProgressIndicator());
// return ListView.builder(
// itemCount: snapshot.data.documents.length,
// itemBuilder: (context, index){
// DocumentSnapshot power = snapshot.data.documents[index];
// print(power['from']);
// print(power['to']);
// return Container(
// height: 200,
// width: MediaQuery.of(context).size.width,
// child: Column(
// children: [
// Text(power['from']),
// Text(power['to'])
// ],
// ),
// );
// }
// );
// },
// ),
// ),
],
)
);
}
}
class TripCard extends StatefulWidget {
#override
_TripCardState createState() => _TripCardState();
}
class _TripCardState extends State<TripCard> {
#override
Widget build(BuildContext context) {
return Container();
}
}
below is my first page code which includes the values
import 'package:flutter/material.dart';
import 'search.dart';
class Other extends StatefulWidget {
#override
_OtherState createState() => _OtherState();
}
class _OtherState extends State<Other> {
var from = [
'Addis Ababa', 'Adama', 'Dire Dawa', 'Ali Sabieh', 'Djibouti'
];
var fromSel = 'Addis Ababa';
var to = [
'Addis Ababa', 'Adama', 'Dire Dawa', 'Ali Sabieh', 'Djibouti'
];
var toSel = 'Djibouti';
#override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: Container(
//height: 203,
child: Column(
children: [
SizedBox(height: 15,),
Container(
//decoration: BoxDecoration(border: Border.all(color: Colors.grey)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: MediaQuery.of(context).size.width/2-19,
height: 60,
padding: EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('From', style: TextStyle(
fontSize: 18,
color: Colors.grey
),),
SizedBox(height: 0,),
Expanded(
child: DropdownButton<String>(
underline: Container(color: Colors.transparent),
items: from.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value, style: TextStyle(
fontSize: 18
),),
);
}).toList(),
isExpanded: true,
isDense: false,
elevation: 5,
hint: Text('From'),
value: fromSel,
onChanged: (String newValue){
setState(() {
this.fromSel = newValue;
});
}),
),
],
),
),
Container(height: 50, child: VerticalDivider(color: Colors.grey)),
Container(
width: MediaQuery.of(context).size.width/2-19,
height: 60,
padding: EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('To', style: TextStyle(
fontSize: 18,
color: Colors.grey
),),
SizedBox(height: 0,),
Expanded(
child: DropdownButton<String>(
underline: Container(color: Colors.transparent),
items: to.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value, style: TextStyle(
fontSize: 18
),),
);
}).toList(),
isExpanded: true,
isDense: false,
elevation: 5,
hint: Text('to'),
value: toSel,
onChanged: (String newValue){
setState(() {
this.toSel = newValue;
});
}),
),
],
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
child: MaterialButton(
onPressed: () async{
await Navigator.of(context).push(MaterialPageRoute(builder: (context) => Search (
from: fromSel,
to: toSel,
depart: _startDate,
arrive: _endDate,
seat: _options[_selectedIndex],
adult: adultSel.toString(),
child: childSel.toString(),
infant: infantSel.toString(),
)));
},
minWidth: MediaQuery
.of(context)
.size
.width - 80,
height: 45,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
color: Colors.lightGreen,
splashColor: Colors.green,
child: Text(
"Search",
style: TextStyle(color: Colors.white, fontSize: 18),
),
),
)
],
),
),
),
);
}
}

Streambuilder render twice, the first time with initial data the second one with correct data, but the widget doesn't update

Hi I'm new with flutter and I have troubles with the state. I'm using Bloc to handle state, but when I try to set a state in my first view I can't show it in my second view.
In the second view, streambuilder shows initial value first and connection waiting, then get correct data and state change to active, but the widget doesn't update.
First View
class LoginScreen extends StatefulWidget {
LoginScreen({Key key, this.title}) : super(key: key);
final String title;
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
Widget _divider() {
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: Row(
children: <Widget>[
SizedBox(
width: 30,
),
Expanded(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 30),
child: Divider(
thickness: 1,
),
),
),
SizedBox(
width: 20,
),
],
),
);
}
final _emailController = TextEditingController();
final _passwordController =TextEditingController();
_updateEmail (String text) => userBloc.updateUser(text);
Widget _emailPasswordWidget() {
return Column(
children: <Widget>[
EntryFields("Ingresa tu email", value:_emailController, onchanged: _updateEmail),
EntryFields("Ingresa tu Password",value: _passwordController, isPassword: true),
],
);
}
_goSignupScreen() async { return Navigator.pushNamed(context, Routes.signupRoute ); }
_goHomeScreen() async {
_updateEmail(_emailController.text);
return Navigator.pushNamed(context, Routes.homeRoute );
}
#override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
return Scaffold(
body: Container(
height: height,
child: Stack(
children: <Widget>[
Positioned(
top: -height * .15,
right: -MediaQuery.of(context).size.width * .4,
child: BezierContainer()),
Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: height* 0.2),
Center(child: AppIconWidget(image: 'assets/images/logo.png', scale: 0.1)),
SizedBox(height: 50),
_emailPasswordWidget(),
SizedBox(height: 20),
SubmitButton(title: 'Iniciar Sesión', onPressed: _goHomeScreen ),
Container(
padding: EdgeInsets.symmetric(vertical: 10),
alignment: Alignment.centerRight,
child: Text('Olvidaste tu contraseña?',
style: TextStyle(
fontSize: 14, fontWeight: FontWeight.w500)),
),
_divider(),
FacebookSignInButton(onPressed: (){}),
GoogleSignInButton(onPressed: () {}),
SizedBox(height: height * .055),
AccountLabel(label: 'No tienes cuenta?', btnText: 'Registrate', onPressed: _goSignupScreen ),
],
),
),
),
// Positioned(top: 40, left: 0, child: BackBtn() ),
],
),
),);
}
}
Bloc
class UserBloc {
final _userRepository = UserRepository();
final _userController = PublishSubject();;
Observable get getUser => _userController.stream;
updateUser(user) async {
var currentUser = await _userRepository.updateCurrentUser(user);
_userController.sink.add(currentUser);
return null;
}
dispose() {
_userController.close();
}
}
final userBloc = UserBloc();
Provider
class UserProvider {
Future updateCurrentUser(user) async{
return currentUser = user;
}
}
Repository
class UserRepository {
final userProvider = UserProvider();
Future updateCurrentUser(user) {
return userProvider.updateCurrentUser(user);
}
}
Second View
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('title')),
body: StreamBuilder(
initialData: 'here!',
stream: userBloc.getUser,
builder: (BuildContext context, AsyncSnapshot snapshot) {
print('...');
print('${snapshot.data}');
print('${snapshot.connectionState}');
print('...');
if (snapshot.hasError) return Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Select lot');
case ConnectionState.waiting:
return Text('Awaiting bids...');
case ConnectionState.active:
return Text('\$${snapshot.data}');
case ConnectionState.done:
return Text('\$${snapshot.data} (closed)');
}
return null; // unreachable
},
),
);
}
Thanks!
instead of doing switch for connectionState, i think it is better if you use snapshot.hasData
if (snapshot.hasData) {
return Text('\$${snapshot.data}');
} else {
return Text('Loading;);
}