How to change element color on Stream Builder Flutter - firebase

I have a problem with StreamBuilder. I using FirebaseFirestore and I want to make a quiz app but I don't change my element's color. I used the setState method but it didn't work. How to change element color on Stream Builder?
My codes:
https://paste.tc/dtckRClOTL
import 'package:audioplayers/audio_cache.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:dots_indicator/dots_indicator.dart';
import 'package:exampills/screens/tests/resultScreen.dart';
import 'package:exampills/providers/testProvider.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:random_color/random_color.dart';
class TestScreen extends StatefulWidget {
final String categoryId;
final String subcategoryId;
final String title;
final String testId;
final int questPiece;
const TestScreen(
{Key key,
this.categoryId,
this.subcategoryId,
this.testId,
this.title,
this.questPiece})
: super(key: key);
#override
_TestScreenState createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
int position;
AudioCache audioCache = AudioCache();
AudioPlayer audioPlayer = AudioPlayer();
RandomColor randomColor = RandomColor();
var controller = Get.put(TestProvider());
PageController pageController = PageController();
int testQuestPiece = 0;
Future nextPage() {
pageController.animateToPage(pageController.page.toInt() + 1,
duration: Duration(milliseconds: 400), curve: Curves.easeIn);
}
void previousPage() {
pageController.animateToPage(pageController.page.toInt() - 1,
duration: Duration(milliseconds: 400), curve: Curves.easeIn);
}
getDocs() async {
await FirebaseFirestore.instance
.collection(
"categories/${widget.categoryId}/subcategories/${widget.subcategoryId}/tests/${widget.testId}/questions")
.get()
.then((value) {
setState(() {
testQuestPiece = value.docs.length;
});
});
}
#override
void initState() {
print(controller.position);
controller.updatePosition(0);
getDocs();
super.initState();
}
#override
Widget build(BuildContext context) {
Color color = randomColor.randomColor();
int selectedItem;
bool selectedBool = false;
return Scaffold(
backgroundColor: color,
bottomNavigationBar: Container(
child: DotsIndicator(
dotsCount: testQuestPiece,
position: controller.position,
axis: Axis.horizontal,
reversed: false,
decorator: DotsDecorator(
color: Colors.white,
activeColor: randomColor.randomColor(),
size: const Size.square(9.0),
activeShape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
activeSize: const Size(18.0, 18.0),
),
mainAxisAlignment: MainAxisAlignment.center,
)),
appBar: AppBar(
centerTitle: true,
title: Text(
widget.title,
style: TextStyle(fontWeight: FontWeight.bold),
),
leading: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.arrow_back_ios),
color: Colors.white,
),
backgroundColor: Colors.transparent,
actions: [
IconButton(
icon: Icon(Icons.timer),
onPressed: () {},
)
]),
body: Stack(
fit: StackFit.expand,
children: [
StreamBuilder(
stream: FirebaseFirestore.instance
.collection(
"categories/${widget.categoryId}/subcategories/${widget.subcategoryId}/tests/${widget.testId}/questions")
.snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
return PageView(
physics: NeverScrollableScrollPhysics(),
allowImplicitScrolling: false,
scrollDirection: Axis.horizontal,
controller: pageController,
onPageChanged: controller.updatePosition,
children: snapshot.data.docs.map<Widget>((data) {
var datas = data.data();
return Stack(
fit: StackFit.expand,
children: [
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 350,
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30)),
height: 200,
child: Text(datas['questionTitle'],
style: TextStyle(
color: Colors.black, fontSize: 20))),
SizedBox(
height: 15,
),
Expanded(
child: ListView.builder(
itemCount: datas['answers'].length,
itemBuilder: (context, index) {
return Column(
children: [
InkWell(
onTap: () async {
if (datas['trueAnswer'] == index) {
audioCache
.play("sounds/correct.wav");
} else {
audioCache.play("sounds/wrong.wav");
setState(() {
selectedItem =
datas['trueAnswer'];
selectedBool = true;
});
}
await Future.delayed(
Duration(seconds: 2))
.then((value) {
print(pageController.page.toInt());
print(testQuestPiece);
if ((pageController.page.toInt() +
1) ==
testQuestPiece) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) =>
ResultScreen()));
} else {
nextPage();
}
});
},
child: Container(
width: 350,
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
color: selectedBool == true
? (selectedItem == index
? Colors.green
: Colors.red)
: Colors.white,
borderRadius:
BorderRadius.circular(30)),
height: 80,
child: Text(
"${index + 1}. " +
datas['answers'][index],
style: TextStyle(
color: Colors.black,
fontSize: 20)),
),
),
SizedBox(
height: 15,
),
],
);
},
),
),
],
),
),
],
);
}).toList(),
);
},
),
],
),
);
}
}

