Flutter: Change ListTile based on Firestore query - flutter

I'm trying to configure the appearance of a list tile based on a firestore query.
So I have a set of list tiles as such:
What I want to achieve, when this page is loaded, the left side of the tile marks if a user has completed that particular lesson. So an 'x' means he has not but a 'tick' would mean that he has. Currently it is all hard coded to be 'x':
ListTile makeLessonListTile(Lesson lesson) => ListTile(
contentPadding:
EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: Container(
padding: EdgeInsets.only(right: 12.0),
decoration: new BoxDecoration(
border: new Border(
right: new BorderSide(width: 1.0, color: Colors.white24))),
child: IconButton(
icon: Icon(Icons.close, color: Colors.white), // Hardcoded to be 'x'
),
),
title: Text(
lesson.title,
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
subtitle: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
child: LinearProgressIndicator(
backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
value: lesson.indicatorValue,
valueColor: AlwaysStoppedAnimation(Colors.green)),
)),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(lesson.level,
style: TextStyle(color: Colors.white))),
)
],
),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.white, size: 30.0),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => QuizPage(
lesson: lesson,
auth: widget.auth,
onSignedOut: widget.onSignedOut,
userId: widget.userId,
)
)
);
},
);
Card makeLessonCard(Lesson lesson) => Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Container(
decoration: BoxDecoration(color: Color.fromRGBO(64, 75, 96, .9)),
child: makeLessonListTile(lesson),
),
);
// the scaffold body
final makeLessonBody = Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: lessons.length,
itemBuilder: (BuildContext context, int index) {
return makeLessonCard(lessons[index]);
},
),
);
I know how to do the query, I'm just not sure where to do it such that when the page loads, it is automatically updated to ticks and crosses based on the user results.
The query would be :
FirebaseUser user = await widget.auth.getCurrentUser();
Firestore.instance
.collection('Users')
.document(user.email)
.collection('Quiz Data')
.document('Courses')
.collection(lesson.abbr.toString().substring(5))
.document(lesson.title)
.get()
.then((DocumentSnapshot ds) {
if (ds.exists) {
if (ds['pass']) return true;
}
return false;
});
Base Auth Class I use for Authentication:
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
abstract class BaseAuth {
Future<String> signIn(String email, String password);
Future<String> signUp(String email, String password);
Future<FirebaseUser> getCurrentUser();
Future<void> sendEmailVerification();
Future<void> signOut();
Future<bool> isEmailVerified();
}
class Auth implements BaseAuth {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
Future<String> signIn(String email, String password) async {
FirebaseUser user = await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
return user.uid;
}
Future<String> signUp(String email, String password) async {
FirebaseUser user = await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
return user.uid;
}
Future<FirebaseUser> getCurrentUser() async {
FirebaseUser user = await _firebaseAuth.currentUser();
return user;
}
Future<void> signOut() async {
return _firebaseAuth.signOut();
}
Future<void> sendEmailVerification() async {
FirebaseUser user = await _firebaseAuth.currentUser();
user.sendEmailVerification();
}
Future<bool> isEmailVerified() async {
FirebaseUser user = await _firebaseAuth.currentUser();
return user.isEmailVerified;
}
}
Update - What I tried to do:
Use ternary operator:
class _NavigationPageState extends State<NavigationPage> {
. . . // omitted code
bool passed;
#override
void initState() {
passed = false;
. . . // omitted code
super.initState();
}
checkUserPassedLesson (Lesson lesson) async {
FirebaseUser user = await widget.auth.getCurrentUser();
Firestore.instance
.collection('Users')
.document(user.email)
.collection('Quiz Data')
.document('Courses')
.collection(lesson.abbr.toString().substring(5))
.document(lesson.title)
.get()
.then((DocumentSnapshot ds) {
if (ds.exists) {
if (ds['pass']) {
passed = true;
return;
}
}
passed = false;
});
}
#override
Widget build(BuildContext context) {
// for lesson page
ListTile makeLessonListTile(Lesson lesson) => ListTile(
contentPadding:
EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: Container(
padding: EdgeInsets.only(right: 12.0),
decoration: new BoxDecoration(
border: new Border(
right: new BorderSide(width: 1.0, color: Colors.white24))),
child: IconButton(
icon: passed ? Icon(Icons.done, color: Colors.white) : Icon(Icons.close, color: Colors.white),
),
),
title: Text(
lesson.title,
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
subtitle: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
child: LinearProgressIndicator(
backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
value: lesson.indicatorValue,
valueColor: AlwaysStoppedAnimation(Colors.green)),
)),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(lesson.level,
style: TextStyle(color: Colors.white))),
)
],
),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.white, size: 30.0),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => QuizPage(
lesson: lesson,
auth: widget.auth,
onSignedOut: widget.onSignedOut,
userId: widget.userId,
)
)
);
},
);
Card makeLessonCard(Lesson lesson) => Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Container(
decoration: BoxDecoration(color: Color.fromRGBO(64, 75, 96, .9)),
child: makeLessonListTile(lesson),
),
);
// query here and route accordingly
final makeLessonBody = Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: lessons.length,
itemBuilder: (BuildContext context, int index) {
checkUserPassedLesson(lessons[index]);
return makeLessonCard(lessons[index]);
},
),
);
. . . // omitted code
return Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: topAppBar,
body: makeLessonBody,
bottomNavigationBar: makeBottom,
);
}
}
Put Query in init:
class _NavigationPageState extends State<NavigationPage> {
... // omitted code
bool passed = false;
Container makeLessonBody;
#override
void initState() {
... // omitted code
// for lesson page
ListTile makeLessonListTile(Lesson lesson) => ListTile(
contentPadding:
EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: Container(
padding: EdgeInsets.only(right: 12.0),
decoration: new BoxDecoration(
border: new Border(
right: new BorderSide(width: 1.0, color: Colors.white24))),
child: IconButton(
icon: passed ? Icon(Icons.done, color: Colors.white) : Icon(Icons.close, color: Colors.white),
),
),
title: Text(
lesson.title,
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
subtitle: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
child: LinearProgressIndicator(
backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
value: lesson.indicatorValue,
valueColor: AlwaysStoppedAnimation(Colors.green)),
)),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(lesson.level,
style: TextStyle(color: Colors.white))),
)
],
),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.white, size: 30.0),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => QuizPage(
lesson: lesson,
auth: widget.auth,
onSignedOut: widget.onSignedOut,
userId: widget.userId,
)
)
);
},
);
Card makeLessonCard(Lesson lesson) => Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Container(
decoration: BoxDecoration(color: Color.fromRGBO(64, 75, 96, .9)),
child: makeLessonListTile(lesson),
),
);
makeLessonBody = Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: lessons.length,
itemBuilder: (BuildContext context, int index) {
checkUserPassedLesson(lessons[index]);
debugPrint(passed.toString());
return makeLessonCard(lessons[index]);
},
),
);
super.initState();
}
void checkUserPassedLesson (Lesson lesson) async {
FirebaseUser user = await widget.auth.getCurrentUser();
Firestore.instance
.collection('Users')
.document(user.email)
.collection('Quiz Data')
.document('Courses')
.collection(lesson.abbr.toString().substring(5))
.document(lesson.title)
.get()
.then((DocumentSnapshot ds) {
if (ds.exists) {
if (ds['pass']) {
setState(() {
debugPrint(ds['pass'].toString());
passed = true;
});
}
} else {
setState(() {
passed = false;
});}
});
}
... // omitted code
#override
Widget build(BuildContext context) {
... // omitted code
return Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: topAppBar,
body: makeLessonBody,
bottomNavigationBar: makeBottom,
);
}
}
Latest Update: Since the above methods were not working out, I tried to use a FutureBuilder using the ternary operator and it worked.
Full code:
class NavigationPage extends StatefulWidget {
NavigationPage({Key key, this.auth, this.userId, this.onSignedOut, this.userEmail}) : super(key: key);
final BaseAuth auth;
final VoidCallback onSignedOut;
final String userId;
final String userEmail;
#override
_NavigationPageState createState() => _NavigationPageState();
}
class _NavigationPageState extends State<NavigationPage> {
List courses;
List lessons;
String title;
TabStatus tabStatus;
bool showLessons;
bool _isLoading;
#override
void initState() {
title = COURSE_PAGE_TITLE;
_isLoading = false;
tabStatus = TabStatus.COURSE;
showLessons = false;
courses = StaticMethods.getCourses();
// temp value
lessons = StaticMethods.getLessons(Abbr.P01);
super.initState();
}
_signOut() async {
setState(() {
_isLoading = true;
});
try {
await widget.auth.signOut();
widget.onSignedOut();
setState(() {
_isLoading = false;
});
} catch (e) {
setState(() {
_isLoading = false;
});
print(e);
}
}
Widget _showLoading(){
if (_isLoading) {
return Center(
child: ColorLoader5(
dotOneColor: Colors.white24,
dotTwoColor: Colors.white70,
dotThreeColor: Colors.white,
dotType: DotType.circle,
dotIcon: Icon(Icons.adjust),
duration: Duration(seconds: 1),
)
);
}
return Container(height: 0.0, width: 0.0,);
}
Widget _showLoadingTile() {
return Center (
child: Container(
height: MediaQuery.of(context).size.height/10,
width: MediaQuery.of(context).size.width/2,
child: ColorLoader5(
dotOneColor: Colors.white24,
dotTwoColor: Colors.white70,
dotThreeColor: Colors.white,
dotType: DotType.circle,
dotIcon: Icon(Icons.adjust),
duration: Duration(seconds: 1),
),
)
);
}
Future<bool> checkUserPassedLesson (Lesson lesson) async {
bool passed;
await Firestore.instance
.collection('Users')
.document(widget.userEmail)
.collection('Quiz Data')
.document('Courses')
.collection(lesson.abbr.toString().substring(5))
.document(lesson.title)
.get()
.then((DocumentSnapshot ds) {
debugPrint("querying");
if (ds.exists) {
debugPrint('exists');
passed = ds['pass'];
} else passed = false;
});
return passed;
}
#override
Widget build(BuildContext context) {
// for lesson page
ListTile makeLessonListTile(Lesson lesson, bool passed) => ListTile(
contentPadding:
EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: Container(
padding: EdgeInsets.only(right: 12.0),
decoration: new BoxDecoration(
border: new Border(
right: new BorderSide(width: 1.0, color: Colors.white24))),
child: IconButton(
icon: passed ? Icon(Icons.done, color: Colors.white) : Icon(Icons.close, color: Colors.white),
),
),
title: Text(
lesson.title,
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
subtitle: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
child: LinearProgressIndicator(
backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
value: lesson.indicatorValue,
valueColor: AlwaysStoppedAnimation(Colors.green)),
)),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(lesson.level,
style: TextStyle(color: Colors.white))),
)
],
),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.white, size: 30.0),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => QuizPage(
lesson: lesson,
auth: widget.auth,
onSignedOut: widget.onSignedOut,
userId: widget.userId,
)
)
);
},
);
Card makeLessonCard(Lesson lesson, bool passed) => Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Container(
decoration: BoxDecoration(color: Color.fromRGBO(64, 75, 96, .9)),
child: makeLessonListTile(lesson, passed),
),
);
final makeLessonBody = Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: lessons.length,
itemBuilder: (BuildContext context, int index) {
return FutureBuilder<bool>(
future: checkUserPassedLesson(lessons[index]),
builder: (BuildContext context,
AsyncSnapshot<bool> snapshot) {
if (snapshot.hasError) return new Text('${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(child: _showLoadingTile());
default:
return makeLessonCard(lessons[index], snapshot.data);
}
},
);
},
),
);
return Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: topAppBar, // omitted code
body: makeLessonBody,
bottomNavigationBar: makeBottom, // omitted code
);
}
}

