Skip to content

Commit

Permalink
feat: full working app
Browse files Browse the repository at this point in the history
  • Loading branch information
codediodeio committed May 14, 2019
1 parent bcc014a commit e745d5b
Show file tree
Hide file tree
Showing 3 changed files with 264 additions and 2 deletions.
Binary file added assets/congrats.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
264 changes: 262 additions & 2 deletions lib/screens/quiz.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,272 @@
import 'package:flutter/material.dart';
import '../shared/shared.dart';
import '../services/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:provider/provider.dart';

// Shared Data
class QuizState with ChangeNotifier {
double _progress = 0;
Option _selected;

final PageController controller = PageController();

get progress => _progress;
get selected => _selected;

set progress(double newValue) {
_progress = newValue;
notifyListeners();
}

set selected(Option newValue) {
_selected = newValue;
notifyListeners();
}

void nextPage() async {
await controller.nextPage(
duration: Duration(milliseconds: 500),
curve: Curves.easeOut,
);
}
}

class QuizScreen extends StatelessWidget {
QuizScreen({this.quizId});
final String quizId;

@override
Widget build(BuildContext context) {
return LoadingScreen();
return ChangeNotifierProvider(
builder: (_) => QuizState(),
child: FutureBuilder(
future: Document<Quiz>(path: 'quizzes/$quizId').getData(),
builder: (BuildContext context, AsyncSnapshot snap) {
var state = Provider.of<QuizState>(context);

if (!snap.hasData || snap.hasError) {
return LoadingScreen();
} else {
Quiz quiz = snap.data;
return Scaffold(
appBar: AppBar(
title: AnimatedProgressbar(value: state.progress),
leading: IconButton(
icon: Icon(FontAwesomeIcons.times),
onPressed: () => Navigator.pop(context),
),
),
body: PageView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
controller: state.controller,
onPageChanged: (int idx) =>
state.progress = (idx / (quiz.questions.length + 1)),
itemBuilder: (BuildContext context, int idx) {
if (idx == 0) {
return StartPage(quiz: quiz);
} else if (idx == quiz.questions.length + 1) {
return CongratsPage(quiz: quiz);
} else {
return QuestionPage(question: quiz.questions[idx - 1]);
}
},
),
);
}
},
),
);
}
}

class StartPage extends StatelessWidget {
final Quiz quiz;
final PageController controller;
StartPage({this.quiz, this.controller});

@override
Widget build(BuildContext context) {
var state = Provider.of<QuizState>(context);

return Container(
padding: EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(quiz.title, style: Theme.of(context).textTheme.headline),
Divider(),
Expanded(child: Text(quiz.description)),
ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton.icon(
onPressed: state.nextPage,
label: Text('Start Quiz!'),
icon: Icon(Icons.poll),
color: Colors.green,
)
],
)
],
),
);
}
}

class CongratsPage extends StatelessWidget {
final Quiz quiz;
CongratsPage({this.quiz});

@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(8),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Congrats! You completed the ${quiz.title} quiz',
textAlign: TextAlign.center,
),
Divider(),
Image.asset('assets/congrats.gif'),
Divider(),
FlatButton.icon(
color: Colors.green,
icon: Icon(FontAwesomeIcons.check),
label: Text(' Mark Complete!'),
onPressed: () {
_updateUserReport(quiz);
Navigator.pushNamedAndRemoveUntil(
context,
'/topics',
(route) => false,
);
},
)
],
),
);
}

/// Database write to update report doc when complete
Future<void> _updateUserReport(Quiz quiz) {
return Global.reportRef.upsert(
({
'total': FieldValue.increment(1),
'topics': {
'${quiz.topic}': FieldValue.arrayUnion([quiz.id])
}
}),
);
}
}

class QuestionPage extends StatelessWidget {
final Question question;
QuestionPage({this.question});

@override
Widget build(BuildContext context) {
var state = Provider.of<QuizState>(context);

return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(
child: Container(
padding: EdgeInsets.all(16),
alignment: Alignment.center,
child: Text(question.text),
),
),
Container(
padding: EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: question.options.map((opt) {
return Container(
height: 90,
margin: EdgeInsets.only(bottom: 10),
color: Colors.black26,
child: InkWell(
onTap: () {
state.selected = opt;
_bottomSheet(context, opt);
},
child: Container(
padding: EdgeInsets.all(16),
child: Row(
children: [
Icon(
state.selected == opt
? FontAwesomeIcons.checkCircle
: FontAwesomeIcons.circle,
size: 30),
Expanded(
child: Container(
margin: EdgeInsets.only(left: 16),
child: Text(
opt.value,
style: Theme.of(context).textTheme.body2,
),
),
)
],
),
),
),
);
}).toList(),
),
)
],
);
}

/// Bottom sheet shown when Question is answered
_bottomSheet(BuildContext context, Option opt) {
bool correct = opt.correct;
var state = Provider.of<QuizState>(context);
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 250,
padding: EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(correct ? 'Good Job!' : 'Wrong'),
Text(
opt.detail,
style: TextStyle(fontSize: 18, color: Colors.white54),
),
FlatButton(
color: correct ? Colors.green : Colors.red,
child: Text(
correct ? 'Onward!' : 'Try Again',
style: TextStyle(
color: Colors.white,
letterSpacing: 1.5,
fontWeight: FontWeight.bold,
),
),
onPressed: () {
if (correct) {
state.nextPage();
}
Navigator.pop(context);
},
),
],
),
);
},
);
}
}
}
2 changes: 2 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ flutter:
assets:
- assets/
- assets/covers/
- assets/congrats.gif


# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
Expand Down

0 comments on commit e745d5b

Please sign in to comment.