Download firestore data into Flutter List - flutter

I am a complete newbie of flutter.
I want to download a simple carparkList from Firestore and put it into a list (or a map??). It appears that the dataset has been successfully downloaded (proved by actually seeing the data from the print(cp)).
But synatx error (a red undeline) apppears at the "[" of both lines:
title: Text(widget.carparkList[index].data().['name']),
subtitle: Text(widget.carparkList[index].data().['district']),
Pls help point out how to correct the syntax error for the following code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class DownloadDataScreen extends StatefulWidget {
List<DocumentSnapshot> carparkList = []; //List for storing carparks
#override
_DownloadDataScreen createState() => _DownloadDataScreen();
}
class _DownloadDataScreen extends State<DownloadDataScreen> {
#override
void initState() {
readFromFirebase();
super.initState();
}
void readFromFirebase() async {
await FirebaseFirestore.instance
.collection('carpark')
.get()
.then((QuerySnapshot snapshot) {
snapshot.docs.forEach((DocumentSnapshot cp) {
widget.carparkList.add(cp);
// the following 'print' proves that data are successfully downloaded from firestore.
print('printing cp');
print(cp.data().runtimeType);
print(cp.data());
});
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(
'Car Park',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: Column(
children: [
ListView.builder(
itemCount: widget.carparkList.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(widget.carparkList[index].data().['name']),
subtitle: Text(widget.carparkList[index].data().['district']),
);
},
),
],
),
);
}
}

Change them to this:
title: Text(widget.carparkList[index].get('name')),
subtitle: Text(widget.carparkList[index].get('district')),

Related

The search bar does not return any results