You don't have to repeat the function just to change the icon. Use a ternary operator instead (C# example but the concept is the same).
bool passed = checkUserPassedLesson(lesson);
...
IconButton(
icon: passed ? Icon(Icons.done, color: Colors.white) : Icon(Icons.close, color: Colors.white),
),
If passed is true it uses the done icon and close icon if its not.

Related

How to pass a variable (TextEditingController) to another class

class that i have the variable in
...
class _ActivitiesParticipantsState extends State<ActivitiesParticipants> {
final activityController = TextEditingController();
final user = FirebaseAuth.instance.currentUser!;
//Activities participants
List<String> docIDs = [];
//get docIDS
Future getDocId() async {
await FirebaseFirestore.instance
.collection(
activityController.text.trim(),
)
.get()
.then(
(snapshot) => snapshot.docs.forEach(
(element) {
docIDs.add(element.reference.id);
},
),
);
//stuff
}
#override
void dispose() {
activityController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextFormField(
controller: activityController,
decoration: InputDecoration(
labelText: 'e',
border: InputBorder.none,
),
),
GestureDetector(
onTap: () async {
setState(
() {
getDocId();
},
);
},
child: Container(
padding: EdgeInsets.all(
20,
),
decoration: BoxDecoration(
color: Colors.deepPurple,
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: Text(
'Test',
style: TextStyle(
color: Colors.white,
fontFamily: 'Quicksand',
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
),
),
),
Expanded(
child: FutureBuilder(
builder: (context, snapshot) {
return ListView.builder(
itemCount: wee(),
//docIDs.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: ListTile(
dense: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
tileColor: Color.fromARGB(255, 235, 235, 235),
title: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 20),
child: Column(
children: [
SizedBox(
height: 5,
),
Align(
alignment: Alignment.centerLeft,
child: Title(
color: Colors.black,
child: InterestedName(
documentID: docIDs[index]),
),
),
SizedBox(
height: 20,
),
],
),
),
),
);
},
);
},
),
),
],
),
),
),
);
}
}
...
How do I get the variable "activityController" to another class?
This other class is used to get Text to fill the ListTile
class that I want to get the variable
final String documentID;
InterestedName({required this.documentID});
#override
Widget build(BuildContext context) {
// get the collection
CollectionReference users = FirebaseFirestore.instance.collection('Project Koalas [test]');
return FutureBuilder<DocumentSnapshot>(
future: users.doc(documentID).get(),
builder: ((context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Text(
'Name: ${data['name']}',
style: TextStyle(
fontSize: 16,
fontFamily: 'Quicksand',
fontWeight: FontWeight.w600),
);
}
return Text('loading...');
}),
);
}
}
I would like to get the variable to be able to get the collection name that I want to take data from, as the collection I would like to take from is dependent on the user's choice.
If there is any way else to somehow fill the List tile in the same class, please let me know how.
Any help appreciated!

