The method '[]' was called on null & receiver: null - Flutter Android - flutter

There is an exception caught by widgets library, not sure whats wrong. Seems kinda issue with the Future builder here. Is that something missing like ELSE clause? Please guide. Code:
buildProfileHeader() {
return FutureBuilder(
future: usersRef.document(widget.profileId).get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
User user = User.fromDocument(snapshot.data);
return Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
CircleAvatar(
radius: 40.0,
backgroundColor: Colors.grey,
backgroundImage: CachedNetworkImageProvider(user.photoUrl),
),
Expanded(
flex: 1,
child: Column(
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
buildCountColumn("Videos", postCount),
buildCountColumn("Followers", 0),
buildCountColumn("Following", 0),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[buildProfileButton()],
),
],
),
),
],
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(top: 12.0),
child: Text(
user.username,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(top: 4.0),
child: Text(
user.displayName,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(top: 2.0),
child: Text(
user.bio,
),
),
],
),
);
},
);
}
The debug console shows:
The method '[]' was called on null.
Receiver: null
Tried calling:
The relevant error-causing widget was
FutureBuilder
Even though, the buildProfileButton() is also in place above the buildProfileHeader():
buildProfileButton() {
bool isProfileOwner = currentUserId == widget.profileId;
if (isProfileOwner) {
return buildButton(text: "Edit Profile", function: editProfile);
}
}

As can be seen in your buildProfileButton() function it will not return anything if condition is false. So you have to return something.
Return empty container at the end could be best solution.

Related

