How am i able to retrieve specific users data using StreamBuilder? - firebase

1) This is the view team/view roster screen. https://imgur.com/a/k63lQrt
class ViewTeamScreen extends StatelessWidget {
static const routeName = '/view-team';
const ViewTeamScreen({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamProvider<List<User>>.value(
value: DBService().getAllUsers,
child: Scaffold(
body: TeamList()
),
);
}
}
2) This is the team list code that displays all user data on the ViewTeamScreen and returns a TeamTile widget i created.
class TeamList extends StatefulWidget {
#override
_TeamListState createState() => _TeamListState();
}
class _TeamListState extends State<TeamList> {
#override
Widget build(BuildContext context) {
final users = Provider.of<List<User>>(context) ?? [];
//print(users);
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return TeamTile(
user: users[index],
);
},
);
3) This is the TeamTile, which returns ListViewBuilder for a team member once they sign up to the app.
class TeamTile extends StatelessWidget {
final User user;
TeamTile({this.user});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 8.0),
child: Card(
margin: EdgeInsets.fromLTRB(20, 6, 20, 0),
child: ListTile(
leading: CircleAvatar(
radius: 30.0,
backgroundColor: Colors.brown,
),
title: Text(
'${user.firstName}'
" "
'${user.lastName}', //how do i make the first letter of name always CAPS?
style: TextStyle(fontSize: 23, letterSpacing: 1.0),
),
trailing: Text(user.email),
subtitle: Text('+44 0000 000 000'),
onTap: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TeamDetailScreen(),
),
);
},
),
4) This is the team detail screen, once the user taps on the ListTile in the ViewTeamScreen, this page will apear. https://imgur.com/a/7tSUO1c
class TeamDetailScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return Scaffold(
appBar: AppBar(
title: Text('Employee Contact Info'),
),
body: StreamBuilder<User>(
stream: DBService(uid: user.uid).usersData,
builder: (context, snapshot) {
if (snapshot.hasData) {
User userData = snapshot.data;
return Column(children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Name: ${userData.firstName}'
" "
'${userData.lastName}\n'
'Email: ${userData.email}',
style: TextStyle(fontSize: (20)),
),
)),
]);
} else {
return Loading();

This is going to exclude StreamProvider and just use StreamBuilder. This concept is easy to understand, as all we are doing is passing the widget.index down to other Widgets as arguments.
1
class ViewTeamScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<List<User>>(
stream: DBService().getAllUsers,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<User> userData = snapshot.data;
return Scaffold(body: TeamList(myData: userData));
} else {
return Loading();
}
});
}
}
2
class TeamList extends StatefulWidget {
final List<User> myData;
TeamList({this.myData});
#override
_TeamListState createState() => _TeamListState();
}
class _TeamListState extends State<TeamList> {
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.myData.length,
itemBuilder: (context, index) {
return TeamTile(
usersInfo: widget.myData[index],
);
},
);
}
}
3
class TeamTile extends StatelessWidget {
final User usersInfo;
TeamTile({this.usersInfo});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 8.0),
child: Card(
margin: EdgeInsets.fromLTRB(20, 6, 20, 0),
child: ListTile(
leading: CircleAvatar(
radius: 30.0,
backgroundColor: Colors.brown,
),
title: Text(
'${usersInfo.firstName}'
" "
'${usersInfo.lastName}', //how do i make the first letter of name always CAPS?
style: TextStyle(fontSize: 23, letterSpacing: 1.0),
),
trailing: Text(usersInfo.email),
subtitle: Text('+44 0000 000 000'),
onTap: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TeamDetailScreen(myDetails: usersInfo),
),
);
},
),
),
);
}
}
4
class TeamDetailScreen extends StatelessWidget {
final User myDetails;
TeamDetailScreen({this.myDetails});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Name: ${myDetails.firstName}'
" "
'${myDetails.lastName}\n'
'Email: ${myDetails.email}',
style: TextStyle(fontSize: (20)),
),
)),
]),
);
}
}