Flutter how to get list of selected FilterChips

i have created a Widget which displays chips to select your interests. The data is loaded from firestore. Now i want to check which ones are selected after i clicked the button. The problem is that i'm really new and i have no idea how to do this. Here is the code of my chip widget:
class _filterChipWidgetState extends State<filterChipWidget> {
var _isSelected = false;
#override
Widget build(BuildContext context) {
return FilterChip(
label: Text(widget.chipName),
labelStyle: TextStyle(color: Color.fromRGBO(254, 60, 110, 1),
fontSize: 16.0, fontWeight: FontWeight.bold),
selected: _isSelected,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
30.0),),
backgroundColor: Color(0xffededed),
checkmarkColor:Color.fromRGBO(254, 60, 110, 1),
onSelected: (isSelected) {
setState(() {
_isSelected = isSelected;
});
},
selectedColor: const Color.fromRGBO(255, 109, 147, 0.23137254901960785));
}
}
And here is how i implement it in my page:
class _SelectInterestState extends State<SelectInterest> {
#override
Widget build(BuildContext context) {
// TODO: implement build
CollectionReference interest =
FirebaseFirestore.instance.collection('interests');
return FutureBuilder<DocumentSnapshot>(
future: interest.doc('interests').get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Column(
children: [
generateChipList(data),
Padding(
padding: const EdgeInsets.all(30.0),
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
gradient: const LinearGradient(colors: [
Color.fromRGBO(254, 60, 110, 1),
Color.fromRGBO(226, 132, 78, 1.0),
]),
),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0, primary: Colors.transparent),
onPressed: () {
// HERE I WANT TO SEE THE SELECTED CHIPS Array
},
child: SizedBox(
width: double.infinity,
child: Center(
child: Text("NEXT"),
)))),
)
],
);
return Text("${data.values} ");
}
return const Text("loading");
},
);
}
Widget generateChipList(Map<String, dynamic> data) {
return Padding(
padding: const EdgeInsets.only(top: 30.0),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Wähle deine Interessen",
style: TextStyle(color: Colors.black87, fontSize: 30)),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Wrap(
spacing: 5.0,
runSpacing: 5.0,
children: List.generate(data['values'].length, (index) {
return filterChipWidget(
chipName: data['values'][index]['label'],
);
})),
),
)
],
),
);
}
}
Dominik Hartl try to edit filterChipWidget class:
Add new function
class filterChipWidget extends StatefulWidget {
filterChipWidget ({Key? key, required this.onSelected}) : super(key: key);
// Other declarations
// ....................
// End
Function(bool, String) onSelected;
#override
State<filterChipWidget> createState() => _filterChipWidgetState();
}
Update _filterChipWidgetState class
class _filterChipWidgetState extends State<filterChipWidget> {
var _isSelected = false;
#override
Widget build(BuildContext context) {
return FilterChip(
label: Text(widget.chipName),
labelStyle: TextStyle(color: Color.fromRGBO(254, 60, 110, 1),
fontSize: 16.0, fontWeight: FontWeight.bold),
selected: _isSelected,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
30.0),),
backgroundColor: Color(0xffededed),
checkmarkColor:Color.fromRGBO(254, 60, 110, 1),
onSelected: (isSelected) {
setState(() {
_isSelected = isSelected;
widget.onSelected(isChecked, widget.chipName);
});
},
selectedColor: const Color.fromRGBO(255, 109, 147, 0.23137254901960785));
}
}
Add new variable LIST, for selected values
class _SelectInterestState extends State<SelectInterest> {
late List<String> selectedItems = [];
#override
Widget build(BuildContext context) {
// TODO: implement build
CollectionReference interest =
FirebaseFirestore.instance.collection('interests');
return FutureBuilder<DocumentSnapshot>(
future: interest.doc('interests').get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Column(
children: [
generateChipList(data),
Padding(
padding: const EdgeInsets.all(30.0),
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
gradient: const LinearGradient(colors: [
Color.fromRGBO(254, 60, 110, 1),
Color.fromRGBO(226, 132, 78, 1.0),
]),
),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0, primary: Colors.transparent),
onPressed: () {
// HERE I WANT TO SEE THE SELECTED CHIPS Array
// Now you can get selected values
print(selectedItems);
},
child: SizedBox(
width: double.infinity,
child: Center(
child: Text("NEXT"),
)))),
)
],
);
return Text("${data.values} ");
}
return const Text("loading");
},
);
Finally add or remove values to/from the selectedItems LIST
Widget generateChipList(Map<String, dynamic> data) {
return Padding(
padding: const EdgeInsets.only(top: 30.0),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Wähle deine Interessen",
style: TextStyle(color: Colors.black87, fontSize: 30)),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Wrap(
spacing: 5.0,
runSpacing: 5.0,
children: List.generate(data['values'].length, (index) {
return filterChipWidget(
chipName: data['values'][index]['label'],
onSelected: (isChecked, item) {
if (isChecked) {
// Check the value exists in the list: add if NOT EXISTS
if (!selectedItems.contains(item)) {
selectedItems.add(item);
}
} else {
// Check the value exists in the list: remove if EXISTS
if (selectedItems.contains(item)) {
selectedItems.remove(item);
}
}
Not that generateChipList is _SelectInterestState class member.

Flutter General dialog box - set state not working

I have an issue with my General Dialog Box. I would like to display a star. Then I would like to change it state when the star is taped and replace the icon by a yellow Star.
But is does not work. The Dialog Box is not refreshed so the icon is not changing. Please, can you look at the source code below and point me into the right direction please?
Many thanks.
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:date_time_picker/date_time_picker.dart';
import 'package:gtd_official_sharped_focused/snackbar.dart';
String _isImportantInboxTask ;
String _isUrgentInboxTask ;
String inboxTaskDisplayed;
String isImportant = "false" ;
String isUrgent = "false" ;
String myProjectName ;
var taskSelectedID;
//---------------
//String _initialValue;
//_-----------------
var documentID;
var textController = TextEditingController();
var popUpTextController = TextEditingController();
class Inbox extends StatefulWidget {
Inbox({Key key}) : super(key: key);
#override
_InboxState createState() => _InboxState();
}
class _InboxState extends State<Inbox> {
GlobalKey<FormState> _captureFormKey = GlobalKey<FormState>();
bool isOn = true;
#override
Widget build(BuildContext context) {
void showAddNote() {
TextEditingController _noteField = new TextEditingController();
showDialog(
context: context,
builder: (BuildContext context) {
return CustomAlertDialog(
content: Container(
width: MediaQuery.of(context).size.width / 1.3,
height: MediaQuery.of(context).size.height / 4,
child: Column(
children: [
TextField(
controller: _noteField,
maxLines: 4,
decoration: InputDecoration(
border: const OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.black, width: 1.0),
),
),
),
SizedBox(height: 10),
Material(
elevation: 5.0,
borderRadius: BorderRadius.circular(25.0),
color: Colors.white,
child: MaterialButton(
minWidth: MediaQuery.of(context).size.width / 1.5,
onPressed: () {
Navigator.of(context).pop();
CollectionReference users = FirebaseFirestore.instance
.collection('Users')
.doc(FirebaseAuth.instance.currentUser.uid)
.collection('allTasks');
users
.add({'task_Name': _noteField.text,'task_Status': 'Inbox' })
.then((value) => print("User Document Added"))
.catchError((error) =>
print("Failed to add user: $error"));
},
padding: EdgeInsets.fromLTRB(10.0, 15.0, 10.0, 15.0),
child: Text(
'Add Note',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.0,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
);
});
}
return Scaffold(
appBar: new AppBar(
title: new Text('Inbox Page'),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.add_circle_outline,
color: Colors.white,
),
onPressed: () {
showAddNote();
// do something
},
),
],
),
drawer: MyMenu(),
backgroundColor: Colors.white,
body: Column(
//mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: MediaQuery.of(context).size.height / 1.4,
width: MediaQuery.of(context).size.width,
child: StreamBuilder(
stream: FirebaseFirestore.instance
.collection('Users')
.doc(FirebaseAuth.instance.currentUser.uid)
.collection('allTasks')
.where('task_Status', isEqualTo: 'Inbox')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView(
children: snapshot.data.docs.map((document) {
return Wrap(
children: [Card(
child: SwipeActionCell(
key: ObjectKey(document.data()['task_Name']),
actions: <SwipeAction>[
SwipeAction(
title: "delete",
onTap: (CompletionHandler handler) {
CollectionReference users = FirebaseFirestore
.instance
.collection('Users')
.doc(
FirebaseAuth.instance.currentUser.uid)
.collection('allTasks');
users
.doc(document.id)
.delete()
.then((value) => print("Note Deleted"))
.catchError((error) => print(
"Failed to delete Task: $error"));
},
color: Colors.red),
],
child: Padding(
padding: const EdgeInsets.all(0.0),
child: ListTile(
leading: ConstrainedBox(
constraints: BoxConstraints(
minWidth: leadingIconMinSize,
minHeight: leadingIconMinSize,
maxWidth: leadingIconMaxSize,
maxHeight: leadingIconMaxSize,
),
child: Image.asset('assets/icons/inbox.png'),
),
title: GestureDetector(
child: Text(
//'task_Name' correspond au nom du champ dans la table
document.data()['task_Name'],
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
// Pour editer task
onDoubleTap: (){
taskSelectedID = FirebaseFirestore
.instance
.collection('Users')
.doc(
FirebaseAuth.instance.currentUser.uid)
.collection('allTasks')
.doc(document.id);
//Dialog
return showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: MaterialLocalizations.of(context)
.modalBarrierDismissLabel,
barrierColor: Colors.black45,
transitionDuration: const Duration(milliseconds: 20),
pageBuilder: (BuildContext buildContext,
Animation animation,
Animation secondaryAnimation) {
return Scaffold(
appBar: AppBar(
title: Text ('Edit Task'),
leading: InkWell(
child: Icon(Icons.close),
onTap:(){Navigator.of(context).pop();}
),
actions: [Padding(
padding: const EdgeInsets.fromLTRB(0, 0,16.0,0),
child: InkWell(
child: Icon(Icons.save),
onTap: () {
final loFormInbox = _captureFormKey
.currentState;
if (loFormInbox.validate()) {
loFormInbox.save();
CollectionReference users = FirebaseFirestore
.instance
.collection(
'Users')
.doc(FirebaseAuth
.instance
.currentUser.uid)
.collection(
'allTasks');
users
.add({
'task_Name': _valueTaskNameSaved,
})
.then((value) =>
print(
"Task Created"))
.catchError((
error) =>
print(
"Failed to add task: $error"));
showSimpleFlushbar(
context,
'Task Saved',
_valueTaskNameSaved,
Icons
.mode_comment);
loFormInbox.reset();
isImportant = 'false';
isUrgent = 'false';
}
}
),
)],
),
body: Center(
child: Container(
width: MediaQuery.of(context).size.width - 10,
height: MediaQuery.of(context).size.height - 80,
padding: EdgeInsets.all(20),
color: Colors.white,
child: Column(
children: [
Theme(
data: ThemeData(
inputDecorationTheme: InputDecorationTheme(
border: InputBorder.none,
)
),
child: Padding(
padding: const EdgeInsets.fromLTRB(8.0, 0.0, 15.0, 1.0),
child: TextFormField(
initialValue: document.data()['task_Name'],
decoration: InputDecoration(hintText: "Task Name"),
maxLength: 70,
maxLines: 2,
onChanged: (valProjectName) => setState(() => _valueTaskNameChanged = valProjectName),
validator: (valProjectName) {
setState(() => _valueTaskNameToValidate = valProjectName);
return valProjectName.isEmpty? "Task name cannot be empty" : null;
},
onSaved: (valProjectName) => setState(() => _valueTaskNameSaved = valProjectName),
),
)),
//Test Energy et Time / Important /urgent
Material(
child:
Container(
// color: Colors.red,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
//Important
FlatButton(
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
isImportant =="true" ? Icon(Icons.star,color: Colors.orange,) :
Icon(Icons.star_border, color: Colors.grey,),
// Icon(Icons.battery_charging_full),
Text('Important'),
],
)
),
onTap: () {
setState(() {
if (isImportant=='true'){
isImportant = 'false';}
else
{isImportant= 'true';
}
});
},
),
),
RaisedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
"Close",
style: TextStyle(color: Colors.white),
),
color: const Color(0xFF1BC0C5),
)
//++++++++++++++++
],
),
),
),
);
});
},
),
),
),
),
),
),
]
);
}).toList(),
);
}),
),
],
),
bottomNavigationBar: MyBottomAppBar(), //PersistentBottomNavBar(),
);
}
}
#override
Widget build(BuildContext context){
return _widget();
}
}
Thanks to your solution, I am able to do what I was willing to do. But now, I have an other issue. In the version 1 of my code, I am using this code
Theme(
data: ThemeData(
inputDecorationTheme: InputDecorationTheme(
border: InputBorder.none,
)
),
child: Padding(
padding: const EdgeInsets.fromLTRB(8.0, 0.0, 15.0, 1.0),
child: TextFormField(
initialValue: document.data()['task_Name'],
decoration: InputDecoration(hintText: "Task Name"),
maxLength: 70,
maxLines: 2,
onChanged: (valProjectName) => setState(() => _valueTaskNameChanged = valProjectName),
validator: (valProjectName) {
setState(() => _valueTaskNameToValidate = valProjectName);
return valProjectName.isEmpty? "Task name cannot be empty" : null;
},
onSaved: (valProjectName) => setState(() => _valueTaskNameSaved = valProjectName),
),
)),
This part was working well. But after the modifications, I am getting an error. The error is about document.
Undefined name 'document'. Try correcting the name to one that is defined, or defining the name.
Please, can you help me with this so I can finalize this page. Thank you
So you want to change the color of icon on clicking it inside dialogBox,
but unfortunately you are using stateless widget Scaffold in return of showGeneralDialog builder so one thing that can possibly help is to make a separate StateFull Widget RatingDialogBox and use that in the builder.
Also instead of InkWell you can use IconButton
I will suggest you to use this package it is great
flutter_rating_bar
also feel free to comment is this doesn't satisfy your need

