Я пытаюсь настроить внешний вид плитки списка на основе запроса пожарного депо.
Итак, у меня есть набор плиток списка как таковой:
Чего я хочу достичь, когда эта страница загружена, левая сторона плитки помечается, если пользователь завершил этот конкретный урок. Таким образом, «х» означает, что у него нет, но «галочка» будет означать, что у него есть. В настоящее время все это жестко закодировано, чтобы быть '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]);
},
),
);
Я знаю, как выполнить запрос, но я просто не уверен, где это сделать, чтобы при загрузке страницы она автоматически обновлялась до тиков и крестов в зависимости от результатов пользователя.
Запрос будет:
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;
});
Базовый класс аутентификации I, используемый для аутентификации:
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;
}
}
Обновление - что я пытался сделать:
Использовать троичный оператор:
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,
);
}
}
Поместите запрос в 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,
);
}
}
Последнее обновление: так как вышеперечисленные методы не сработали, я попытался использовать FutureBuilder с использованием троичного оператора, и это сработало.
Полный код:
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
);
}
}