Related

How to get userdata from firestore when refreshing the browser?

I have a Flutter web application where I sign in and navigate to a homepage.
Here I display the name of the user and that is working fine until I refresh my browser.
When I refresh my browser it returns a null value, but when I navigate to another page and back again I retrieve the users name. So I hoping there is another way to do this so I get my users name after refreshing the browser.
When I try to retrieve the users email from FirebaseAuth instead of the usersname from Firestore it works fine when refreshing the browser. So I think it has something to do with how I retrieve it from Firestore.
Here is some of my code:
Main.dart
class MyApp extends StatelessWidget {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
final FirebaseAuth auth = FirebaseAuth.instance;
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initialization,
builder: (context, snapshot)
{
if (snapshot.hasError) {
return (MaterialApp(
home: UserLoginPage(
),
));
}
if (snapshot.connectionState == ConnectionState.done) {
print('CONNECTED');
return StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, snapshot) {
return MaterialApp(
home: snapshot.hasData && snapshot.data != null
? const UserHomePage()
: const UserLoginPage(),
routes: {
UserLoginPage.id: (context) => const UserLoginPage(),
UserHomePage.id: (context) => const UserHomePage(),
},
debugShowCheckedModeBanner: false,
);
}
);
}
return Column();
});
}
}
HomePage
class _UserHomePageState extends State<UserHomePage> {
final scaffoldkey = GlobalKey<ScaffoldState>();
User? user = FirebaseAuth.instance.currentUser;
Future _getUserData() async {
await FirebaseFirestore.instance.collection('users').doc(user?.uid)
.get()
.then((snapshot) async {
if (snapshot.exists) {
setState(() {
name = snapshot.data()!['Navn'];
print(name!);
});
}
});
}
DateTime now = DateTime.now();
#override
void initState() {
super.initState();
_getUserData();
}
//String
String? name = '';
String? formattedDate = DateFormat('yyyy-MM-dd').format(DateTime.now());
#override
Widget build(BuildContext context) {
var appBarHeight = kToolbarHeight;
return Scaffold(
key: scaffoldkey,
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: const Color.fromRGBO(119, 221, 167, 1),
title: const Text(
'Test',
style: TextStyle(
fontFamily: 'Poppins',
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
centerTitle: true,
),
backgroundColor: Colors.white,
drawer: Container(
padding: EdgeInsets.only(top: appBarHeight + 1),
child: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(name!),
),
const SizedBox(
height: 10,
),
],
),
),
),
body: SafeArea(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(
height: 20,
),
Text('Hei, $name!',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),),
],
),
),
));
}
}

I am encountering "error: The operator '[]' isn't defined for the type 'Object'." How do i solve this?