Flutter Firebase: not able update Database

I want to update my Collection with an NumberPicker in a Alert Dialog. I do not get any errors in code or from the emulator. When i press the button to update the code the terminal do not give any errors. Everything looks fine but for some reason i do not work. When you need more Information just leave a comment with what you excactly need. :)
import 'package:flutter/material.dart';
import 'package:numberpicker/numberpicker.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
import 'package:testapp/services/Services.dart';
import 'models/Goals.dart';
class Statistics extends StatefulWidget {
#override
_StatisticsState createState() => _StatisticsState();
}
class _StatisticsState extends State<Statistics> {
int _currentFirstValue = 1;
int totalFirst;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: 260,
child: StreamBuilder(
stream: FirestoreService().getGoals(),
builder: (context, AsyncSnapshot<List<Goal>> snapshot) {
if (snapshot.hasError || !snapshot.hasData) {
return Center(child: CircularProgressIndicator(
backgroundColor: Color(0XFF1954A1),
));
}
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
// ignore: missing_return
Goal goal = snapshot.data[index];
return Row(
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
height: 230,
width: 350,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(10.0)),
boxShadow: [
BoxShadow(
color: Colors.grey[300],
offset: const Offset(0.5, 1),
blurRadius: 4.0,
spreadRadius: 0.1,
),
]),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text('WeekGoals', style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.w500,
),),
SizedBox(width: 100),
SizedBox(
height: 20,
width: 87,
child: FlatButton(
child: Text('edit', style: TextStyle(
fontSize: 17,
color: Colors.yellow[700]
),),
onPressed: () {
return showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
content: Column(
children: <Widget>[
Text('weekly goals'),
NumberPicker.integer(
initialValue: _currentFirstValue,
minValue: 1,
maxValue: 100,
onChanged: (newGoal) => setState(() => {
_currentFirstValue = newGoal,
totalFirst = _currentFirstValue,
})
),
Row(
children: <Widget>[
RaisedButton(
child: Text('edit goals'),
onPressed: () async {
Goal goal = Goal(
weekActivityGoal: totalFirst,
);
await FirestoreService().updateGoal(goal);
Navigator.pop(context, false);
},
),
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.pop(context, false);
},
)
],
)
],
),
)
);
},
),
)
],
),
SizedBox(height: 10),
Row(
children: <Widget>[
Container(
padding: EdgeInsets.symmetric(horizontal: 17.5),
child: CircularPercentIndicator(
header: Text('activitys', style: TextStyle(
fontSize: 17,
),),
radius: 130,
progressColor: Colors.red,
lineWidth: 8,
backgroundColor: Colors.grey[200],
percent: goal.weekActivity*100/goal.weekActivityGoal,
center: Text('${goal.weekActivity}/${goal.weekActivityGoal}'),
),
),
],
),
],
),
),
],
);
});
}),
),
);
}
}
Here this has been helping a lot of people try i out might help you too.
StreamBuilder(
stream: Firestore.instance.collection('Hearings').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) return Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Select lot');
case ConnectionState.waiting:
return Text('Awaiting bids...');
case ConnectionState.active:
{
print('active');
return Text('${snapshot.data}');
}
case ConnectionState.done:
{
print('Done');
return _buildList(context, snapshot.data);
}
}
return null;
}),
));
}
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return ListView(
padding: const EdgeInsets.only(top: 20.0),
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
);
}
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
return Padding(
key: ValueKey(record.name),
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(5.0),
),
child: ListTile(
title: Text(record.name),
trailing: Text(record.votes.toString()),
onTap: () => Firestore.instance.runTransaction((transaction) async {
final freshSnapshot = await transaction.get(record.reference);
final fresh = Record.fromSnapshot(freshSnapshot);
await transaction
.update(record.reference, {'votes': fresh.votes + 1});
}),
),
),
);
}
}
class Record {
final String name;
final int votes;
final DocumentReference reference;
Record.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['name'] != null),
assert(map['votes'] != null),
name = map['name'],
votes = map['votes'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
#override
String toString() => "Record<$name:$votes>";
}
This is where the link this info came from.