Everything in Firestore is working except when the document doesn't exist

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class OrderWidget extends StatelessWidget {
String companyId;
OrderWidget(this.companyId);
Stream<DocumentSnapshot> getData() async*{
var user = await FirebaseAuth.instance.currentUser;
yield* FirebaseFirestore.instance.collection('companies').doc(companyId).collection('orders').doc(user.uid).snapshots();
}
#override
Widget build(BuildContext context) {
return StreamBuilder<DocumentSnapshot>(
stream: getData(),
builder: (ctx, snapshots){
if(snapshots.hasData){
================================================here is the problem========================
return Column(children: [
SizedBox(height: 70,),
Container(
height: 350,
width: double.infinity,
child: Card(
elevation: 5,
child: Column(
children: [
SizedBox(height: 10,),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('OrderID:', style: TextStyle(fontSize: 18),),
Text(snapshots.data['orderId'], style: TextStyle(fontSize:18),),
],
),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Service:', style: TextStyle(fontSize: 18),),
Text(snapshots.data['partName'], style: TextStyle(fontSize: 18),
),
],
),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Old price:', style: TextStyle(fontSize: 18),),
Text(snapshots.data['oldPrice'], style:TextStyle(fontSize:18),),
],),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Price:', style: TextStyle(fontSize: 18),),
Text(snapshots.data['price'], style: TextStyle(fontSize: 18),),
],
),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Discount:', style: TextStyle(fontSize: 18),),
Text(snapshots.data['discount'], style: TextStyle(fontSize: 18),),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: FlatButton(
onPressed: (){
snapshots.data.reference.delete();
},
child: Text('Remove'),
color: Colors.red,
textColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
),
)
],
),
],
),
),
),
]
);
}else{
if(snapshots.hasError){
return Center(child: Text('There is no Orders yet!'),);}
}
}
);
}
}
Here is the error in console:
The following StateError was thrown building StreamBuilder<DocumentSnapshot<Object?>>(dirty, state: _StreamBuilderBaseState<DocumentSnapshot<Object?>, AsyncSnapshot<DocumentSnapshot<Object?>>>#4c964):
Bad state: cannot get a field on a DocumentSnapshotPlatform which does not exist
The relevant error-causing widget was
StreamBuilder<DocumentSnapshot<Object?>>
package:iparts_user/widgets/orders_widget.dart:18
When the exception was thrown, this was the stack
#0 DocumentSnapshotPlatform.get
package:cloud_firestore_platform_interface/…/platform_interface/platform_interface_document_snapshot.dart:76
#1 _JsonDocumentSnapshot.get
package:cloud_firestore/src/document_snapshot.dart:92
#2 _JsonDocumentSnapshot.[]
package:cloud_firestore/src/document_snapshot.dart:96
#3 OrderWidget.build.<anonymous closure>
package:iparts_user/widgets/orders_widget.dart:39
#4 StreamBuilder.build
package:flutter/…/widgets/async.dart:545
...
The error is in how you're reading the information from the DocumentSnapshot.
This line below:
snapshots.data['orderId']
should be updated to:
snapshots.data.data()['orderId']
DocumentSnapshotPlatform class Contains data read from a document in
your Firestore database.
The data can be extracted by calling data() or by calling get() to get
a specific field.
DocumentSnapshotPlatform class

Flutter error:Failed assertion: line 1785 pos 12: 'hasSize'

I have a code of recording Audio in flutter. The code should work perfectly without errors, whenever I try to call it from an alert dialog I end up with an error
The following assertion was thrown during performLayout():
RenderShrinkWrappingViewport does not support returning intrinsic
dimensions.
Calculating the intrinsic dimensions would require instantiating every
child of the viewport, which defeats the point of viewports being
lazy.
If you are merely trying to shrink-wrap the viewport in the main axis
direction, you should be able to achieve that effect by just giving
the viewport loose constraints, without needing to measure its
intrinsic dimensions.
Am trying to pass an option to record audio to an alert dialog. Users to record audio from a pop up instead of a main screen. What am I doing wrong?
What i have so far
Widget setupAlertDialoadContainer() {
return ListView(
shrinkWrap: true, //just set this property
padding: const EdgeInsets.all(8.0),
//children: listItems.toList(),
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 24.0, bottom: 16.0),
child: Text(
this._recorderTxt,
style: TextStyle(
fontSize: 48.0,
color: Colors.black,
),
),
),
_isRecording
? LinearProgressIndicator(
value: 100.0 / 160.0 * (this._dbLevel ?? 1) / 100,
valueColor: AlwaysStoppedAnimation<Color>(Colors.green),
backgroundColor: Colors.red,
)
: Container()
],
),
Row(
children: <Widget>[
Container(
width: 56.0,
height: 56.0,
margin: EdgeInsets.all(10.0),
child: FloatingActionButton(
heroTag: "Record",
onPressed: () {
if (!this._isRecording) {
return this.startRecorder();
}
this.stopRecorder();
},
child: this._isRecording ? Icon(Icons.stop) : Icon(Icons.mic),
),
),
],
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 60.0, bottom: 16.0),
child: Text(
this._playerTxt,
style: TextStyle(
fontSize: 48.0,
color: Colors.black,
),
),
),
],
),
Row(
children: <Widget>[
Container(
width: 56.0,
height: 56.0,
margin: EdgeInsets.all(8.0),
child: FloatingActionButton(
heroTag: "Start",
onPressed: () {
startPlayer();
},
child: Icon(Icons.play_arrow),
),
),
Container(
width: 56.0,
height: 56.0,
margin: EdgeInsets.all(8.0),
child: FloatingActionButton(
heroTag: "Pause",
onPressed: () {
pausePlayer();
},
child: Icon(Icons.pause),
),
),
Container(
width: 56.0,
height: 56.0,
margin: EdgeInsets.all(8.0),
child: FloatingActionButton(
heroTag: "Stop",
onPressed: () {
stopPlayer();
},
child: Icon(Icons.stop),
),
),
],
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
),
Container(
height: 56.0,
child: Slider(
value: slider_current_position,
min: 0.0,
max: max_duration,
onChanged: (double value) async {
await flutterSound.seekToPlayer(value.toInt());
},
divisions: max_duration.toInt()))
],
);
}
How am passing the data to the Alert dialog
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Record the data collection'),
content: setupAlertDialoadContainer(),
);
});
is the error is showing when alert box is opened??
if yes my suggestion is using
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Record the data collection'),
content: Container(
child:setupAlertDialoadContainer(),
height:200,
width:200,
),
);
});
change the width and height of container according to your need

Flutter: How to merge two StreamBuilder and show the output in a card

