Related
I have this problem with this code. I tried to solve the problem, but I did not succeed. Please Help
Please see the screenshots to understand the problem well
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 370 pos 10: 'data != null'
Pictures description error
null in firebase
The users email address.Will be null if signing in anonymously.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flash_chat/constants.dart';
class ChatScreen extends StatefulWidget {
static const Id = 'chat_screen';
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
// ignore: deprecated_member_use
final _firestore = Firestore.instance;
final _auth = FirebaseAuth.instance;
// ignore: deprecated_member_use
FirebaseUser loggedInUser;
String messageText;
#override
void initState() {
super.initState();
getCurrentUser();
}
void getCurrentUser() async {
try {
// ignore: await_only_futures
final user = await _auth.currentUser;
if (user != null) {
loggedInUser = user;
print(loggedInUser.email);
}
} catch (e) {
print(e);
}
}
// void getMessages() async {
// // ignore: deprecated_member_use
// final messages = await _firestore.collection('Messages').getDocuments();
// // ignore: deprecated_member_use
// for (var message in messages.docs) {
// print(message.data());
// }
// }
void messagesStream() async {
await for (var snapshot in _firestore.collection('Messages').snapshots()) {
for (var message in snapshot.docs) {
print(message.data());
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
messagesStream();
//_auth.signOut();
//Navigator.pop(context);
}),
],
title: Text('⚡️Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('Messages').snapshots(),
// ignore: missing_return
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
));
}
// ignore: deprecated_member_use
final messages = snapshot.data.documents;
List<Messagebubble> messagebubbles = [];
for (var message in messages) {
final messageText = message.data()['text'];
final messagesendar = message.data()['Sender'];
final messagebubble = Messagebubble(
sendar: messagesendar,
text: messageText,
);
messagebubbles.add(messagebubble);
}
return Expanded(
child: ListView(
padding: EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 20.0,
),
children: messagebubbles,
),
);
},
),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
FlatButton(
onPressed: () {
_firestore.collection('Messages').add({
'text': messageText,
'Sender': loggedInUser,
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class Messagebubble extends StatelessWidget {
Messagebubble({
Key key,
this.sendar,
this.text,
}) : super(key: key);
final String sendar;
final String text;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
children: [
Text(
sendar,
style: TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
Material(
borderRadius: BorderRadius.circular(30.0),
elevation: 5.0,
color: Colors.lightBlueAccent,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
child: Text(
text,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
),
),
),
),
],
),
);
}
}
You just need to check whether the text that you are passing is null or not. If it is null, you can show that the user is Anonymous.
final messageText = message.data()['text'];
final messagesendar = message.data()['Sender'] ?? 'Anonymous'; // If null then use 'Anonymous'
final messagebubble = Messagebubble(
sendar: messagesendar,
text: messageText,
);
Flutter doesn't allow you to pass null to Text widgets.
https://i.stack.imgur.com/9k5MB.png
I am new to flutter and I'm working on social distancing app in flutter. I wanted to push the uuid of bluetooth devices discovered to the firestore can someone please help me in doing this
I can print out the discovered devices in my app and i can get rssi uuid txpower
but as rssi keeps varying and scanning happens continuously the devices get pushed into firestore multiple times
i wanted UUID to be pushed into the firestore only once.
Nearby.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:beacon_broadcast/beacon_broadcast.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'homescreen.dart';
import 'material.dart';
class BlueApp extends StatefulWidget {
#override
_BlueAppState createState() => _BlueAppState();
}
BeaconBroadcast beaconBroadcast = BeaconBroadcast();
BeaconStatus _isTransmissionSupported;
bool _isAdvertising = false;
StreamSubscription<bool> _isAdvertisingSubscription;
final databaseReference=Firestore.instance;
String UUID = "3E4D7TJ9008";
void createRecord(String usid) async {
await databaseReference.collection("users")
.document("1")
.setData({
'uuid':usid
});
print('senddddddddingggggg');
DocumentReference ref = await databaseReference.collection("users")
.add({
'uuid':usid
});
print(ref.documentID);
}
class _BlueAppState extends State<BlueApp> {
static const UUID = '39ED98FF';
static const MAJOR_ID = 1;
static const MINOR_ID = 100;
static const TRANSMISSION_POWER = -59;
static const IDENTIFIER = 'com.example.myDeviceRegion';
static const LAYOUT = BeaconBroadcast.ALTBEACON_LAYOUT;
static const MANUFACTURER_ID = 0x0118;
void initState() {
// TODO: implement initState
super.initState();
FlutterBlue.instance.state.listen((state) {
print("im in the init");
print(state);
if (state == BluetoothState.off) {
print("bluetooth is off");
} else if (state == BluetoothState.on) {
print("bluethooth on");
//print(device.id);
}
print("printing eacon");
});
beaconBroadcast.checkTransmissionSupported().then((isTransmissionSupported) {
setState(() {
_isTransmissionSupported = isTransmissionSupported;
print(_isTransmissionSupported);
});
});
_isAdvertisingSubscription =
beaconBroadcast.getAdvertisingStateChange().listen((isAdvertising) {
setState(() {
_isAdvertising = isAdvertising;
});
});
beaconBroadcast
.setUUID(UUID)
.setMajorId(MAJOR_ID)
.setMinorId(MINOR_ID)
.setTransmissionPower(-59)
.setIdentifier(IDENTIFIER)
.setLayout(LAYOUT)
.setManufacturerId(MANUFACTURER_ID)
.start();
if(_isAdvertising==true){
print('Beacon started Advertising');
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
color: Colors.lightBlue,
home: StreamBuilder<BluetoothState>(
stream: FlutterBlue.instance.state,
initialData: BluetoothState.turningOn,
builder: (c, snapshot) {
final state = snapshot.data;
print(state);
if (state == BluetoothState.on) {
print("BlueTooth is on");
return FindDevicesScreen();
}
print("BlueTooth is off");
return BluetoothOffScreen(state: state);
}),
);
}
}
class BluetoothOffScreen extends StatelessWidget {
const BluetoothOffScreen({Key key, this.state}) : super(key: key);
final BluetoothState state;
#override
Widget build(BuildContext context) {
_BlueAppState a=new _BlueAppState();
createRecord(UUID);
return Scaffold(
backgroundColor: Colors.lightBlue,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.bluetooth_disabled,
size: 200.0,
color: Colors.white54,
),
Text(
'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.',
style: Theme.of(context)
.primaryTextTheme
.subhead
.copyWith(color: Colors.white),
),
],
),
),
);
}
}
class FindDevicesScreen extends StatefulWidget {
#override
_FindDevicesScreenState createState() => _FindDevicesScreenState();
}
class _FindDevicesScreenState extends State<FindDevicesScreen> {
#override
void initState() {
// TODO: implement initState
super.initState();
FlutterBlue.instance.startScan();
beaconBroadcast.checkTransmissionSupported().then((isTransmissionSupported) {
setState(() {
_isTransmissionSupported = isTransmissionSupported;
print(_isTransmissionSupported);
});
});
_isAdvertisingSubscription =
beaconBroadcast.getAdvertisingStateChange().listen((isAdvertising) {
setState(() {
_isAdvertising = isAdvertising;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Find Devices'),
),
body: RefreshIndicator(
onRefresh: () =>
FlutterBlue.instance.startScan(),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
StreamBuilder<List<BluetoothDevice>>(
stream: Stream.periodic(Duration(seconds: 4))
.asyncMap((_) => FlutterBlue.instance.connectedDevices),
initialData: [],
builder: (c, snapshot) => Column(
children: snapshot.data
.map((d) => ListTile(
title: Text(d.name),
subtitle: Text(d.id.toString()),
trailing: StreamBuilder<BluetoothDeviceState>(
stream: d.state,
initialData: BluetoothDeviceState.disconnected,
builder: (c, snapshot) {
print('entering if');
if (true) {
print('id----------------------------------------------did');
}
return Text(snapshot.data.toString());
},
),
))
.toList(),
),
),
StreamBuilder<List<ScanResult>>(
stream: FlutterBlue.instance.scanResults,
initialData: [],
builder: (c, snapshot) => Column(
children: snapshot.data
.map(
(r) => Card(
child: ScanResultTile(
result: r,
onTap: () => Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
return null;
})),
),
),
)
.toList(),
),
),
],
),
),
),
);
}
}
material.dart
import 'package:flutter_blue/flutter_blue.dart';
import 'nearby.dart';
class ScanResultTile extends StatelessWidget {
const ScanResultTile({Key key, this.result, this.onTap}) : super(key: key);
final ScanResult result;
final VoidCallback onTap;
Widget _buildTitle(BuildContext context) {
if (result.device.name.length > 0) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
result.device.name,
overflow: TextOverflow.ellipsis,
),
Text(
result.device.id.toString(),
style: Theme.of(context).textTheme.caption,
),
// _buildAdvRow(
// context, 'Distance of the device',(result.rssi!=null && result.advertisementData.txPowerLevel!=null)?"${getDistance(result.rssi,result.advertisementData.txPowerLevel)}":"N/A" ),
],
);
} else {
return Text(result.device.id.toString());
}
}
Widget _buildAdvRow(BuildContext context, String title, String value) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(title, style: Theme.of(context).textTheme.caption),
SizedBox(
width: 12.0,
),
Expanded(
child: Text(
value,
style: Theme.of(context)
.textTheme
.caption
.apply(color: Colors.black),
softWrap: true,
),
),
],
),
);
}
String getNiceHexArray(List<int> bytes) {
return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
.toUpperCase();
}
int getDistance(int rssi, int txPower) {
print("rssi");
print(rssi);
return 10 ^ ((txPower - rssi) / (10 * 2)).round();
}
#override
Widget build(BuildContext context) {
print("rssi");
print(result.rssi);
print("Transmit power");
print(result.advertisementData.txPowerLevel);
// print(result.device.name);
print(result);
// if((getDistance(result.rssi,result.advertisementData.txPowerLevel))<=2)
// {
// createRecord(result.advertisementData.serviceUuids.iterator.moveNext().toString());
// }
return ExpansionTile(
title: _buildTitle(context),
leading: Column(
children: <Widget>[
Text("Tap for more...",style: TextStyle(fontSize: 10.0,color: Colors.lightBlueAccent),)
],
),
children: <Widget>[
_buildAdvRow(
context, 'Distance of the device',(result.rssi!=null && result.advertisementData.txPowerLevel!=null)?"${getDistance(result.rssi,result.advertisementData.txPowerLevel)}":"N/A" ),
_buildAdvRow(context, 'Tx Power Level',
'${result.advertisementData.txPowerLevel ?? 'N/A'}'),
_buildAdvRow(
context,
'Service UUIDs',
(result.advertisementData.serviceUuids.isNotEmpty)? result.advertisementData.serviceUuids.join(', ').toUpperCase(): 'N/A'),
],
);
}
}
class ServiceTile extends StatelessWidget {
final BluetoothService service;
final List<CharacteristicTile> characteristicTiles;
const ServiceTile({Key key, this.service, this.characteristicTiles})
: super(key: key);
#override
Widget build(BuildContext context) {
if (characteristicTiles.length > 0) {
return ExpansionTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Service'),
Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Theme.of(context).textTheme.caption.color))
],
),
children: characteristicTiles,
);
} else {
return ListTile(
title: Text('Service'),
subtitle:
Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}'),
);
}
}
}
class CharacteristicTile extends StatelessWidget {
final BluetoothCharacteristic characteristic;
final List<DescriptorTile> descriptorTiles;
final VoidCallback onReadPressed;
final VoidCallback onWritePressed;
final VoidCallback onNotificationPressed;
const CharacteristicTile(
{Key key,
this.characteristic,
this.descriptorTiles,
this.onReadPressed,
this.onWritePressed,
this.onNotificationPressed})
: super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder<List<int>>(
stream: characteristic.value,
initialData: characteristic.lastValue,
builder: (c, snapshot) {
final value = snapshot.data;
return ExpansionTile(
title: ListTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Characteristic'),
Text(
'0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context).textTheme.body1.copyWith(
color: Theme.of(context).textTheme.caption.color))
],
),
subtitle: Text(value.toString()),
contentPadding: EdgeInsets.all(0.0),
),
children: descriptorTiles,
);
},
);
}
}
class DescriptorTile extends StatelessWidget {
final BluetoothDescriptor descriptor;
final VoidCallback onReadPressed;
final VoidCallback onWritePressed;
const DescriptorTile(
{Key key, this.descriptor, this.onReadPressed, this.onWritePressed})
: super(key: key);
#override
Widget build(BuildContext context) {
return ListTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Descriptor'),
Text('0x${descriptor.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Theme.of(context).textTheme.caption.color))
],
),
subtitle: StreamBuilder<List<int>>(
stream: descriptor.value,
initialData: descriptor.lastValue,
builder: (c, snapshot) => Text(snapshot.data.toString()),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(
Icons.file_download,
color: Theme.of(context).iconTheme.color.withOpacity(0.5),
),
onPressed: onReadPressed,
),
IconButton(
icon: Icon(
Icons.file_upload,
color: Theme.of(context).iconTheme.color.withOpacity(0.5),
),
onPressed: onWritePressed,
)
],
),
);
}
}
class AdapterStateTile extends StatelessWidget {
const AdapterStateTile({Key key, #required this.state}) : super(key: key);
final BluetoothState state;
#override
Widget build(BuildContext context) {
return Container(
color: Colors.redAccent,
child: ListTile(
title: Text(
'Bluetooth adapter is ${state.toString().substring(15)}',
style: Theme.of(context).primaryTextTheme.subhead,
),
trailing: Icon(
Icons.error,
color: Theme.of(context).primaryTextTheme.subhead.color,
),
),
);
}
}```
To avoid adding it additional times there are two altenatives.
Alternative 1:
Index the uuid field, as this will allow you to query over this field
Before writing query for documents with this uuid
Write only if the response is empty
This alternative has the advantage that no changes need to be done on firestore and minimun changes on the code, however will have the disadvantage that each write attempt will be preceeded by a read and reads are billed.
Alternative 2:
Change the data structucture on Firestore so that the UUID is the document ID
This has the advantage that the writes won't be preceeded by a read therefore its cheaper on firestore costs. However it needs more code edition and will need to change the data stucture.
for the code the main change is on the following method:
void createRecord(String usid) async {
await databaseReference.collection("users")
.document(usid)
.setData({
'uuid':usid
});
print('senddddddddingggggg');
DocumentReference ref = await databaseReference.collection("users")
.document(usid)
.setData({
'uuid':usid
});
print(ref.documentID);
}
I tried many things but couldn't get any workable solution, please help.
Even wit the FutureBuilder it doesn't seem to work and without it, I get the result when I hot reload. I don't know how to change the code to make it work. Probably there is something small missing, but I couldn't figure yet what it is or how to solve it.
"""import 'package:flutter/material.dart';
import 'package:list/screens/add_new_item_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
final _firestore = Firestore.instance;
FirebaseUser loggedinUser;
Future<void> _fetchdata;
FirebaseAuth _auth = FirebaseAuth.instance;
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
void initState() {
super.initState();
_fetchdata = getCurrentUser();
}
Future<void> getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedinUser = user;
// print(loggedinUser.email);
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(
builder: (context) => Addnewitem()));
},
child: Icon(Icons.add),
),
appBar: AppBar(
leading: Container(),
title: Text("Shopping List"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
// messagesStream();
_auth.signOut();
Navigator.pop(context);
})
],
),
body: SafeArea(child:
MessagesStream(),
),
);
}
}
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
FutureBuilder(
future: _fetchdata,
builder: (context, myFuture){
if (myFuture.connectionState == ConnectionState.done && !myFuture.hasError && myFuture.hasData) {
if (myFuture.data != null) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('users')
.document(loggedinUser.uid)
.collection('items')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.hasError || snapshot.data == null || snapshot.connectionState == ConnectionState.waiting || loggedinUser.email == null) {
return (Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent)));
}
final items = snapshot.data.documents.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in items) {
final item = message.data['item'];
final quant = message.data['quant'];
final id = message.data['id'];
final boli = message.data['bool'];
// final currentUser = loggedinUser.email;
final messageBubble = MessageBubble(
text: item,
quant: quant,
documentReference: message.reference,
);
messageBubbles.add(messageBubble);
}
try {
return Expanded(
child: ListView(
// reverse: true,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
children: messageBubbles,
),
);
} catch (e) {
return Container();
}
});
}else {
return Container();
}
} else {
return CircularProgressIndicator();
}
});
}
}
class MessageBubble extends StatelessWidget {
MessageBubble({this.text, this.quant, this.documentReference});
final String text;
final String quant;
final DocumentReference documentReference;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
color: Colors.tealAccent,
child: FlatButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
text,
style: TextStyle(color: Colors.black, fontSize: 20),
),
Text(quant,
style: TextStyle(color: Colors.black, fontSize: 20))
],
),
onPressed: () {
documentReference.delete();
}),
)
],
),
),
);
}
}"""
Flutter doctor:
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.4)
[✓] Chrome - develop for the web
[✓] Android Studio (version 3.5)
[✓] VS Code (version 1.44.0)
[✓] Connected device (3 available)
• No issues found!
You need to add return keyword when using the build function since it returns a Widget:
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _fetchdata,
builder: (context, myFuture){
if (myFuture.connectionState == ConnectionState.done && !myFuture.hasError && myFuture.hasData) {
if (myFuture.data != null) {
return StreamBuilder<QuerySnapshot>(
For people having the same issue - here is my full code! Hope it helps
import 'package:flutter/material.dart';
import 'package:list/screens/add_new_item_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
final _firestore = Firestore.instance;
FirebaseUser loggedinUser;
Future<void> _fetchdata;
FirebaseAuth _auth = FirebaseAuth.instance;
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
void initState() {
super.initState();
_fetchdata = getCurrentUser();
}
Future<void> getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedinUser = user;
// print(loggedinUser.email);
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Addnewitem()));
},
child: Icon(Icons.add),
),
appBar: AppBar(
leading: Container(),
title: Text("Shopping List"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
// messagesStream();
_auth.signOut();
Navigator.pop(context);
})
],
),
body: SafeArea(
child: MessagesStream(),
),
);
}
}
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _fetchdata,
builder: (context, myFuture) {
if (myFuture.connectionState == ConnectionState.done &&
!myFuture.hasError) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('users')
.document(loggedinUser.uid)
.collection('items')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData ||
snapshot.hasError ||
snapshot.data == null ||
snapshot.connectionState == ConnectionState.waiting ||
loggedinUser.email == null) {
return (Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent)));
}
final items = snapshot.data.documents.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in items) {
final item = message.data['item'];
final quant = message.data['quant'];
final id = message.data['id'];
final boli = message.data['bool'];
// final currentUser = loggedinUser.email;
final messageBubble = MessageBubble(
text: item,
quant: quant,
documentReference: message.reference,
);
messageBubbles.add(messageBubble);
}
try {
return Expanded(
child: ListView(
// reverse: true,
padding:
EdgeInsets.symmetric(horizontal: 10, vertical: 10),
children: messageBubbles,
),
);
} catch (e) {
return Container();
}
});
} else {
return CircularProgressIndicator();
}
});
}
}
class MessageBubble extends StatelessWidget {
MessageBubble({this.text, this.quant, this.documentReference});
final String text;
final String quant;
final DocumentReference documentReference;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
color: Colors.tealAccent,
child: FlatButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
text,
style: TextStyle(color: Colors.black, fontSize: 20),
),
Text(quant,
style: TextStyle(color: Colors.black, fontSize: 20))
],
),
onPressed: () {
documentReference.delete();
}),
)
],
),
),
);
}
}
I'm kinda new to flutter, I've been building a small app using firebase as the backend, whenever I try to load data from firebase I'm not able to fetch the value until I reload the app, this isn't the entire code,
I think the widgets are loading before the data itself, could really use ur help, is there any way that I could use the state to refresh the value?
mycode:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import "package:flutter/material.dart";
import 'package:mine_app/textingpage.dart';
class FriendsPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _FriendsPage();
}
}
class Friends {
final int theirTexts;
final String username;
final int myTexts;
final int totalTexts;
final String friendId;
Friends(this.theirTexts,this.totalTexts,this.username,this.myTexts,this.friendId);
Friends.fromMap(DocumentSnapshot map)
:assert(map["username"]!=null),
assert(map["myTexts"]!=null),
assert(map["theirTexts"]!=null),
assert(map["totalTexts"]!=null),
assert(map["uid"]!=null),
username = map["username"],
myTexts = map["myTexts"],
theirTexts = map["theirTexts"],
totalTexts = map["totalTexts"],
friendId = map["uid"];
}
class _FriendsPage extends State<FriendsPage> {
String user;
String globalid = "";
Future<void> getuser() async {
user = (await FirebaseAuth.instance.currentUser()).uid;
}
#override
void initState() {
getuser();
super.initState();
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: Color(0xff723881),
centerTitle: true,
title: Text(
"Chats",
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.people), text: "People"),
Tab(icon: Icon(Icons.search), text: "Find"),
],
indicatorColor: Colors.white,
),
),
body: TabBarView(
children: <Widget>[
Container(
child: snapShotBuilder(context)
),
Container()
],
)),
);
}
Widget snapShotBuilder(BuildContext context){
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("users").document(user).collection("friends").snapshots(),
builder:(context,snapshot){
if (!snapshot.hasData) {
return LinearProgressIndicator();
}
return myListView(context,snapshot.data.documents);
} );
}
Widget myListView(BuildContext context,List<DocumentSnapshot> snapshot){
return Container(
child: ListView(
children: snapshot.map((data)=>myfriends(Friends.fromMap(data))).toList(),
),
);
}
Widget myfriends(Friends friend) {
return Container(
margin: EdgeInsets.only(top: 10.0),
padding: EdgeInsets.all(5.0),
child: ListTile(
onTap:(){
setState(() {
globalid = friend.friendId;
});
print(friend.friendId);
Navigator.push(context, MaterialPageRoute(builder: (context)=>ChatPage(userid:friend.friendId)));
},
trailing: Container(
// margin: EdgeInsets.only(top:30.0,left:10.0,right:0.0),
child: Text(
friend.totalTexts.toString(),),
leading: Container(
width: 60.0,
height: 60.0,
),
title: Text(friend.username,),
),
);
}
}
Yo need to setState() in getUser() and also check if snapshot has data or not also.so the modified code will be
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import "package:flutter/material.dart";
import 'package:mine_app/textingpage.dart';
class FriendsPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _FriendsPage();
}
}
class Friends {
final int theirTexts;
final String username;
final int myTexts;
final int totalTexts;
final String friendId;
Friends(this.theirTexts,this.totalTexts,this.username,this.myTexts,this.friendId);
Friends.fromMap(DocumentSnapshot map)
:assert(map["username"]!=null),
assert(map["myTexts"]!=null),
assert(map["theirTexts"]!=null),
assert(map["totalTexts"]!=null),
assert(map["uid"]!=null),
username = map["username"],
myTexts = map["myTexts"],
theirTexts = map["theirTexts"],
totalTexts = map["totalTexts"],
friendId = map["uid"];
}
class _FriendsPage extends State<FriendsPage> {
String user;
String globalid = "";
Future<void> getuser() async{
setState((){
user = (await FirebaseAuth.instance.currentUser()).uid;
});
}
#override
void initState() {
getuser();
super.initState();
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: Color(0xff723881),
centerTitle: true,
title: Text(
"Chats",
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.people), text: "People"),
Tab(icon: Icon(Icons.search), text: "Find"),
],
indicatorColor: Colors.white,
),
),
body: TabBarView(
children: <Widget>[
Container(
child: snapShotBuilder(context)
),
Container()
],
)),
);
}
Widget snapShotBuilder(BuildContext context){
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("users").document(user).collection("friends").snapshots(),
builder:(context,snapshot){
if (snapshot.hasData) {
return myListView(context,snapshot.data.documents);
}else if(snapshot.hasError){
return Center(
child:Text(snapshot.error.toString()));
}else{
return LinearProgressIndicator();
}
} );
}
Widget myListView(BuildContext context,List<DocumentSnapshot> snapshot){
return Container(
child: ListView(
children: snapshot.map((data)=>myfriends(Friends.fromMap(data))).toList(),
),
);
}
Widget myfriends(Friends friend) {
return Container(
margin: EdgeInsets.only(top: 10.0),
padding: EdgeInsets.all(5.0),
child: ListTile(
onTap:(){
setState(() {
globalid = friend.friendId;
});
print(friend.friendId);
Navigator.push(context, MaterialPageRoute(builder: (context)=>ChatPage(userid:friend.friendId)));
},
trailing: Container(
// margin: EdgeInsets.only(top:30.0,left:10.0,right:0.0),
child: Text(
friend.totalTexts.toString(),),
leading: Container(
width: 60.0,
height: 60.0,
),
title: Text(friend.username,),
),
);
}
}
You are right. Widget is built at once after call of initState but you getting user data using Future so it is possilbe that Future is not completed yet. So you just need to wrap your main widget with FutureBuilder:
#override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: getUser(), // <-- your future
builder: (context,snapshot) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: Color(0xff723881),
centerTitle: true,
title: Text(
"Chats",
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.people), text: "People"),
Tab(icon: Icon(Icons.search), text: "Find"),
],
indicatorColor: Colors.white,
),
),
body: TabBarView(
children: <Widget>[
Container(
child: snapShotBuilder(context)
),
Container()
],
),
),
),
},
);
}
I using firebase to save my data and use flutter (dart) to access this data
Now. I have collection have the name (Customer_payment_details) I put random unique ID like this (tZ9d9cYeUvXKm1easHtr) and in this ID I have Sub Collection (Payment_info). in this subcollection have a unique ID. And in this id have many values.
I want to read this data as List
I write this code to access this data
This Code Belo Is My model name (Customer_payment_details)
class Customer_payment_details {
String customer_id;
String payment_date;
String stay_balance;
String amount_balance;
String customer_note;
String dept_now;
String id;
Customer_payment_details({ this.id ,this.customer_id, this.payment_date, this.stay_balance ,
this.customer_note , this.amount_balance , this.dept_now });
Customer_payment_details.fromMap_details(Map snapshot,String id) :
id = id ?? '',
customer_id = snapshot['customer_id'] ?? '',
payment_date = snapshot['payment_date'] ?? '',
stay_balance = snapshot['stay_balance'] ?? '',
amount_balance =snapshot["amount_balance"] ?? '',
customer_note = snapshot['customer_note'],
dept_now = snapshot['dept_now'];
toJson() {
return {
"customer_id" : customer_id,
"payment_date": payment_date,
"stay_balance" : stay_balance,
"amount_balance" : amount_balance,
"customer_note" : customer_note,
"dept_now" : dept_now,
};
}
}
This is my API:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
class payment_api {
final Firestore _db = Firestore.instance;
final String path;
CollectionReference ref;
payment_api(this.path) {
ref = _db.collection(path);
}
Future<QuerySnapshot> getDataCollection() {
return ref.getDocuments();
}
Stream<QuerySnapshot> streamDataCollection() {
return ref.snapshots();
}
Future<DocumentSnapshot> getDocumentById(String id) {
return ref.document(id).get();
}
Future<void> removeDocument(String id) {
return ref.document(id).delete();
}
Future<DocumentReference> addDocument(Map data, String customer_id) {
return ref.document(customer_id).collection("Payment_info").add(data);
}
Future<void> updateDocument(Map data, String id) {
return ref.document(id).updateData(data);
}
}
This is my screen:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:login_example/CustomerCore/models/cstomer_payment_detailsModel.dart';
import 'package:login_example/CustomerCore/models/productModel.dart';
import 'package:login_example/CustomerCore/viewmodels/CRUDModel.dart';
import 'package:login_example/CustomerCore/viewmodels/customer_paymentCRUD.dart';
import 'package:login_example/uiCustomer/widgets/payment_details_card.dart';
import 'package:login_example/uiCustomer/widgets/productCard.dart';
import 'package:provider/provider.dart';
class payment_details_view extends StatefulWidget {
#override
_payment_details_viewState createState() => _payment_details_viewState();
}
class _payment_details_viewState extends State<payment_details_view> {
List<Customer_payment_details> customers_information;
#override
Widget build(BuildContext context) {
final productProvider = Provider.of<customer_paymentCRUD>(context);
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepPurple,
title: Center(child: Text('ايوب محمد ابراهيم')),
),
body: Container(
child: StreamBuilder(
stream: productProvider.fetchcustomer_paymentsAsStream(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
customers_information = snapshot.data.documents
.map((doc) => Customer_payment_details.fromMap_details(doc.data,
doc.documentID)).toList();
return ListView.builder(
itemCount: customers_information.length,
itemBuilder: (buildContext, index) => payment_details_card(
customer_details: customers_information[index]),
);
This is my card:
class payment_details_card extends StatelessWidget {
final Customer_payment_details customer_details;
MoneyFormatterOutput fmf;
String convert_value (String value){
fmf = FlutterMoneyFormatter(
amount: double.parse(value),
settings: MoneyFormatterSettings(
symbol: 'د.ع',
thousandSeparator: ',',
decimalSeparator: '.',
symbolAndNumberSeparator: ' ',
fractionDigits: 0,
compactFormatType: CompactFormatType.short
)
).output;
return fmf.symbolOnLeft;
}
payment_details_card({#required this.customer_details});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
// Navigator.push(context, MaterialPageRoute(builder: (_) => CustomerProfilePage(customer_info:
customer_details)));
print(customer_details.id);
},
child: Padding(
padding: EdgeInsets.all(8),
child: Card(
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Container(
height: MediaQuery
.of(context)
.size
.height * 0.30,
width: MediaQuery
.of(context)
.size
.width * 0.9,
child: Column(
children: <Widget>[
Hero(
tag: customer_details.customer_id,
child : Material(
color: Colors.white70,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.only(right: 10.0 , top: 15.0),
child: Text(
//اسم الزبون
customer_details.customer_id,
textDirection: TextDirection.rtl,
style: TextStyle(
fontFamily: 'JannaLT-Regular',
fontWeight: FontWeight.w900,
fontSize: 22,
color: Colors.black,
),
),
),
etc...
The image below shows the database:
and this image for subcollection
I want to load this data as listview in card. Can anyone help for this?
Check this code.
stream: productProvider.fetchcustomer_paymentsAsStream(),
builder: (context,snapshot) {
if (snapshot.hasData) {
List<Customer_payment_details> customers_information= snapshot.data;
return ListView.builder(
itemCount: customers_information.length,
itemBuilder: (context, index){
return YourCardClass(
customers_information: customers_information[index]);
}