Bad state: Stream has already been listened

I've got Bad state: Stream has already been listened when running the code below i call my stream inside a Tabview the run work fine but when i play around with the tab view its shows me Stream has already been listened.I don't understand what's the matter.
class DataServiceColi {
static Future loadJson(String url) async {
await Future.delayed(Duration(seconds: 5));
// Await the http get response, then decode t he json-formatted response.
http.Response response = await http.get(url);
if (response.statusCode == 200) {
String content = response.body;
collectionColi = json.decode(content);
print('$collectionColi');
return collectionColi;
} else {
print('Request failed with status: ${response.statusCode}.');
}
}
}
class DataManagerColis{
final StreamController<int> _counter = StreamController<int>();
final StreamController<List> streamController = new BehaviorSubject();
Stream<List> get counterlist => streamController.stream;
Stream<List> get colistView async*{
yield await DataServiceColi.loadJson(colis);
}
#override
void dispose() {
print('Disposed Statistics Bloc');
streamController.close();
}
DataManagerColis(){
colistView.listen((list) => streamController.add(list));
}
}
this my UI widget:
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: topAppBar,
body:TabBarView(children:[
StreamBuilder<List>(
stream: manager.colistView,
builder:(BuildContext context, AsyncSnapshot<List<dynamic>> snapshot){
switch (snapshot.connectionState) {
case ConnectionState.none: return Text('Select lot');
case ConnectionState.waiting:return Center(child: CircularProgressIndicator(backgroundColor:Colors.amberAccent,));
case ConnectionState.active: return Center(child: CircularProgressIndicator(backgroundColor: Colors.cyanAccent,));
case ConnectionState.done:
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data?.length ?? 0,
//separatorBuilder: (context, index) => Divider(),
itemBuilder: (BuildContext context, int index) {
print(index);
return Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Container(
decoration: BoxDecoration(color: Color.fromRGBO(64, 75, 96, .9)),
child: ListTile(
onTap: (){
if(snapshot.data[index]["itinéraires"].length == 0 ){
showDialog(
context: context,
builder: (_) => NetworkGiffyDialog(
buttonOkColor: Color.fromRGBO(64, 75, 96, .9),
key: keys[1],
image: Image.network(
"https://raw.githubusercontent.com/Shashank020519.gif"
fit: BoxFit.cover,
),
entryAnimation: EntryAnimation.DEFAULT,
title: Text(
'Pas encore defini',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22.0, fontWeight: FontWeight.w600),
),
description: Text(
"nothing"
textAlign: TextAlign.center,
),
onOkButtonPressed: () {},
));
}else{
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TimelinePage(title: 'suivi ${snapshot.data[index]["libelle_coli"]}',
trajet:snapshot.data[index]["itinéraires"],
)
));
}
},
contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: Container(
padding: EdgeInsets.only(right: 12.0),
decoration: new BoxDecoration(
border: new Border(
right: new BorderSide(width: 1.0, color: Colors.white24))),
child: Icon(Icons.autorenew, color: Colors.white),
),
title: Text(
"${snapshot.data[index]["libelle_coli"]}",
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
// subtitle: Text("Intermediate", style: TextStyle(color: Colors.white)),
subtitle:staut(index,snapshot.data),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.white, size: 30.0)),
),
);
},
);
}
//return null;
}
),
new Container(
child: Center(
child: Text("History"),
),
),
MessagingWidget()
]),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page_init()
));
},
child: Icon(Icons.add, color:Colors.amber,),
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
tooltip: "register something",
),
),
);
Please can someone help me?
try this:
final StreamController _counter = StreamController.broadcast();