I'm kinda stuck with what I'm trying to do. I'm trying to merge my two Stream Builder to show the output as one in a card. In my first StreamBuilder thats where I'm getting some infos of the user like the info that he posted, what they need like that. And in my 2nd StreamBuilder thats where I get his/her name, contacts like that. Is it possible to merge it as one? so I'll get the data as one also.
This is how I use my StreamBuilders.
1st stream:
StreamBuilder<QuerySnapshot>(
stream: db.collection('HELP REQUEST').where('Type_OfDisaster', isEqualTo: '[Drought]').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList()
);
} else {
return Container(
child: Center(
child: CircularProgressIndicator()
)
);
}
}
);
2nd Stream:
StreamBuilder<QuerySnapshot>(
stream: db.collection('USERS').where('User_ID', isEqualTo: widget.Uid).snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList()
);
} else {
return Container(
child: Center(
child: CircularProgressIndicator()
)
);
}
}
);
Here is where I output the data I get in the stream builder:
Container buildItem(DocumentSnapshot doc) {
final _width = MediaQuery.of(context).size.width;
final _height = MediaQuery.of(context).size.height;
return Container(
child: Card(
elevation: 5,
child: Padding(
padding: const EdgeInsets.only(top: 20, left: 20, right: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
CircleAvatar(
radius: 30,
backgroundColor: Colors.black,
),
SizedBox(
width: 10,
),
Text('Name: '),
Text(
'${doc.data['Name_ofUser']}',
style: TextStyle(
fontSize: 15, fontWeight: FontWeight.w500),
)
],
),
],
),
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 20,
),
Row(
children: <Widget>[
Text('Date:'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'${doc.data['Help_DatePosted']}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 15, fontWeight: FontWeight.w500),
),
),
],
),
Row(
children: <Widget>[
Text('Location:'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'${doc.data['Help_Location']}',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.w500),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text('Description:'),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'${doc.data['Help_Description']}',
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.w500),
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Container(
height: _height * 0.05,
width: _width * 0.20,
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(20.0))),
color: Color(0xFF121A21),
onPressed: () {
_viewingRequest(doc.data);
},
child: Text(
'View',
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w800),
),
),
),
)
],
),
],
),
),
),
);
}
Is it possible to do it? Please help me.
You can listen to the snapshots without using a StreamBuilder directly, like this:
List<HelpRequestsPlusUsers> helpRequestsPlusUsers = [];
List<User> allUsers = [];
List<HelpRequest> helpRequests = [];
#override
void initState() {
db.collection('USERS').where('User_ID', isEqualTo: widget.Uid).snapshots().listen((snapshot){
allusers = snapshot.data.documents;
mergeUsersWithHelpRequests();
});
db.collection('HELP REQUEST').where('Type_OfDisaster', isEqualTo: '[Drought]').snapshots().listen((snapshot){
helpRequests = snapshot.data.documents;
mergeUsersWithHelpRequests();
});
super.initState();
}
void mergeUsersWithHelpRequests(){
// Run the code to merge your allUsers and helpRequests data into a helpRequestsPlusUsers List
}
Widget
Widget _buildHelpRequestsPlusUsersWidget (){
if (helpRequestsPlusUsers.isNotEmpty) {
return ListView.builder(
itemBuilder: (context, index){
return buildItem(helpRequestsPlusUsers[index]);
}
);
} else {
return Container(
child: Center(
child: CircularProgressIndicator()
)
);
}
}

Make a image visible instead of text for a particular time

I have built a chatbot using flutter and DialogueFlow I wanted to add a loading animation before the bot answers the question .
I have already made the loading animation but i am not able to show both, the text and the loading image.
class ChatMessage extends StatelessWidget {
ChatMessage({this.text, this.name, this.type});
final String text;
final String name;
final bool type;
List<Widget> botMessage(context) {
return <Widget>[
Container(
margin: const EdgeInsets.only(right: 16.0),
child: CircleAvatar(child: Image(
image:
NetworkImage('https://cdn3.iconfinder.com/data/icons/customer-support-
7/32/40_robot_bot_customer_help_support_automatic_reply-512.png'),
)
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(this.name,
style: TextStyle(fontWeight: FontWeight.bold)),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Text(text),
),
],
),
),
];
}
List<Widget> loader(context) {
return <Widget>[
Container(
margin: const EdgeInsets.only(right: 16.0),
child: CircleAvatar(child: Image(
image:
NetworkImage('https://cdn3.iconfinder.com/data/icons/customer-support-
7/32/40_robot_bot_customer_help_support_automatic_reply-512.png'),
)
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(this.name,
style: TextStyle(fontWeight: FontWeight.bold)),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Image(
image: AssetImage('assets/loader.gif'),
width: 25,
height: 25,
),
),
],
),
),
];
}
List<Widget> myMessage(context) {
return <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(this.name, style: Theme.of(context).textTheme.subhead),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Text(text),
),
],
),
),
Container(
margin: const EdgeInsets.only(left: 16.0),
child: CircleAvatar(
child: Text(
this.name[0],
style: TextStyle(fontWeight: FontWeight.bold),
)),
),
];
}
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: this.type ? myMessage(context) : botMessage(context),
),
);
}
}
I have just put loader instead of the botMessage in the last line of the code but how can i just show the loader for 5 seconds or so.
Mainly i want the loading animation like Google Assistant.
There are two ways to do what you want to do.
Create the object with a Boolean flag which is updated to true when data is received and using this flag as condition switch between text & loader widgets.
Use a futurebuilder widget & in future parameter use Future.delay with 5 seconds duration which is returning some value like 1 or true. Then inside the builder of futurebuilder check of snapshot has data. If snapshot don't have data, just show your loader else show your text.
See this video of futurebuilder to understand how it works.
https://youtu.be/ek8ZPdWj4Qo
Edited as #Maadhav asking for code,
Here is a little snippet which might help you.
FutureBuilder(
future: Future.delayed(Duration(seconds: 5), () => true),
builder: (context, snapshot){
if(!snapshot.hasData)
return CircularProgressIndicator();
return Text("Yay");
}
)
Here this FutureBuilder should be the container of your reply bubble in which you can return Text or any other widget according to your need.
For demo click here
The following can be used:
Future.delay(Duration(seconds: 5), () { });

