mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Adds trivia to Veggie details screen (#61)
This commit is contained in:
@@ -19,6 +19,35 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 8,
|
||||
servingSize: 'One large apple',
|
||||
caloriesPerServing: 130,
|
||||
trivia: [
|
||||
Trivia(
|
||||
'A peck of apples (that\'s a real unit of mesaurement!) weighs approximately how many pounds?',
|
||||
[
|
||||
'10 pounds',
|
||||
'20 pounds',
|
||||
'30 pounds',
|
||||
],
|
||||
0,
|
||||
),
|
||||
Trivia(
|
||||
'Which of these is an actual variety of apples?',
|
||||
[
|
||||
'Dancing Turkey',
|
||||
'Winter Banana',
|
||||
'Red Sloth',
|
||||
],
|
||||
1,
|
||||
),
|
||||
Trivia(
|
||||
'In Greek mythology, Paris gives a golden apple marked "To the Fairest" to a goddess. Which one?',
|
||||
[
|
||||
'Hera',
|
||||
'Athena',
|
||||
'Aphrodite',
|
||||
],
|
||||
2,
|
||||
),
|
||||
],
|
||||
),
|
||||
Veggie(
|
||||
id: 2,
|
||||
@@ -32,6 +61,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 25,
|
||||
servingSize: '1 medium artichoke',
|
||||
caloriesPerServing: 60,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 3,
|
||||
@@ -45,6 +75,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 15,
|
||||
servingSize: '5 spears',
|
||||
caloriesPerServing: 20,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 4,
|
||||
@@ -58,6 +89,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 4,
|
||||
servingSize: '1/5 medium avocado',
|
||||
caloriesPerServing: 50,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 5,
|
||||
@@ -71,6 +103,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 4,
|
||||
servingSize: '1 cup',
|
||||
caloriesPerServing: 62,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 6,
|
||||
@@ -84,6 +117,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 80,
|
||||
servingSize: '1/4 medium canteloupe',
|
||||
caloriesPerServing: 50,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 7,
|
||||
@@ -97,6 +131,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 100,
|
||||
servingSize: '1/6 medium head',
|
||||
caloriesPerServing: 25,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 8,
|
||||
@@ -110,6 +145,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 2,
|
||||
servingSize: '1/2 cup, chopped',
|
||||
caloriesPerServing: 4,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 9,
|
||||
@@ -123,6 +159,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 2,
|
||||
servingSize: '1 large fig',
|
||||
caloriesPerServing: 50,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 10,
|
||||
@@ -136,6 +173,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 2,
|
||||
servingSize: '3/4 cup',
|
||||
caloriesPerServing: 90,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 11,
|
||||
@@ -149,6 +187,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 190,
|
||||
servingSize: '1 medium pepper',
|
||||
caloriesPerServing: 25,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 12,
|
||||
@@ -162,6 +201,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 100,
|
||||
servingSize: '1 pepper',
|
||||
caloriesPerServing: 20,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 13,
|
||||
@@ -175,6 +215,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 134,
|
||||
servingSize: '1 cup, chopped',
|
||||
caloriesPerServing: 33,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 14,
|
||||
@@ -188,6 +229,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 240,
|
||||
servingSize: '2 medium kiwis',
|
||||
caloriesPerServing: 90,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 15,
|
||||
@@ -201,6 +243,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 40,
|
||||
servingSize: '1 medium lemon',
|
||||
caloriesPerServing: 15,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 16,
|
||||
@@ -214,6 +257,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 35,
|
||||
servingSize: '1 medium lime',
|
||||
caloriesPerServing: 20,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 17,
|
||||
@@ -227,6 +271,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 203,
|
||||
servingSize: '1 fruit',
|
||||
caloriesPerServing: 201,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 18,
|
||||
@@ -240,6 +285,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 2,
|
||||
servingSize: '5 medium \'shrooms',
|
||||
caloriesPerServing: 20,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 19,
|
||||
@@ -253,6 +299,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 15,
|
||||
servingSize: '1 medium nectarine',
|
||||
caloriesPerServing: 60,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 20,
|
||||
@@ -266,6 +313,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 27,
|
||||
servingSize: '1 fruit',
|
||||
caloriesPerServing: 32,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 21,
|
||||
@@ -279,6 +327,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 10,
|
||||
servingSize: '2 medium plums',
|
||||
caloriesPerServing: 70,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 22,
|
||||
@@ -292,6 +341,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 45,
|
||||
servingSize: '1 medium spud',
|
||||
caloriesPerServing: 110,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 23,
|
||||
@@ -305,6 +355,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 10,
|
||||
servingSize: '2 cups shredded',
|
||||
caloriesPerServing: 20,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 24,
|
||||
@@ -318,6 +369,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 30,
|
||||
servingSize: '7 radishes',
|
||||
caloriesPerServing: 10,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 25,
|
||||
@@ -331,6 +383,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 48,
|
||||
servingSize: '1 cup diced butternut',
|
||||
caloriesPerServing: 63,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 26,
|
||||
@@ -345,6 +398,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 160,
|
||||
servingSize: '8 medium strawberries',
|
||||
caloriesPerServing: 50,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 27,
|
||||
@@ -358,6 +412,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 181,
|
||||
servingSize: '1 medium tangelo',
|
||||
caloriesPerServing: 60,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 28,
|
||||
@@ -371,6 +426,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 40,
|
||||
servingSize: '1 medium tomato',
|
||||
caloriesPerServing: 25,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 29,
|
||||
@@ -384,6 +440,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 25,
|
||||
servingSize: '2 cups diced',
|
||||
caloriesPerServing: 80,
|
||||
trivia: [],
|
||||
),
|
||||
Veggie(
|
||||
id: 30,
|
||||
@@ -397,6 +454,7 @@ class LocalVeggieProvider {
|
||||
vitaminCPercentage: 190,
|
||||
servingSize: '1 medium pepper',
|
||||
caloriesPerServing: 25,
|
||||
trivia: [],
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -33,6 +33,14 @@ enum Season {
|
||||
autumn,
|
||||
}
|
||||
|
||||
class Trivia {
|
||||
final String question;
|
||||
final List<String> answers;
|
||||
final int correctAnswerIndex;
|
||||
|
||||
const Trivia(this.question, this.answers, this.correctAnswerIndex);
|
||||
}
|
||||
|
||||
const Map<VeggieCategory, String> veggieCategoryNames = {
|
||||
VeggieCategory.allium: 'Allium',
|
||||
VeggieCategory.berry: 'Berry',
|
||||
@@ -67,6 +75,7 @@ class Veggie {
|
||||
@required this.vitaminCPercentage,
|
||||
@required this.servingSize,
|
||||
@required this.caloriesPerServing,
|
||||
@required this.trivia,
|
||||
this.isFavorite = false,
|
||||
});
|
||||
|
||||
@@ -80,7 +89,7 @@ class Veggie {
|
||||
|
||||
final VeggieCategory category;
|
||||
|
||||
/// A short, snappy line, possibly with trivia.
|
||||
/// A short, snappy line.
|
||||
final String shortDescription;
|
||||
|
||||
/// A color value to use when constructing UI elements to match the image
|
||||
@@ -108,5 +117,8 @@ class Veggie {
|
||||
/// as a favorite).
|
||||
bool isFavorite;
|
||||
|
||||
/// A set of trivia questions and answers related to the veggie.
|
||||
final List<Trivia> trivia;
|
||||
|
||||
String get categoryName => veggieCategoryNames[category];
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:veggieseasons/data/preferences.dart';
|
||||
import 'package:veggieseasons/data/veggie.dart';
|
||||
import 'package:veggieseasons/styles.dart';
|
||||
import 'package:veggieseasons/widgets/close_button.dart';
|
||||
import 'package:veggieseasons/widgets/trivia.dart';
|
||||
|
||||
class ServingInfoChart extends StatelessWidget {
|
||||
const ServingInfoChart(this.veggie, this.prefs);
|
||||
@@ -211,20 +212,6 @@ class InfoView extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class TriviaView extends StatelessWidget {
|
||||
final int id;
|
||||
|
||||
const TriviaView(this.id);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(32.0),
|
||||
child: Text('Trivia goes here.'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DetailsScreen extends StatefulWidget {
|
||||
final int id;
|
||||
|
||||
|
||||
@@ -127,6 +127,30 @@ abstract class Styles {
|
||||
fontWeight: FontWeight.normal,
|
||||
);
|
||||
|
||||
static const triviaFinishedTitleText = TextStyle(
|
||||
color: Color.fromRGBO(0, 0, 0, 0.9),
|
||||
fontFamily: 'NotoSans',
|
||||
fontSize: 32.0,
|
||||
fontStyle: FontStyle.normal,
|
||||
fontWeight: FontWeight.normal,
|
||||
);
|
||||
|
||||
static const triviaFinishedText = TextStyle(
|
||||
color: Color.fromRGBO(0, 0, 0, 0.9),
|
||||
fontFamily: 'NotoSans',
|
||||
fontSize: 16.0,
|
||||
fontStyle: FontStyle.normal,
|
||||
fontWeight: FontWeight.normal,
|
||||
);
|
||||
|
||||
static const triviaFinishedBigText = TextStyle(
|
||||
color: Color.fromRGBO(0, 0, 0, 0.9),
|
||||
fontFamily: 'NotoSans',
|
||||
fontSize: 48.0,
|
||||
fontStyle: FontStyle.normal,
|
||||
fontWeight: FontWeight.normal,
|
||||
);
|
||||
|
||||
static const appBackground = Color(0xffd0d0d0);
|
||||
|
||||
static const scaffoldBackground = Color(0xfff0f0f0);
|
||||
|
||||
210
veggieseasons/lib/widgets/trivia.dart
Normal file
210
veggieseasons/lib/widgets/trivia.dart
Normal file
@@ -0,0 +1,210 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:scoped_model/scoped_model.dart';
|
||||
import 'package:veggieseasons/data/app_state.dart';
|
||||
import 'package:veggieseasons/data/veggie.dart';
|
||||
import 'package:veggieseasons/styles.dart';
|
||||
|
||||
/// Presents a series of trivia questions about a particular widget, and tracks
|
||||
/// the user's score.
|
||||
class TriviaView extends StatefulWidget {
|
||||
final int id;
|
||||
|
||||
const TriviaView(this.id);
|
||||
|
||||
@override
|
||||
_TriviaViewState createState() => _TriviaViewState();
|
||||
}
|
||||
|
||||
/// Possible states of the game.
|
||||
enum PlayerStatus {
|
||||
readyToAnswer,
|
||||
wasCorrect,
|
||||
wasIncorrect,
|
||||
}
|
||||
|
||||
class _TriviaViewState extends State<TriviaView> {
|
||||
/// Current app state. This is used to fetch veggie data.
|
||||
AppState appState;
|
||||
|
||||
/// The veggie trivia about which to show.
|
||||
Veggie veggie;
|
||||
|
||||
/// Index of the current trivia question.
|
||||
int triviaIndex = 0;
|
||||
|
||||
/// User's score on the current veggie.
|
||||
int score = 0;
|
||||
|
||||
/// Trivia question currently being displayed.
|
||||
Trivia get currentTrivia => veggie.trivia[triviaIndex];
|
||||
|
||||
/// The current state of the game.
|
||||
PlayerStatus status = PlayerStatus.readyToAnswer;
|
||||
|
||||
// Called at init and again if any dependencies (read: InheritedWidgets) on
|
||||
// on which this object relies are changed.
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
|
||||
final newAppState =
|
||||
ScopedModel.of<AppState>(context, rebuildOnChange: true);
|
||||
|
||||
setState(() {
|
||||
appState = newAppState;
|
||||
veggie = appState.getVeggie(widget.id);
|
||||
});
|
||||
}
|
||||
|
||||
// Called when the widget associated with this object is swapped out for a new
|
||||
// one. If the new widget has a different Veggie ID value, the state object
|
||||
// needs to do a little work to reset itself for the new Veggie.
|
||||
@override
|
||||
void didUpdateWidget(TriviaView oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
|
||||
if (oldWidget.id != widget.id) {
|
||||
setState(() {
|
||||
veggie = appState.getVeggie(widget.id);
|
||||
});
|
||||
|
||||
_resetGame();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (triviaIndex >= veggie.trivia.length) {
|
||||
return _buildFinishedView();
|
||||
} else if (status == PlayerStatus.readyToAnswer) {
|
||||
return _buildQuestionView();
|
||||
} else {
|
||||
return _buildResultView();
|
||||
}
|
||||
}
|
||||
|
||||
void _resetGame() {
|
||||
setState(() {
|
||||
triviaIndex = 0;
|
||||
score = 0;
|
||||
status = PlayerStatus.readyToAnswer;
|
||||
});
|
||||
}
|
||||
|
||||
void _processAnswer(int answerIndex) {
|
||||
setState(() {
|
||||
if (answerIndex == currentTrivia.correctAnswerIndex) {
|
||||
status = PlayerStatus.wasCorrect;
|
||||
score++;
|
||||
} else {
|
||||
status = PlayerStatus.wasIncorrect;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Widget shown when the game is over. It includes the score and a button to
|
||||
// restart everything.
|
||||
Widget _buildFinishedView() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(32.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'All done!',
|
||||
style: Styles.triviaFinishedTitleText,
|
||||
),
|
||||
SizedBox(height: 16.0),
|
||||
Text(
|
||||
'You answered',
|
||||
style: Styles.triviaFinishedText,
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
Text(
|
||||
'$score',
|
||||
style: Styles.triviaFinishedBigText,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Text(
|
||||
' of ',
|
||||
style: Styles.triviaFinishedText,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${veggie.trivia.length}',
|
||||
style: Styles.triviaFinishedBigText,
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'questions correctly!',
|
||||
style: Styles.triviaFinishedText,
|
||||
),
|
||||
SizedBox(height: 16.0),
|
||||
CupertinoButton(
|
||||
child: Text('Try Again'),
|
||||
onPressed: () => _resetGame(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Presents the current trivia's question and answer choices.
|
||||
Widget _buildQuestionView() {
|
||||
List<Widget> buttons = [];
|
||||
|
||||
for (int i = 0; i < currentTrivia.answers.length; i++) {
|
||||
buttons.add(Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: CupertinoButton(
|
||||
color: CupertinoColors.activeBlue,
|
||||
child: Text(
|
||||
currentTrivia.answers[i],
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
onPressed: () => _processAnswer(i),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 16.0),
|
||||
Text(currentTrivia.question),
|
||||
SizedBox(height: 32.0),
|
||||
]..addAll(buttons),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Shows whether the last answer was right or wrong and prompts the user to
|
||||
// continue through the game.
|
||||
Widget _buildResultView() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(32.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(status == PlayerStatus.wasCorrect
|
||||
? 'That\'s right!'
|
||||
: 'Sorry, that wasn\'t the right answer.'),
|
||||
SizedBox(height: 16.0),
|
||||
CupertinoButton(
|
||||
child: Text('Next Question'),
|
||||
onPressed: () => setState(() {
|
||||
triviaIndex++;
|
||||
status = PlayerStatus.readyToAnswer;
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user