I am following this tutorial to make a chat app.
I am encountering this problem, as the tutorial is outdated, things have changed and the function QueryDocumentSnapshot has changed how it works. I tried using different methods but nothing. Hoping to get some help here, here is the code:
import 'package:chat_app/services/database.dart';
import 'package:chat_app/widgets/widget.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({Key? key}) : super(key: key);
#override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
DatabaseMethods databaseMethods = new DatabaseMethods();
TextEditingController searchTextEditingController = new TextEditingController();
late QuerySnapshot searchSnapshot;
initiateSearch(){
databaseMethods
.getUserByUsername(searchTextEditingController.text)
.then((val) {
setState(() { searchSnapshot = val; });
});
}
Widget searchList() {
return searchSnapshot!= null ? ListView.builder(
itemCount: searchSnapshot.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return SearchTile(
//TODO: controlla che funzioni
userName: searchSnapshot.docs[index].data()!['name'],
userEmail: searchSnapshot.docs[index].data()!['email']
);
}) : Container();
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBarMain(context),
body: Container(
child: Column(
children: [
Container(
color: Color(0x54000000),
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
Expanded(
child: TextField(
controller: searchTextEditingController,
style: TextStyle(
color: Colors.white
),
decoration: InputDecoration(
hintText: "search username...",
hintStyle: TextStyle(
color:Colors.white54
),
border: InputBorder.none
),
)
),
GestureDetector(
onTap: (){
initiateSearch();
},
child: Container(
height: 40,
width: 40,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
const Color(0x36FFFFFF),
const Color(0x0FFFFFFF)
]
),
borderRadius: BorderRadius.circular(40)
),
padding: EdgeInsets.all(8),
child: Image.asset("assets/images/search_white.png")
),
)
],
),
),
searchList()
],
),
),
);
}
}
class SearchTile extends StatelessWidget {
final String userName;
final String userEmail;
SearchTile({required this.userName, required this.userEmail});
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: [
Column(
children: [
Text(userName, style: simpleTextStyle(),),
Text(userEmail, style: simpleTextStyle(),)
],
),
Spacer(),
Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(30)
),
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Text("Message"),
)
],
),
);
}
}
The problem resides here specifically:
Widget searchList() {
return searchSnapshot!= null ? ListView.builder(
itemCount: searchSnapshot.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return SearchTile(
//TODO: controlla che funzioni
userName: searchSnapshot.docs[index].data()!['name'],
userEmail: searchSnapshot.docs[index].data()!['email']
);
}) : Container();
}
Any help is appreciated!
Try this:
Widget searchList() {
return searchSnapshot!= null ? ListView.builder(
itemCount: searchSnapshot.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final _searchSnapshot = searchSnapshot.docs[index].data() as Map<String, dynamic>;
return SearchTile(
//TODO: controlla che funzioni
userName: _searchSnapshot['name'],
userEmail: _searchSnapshot['email']
);
}) : Container();
}

Retrieve array from Firebase in Flutter

I want to retrieve array from firebase or cloud_firestore.
I have no problem with retrieving single data but i am having problem with retrieving array data
please help my beginner mind is at the verge of exploding.
I have google it and gone through many tutorials videos but i can't find the solution
database image here
pubspec.yaml
dependencies:
cloud_firestore: ^0.13.6
main.dart
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Scaffold(
appBar: AppBar(title: Text("Flutter Fire CRUD")),
body: ListPage(),
),
);
}
}
class ListPage extends StatefulWidget {
#override
_ListPageState createState() => _ListPageState();
}
class _ListPageState extends State<ListPage> {
Future _data;
Future getUsers() async {
var firestore = Firestore.instance;
firestore.collection("users").getDocuments();
QuerySnapshot qn = await firestore.collection("users").getDocuments();
return qn.documents;
}
navigateToDetail(DocumentSnapshot users) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailList(users: users)));
}
#override
void initState() {
super.initState();
_data = getUsers();
}
#override
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: _data,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading ...");
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data[index].data['name']),
onTap: () {
navigateToDetail(snapshot.data[index]);
});
},
);
}
},
),
);
}
}
class DetailList extends StatefulWidget {
final DocumentSnapshot users;
DetailList({Key key, #required this.users}) : super(key: key);
#override
_DetailListState createState() => _DetailListState();
}
class _DetailListState extends State<DetailList> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("${widget.users.data['name']}"),
),
body: Column(
children: [
Container(
height: MediaQuery.of(context).size.height / 2.0,
width: MediaQuery.of(context).size.width,
child: Center(
child: Image.network(widget.users.data["img"]),
),
),
Container(
child: Card(
child: ListTile(
title: Text(widget.users.data["name"]),
subtitle: Text("Age:" + widget.users.data["age"]),
),
),
),
ListView.builder(
itemCount: widget.users.data["skills"],
itemBuilder: (context, index) {
return ListTile(
//title: Text(widget.users.data["skills"][index]),
title: here............
);
},
)
],
),
);
}
}
StreamBuilder(
stream: Firestore.instance
.collection('users')
.document(id)
.collection('chatWith')
.orderBy('timestamp', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
AppColor.colorCustom),
),
);
} else {
if (snapshot.data.documents.length == 0) {
return Container(
alignment: Alignment.center,
child: Text(
"No Chat History Found",
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.normal,
fontSize:
Util.px_23 * SizeConfig.textMultiplier,
fontFamily: 'Roboto',
),
softWrap: true,
),
);
} else {
return ListView.builder(
padding: EdgeInsets.all(
Util.px_10 * SizeConfig.heightMultiplier),
itemBuilder: (context, index) => _listItem(
context, snapshot.data.documents[index]),
itemCount: snapshot.data.documents.length,
);
}
}
},
)
You can fetch list of data from firestore. this code I have used in my project. You can modify as per your requirement.