Related

Firebase List view is not displayed in real-time while adding data

I am storing Contact information on Firebase real-time DB after picking a contact from the phone.
When I add the data which is displayed using ListView and DataSnapshot the data is not refreshed in real-time until I restart the Activity. The ListView loads and displays all the data without any problem. How do I resolve this issue?
My screen looks like this:
Code for Screen:
import 'package:epicare/CaregiverClass.dart';
import 'package:epicare/Homepage.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_switch/flutter_switch.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:contact_picker/contact_picker.dart';
//Check contacts permission
Future<PermissionStatus> _getPermission() async {
final PermissionStatus permission = await Permission.contacts.status;
if (permission != PermissionStatus.granted &&
permission != PermissionStatus.denied) {
final Map<Permission, PermissionStatus> permissionStatus =
await [Permission.contacts].request();
return permissionStatus[Permission.contacts] ??
PermissionStatus.undetermined;
} else {
return permission;
}
}
class CaregiverScreen extends StatefulWidget {
#override
_CaregiverScreenState createState() => _CaregiverScreenState();
}
class _CaregiverScreenState extends State<CaregiverScreen> {
//Firebase
FirebaseAuth firebaseAuth = FirebaseAuth.instance;
final ref = FirebaseDatabase.instance.reference();
User cuser = FirebaseAuth.instance.currentUser;
final fb = FirebaseDatabase.instance.reference().child("User_data");
List <CaregiverList> list = List();
// Adding data into Firebase
void addData(String name, String number) {
print("Saving data to firebase");
ref.child('User_data').child(cuser.uid).child("caregivers").push().set({'Caregiver_Name': name, 'Caregiver_Number': number});
}
// Get location
Position _currentPosition;
String _currentAddress;
final Geolocator geolocator = Geolocator()..forceAndroidLocationManager;
#override
void initState() {
// Firebase
fb.child(cuser.uid).child("caregivers").once().then((DataSnapshot snapshot)
{
var data = snapshot.value;
list.clear();
data.forEach((key,value){
print(value['Caregiver_Name']);
CaregiverList contact_list = new CaregiverList(
name: value['Caregiver_Name'],
phone_number: value['Caregiver_Number'],
isActive: true,
key: key,
);
list.add(contact_list);
});
setState(() {
});
}
);
super.initState();
}
final ContactPicker _contactPicker = new ContactPicker();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
//Size size = MediaQuery.of(context).size;
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: const Color(0xffE5E0A1),
elevation: 0,
centerTitle: true,
title: Text(
"Add Caregiver",
style: TextStyle(
fontSize: 15.0,
color: Colors.black,
fontFamily: 'Montserrat',
fontWeight: FontWeight.normal,
),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return Homepage();
},
),
);
},
),
),
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
MaterialButton(
onPressed: () async {
final PermissionStatus permissionStatus =
await _getPermission();
if (permissionStatus == PermissionStatus.granted) {
//We can now access our contacts here
Contact contact = await _contactPicker.selectContact();
print("Contact name: ${contact.fullName}");
print("Contact number: ${contact.phoneNumber}");
List<String> num =
contact.phoneNumber.toString().split('(Work)');
print(num);
print(num[0]);
final pattern = RegExp('\\s+');
num[0].replaceAll(pattern, '');
num[0].replaceAll(new RegExp('-'),'');
addData(contact.fullName.toString(),num[0]);
} else {
//If permissions have been denied show standard cupertino alert dialog
showDialog(
context: context,
builder: (BuildContext context) =>
CupertinoAlertDialog(
title: Text('Permissions error'),
content: Text('Please enable contacts access '
'permission in system settings'),
actions: <Widget>[
CupertinoDialogAction(
child: Text('OK'),
onPressed: () =>
Navigator.of(context).pop(),
)
],
));
}
},
color: const Color(0xffd4d411),
textColor: Colors.white,
child: Icon(
Icons.add,
size: 32,
),
padding: EdgeInsets.all(3),
shape: CircleBorder(),
),
Text(
'Add a Caregiver',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 13,
color: const Color(0xff000000),
height: 1.5384615384615385,
fontWeight: FontWeight.w600),
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: false),
textAlign: TextAlign.left,
)
],
),
list.length == 0 ? Center(child: Text("Please add Caregivers"))
: ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
primary: false,
itemBuilder: (context, index) {
return _caregiverWidget(list[index].name,list[index].phone_number,list[index].isActive,list[index].key
);
},
separatorBuilder: (_, __) => Container(),
itemCount: list.length),
// _contact == null ? Container() : CaregiversList(_contact.fullName),
],
),
),
),
);
}
Widget _caregiverWidget( String name, String phone_number, bool isActive, String key
) {
print(name);
var c = name.split(' ');
print(c[0]);
var caregiver = c[0];
var output = getInitials(string: caregiver, limitTo: 1);
print(output);
return GestureDetector(
onLongPress: (){},
onTap: (){},
child: Card(
elevation: 0,
child: Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 27),
child: Row(
//crossAxisAlignment: CrossAxisAlignment.center,
//mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CircleAvatar(
radius: 24,
backgroundColor: const Color(0xffd4d411),
child: CircleAvatar(
radius: 22,
backgroundColor: Colors.white,
child: Text(
output,
style: TextStyle(
fontFamily: 'Segoe UI',
fontSize: 20,
color: const Color(0xff000000),
),
),
),
),
SizedBox(width: 19),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
caregiver,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 13,
color: const Color(0xff000000),
height: 1.5384615384615385,
fontWeight: FontWeight.w600),
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: false),
textAlign: TextAlign.left,
),
isActive
? Text(
"Activated",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 10,
color: const Color(0x80232425),
fontWeight: FontWeight.w500),
textAlign: TextAlign.left,
)
: Text(
"Disabled",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 10,
color: const Color(0x80232425),
fontWeight: FontWeight.w500),
textAlign: TextAlign.left,
),
],
),
SizedBox(width: 143),
FlutterSwitch(
width: 40.0,
height: 20.0,
value: isActive,
toggleSize: 15,
borderRadius: 40.0,
padding: 2.0,
showOnOff: false,
activeColor: const Color(0xffd4d411),
activeToggleColor: Colors.white,
inactiveColor: const Color(0xffDDDBAF),
inactiveToggleColor: Colors.white,
onToggle: (value) {
print(value);
setState(() {
isActive = value;
// _careList.removeAt(index);
// _careList.insert(index, _caregiver);
});
},
),
],
),
),
),
);
}
String getInitials({String string, int limitTo}) {
var buffer = StringBuffer();
var split = string.split(' ');
for (var i = 0; i < (limitTo ?? split.length); i++) {
buffer.write(split[i][0]);
}
return buffer.toString();
}
}
The issue is that this part:
fb.child(cuser.uid).child("caregivers").once()..
is only getting the value once.
To se realtime updates you should either use a listener like here:
CollectionReference reference = Firestore.instance.collection('caregivers');
reference.snapshots().listen((querySnapshot) {
querySnapshot.documentChanges.forEach((change) {
// Do something with change
});
});
or a StreamBuilder like here:
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('caregivers').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text('Loading...');
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document['name']),
);
}).toList(),
);
},
);
for the RTDB the StreamBuilder would look like this:
StreamBuilder(
stream: _database.reference().child('caregivers').onValue,
builder: (context, event) {
if (event.hasData &&
!event.hasError &&
event.data.snapshot.value != null) {
DataSnapshot snapshot = event.data.snapshot;
}
})
the listener would be like:
_database.reference().child('caregivers').onValue.listen((event){
})
onValue will give you everytime the whole list so you need to empty it before you add again every item:
var data = event.snapshot.value;
list= List(); //Clear the list here
data.forEach((key, value) {
print(value['Caregiver_Name']);
CaregiverList contact_list = new CaregiverList(
name: value['Caregiver_Name'],
phone_number: value['Caregiver_Number'],
isActive: true,
key: key,
);
list.add(contact_list);
});