I am trying to add a search function in my flutter app, the search bar is showing and there's not errors but its not working and it doesn't return any results.
the data list is from an API that I already called using the rest API
// ignore_for_file: use_key_in_widget_constructors, avoid_print, avoid_unnecessary_containers, curly_braces_in_flow_control_structures, prefer_const_constructors, non_constant_identifier_names, unnecessary_new, avoid_function_literals_in_foreach_calls, unused_import, avoid_types_as_parameter_names, unused_label
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:myapp2/Service_Request/SR.dart';
import 'package:myapp2/main.dart';
import 'package:myapp2/Service_Request/second.dart';
import '../Classes/demandes.dart';
import 'SR_details.dart';
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DataFromAPI(),
);
}
}
class DataFromAPI extends StatefulWidget {
#override
_DataFromAPIState createState() => _DataFromAPIState();
}
List<Attributes> _MyAllData = [];
var _srAttributes = [];
class _DataFromAPIState extends State<DataFromAPI> {
#override
void initState() {
loadData().then((value) {
setState(() {
_srAttributes.addAll(value);
});
});
super.initState();
}
Future<List<Sr>> loadData() async {
try {
var response = await http.get(Uri.parse(
'http://192.168.1.30:9080/maxrest/rest/mbo/sr/?_lid=azizl&_lpwd=max12345m&_format=json'));
if (response.statusCode == 200) {
final jsonBody = json.decode(response.body);
Demandes data = Demandes.fromJson(jsonBody);
final srAttributes = data.srMboSet.sr;
return srAttributes;
}
} catch (e) {
throw Exception(e.toString());
}
throw Exception("");
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
appBar: AppBar(
title: Text('Liste des Demandes'),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.push(
context, MaterialPageRoute(builder: (context) => SR()))),
),
body: FutureBuilder<List<Sr>?>(
future: loadData(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
} else {
return new ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: ((_, index) {
return index == 0
? _searchbar()
: new ListTile(
title: new Card(
margin: new EdgeInsets.symmetric(
vertical: 2.0, horizontal: 8.0),
elevation: 10,
child: new ListTile(
title: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(padding: new EdgeInsets.all(2.0)),
new Text(
'Ticket ID : ${snapshot.data![index].attributes.ticketid.content}'),
new Text(
'status : ${snapshot.data![index].attributes.status.content}'),
new Text(
'description : ${snapshot.data![index].attributes.description?.content}'),
new Text(
'Reported by : ${snapshot.data![index].attributes.reportedby.content}'),
new Text(
'Reoprt date : ${snapshot.data![index].attributes.statusdate.content}'),
],
),
trailing: Icon(Icons.arrow_forward_ios_rounded),
),
),
onTap: () {
Navigator.of(context)
.push(
new MaterialPageRoute(
builder: (BuildContext context) =>
new SrDetailsScreen(
sr: snapshot.data![index]),
),
)
.then((data) {});
});
}),
);
}
},
),
),
);
}
_searchbar() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(hintText: "Search ..."),
onChanged: (text) {
text = text.toLowerCase();
setState(() {
_srAttributes = _MyAllData.where((srAttributes) {
var idticket = srAttributes.description!.content.toLowerCase();
return idticket.contains(text);
}).toList();
});
},
),
);
}
}
FutureBuilder loads values of current future. You are assigning a function result to FutureBuilder so its value always changes dynamically.
Create variable to keep Future's value.
Future<List<Sr>>? dataToLoad;
Whenever you want to load data from server ( for example, on text changed ):
setState((){
dataToLoad = loadData();
});
And use it in FutureBuilder:
FutureBuilder<List<Sr>?>(
future: dataToLoad,

Cannot display data downloaded from Firestore using Listview.Builder and ListTile

I want to display a list from downloading the data from firestore. The download is successful (the full list can be printed) but somehow it cannot be displayed. Simply nothing is shown when I use the ListView.builder and ListTile. Pls help what is the problem of my code. Great thanks.
class DownloadDataScreen extends StatefulWidget {
#override
List<DocumentSnapshot> carparkList = []; //List for storing carparks
_DownloadDataScreen createState() => _DownloadDataScreen();
}
class _DownloadDataScreen extends State<DownloadDataScreen> {
void initState() {
super.initState();
readFromFirebase();
}
void readFromFirebase() async {
await FirebaseFirestore.instance
.collection('carpark')
.get()
.then((QuerySnapshot snapshot) {
snapshot.docs.forEach((DocumentSnapshot cp) {
widget.carparkList.add(cp);
//to prove data are successfully downloaded
print('printing cp');
print(cp.data());
print(cp.get('name'));
});
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(
'Car Park',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: SafeArea(
child: Column(
children: [
Expanded(
flex: 9,
child: Container(
child: ListView.builder(
itemCount: widget.carparkList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(widget.carparkList[index].get('name')),
subtitle: Text(
widget.carparkList[index].get('district')),
onTap: () {
},
);
},
),
),
),
],
),
),
);
}
}
create the list in state add it to the top line of the initState method List carparkList = [];
class DownloadDataScreen extends StatefulWidget {
_DownloadDataScreen createState() => _DownloadDataScreen();
}
class _DownloadDataScreen extends State<DownloadDataScreen> {
List<DocumentSnapshot> carparkList = []; //List for storing carparks
void initState() {
super.initState();
readFromFirebase();
}
void readFromFirebase() async {
await FirebaseFirestore.instance
.collection('carpark')
.get()
.then((QuerySnapshot snapshot) {
snapshot.docs.forEach((DocumentSnapshot cp) {
widget.carparkList.add(cp);
//to prove data are successfully downloaded
print('printing cp');
print(cp.data());
print(cp.get('name'));
});
});
}

Null check operator used on null value

I need to grab a list of all messages in the database where the level is less than or equal to the user's current level. To do this I am attempting to use a nested streambuilder. First one pulls the user info, then I use the user level to make the second query. My problem is I get an error.
Null check operator used on null value
I do not understand this error. I checked firestore to see that there is data in the collection, and I also made sure to put the proper rules in place. I've tried several variations of this code and this is the only one so far that at least doesn't give me an error in the emulator. My emulator shows the appbar and the body is blank.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../screens/welcome_screen.dart';
class MessagesScreen extends StatefulWidget {
static const String id = 'messages_screen';
#override
_MessagesScreenState createState() => _MessagesScreenState();
}
class _MessagesScreenState extends State<MessagesScreen> {
final _firestore = FirebaseFirestore.instance;
final _auth = FirebaseAuth.instance;
User loggedInUser;
int _userCurrentLevel;
#override
void initState() {
super.initState();
getCurrentUser();
}
void getCurrentUser() {
try {
final user = _auth.currentUser;
if (user != null) {
loggedInUser = user;
}
} catch (e) {
print(e);
}
}
getMessages(AsyncSnapshot<QuerySnapshot> snapshot2) {
return snapshot2.data.docs
.map((doc) => new ListTile(title: Text(doc['from']), subtitle: Text(doc['text'])))
.toList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Darker Slate'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.chat),
tooltip: 'Messages',
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.exit_to_app),
tooltip: 'Log Out',
onPressed: () {
_auth.signOut();
Navigator.pushNamed(context, WelcomeScreen.id);
},
),
],
),
body: StreamBuilder<DocumentSnapshot>(
stream: _firestore.collection('users')
.doc(_auth.currentUser.uid)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red[900],
),
);
}
_userCurrentLevel = snapshot.data['userlevel'];
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('messages')
.where('level', isLessThanOrEqualTo: _userCurrentLevel).snapshots(),
builder: (context, snapshot2) {
if (!snapshot2.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red[900],
),
);
}
return Column(
children: [
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot2.data.docs.length,
itemBuilder: (_, index) {
return new ListView(children: getMessages(snapshot2));
}),
],
);
}
);
}),
);
}
}

