mirror of
https://github.com/flutter/samples.git
synced 2025-11-10 14:58:34 +00:00
State Restoration support for Veggie Seasons app (#433)
This commit is contained in:
committed by
GitHub
parent
d30bfd59ec
commit
ed1503143e
@@ -1,315 +0,0 @@
|
||||
// Copyright 2018 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:veggieseasons/data/app_state.dart';
|
||||
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);
|
||||
|
||||
final Veggie veggie;
|
||||
|
||||
final Preferences prefs;
|
||||
|
||||
// Creates a [Text] widget to display a veggie's "percentage of your daily
|
||||
// value of this vitamin" data adjusted for the user's preferred calorie
|
||||
// target.
|
||||
Widget _buildVitaminText(int standardPercentage, Future<int> targetCalories) {
|
||||
return FutureBuilder<int>(
|
||||
future: targetCalories,
|
||||
builder: (context, snapshot) {
|
||||
final target = snapshot?.data ?? 2000;
|
||||
final percent = standardPercentage * 2000 ~/ target;
|
||||
final themeData = CupertinoTheme.of(context);
|
||||
|
||||
return Text(
|
||||
'$percent% DV',
|
||||
textAlign: TextAlign.end,
|
||||
style: Styles.detailsServingValueText(themeData),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final themeData = CupertinoTheme.of(context);
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(height: 16),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 9,
|
||||
bottom: 4,
|
||||
),
|
||||
child: Text(
|
||||
'Serving info',
|
||||
style: Styles.detailsServingHeaderText,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Styles.servingInfoBorderColor),
|
||||
),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
children: [
|
||||
Table(
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
TableCell(
|
||||
child: Text(
|
||||
'Serving size:',
|
||||
style: Styles.detailsServingLabelText(themeData),
|
||||
),
|
||||
),
|
||||
TableCell(
|
||||
child: Text(
|
||||
veggie.servingSize,
|
||||
textAlign: TextAlign.end,
|
||||
style: Styles.detailsServingValueText(themeData),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
TableCell(
|
||||
child: Text(
|
||||
'Calories:',
|
||||
style: Styles.detailsServingLabelText(themeData),
|
||||
),
|
||||
),
|
||||
TableCell(
|
||||
child: Text(
|
||||
'${veggie.caloriesPerServing} kCal',
|
||||
textAlign: TextAlign.end,
|
||||
style: Styles.detailsServingValueText(themeData),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
TableCell(
|
||||
child: Text(
|
||||
'Vitamin A:',
|
||||
style: Styles.detailsServingLabelText(themeData),
|
||||
),
|
||||
),
|
||||
TableCell(
|
||||
child: _buildVitaminText(
|
||||
veggie.vitaminAPercentage,
|
||||
prefs.desiredCalories,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
TableCell(
|
||||
child: Text(
|
||||
'Vitamin C:',
|
||||
style: Styles.detailsServingLabelText(themeData),
|
||||
),
|
||||
),
|
||||
TableCell(
|
||||
child: _buildVitaminText(
|
||||
veggie.vitaminCPercentage,
|
||||
prefs.desiredCalories,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: FutureBuilder(
|
||||
future: prefs.desiredCalories,
|
||||
builder: (context, snapshot) {
|
||||
return Text(
|
||||
'Percent daily values based on a diet of '
|
||||
'${snapshot?.data ?? '2,000'} calories.',
|
||||
style: Styles.detailsServingNoteText(themeData),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class InfoView extends StatelessWidget {
|
||||
final int id;
|
||||
|
||||
const InfoView(this.id);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appState = Provider.of<AppState>(context);
|
||||
final prefs = Provider.of<Preferences>(context);
|
||||
final veggie = appState.getVeggie(id);
|
||||
final themeData = CupertinoTheme.of(context);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
FutureBuilder<Set<VeggieCategory>>(
|
||||
future: prefs.preferredCategories,
|
||||
builder: (context, snapshot) {
|
||||
return Text(
|
||||
veggie.categoryName.toUpperCase(),
|
||||
style: (snapshot.hasData &&
|
||||
snapshot.data.contains(veggie.category))
|
||||
? Styles.detailsPreferredCategoryText(themeData)
|
||||
: Styles.detailsCategoryText(themeData),
|
||||
);
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
for (Season season in veggie.seasons) ...[
|
||||
SizedBox(width: 12),
|
||||
Padding(
|
||||
padding: Styles.seasonIconPadding[season],
|
||||
child: Icon(
|
||||
Styles.seasonIconData[season],
|
||||
semanticLabel: seasonNames[season],
|
||||
color: Styles.seasonColors[season],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
veggie.name,
|
||||
style: Styles.detailsTitleText(themeData),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
veggie.shortDescription,
|
||||
style: Styles.detailsDescriptionText(themeData),
|
||||
),
|
||||
ServingInfoChart(veggie, prefs),
|
||||
SizedBox(height: 24),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CupertinoSwitch(
|
||||
value: veggie.isFavorite,
|
||||
onChanged: (value) {
|
||||
appState.setFavorite(id, value);
|
||||
},
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'Save to Garden',
|
||||
style: CupertinoTheme.of(context).textTheme.textStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DetailsScreen extends StatefulWidget {
|
||||
final int id;
|
||||
|
||||
DetailsScreen(this.id);
|
||||
|
||||
@override
|
||||
_DetailsScreenState createState() => _DetailsScreenState();
|
||||
}
|
||||
|
||||
class _DetailsScreenState extends State<DetailsScreen> {
|
||||
int _selectedViewIndex = 0;
|
||||
|
||||
Widget _buildHeader(BuildContext context, AppState model) {
|
||||
final veggie = model.getVeggie(widget.id);
|
||||
|
||||
return SizedBox(
|
||||
height: 150,
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
right: 0,
|
||||
left: 0,
|
||||
child: Image.asset(
|
||||
veggie.imageAssetPath,
|
||||
fit: BoxFit.cover,
|
||||
semanticLabel: 'A background image of ${veggie.name}',
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 16,
|
||||
left: 16,
|
||||
child: SafeArea(
|
||||
child: CloseButton(() {
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appState = Provider.of<AppState>(context);
|
||||
|
||||
return CupertinoPageScaffold(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
_buildHeader(context, appState),
|
||||
SizedBox(height: 20),
|
||||
CupertinoSegmentedControl<int>(
|
||||
children: {
|
||||
0: Text('Facts & Info'),
|
||||
1: Text('Trivia'),
|
||||
},
|
||||
groupValue: _selectedViewIndex,
|
||||
onValueChanged: (value) {
|
||||
setState(() => _selectedViewIndex = value);
|
||||
},
|
||||
),
|
||||
_selectedViewIndex == 0
|
||||
? InfoView(widget.id)
|
||||
: TriviaView(widget.id),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright 2018 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:veggieseasons/data/app_state.dart';
|
||||
import 'package:veggieseasons/data/veggie.dart';
|
||||
import 'package:veggieseasons/styles.dart';
|
||||
import 'package:veggieseasons/widgets/veggie_headline.dart';
|
||||
|
||||
class FavoritesScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoTabView(
|
||||
builder: (context) {
|
||||
final model = Provider.of<AppState>(context);
|
||||
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: Text('My Garden'),
|
||||
),
|
||||
child: Center(
|
||||
child: model.favoriteVeggies.isEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Text(
|
||||
'You haven\'t added any favorite veggies to your garden yet.',
|
||||
style: Styles.headlineDescription(
|
||||
CupertinoTheme.of(context)),
|
||||
),
|
||||
)
|
||||
: ListView(
|
||||
children: [
|
||||
SizedBox(height: 24),
|
||||
for (Veggie veggie in model.favoriteVeggies)
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(16, 0, 16, 24),
|
||||
child: VeggieHeadline(veggie),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright 2018 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:veggieseasons/screens/favorites.dart';
|
||||
import 'package:veggieseasons/screens/list.dart';
|
||||
import 'package:veggieseasons/screens/search.dart';
|
||||
import 'package:veggieseasons/screens/settings.dart';
|
||||
|
||||
class HomeScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoTabScaffold(
|
||||
tabBar: CupertinoTabBar(items: [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.home),
|
||||
label: 'Home',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.book),
|
||||
label: 'My Garden',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.search),
|
||||
label: 'Search',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.settings),
|
||||
label: 'Settings',
|
||||
),
|
||||
]),
|
||||
tabBuilder: (context, index) {
|
||||
if (index == 0) {
|
||||
return ListScreen();
|
||||
} else if (index == 1) {
|
||||
return FavoritesScreen();
|
||||
} else if (index == 2) {
|
||||
return SearchScreen();
|
||||
} else {
|
||||
return SettingsScreen();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright 2018 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:veggieseasons/data/app_state.dart';
|
||||
import 'package:veggieseasons/data/preferences.dart';
|
||||
import 'package:veggieseasons/data/veggie.dart';
|
||||
import 'package:veggieseasons/styles.dart';
|
||||
import 'package:veggieseasons/widgets/veggie_card.dart';
|
||||
|
||||
class ListScreen extends StatelessWidget {
|
||||
Widget _generateVeggieRow(Veggie veggie, Preferences prefs,
|
||||
{bool inSeason = true}) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: 16, right: 16, bottom: 24),
|
||||
child: FutureBuilder<Set<VeggieCategory>>(
|
||||
future: prefs.preferredCategories,
|
||||
builder: (context, snapshot) {
|
||||
final data = snapshot.data ?? <VeggieCategory>{};
|
||||
return VeggieCard(veggie, inSeason, data.contains(veggie.category));
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoTabView(
|
||||
builder: (context) {
|
||||
var dateString = DateFormat('MMMM y').format(DateTime.now());
|
||||
|
||||
final appState = Provider.of<AppState>(context);
|
||||
final prefs = Provider.of<Preferences>(context);
|
||||
final themeData = CupertinoTheme.of(context);
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: ListView.builder(
|
||||
itemCount: appState.allVeggies.length + 2,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == 0) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 24, 16, 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(dateString.toUpperCase(), style: Styles.minorText),
|
||||
Text('In season today',
|
||||
style: Styles.headlineText(themeData)),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else if (index <= appState.availableVeggies.length) {
|
||||
return _generateVeggieRow(
|
||||
appState.availableVeggies[index - 1],
|
||||
prefs,
|
||||
);
|
||||
} else if (index <= appState.availableVeggies.length + 1) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 24, 16, 16),
|
||||
child: Text('Not in season',
|
||||
style: Styles.headlineText(themeData)),
|
||||
);
|
||||
} else {
|
||||
var relativeIndex =
|
||||
index - (appState.availableVeggies.length + 2);
|
||||
return _generateVeggieRow(
|
||||
appState.unavailableVeggies[relativeIndex], prefs,
|
||||
inSeason: false);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
// Copyright 2018 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:veggieseasons/data/app_state.dart';
|
||||
import 'package:veggieseasons/data/veggie.dart';
|
||||
import 'package:veggieseasons/styles.dart';
|
||||
import 'package:veggieseasons/widgets/search_bar.dart';
|
||||
import 'package:veggieseasons/widgets/veggie_headline.dart';
|
||||
|
||||
class SearchScreen extends StatefulWidget {
|
||||
@override
|
||||
_SearchScreenState createState() => _SearchScreenState();
|
||||
}
|
||||
|
||||
class _SearchScreenState extends State<SearchScreen> {
|
||||
final controller = TextEditingController();
|
||||
final focusNode = FocusNode();
|
||||
String terms = '';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
controller.addListener(_onTextChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onTextChanged() {
|
||||
setState(() => terms = controller.text);
|
||||
}
|
||||
|
||||
Widget _createSearchBox() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: SearchBar(
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchResults(List<Veggie> veggies) {
|
||||
if (veggies.isEmpty) {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Text(
|
||||
'No veggies matching your search terms were found.',
|
||||
style: Styles.headlineDescription(CupertinoTheme.of(context)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: veggies.length + 1,
|
||||
itemBuilder: (context, i) {
|
||||
if (i == 0) {
|
||||
return Visibility(
|
||||
// This invisible and otherwise unnecessary search box is used to
|
||||
// pad the list entries downward, so none will be underneath the
|
||||
// real search box when the list is at its top scroll position.
|
||||
child: _createSearchBox(),
|
||||
visible: false,
|
||||
maintainSize: true,
|
||||
maintainAnimation: true,
|
||||
maintainState: true,
|
||||
);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: 16, right: 16, bottom: 24),
|
||||
child: VeggieHeadline(veggies[i - 1]),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final model = Provider.of<AppState>(context);
|
||||
|
||||
return CupertinoTabView(
|
||||
builder: (context) {
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: Stack(
|
||||
children: [
|
||||
_buildSearchResults(model.searchVeggies(terms)),
|
||||
_createSearchBox(),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
// Copyright 2018 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:veggieseasons/data/preferences.dart';
|
||||
import 'package:veggieseasons/data/veggie.dart';
|
||||
import 'package:veggieseasons/styles.dart';
|
||||
import 'package:veggieseasons/widgets/settings_group.dart';
|
||||
import 'package:veggieseasons/widgets/settings_item.dart';
|
||||
|
||||
class VeggieCategorySettingsScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final model = Provider.of<Preferences>(context);
|
||||
final currentPrefs = model.preferredCategories;
|
||||
var brightness = CupertinoTheme.brightnessOf(context);
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: Text('Preferred Categories'),
|
||||
previousPageTitle: 'Settings',
|
||||
),
|
||||
backgroundColor: Styles.scaffoldBackground(brightness),
|
||||
child: FutureBuilder<Set<VeggieCategory>>(
|
||||
future: currentPrefs,
|
||||
builder: (context, snapshot) {
|
||||
final items = <SettingsItem>[];
|
||||
|
||||
for (final category in VeggieCategory.values) {
|
||||
CupertinoSwitch toggle;
|
||||
|
||||
// It's possible that category data hasn't loaded from shared prefs
|
||||
// yet, so display it if possible and fall back to disabled switches
|
||||
// otherwise.
|
||||
if (snapshot.hasData) {
|
||||
toggle = CupertinoSwitch(
|
||||
value: snapshot.data.contains(category),
|
||||
onChanged: (value) {
|
||||
if (value) {
|
||||
model.addPreferredCategory(category);
|
||||
} else {
|
||||
model.removePreferredCategory(category);
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
toggle = CupertinoSwitch(
|
||||
value: false,
|
||||
onChanged: null,
|
||||
);
|
||||
}
|
||||
|
||||
items.add(SettingsItem(
|
||||
label: veggieCategoryNames[category],
|
||||
content: toggle,
|
||||
));
|
||||
}
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
SettingsGroup(
|
||||
items: items,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CalorieSettingsScreen extends StatelessWidget {
|
||||
static const max = 1000;
|
||||
static const min = 2600;
|
||||
static const step = 200;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final model = Provider.of<Preferences>(context);
|
||||
var brightness = CupertinoTheme.brightnessOf(context);
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
previousPageTitle: 'Settings',
|
||||
),
|
||||
backgroundColor: Styles.scaffoldBackground(brightness),
|
||||
child: ListView(
|
||||
children: [
|
||||
FutureBuilder<int>(
|
||||
future: model.desiredCalories,
|
||||
builder: (context, snapshot) {
|
||||
final steps = <SettingsItem>[];
|
||||
|
||||
for (var cals = max; cals < min; cals += step) {
|
||||
steps.add(
|
||||
SettingsItem(
|
||||
label: cals.toString(),
|
||||
icon: SettingsIcon(
|
||||
icon: Styles.checkIcon,
|
||||
foregroundColor: snapshot.hasData && snapshot.data == cals
|
||||
? CupertinoColors.activeBlue
|
||||
: Styles.transparentColor,
|
||||
backgroundColor: Styles.transparentColor,
|
||||
),
|
||||
onPress: snapshot.hasData
|
||||
? () => model.setDesiredCalories(cals)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return SettingsGroup(
|
||||
items: steps,
|
||||
header: SettingsGroupHeader('Available calorie levels'),
|
||||
footer: SettingsGroupFooter('These are used for serving '
|
||||
'calculations'),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsScreen extends StatelessWidget {
|
||||
SettingsItem _buildCaloriesItem(BuildContext context, Preferences prefs) {
|
||||
return SettingsItem(
|
||||
label: 'Calorie Target',
|
||||
icon: SettingsIcon(
|
||||
backgroundColor: Styles.iconBlue,
|
||||
icon: Styles.calorieIcon,
|
||||
),
|
||||
content: FutureBuilder<int>(
|
||||
future: prefs.desiredCalories,
|
||||
builder: (context, snapshot) {
|
||||
return Row(
|
||||
children: [
|
||||
Text(
|
||||
snapshot.data?.toString() ?? '',
|
||||
style: CupertinoTheme.of(context).textTheme.textStyle,
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
SettingsNavigationIndicator(),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
onPress: () {
|
||||
Navigator.of(context).push<void>(
|
||||
CupertinoPageRoute(
|
||||
builder: (context) => CalorieSettingsScreen(),
|
||||
title: 'Calorie Target',
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
SettingsItem _buildCategoriesItem(BuildContext context, Preferences prefs) {
|
||||
return SettingsItem(
|
||||
label: 'Preferred Categories',
|
||||
subtitle: 'What types of veggies you prefer!',
|
||||
icon: SettingsIcon(
|
||||
backgroundColor: Styles.iconGold,
|
||||
icon: Styles.preferenceIcon,
|
||||
),
|
||||
content: SettingsNavigationIndicator(),
|
||||
onPress: () {
|
||||
Navigator.of(context).push<void>(
|
||||
CupertinoPageRoute(
|
||||
builder: (context) => VeggieCategorySettingsScreen(),
|
||||
title: 'Preferred Categories',
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final prefs = Provider.of<Preferences>(context);
|
||||
|
||||
return CupertinoPageScaffold(
|
||||
child: Container(
|
||||
color: Styles.scaffoldBackground(CupertinoTheme.brightnessOf(context)),
|
||||
child: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
CupertinoSliverNavigationBar(
|
||||
largeTitle: Text('Settings'),
|
||||
),
|
||||
SliverSafeArea(
|
||||
top: false,
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildListDelegate(
|
||||
<Widget>[
|
||||
SettingsGroup(
|
||||
items: [
|
||||
_buildCaloriesItem(context, prefs),
|
||||
_buildCategoriesItem(context, prefs),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user