How can I make that the on ttap button only be pressed one time? - Flutter

I have an issue with flutter, and the isComplet bool are not working well. When I press it twice in the app, it make the task as may times as you tap on there. How can I solve it? This is the entire code. The todos list is a list of tasks to do in a task app, but it works fine:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:mrplan/loading.dart';
import 'package:mrplan/services/database_services.dart';
import 'package:mrplan/src/models/todo.dart';
import 'package:mrplan/src/pages/graficas_circulares_page.dart';
import 'package:mrplan/src/widgets/appbar.dart';
bool isComplet = false;
TextEditingController todoTitleController = TextEditingController();
class Todolist extends StatefulWidget {
#override
_TodolistState createState() => _TodolistState();
}
class _TodolistState extends State<Todolist> {
TextEditingController todoTitleController = TextEditingController();
#override
Widget build(BuildContext context) {
setState(() {
});
return Scaffold(
body: SafeArea(
child: StreamBuilder<List<Todo>>(
stream: DatabaseService().listTodos(),
builder: (context, snapshot) {
if(!snapshot.hasData){
return Loading();
}
List<Todo> todos = snapshot.data;
if(todos.length == 0){
return Center(child: Text('No hay tareas agregadas!'));
}
return Padding(
padding:EdgeInsets.all(0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20),
Expanded(
child: ListView.separated(
separatorBuilder: (context, index)=> Divider(color: Colors.white),
shrinkWrap: true,
itemCount: todos.length,
itemBuilder: (context, index){
return Dismissible(
key: UniqueKey(),
background: Container(padding: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
child: Icon(Icons.delete),
color: Colors.red),
onDismissed: (direction) async {
await DatabaseService().removeTodo(todos[index].uid);
quitar();
},
child: StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance.collection('Todos').doc().snapshots(),
builder: (context, snapshot) {
var todoss = snapshot.data;
return ListTile(
onTap: (){
isComplet = !isComplet;
if (Todo().isComplet = true)
{DatabaseService().completTask(todos[index].uid);}
if (Todo().isComplet = false)
{DatabaseService().uncompletTask(todos[index].uid);}},
leading: Container(
padding: EdgeInsets.all(2),
height: 30,
width: 30,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
shape: BoxShape.circle
),
child: todos[index].isComplet
? Icon(
Icons.check,
color: Colors.white,)
: Container(),
),
title: Text(
todos[index].title,
style: todos[index].isComplet
? TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
decoration: TextDecoration.lineThrough,
decorationColor: Colors.red,
)
: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
decoration: null
)
),
);
}
),
);
}
),
)
],
),
);
}
)
),
);
}
}
class Appbar extends StatefulWidget {
#override
_AppbarState createState() => _AppbarState();
}
class _AppbarState extends State<Appbar> {
#override
Widget build(BuildContext context) {
bool isbuttondisabled = false;
setState(() {
});
return StreamBuilder<Object>(
stream: null,
builder: (context, snapshot) {
return Container(
alignment: Alignment.bottomCenter,
child: BottomAppBar(
elevation: 0,
child: Container(
height: MediaQuery.of(context).size.height * 0.05,
width: MediaQuery.of(context).size.width,
child: Row(
children: [
Container(
decoration: BoxDecoration(
color:Colors.grey[100],
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(5.0),
)
),
height: MediaQuery.of(context).size.height,
padding: EdgeInsets.symmetric(horizontal: 10.0),
width: MediaQuery.of(context).size.width * 0.835,
child: Center(
child: TextFormField(
controller: todoTitleController,
autofocus: true,
decoration: InputDecoration(
hintStyle: TextStyle(color: Colors.blue[800]),
hintText: "Inserte una tarea...",
border: InputBorder.none
),
),
),
),
TextButton(
child: Container(
height: MediaQuery.of(context).size.height,
child: Center(child: Icon(Icons.add))),
style: TextButton.styleFrom(
primary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: const Radius.circular(10.0),
)
),
backgroundColor: Theme.of(context).primaryColor
),
onPressed: isbuttondisabled ? null : ()async {
if(todoTitleController.text.isNotEmpty){
await DatabaseService().createNewTodo(todoTitleController.text.trim());
FocusScope.of(context).unfocus();
anadir();
todoTitleController.clear();
isComplet = !isComplet;
}
}
)
],
),
)
)
);
}
);
}
}
The relevant code where I am stucked is this:
onTap: (){
isComplet = !isComplet;
if (Todo().isComplet = true)
{DatabaseService().completTask(todos[index].uid);}
if (Todo().isComplet = false)
{DatabaseService().uncompletTask(todos[index].uid);}},
Thanks a lot!
It would be better if you could refactor the code a little bit. But heres the problem
remove this code inside the build method
bool isbuttondisabled = false;
setState(() {
});
add bool isbuttondisabled = false;
outside the build method.
where ever your button is,
in the onPressed parameter
setState(() {
isbuttondisabled=true;
//Todo add your code
});```

read number of children from the firebase realtime database using flutter

I'm new to flutter and really need help with my problem regarding reading/calculating the number of children from the firebase real-time database.
The database I use has several categories.
Each category has several cases.
What I want, is to extract the information from the database, how many cases each category has and to show this information in a list. That means - to show the name of the category AND how many children (cases) this category has (totalCases)...
Here is my code, I'm struggling with:
import '../components/category_list_tile.dart';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'package:flutter/material.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import '../constants.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_database/firebase_database.dart';
import 'dart:async';
class ScreenCategoryList extends StatefulWidget {
static String id = 'screen_category_list';
final FirebaseApp app;
ScreenCategoryList({this.app});
#override
_ScreenCategoryListState createState() => _ScreenCategoryListState();
}
class _ScreenCategoryListState extends State<ScreenCategoryList> {
final referenceDatabase = FirebaseDatabase.instance;
final _dbRef = FirebaseDatabase.instance.reference().child("de");
static int number = 100;
bool showSpinner = false;
DatabaseReference _databaseReference;
#override
void initState() {
final FirebaseDatabase database = FirebaseDatabase(app: widget.app);
_databaseReference = database.reference().child("de");
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.white, Colors.white],
),
image: const DecorationImage(
image: AssetImage("images/background.png"), fit: BoxFit.cover),
),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
toolbarHeight: 60.0,
elevation: 0.0,
backgroundColor: Colors.black12,
leading: Padding(
padding: EdgeInsets.only(left: 12.0, top: 12.0, bottom: 12.0),
child: Image(image: AssetImage('images/lexlogo_black.png'))),
title: Center(
child: Column(
children: [
Text(
'Kategorien',
style: TextStyle(
color: kMainDarkColor,
fontFamily: 'Roboto',
fontSize: 21.0,
fontWeight: FontWeight.bold),
),
],
),
),
actions: [
Padding(
padding: EdgeInsets.only(right: 8.0),
child: IconButton(
icon: Icon(Icons.more_vert_rounded),
iconSize: 30.0,
color: kMainDarkColor,
onPressed: () {},
//onPressed: onPressMenuButton,
),
),
],
),
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: FirebaseAnimatedList(
query: _databaseReference.child('category'),
itemBuilder: (
BuildContext context,
DataSnapshot snapshot,
Animation<double> animation,
int index,
) {
Future<int> getNumberOfNodes() async {
final response = await FirebaseDatabase.instance
.reference()
.child('de')
.child('category')
.child('$index')
.child('cases')
.once();
var nodes = [];
response.value.forEach((v) => nodes.add(v));
return nodes.length;
}
var myNumber = getNumberOfNodes();
int myInt = 99;
myNumber.then((value) {
myInt = value;
});
number = myInt;
return CategoryListTile(
title: snapshot.value['name'].toString(),
successfulCases: 1,
totalCases: number,
onTitleClick: () {},
onInfoButtonClick: () {},
);
},
reverse: false,
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
),
),
),
);
}
}
Since you declare Future<int> getNumberOfNodes() async, you need to FutureBuilder to display that value.
Something like this:
child: FutureBuilder<int>(
future: FirebaseDatabase.instance
.reference()
.child('de')
.child('category')
.child('$index')
.child('cases')
.once();
var nodes = [];
response.value.forEach((v) => nodes.add(v));
return nodes.length;
}
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
return Text("Case count: "+snapshot.data);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}'),
} else {
return CircularProgressIndicator();
}
},
)
I did not compile or run this code, so please treat it as a pseudo-code. If you get any errors while using this, try to fix them by searching for the error message before reporting back.
So the future is the code that determines the value, and then the builder renders the correct UI based on whether the value is available yet. You'll want to replace the Text("Case count: "+snapshot.data) with your own UI, so the CategoryListTile(...).
Thank you #Frank van Puffelen for your suggestion. Finally could read the number of children of at least one category.
The code had to be changed like this:
class _ScreenCategoryListState extends State<ScreenCategoryList> {
final referenceDatabase = FirebaseDatabase.instance;
bool showSpinner = false;
DatabaseReference _databaseReference;
#override
void initState() {
final FirebaseDatabase database = FirebaseDatabase(app: widget.app);
_databaseReference = database.reference().child("de");
super.initState();
}
Future<Map<int, int>> getNumberOfNodes() async {
Map<int, int> caseNumbers = new Map<int, int>();
// read number of category nodes
final categoriesNumbersResponse = await FirebaseDatabase.instance
.reference()
.child('de')
.child('category')
// .child('0')
// .child('cases')
.once();
var categoryNodes = [];
categoriesNumbersResponse.value.forEach((v) => categoryNodes.add(v));
int numberOfCategories = categoryNodes.length;
//read number of cases in category
for (int i = 0; i < numberOfCategories; i++) {
final caseResponse = await FirebaseDatabase.instance
.reference()
.child('de')
.child('category')
.child('$i')
.child('cases')
.once();
var caseNodes = [];
caseResponse.value.forEach((v) => caseNodes.add(v));
int numberOfCases = caseNodes.length;
caseNumbers[i] = numberOfCases;
}
return caseNumbers;
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.white, Colors.white],
),
image: const DecorationImage(
image: AssetImage("images/background.png"), fit: BoxFit.cover),
),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
toolbarHeight: 60.0,
elevation: 0.0,
backgroundColor: Colors.black12,
leading: Padding(
padding: EdgeInsets.only(left: 12.0, top: 12.0, bottom: 12.0),
child: Image(image: AssetImage('images/lexlogo_black.png'))),
title: Center(
child: Column(
children: [
Text(
'Kategorien',
style: TextStyle(
color: kMainDarkColor,
fontFamily: 'Roboto',
fontSize: 21.0,
fontWeight: FontWeight.bold),
),
],
),
),
actions: [
Padding(
padding: EdgeInsets.only(right: 8.0),
child: IconButton(
icon: Icon(Icons.more_vert_rounded),
iconSize: 30.0,
color: kMainDarkColor,
onPressed: () {},
//onPressed: onPressMenuButton,
),
),
],
),
body: FutureBuilder<Map<int, int>>(
future: getNumberOfNodes(),
builder: (BuildContext context,
AsyncSnapshot<Map<int, int>> casesSnapshot) {
if (casesSnapshot.hasData) {
return FirebaseAnimatedList(
reverse: false,
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
query: _databaseReference.child('category'),
itemBuilder: (
BuildContext context,
DataSnapshot categorySnapshot,
Animation<double> animation,
int index,
) {
int numberOfCases = casesSnapshot.data[index];
//print('number of cases $_counter, $numberOfCases');
return CategoryListTile(
title: categorySnapshot.value['name'].toString(),
successfulCases: 10,
totalCases: numberOfCases,
onTitleClick: () {},
onInfoButtonClick: () {},
);
},
);
} else if (casesSnapshot.hasError) {
return Center(
child: Column(
children: <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${casesSnapshot.error}'),
)
],
),
);
} else {
return Center(
child: Column(
children: <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
],
),
);
}
},
),
),
);
}
}

Download data from firebase Firestore to flutter

I am using Firestore as a database for a Chat in one part of the application that I am building. I have a collection on my Firestore that looks like this:
messages(collection)
userId
userId-otherUserId(sub-collection)
randomId
content : String,
timestamp : Date
...
and I would like to retrieve firstly all of the userIs-otherUserId in a ListView and then to retrieve the lastMessage by retrieving the last randomId(and in that randomId the last message is the last element with key 'content') and I would like it to look something like this.
Prototype
where the Loading represents last message but the name and profilePicture I can get from my API.
The pictures of my Firestore database:
First Image
Second Image
Third Image
Is there any chance that I could save the name and Profile picture on the database in the userId-otherUserId(collection)?
The code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:dio/dio.dart';
import 'package:disby_app/const.dart';
import 'package:disby_app/data/request_model.dart';
import 'package:disby_app/global_widgets/loading_indicator.dart';
import 'package:disby_app/main_screens/main_chat_and_request_screens/chat.dart';
import 'package:disby_app/main_screens/main_chat_and_request_screens/profile_details_screen.dart';
import 'package:disby_app/public/keys.dart';
import 'package:disby_app/services/json_requests.dart';
import 'package:flutter/material.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../global_widgets/chat_and_requests_placeholder.dart';
class MainChatScreen extends StatefulWidget {
#override
_MainChatScreenState createState() => _MainChatScreenState();
}
class _MainChatScreenState extends State<MainChatScreen> {
bool _areThereChats = false;
bool _isLoading = true;
String groupChatId;
String userId = '1';
List<String> listOfLastMessages = [];
List<String> listOfIds = [];
List<ArrayOfRequestsModel> arrayOfRequests = [];
final GlobalKey<AnimatedListState> _listKey = GlobalKey();
Future readLocal() async {
var prefs = await SharedPreferences.getInstance();
userId = prefs.getString(kUserId) ?? '';
print(userId);
setState(() {});
}
Future<void> _getRequests() async {
final prefs = await SharedPreferences.getInstance();
final userId = prefs.getString(kUserId);
try {
await Dio().post(baseUrl + acceptedUsers + "/" + userId).then((snapshot) {
print(snapshot);
final Map<String, dynamic> response = snapshot.data;
print(response);
if (response['response'] == 'success') {
List<dynamic> arrayFromServer = response['acceptedUsers'];
if (arrayFromServer.isNotEmpty) {
arrayFromServer.forEach((userData) {
arrayOfRequests.add(ArrayOfRequestsModel.fromJson(userData));
listOfIds.add(userData['userId']);
print(userData['userId']);
});
_areThereChats = true;
_isLoading = false;
getMessages(userId);
} else {
_areThereChats = false;
_isLoading = false;
}
setState(() {});
} else {
_areThereChats = false;
_isLoading = false;
setState(() {});
}
});
} catch (e) {
print(e);
}
}
getMessages(String userId) {
int i = 0;
print(listOfIds.length);
print(listOfIds);
listOfIds.forEach((element) {
Firestore.instance
.collection('messages')
.document('$userId')
.collection('$userId-$element')
.orderBy('timestamp', descending: true)
.limit(3)
.getDocuments()
.then((QuerySnapshot snapshot) {
print(snapshot.documents[0].data['content']);
snapshot.documents.forEach((f) {
print(f.data['content']);
listOfLastMessages.add(f.data['content']);
setState(() {});
i++;
});
if (i == listOfIds.length) {
setState(() {});
print(listOfLastMessages);
}
});
});
}
#override
void initState() {
readLocal();
_getRequests();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Container(
width: double.infinity,
height: double.infinity,
child: SingleChildScrollView(
// child: (userId != '1')
// ? StreamBuilder(
// stream: Firestore.instance
// .collection('messages')
// .document('5ef4d83175b07cf074525c08')
// .snapshots(),
// builder: (context, snapshot) {
// // if (snapshot.hasData) {
// if (!snapshot.hasData) {
// return Center(
// child: CircularProgressIndicator(
// valueColor: AlwaysStoppedAnimation<Color>(themeColor),
// ),
// );
// } else {
// return Container(
// width: 100,
// height: 200,
// child: ListView.builder(
// padding: EdgeInsets.all(10.0),
// itemBuilder: (context, index) =>
// buildItem(context, snapshot.data.documents),
// itemCount: snapshot.data.documents.length,
// ),
// );
// }
// },
// )
// : LoadingIndicator(
// loading: _isLoading,
// ),
// ),
child: Column(
children: <Widget>[
(_isLoading == false)
? (_areThereChats == true)
? Container(
child: AnimatedList(
key: _listKey,
shrinkWrap: true,
initialItemCount: arrayOfRequests.length,
itemBuilder:
(BuildContext context, index, animation) {
return _buildItem(context, arrayOfRequests[index],
animation, index);
},
),
)
: ChatAndRequestPlaceholder(
text: translate('when_someone_sends_you_a_request'))
: LoadingIndicator(
loading: _isLoading,
),
],
),
),
),
);
}
Widget buildItem(BuildContext context, DocumentSnapshot document) {
if (document['id'] == userId) {
return Container();
} else {
return Container(
child: FlatButton(
child: Row(
children: <Widget>[
Flexible(
child: Container(
child: Column(
children: <Widget>[
Container(
child: Text(
'Nickname: ${document['content']}',
style: TextStyle(color: primaryColor),
),
alignment: Alignment.centerLeft,
margin: EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 5.0),
),
Container(
child: Text(
'About me: ${document['content'] ?? 'Not available'}',
style: TextStyle(color: primaryColor),
),
alignment: Alignment.centerLeft,
margin: EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 0.0),
)
],
),
margin: EdgeInsets.only(left: 20.0),
),
),
],
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Chat(
peerId: document.documentID,
peerAvatar: document['photoUrl'],
),
),
);
},
color: greyColor2,
padding: EdgeInsets.fromLTRB(25.0, 10.0, 25.0, 10.0),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
),
margin: EdgeInsets.only(bottom: 10.0, left: 5.0, right: 5.0),
);
}
}
_buildItem(BuildContext context, ArrayOfRequestsModel arrayOfSentRequests,
Animation animation, int index) {
return GestureDetector(
onTap: () {
print(arrayOfSentRequests.profilePictureUrl);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Chat(
peerId: arrayOfSentRequests.userId,
peerAvatar: arrayOfSentRequests.profilePictureUrl,
),
),
);
},
child: Container(
height: 82,
child: ScaleTransition(
scale: animation,
child: Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Color.fromRGBO(0, 0, 0, 0.07),
offset: Offset(0, 5),
blurRadius: 11,
),
],
),
width: double.infinity,
height: 78,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
height: double.infinity,
child: GestureDetector(
onTap: () {
Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute(
builder: (context) => ProfileDetailsScreen(),
),
);
},
child: Row(
children: <Widget>[
SizedBox(width: 24),
ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Image(
image: NetworkImage(
arrayOfSentRequests.profilePictureUrl,
),
width: 48,
),
),
SizedBox(width: 10),
Expanded(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
arrayOfSentRequests.nameAndSurname,
style: TextStyle(
color: Colors.black,
fontFamily: 'Avenir',
fontWeight: FontWeight.w700,
fontSize: 18,
),
),
Text(
'11/11/2020', //arrayOfSentRequests.nameAndSurname
style: TextStyle(
color: Colors.grey,
fontFamily: 'Avenir',
fontWeight: FontWeight.w500,
fontSize: 15,
),
),
],
),
),
Container(
child: Text(
// (arrayOfSentRequests.lastMessage !=
// null)
// ? arrayOfSentRequests.lastMessage
// : 'Loading..',
(listOfLastMessages.isNotEmpty)
? listOfLastMessages[index]
.toString()
: 'Loading...',
maxLines: 2,
softWrap: true,
style: TextStyle(
color: Colors.black54,
fontFamily: 'Avenir',
fontSize: 15,
),
),
),
],
),
),
),
SizedBox(width: 10),
],
),
),
),
),
Container(
child: Center(
child: Icon(
Icons.keyboard_arrow_right,
size: 22,
color: Colors.black54,
),
),
),
SizedBox(width: 10),
],
),
),
),
),
),
);
}
}

How to get array data back to mobile screen from firebase (Flutter)

How to get back array data to the mobile screen.
The String in the firebase is retrieved easily but I have problem with array data.
1) main.dart :
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'firestoreservice.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'taskscreen.dart';
import 'task.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter ToDo APP',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Color(0xff543B7A),
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Task> items;
FirestoreService fireServ = new FirestoreService();
StreamSubscription<QuerySnapshot> todoTasks;
#override
void initState() {
super.initState();
items=new List();
todoTasks?.cancel();
todoTasks=fireServ.getTaskList().listen((QuerySnapshot snapshot){
final List<Task> tasks=snapshot.documents
.map((documentSnapshot) => Task. fromMap(documentSnapshot.data))
.toList();
setState(() {
this.items = tasks;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Column(
children: <Widget>[
_myAppBar(context),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - 80,
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Stack(children: <Widget>[
// The containers in the background
Column(children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 8.0, right: 8.0),
child: Container(
width: MediaQuery.of(context).size.width,
height: 80.0,
child: Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Material(
color: Colors.white,
elevation: 14.0,
shadowColor: Color(0x802196F3),
child: Center(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'${items[index].name}',
style: TextStyle(
color: Colors.black,
fontSize: 20.0),
),
Text(
'${items[index].size}',
style: TextStyle(
color: Colors.black,
fontSize: 20.0),
),
Container(
child: Image.network(
'${items[index].imageU}',
)),
],
),
),
),
),
),
),
),
]),
]);
}),
),
],
),
);
}
Widget todoType(String icontype) {
IconData iconval;
Color colorval;
switch (icontype) {
case 'travel':
iconval = FontAwesomeIcons.mapMarkerAlt;
colorval = Color(0xff4158ba);
break;
case 'shopping':
iconval = FontAwesomeIcons.shoppingCart;
colorval = Color(0xfffb537f);
break;
case 'gym':
iconval = FontAwesomeIcons.dumbbell;
colorval = Color(0xff4caf50);
break;
case 'party':
iconval = FontAwesomeIcons.glassCheers;
colorval = Color(0xff9962d0);
break;
default:
iconval = FontAwesomeIcons.tasks;
colorval = Color(0xff0dc8f5);
//
}
return CircleAvatar(
backgroundColor: colorval,
child: Icon(iconval, color: Colors.white, size: 20.0),
);
}
Widget _myAppBar(context) {
return Container(
height: 80.0,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
const Color(0xFFFA7397),
const Color(0xFFFDDE42),
],
begin: const FractionalOffset(0.0, 0.0),
end: const FractionalOffset(1.0, 0.0),
stops: [0.0, 1.0],
tileMode: TileMode.clamp),
),
child: Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
flex: 5,
child: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'ToDo Tasks',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 20.0),
),
),
),
),
Expanded(
flex: 1,
child: Container(
child: IconButton(
icon: Icon(
FontAwesomeIcons.search,
color: Colors.white,
),
onPressed: () {
//
}),
),
),
],
)),
),
);
}
}
2) task.dart
class Task{
String _name;
String _size;
Task(this._name ,this._size);
Task.map(dynamic obj){
this._name = obj['name'];
this._size=obj['size'];
List<String> imageU= new List<String>();
}
String get name=> _name;
String get size=>_size;
Task.fromMap(Map<String,dynamic> map){
this._name = map['name'];
this._size= map['size'];
this.imageU= List.from(map['images']);
}
}
3) firestoreservice.dart
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'task.dart';
final CollectionReference myCollection =
Firestore.instance.collection('products');
class FirestoreService {
Future<Task> createTODOTask(String name, String size) async {
final TransactionHandler createTransaction = (Transaction tx) async {
final DocumentSnapshot ds = await tx.get(myCollection.document());
};
return Firestore.instance.runTransaction(createTransaction).then((mapData) {
return Task.fromMap(mapData);
}).catchError((error) {
print('error: $error');
return null;
});
}
Stream<QuerySnapshot> getTaskList({int offset, int limit}) {
Stream<QuerySnapshot> snapshots = myCollection.snapshots();
if (offset != null) {
snapshots = snapshots.skip(offset);
}
if (limit != null) {
snapshots = snapshots.take(limit);
}
return snapshots;
}
}
How to get back array data to the mobile screen. The String in the firebase is retrieved easily but I have a problem with array data.
Convert task.dart to see what solution will work:
class Task{
String name;
List<String> size= new List<String>();
Task.fromMap(Map<String,dynamic> map){
this.name = map['name'];
this.size= List.from(map['size' ]);
}
}
And make sure all the documents in the image have "size" field.

Resources