Adding a loading screen to flutter while fetching data from firestore

I wan't to add a loading screen t my flutter app when it's processing the data using the asyn but i am limited and don't know where to start from and this is my database.dart file which handles the firestore connections and configurations. Help me where can i add a function inside the DatabaseService which will be showing the loading screen and then after the async is done it displays the 'homepage' text.
Database.dart:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:kopala_dictionary/models/words.dart';
class DatabaseService {
//cloud databse colection for words
final CollectionReference wordsCollection =
Firestore.instance.collection('words');
Future insertData(String word, String english_translation,
String bemba_translation, String user_id, DateTime date_posted) async {
return await wordsCollection.document().setData({
'word': word,
'english_translation': english_translation,
'bemba_translation': bemba_translation,
'user_id': user_id,
'date_posted': date_posted
});
}
//words list from snappshots
List<Words> _wordsFromSnapShots(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return Words(
word: doc.data['word'],
englishTranslation: doc.data['english_translation'],
bembaTranslation: doc.data['bemba_translation'],
);
}).toList();
}
//Stream snapshots
Stream<List<Words>> get words {
// This forces an ordering on the documents in the collection
return wordsCollection.orderBy('word').snapshots().map(_wordsFromSnapShots);
}
}
My homepage
logged_home.dart:
import 'package:flutter/material.dart';
import 'package:kopala_dictionary/main/about.dart';
import 'package:kopala_dictionary/models/words.dart';
import 'package:kopala_dictionary/screens/author/profile_page.dart';
import 'package:kopala_dictionary/screens/home/words_list.dart';
import 'package:kopala_dictionary/screens/wrapper.dart';
import 'package:kopala_dictionary/services/auth.dart';
import 'package:kopala_dictionary/services/database.dart';
import 'package:kopala_dictionary/shared/app_bar.dart';
import 'package:provider/provider.dart';
class LoggedInUserHome extends StatelessWidget {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return StreamProvider<List<Words>>.value(
value: DatabaseService().words,
child: Scaffold(
backgroundColor: Colors.green[10],
appBar: LoggedBar(),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text(
'Kopalationary Menu',
style: TextStyle(color: Colors.white),
),
decoration: BoxDecoration(
color: Colors.green[800],
),
),
ListTile(
title: Text('Home'),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => Wrapper()));
},
),
ListTile(
title: Text(
'My profile',
),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => ProfilePage()));
},
),
ListTile(
title: Text('Logout'),
onTap: () async {
dynamic result = await _auth.logoutUser();
},
),
ListTile(
title: Text(
'About',
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => About()),
);
},
),
],
),
),
body: WordsList(),
),
);
}
}
You probably need a StreamBuilder for this. An example might look something like this. You pass a stream into the builder and handle whatever the state of the stream is inside of the builder by looking at the snapshot. If it has an data, you show the content for the data otherwise you show a loading screen or an error screen if there was an error while retrieving the data.
class MyScreen extends StatefulWidget {
#override
_MyScreenState createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
Stream<List<Words>> wordStream;
#override
void initState() {
super.initState();
wordStream = DatabaseService().words;
}
#override
Widget build(BuildContext context) {
return StreamBuilder<List<Words>>(
stream: wordStream,
builder: (context, snapshot) {
if (snapshot.hasError) {
return ErrorWidget();
} else if (snapshot.hasData) {
return ContentWidget(snapshot.data);
} else {
return LoadingWidget();
}
},
);
}
}
There are some other connectionStates on the snapshot, that you might want to handle, but this handles the standard cases.