Flutter display image after decode of BASE64

I believe I have successfully encoded an image to Base64 and stored as a JSON string in a JSON field.
In my app, I retrieve the field and then try to decode it; and, if it's there, I try to display it.
But I keep getting errors and no image appears. I have tried several things, but I keep getting assertion errors, either from Image_provider or Framework.
I have confirmed during debugging that I only have one record coming in with image data and it gets decoded and the assertions look correct.
Any thoughts or ideas?
#override
Widget build(BuildContext context) {
_key = new PageStorageKey('${widget.datediv.toString()}');
return new Column(
children: <Widget>[
new Container(
child: new Text(
mydate,
textAlign: TextAlign.left,
style: new TextStyle( color: Colors.grey, fontWeight: FontWeight.bold,),
),
alignment: Alignment.centerLeft,
padding: new EdgeInsets.only(left: 10.0),
),
new Container(
child: new Divider(
height: 5.0,
color: Colors.grey,
),
padding: new EdgeInsets.only(left: 10.0, right: 10.0),
),
/**/
new FutureBuilder(
future: _responseFuture,
builder:
(BuildContext context, AsyncSnapshot<http.Response> response) {
if (!response.hasData) {
return const Center(
child: const Text('Loading Messages...'),
);
} else if (response.data.statusCode != 200) {
return const Center(
child: const Text('Error loading data'),
);
} else {
List<dynamic> json = JSON.decode(response.data.body);
messagelist = [];
json.forEach((element) {
DateTime submitdate =
DateTime.parse(element['submitdate']).toLocal();
if (element['image'] != null) {
imgStr = element['image'];
Uint8List mybytes = BASE64.decode(imgStr);
}
_addImage() {
assert(imgStr != null);
new Container(
width: 150.0,
child: new Image.memory(mybytes),
);
}
_addNoImage() {
assert(imgStr == null);
new Text('');
}
messagelist.add(new Container(
//width: 300.0,
padding: new EdgeInsets.all(10.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Container(
padding: new EdgeInsets.only(bottom: 5.0),
child: new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new CircleAvatar(
child: new Text(element['sendname'][0], style: new TextStyle(fontSize: 15.0),),
radius: 12.0,
),
new Text(' '),
new Text(
element['sendname'],
style: new TextStyle(
fontSize: 15.0, fontWeight: FontWeight.bold),
),
new Text(' '),
new Text(new DateFormat.Hm().format(submitdate), style: new TextStyle(color: Colors.grey, fontSize: 12.0),),
],
),
),
new Row(
children: <Widget>[
new Text(' '),
new Flexible(
child: new Text('${element['message']}'),
)
],
),
imgStr != null ? _addImage(): _addNoImage(),
],
),
),
);
});
return new Column(children: messagelist);
}
},
),
],
);
}
You may want to consider checking if the image bytes that you're using in Image.memory(bytes) is valid. Flutter's current null-safety feature should help catch this early on. If imgStr is nullable, you can add a null-check for verification before returning Image.memory(). If null, then return a placeholder Widget.
As for your other question on adjusting the dimensions of the widget displayed. Aside from BoxDecoration, you can also use ConstrainedBox with BoxConstraints
ConstrainedBox(
constraints: BoxConstraints(
maxWidth: _maxWidth,
minWidth: _minWidth,
),
child: Image(...)
)