Send data from Flutter Bluetooth app to Firestore

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);
}

NoSuchMethodError: The getter data was called on null, receiver: null

I am trying to create a detail screen to display my Firebase data from the database, and show the image along with some text data including the number of items, date, and geolocation. Is there a way to determine why the data is returning null? The navigator should navigate to the DetailPage.
Here is my Main file -
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:wasteagram/pages/create_waste.dart';
import 'package:wasteagram/services/crud.dart';
import 'pages/create_waste.dart';
import 'pages/detail_screen.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Wasteagram - ',
theme: new ThemeData(
primarySwatch: Colors.deepOrange,
),
home: new MyHomePage(title: 'Wasteagram - '),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
CrudMethods crudMethods = new CrudMethods();
Stream wasteStream;
Widget WasteList() {
return Container(
child: wasteStream != null ? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StreamBuilder(
stream: wasteStream,
builder: (context, snapshot) {
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16),
itemCount: snapshot.data.documents.length,
shrinkWrap: true,
itemBuilder: (context, index){
return WidgetTile(
wastedate:
snapshot.data.documents[index].data['wastedate'],
wastenumber:
snapshot.data.documents[index].data['wastenumber']
);
});
},)
],
) : Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);
}
void initState() {
super.initState();
crudMethods.getData().then((result) {
wasteStream = result;
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: WasteList(),
floatingActionButton: new FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CameraScreen())
);
},
child: new Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
class WidgetTile extends StatelessWidget {
String wastedate, wastenumber;
WidgetTile({#required this.wastedate, #required this.wastenumber});
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(wastedate),
trailing: Text(wastenumber),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailPage())
);
}
);
}
}
Here is my detail_screen.dart
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:wasteagram/data/firestore_service.dart';
class DetailPage extends StatefulWidget {
final DocumentSnapshot post;
DetailPage({this.post});
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.post.data["wastedate"])
),
body: Center(
child: Container(
child: Column(
children: <Widget> [
Image.network(widget.post.data["image"]),
Text(widget.post.data["wastedate"]),
Text(widget.post.data["wastenumber"]),
Text(widget.post.data["wastelocation"].toString()),
]
)
)
),
);
}
}
You are not passing DocumentSnapshot to Detail Page.
Try this:
Widget WasteList() {
return Container(
child: wasteStream != null ? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StreamBuilder(
stream: wasteStream,
builder: (context, snapshot) {
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16),
itemCount: snapshot.data.documents.length,
shrinkWrap: true,
itemBuilder: (context, index){
return WidgetTile(
wastedate:
snapshot.data.documents[index].data['wastedate'],
wastenumber:
snapshot.data.documents[index].data['wastenumber'],
post:
snapshot.data.documents[index]
);
});
},)
],
) : Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);
}
class WidgetTile extends StatelessWidget {
String wastedate, wastenumber;
DocumentSnapshot post;
WidgetTile({#required this.wastedate, #required this.wastenumber,#required this.post});
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(wastedate),
trailing: Text(wastenumber),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailPage(post: post))
);
}
);
}
}

Resources