How can I implement AlertDialog box inside ListView in Flutter Android app automatically without pressing any button?

I am working on a project where I have created a RestApi where I have data of cars and which I keep updating every 3 sec. The cars are at a junction of 4 roads, now when a car is approaching towards a particular road denoted by id the "is_green" will become true and in the ListView -> the CircleAvtar will become green which will indicate that car is comming or not Now My Question is
how can I implement a AlertDialog box which will popup automically whithout pressing any button when bool isGreen = userData[index]["is_green"] will contain value true . I am new to flutter so I don't know how to do that... Please help me out
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
home: Home(),
));
}
class Home extends StatefulWidget {
Home({Key key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
Map data;
List userData;
Future getData() async {
print("updating data...");
http.Response response = await http.get("http://10.100.101.154:3000/xd");
data = jsonDecode(response.body);
setState(() {
userData = data["data"];
});
}
#override
void initState() {
super.initState();
Timer.periodic(new Duration(seconds: 3), (timer) {
getData();
});
}
Color getColor(bool isGreen) {
if (isGreen == true) {
return Colors.green;
} else {
return Colors.red;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SGH'),
centerTitle: true,
),
body: ListView.builder(
itemCount: userData == null ? 0 : userData.length,
itemBuilder: (BuildContext context, int index) {
bool isGreen = userData[index]["is_green"];
return Card(
child: Row(
children: <Widget>[
Padding(
padding: EdgeInsets.all(10),
child: CircleAvatar(
backgroundColor: getColor(isGreen),
minRadius: 6,
),
),
Padding(
padding: EdgeInsets.all(10),
child: Wrap(
direction: Axis.horizontal,
children: <Widget>[
Text(
"Road Id = ${userData[index]["id"]} \CarInQueue = ${userData[index]["car_que"]} \nIsGreen ? --> ${userData[index]["is_green"]} ",
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
],
),
),
],
),
);
}),
);
}
}
Just check any time you update list of cars... Then show a Dialog with informations about which car is crossing
Future getData() async {
print("updating data...");
http.Response response = await http.get("http://10.100.101.154:3000/xd");
data = jsonDecode(response.body);
setState(() {
userData = data["data"];
});
checkDialog();
}
checkDialog(){
var item = userData.where((car)=>car["is_green"]).first;//this is the first car where is_green is true
if(item!=null){
showDialog(context:context,
builder:(BuildContext context)=>AlertDialog(
//.... content here
));
}
}