1
0
mirror of https://github.com/flutter/samples.git synced 2025-11-08 13:58:47 +00:00

Dart 3.9 / Flutter 3.35 [first LLM release] (#2714)

I got carried away with Gemini and basically rewrote CI and the release
process for the new LLM reality. This work was largely completed by
Gemini.

- Bump all SDK versions to the current beta (3.9.0-0)
- Run `flutter channel beta`
- Wrote `ci_script.dart` to replace the bash scripts
- Converted repository to pub workspace #2499 
- Added llm.md and release.md
- Added redirect for deprecated Samples Index

## Pre-launch Checklist

- [x] I read the [Flutter Style Guide] _recently_, and have followed its
advice.
- [x] I signed the [CLA].
- [x] I read the [Contributors Guide].
- [x] I have added sample code updates to the [changelog].
- [x] I updated/added relevant documentation (doc comments with `///`).
This commit is contained in:
Eric Windmill
2025-08-14 12:26:24 -07:00
committed by GitHub
parent 0aa5415d5e
commit 2999d738b8
410 changed files with 28166 additions and 27661 deletions

View File

@@ -15,7 +15,9 @@ class AppState extends ChangeNotifier {
List<Veggie> get availableVeggies {
var currentSeason = _getSeasonForDate(DateTime.now());
return _veggies.where((v) => v.seasons.contains(currentSeason)).toList();
return _veggies
.where((v) => v.seasons.contains(currentSeason))
.toList();
}
List<Veggie> get favoriteVeggies =>
@@ -23,15 +25,16 @@ class AppState extends ChangeNotifier {
List<Veggie> get unavailableVeggies {
var currentSeason = _getSeasonForDate(DateTime.now());
return _veggies.where((v) => !v.seasons.contains(currentSeason)).toList();
return _veggies
.where((v) => !v.seasons.contains(currentSeason))
.toList();
}
Veggie getVeggie(int? id) => _veggies.singleWhere((v) => v.id == id);
List<Veggie> searchVeggies(String? terms) =>
_veggies
.where((v) => v.name.toLowerCase().contains(terms!.toLowerCase()))
.toList();
List<Veggie> searchVeggies(String? terms) => _veggies
.where((v) => v.name.toLowerCase().contains(terms!.toLowerCase()))
.toList();
void setFavorite(int? id, bool isFavorite) {
var veggie = getVeggie(id);
@@ -75,7 +78,9 @@ class AppState extends ChangeNotifier {
case 12:
return date.day < 22 ? Season.autumn : Season.winter;
default:
throw ArgumentError('Can\'t return a season for month #${date.month}.');
throw ArgumentError(
'Can\'t return a season for month #${date.month}.',
);
}
}
}

View File

@@ -12,9 +12,15 @@ class LocalVeggieProvider {
name: 'Apples',
imageAssetPath: 'assets/images/apple.jpg',
category: VeggieCategory.fruit,
shortDescription: 'Green or red, they\'re generally round and tasty.',
shortDescription:
'Green or red, they\'re generally round and tasty.',
accentColor: const Color(0x40de8c66),
seasons: [Season.winter, Season.spring, Season.summer, Season.autumn],
seasons: [
Season.winter,
Season.spring,
Season.summer,
Season.autumn,
],
vitaminAPercentage: 2,
vitaminCPercentage: 8,
servingSize: 'One large apple',
@@ -75,16 +81,24 @@ class LocalVeggieProvider {
'Root',
'Seed',
], 0),
Trivia('"Jerusalem artichoke" is another term for which vegetable?', [
'Potato',
'Cabbage',
'Sunchoke',
], 2),
Trivia('Which city claims to be The Artichoke Capital of the World?', [
'Castroville, California',
'Galveston, Texas',
'London, England',
], 0),
Trivia(
'"Jerusalem artichoke" is another term for which vegetable?',
[
'Potato',
'Cabbage',
'Sunchoke',
],
2,
),
Trivia(
'Which city claims to be The Artichoke Capital of the World?',
[
'Castroville, California',
'Galveston, Texas',
'London, England',
],
0,
),
Trivia('Artichokes are technically which type of plant?', [
'Thistle',
'Azalea',
@@ -97,7 +111,8 @@ class LocalVeggieProvider {
name: 'Asparagus',
imageAssetPath: 'assets/images/asparagus.jpg',
category: VeggieCategory.fern,
shortDescription: 'It\'s been used a food and medicine for millenia.',
shortDescription:
'It\'s been used a food and medicine for millenia.',
accentColor: const Color(0x408cb437),
seasons: [Season.spring],
vitaminAPercentage: 10,
@@ -132,7 +147,8 @@ class LocalVeggieProvider {
name: 'Avocado',
imageAssetPath: 'assets/images/avocado.jpg',
category: VeggieCategory.stealthFruit,
shortDescription: 'One of the oiliest, richest fruits money can buy.',
shortDescription:
'One of the oiliest, richest fruits money can buy.',
accentColor: const Color(0x40b0ba59),
seasons: [Season.winter, Season.spring, Season.summer],
vitaminAPercentage: 0,
@@ -167,7 +183,8 @@ class LocalVeggieProvider {
name: 'Blackberries',
imageAssetPath: 'assets/images/blackberry.jpg',
category: VeggieCategory.berry,
shortDescription: 'Find them on backroads and fences in the Northwest.',
shortDescription:
'Find them on backroads and fences in the Northwest.',
accentColor: const Color(0x409d5adb),
seasons: [Season.summer],
vitaminAPercentage: 6,
@@ -255,11 +272,15 @@ class LocalVeggieProvider {
['Mustard greens', 'Apples', 'Potatoes'],
0,
),
Trivia('Cauliflower\'s green spiral-shaped cousin is known as what?', [
'Romesco',
'Brittany cabbage',
'Muscle sprouts',
], 0),
Trivia(
'Cauliflower\'s green spiral-shaped cousin is known as what?',
[
'Romesco',
'Brittany cabbage',
'Muscle sprouts',
],
0,
),
Trivia('Green cauliflower is sometimes called what?', [
'Broccoflower',
'Avocadoflower',
@@ -290,11 +311,15 @@ class LocalVeggieProvider {
'By rhizome',
'By packing up and moving to Des Moines',
], 0),
Trivia('Some farmers cover their endive with shade to reduce what?', [
'Size',
'Toughness',
'Bitterness',
], 2),
Trivia(
'Some farmers cover their endive with shade to reduce what?',
[
'Size',
'Toughness',
'Bitterness',
],
2,
),
],
),
Veggie(
@@ -385,11 +410,15 @@ class LocalVeggieProvider {
'They\'re grown in the shade',
'They\'re a distinct species',
], 0),
Trivia('How quickly can a green pepper grow from seed to harvest?', [
'10 weeks',
'20 weeks',
'30 weeks',
], 0),
Trivia(
'How quickly can a green pepper grow from seed to harvest?',
[
'10 weeks',
'20 weeks',
'30 weeks',
],
0,
),
],
),
Veggie(
@@ -427,7 +456,8 @@ class LocalVeggieProvider {
name: 'Kale',
imageAssetPath: 'assets/images/kale.jpg',
category: VeggieCategory.cruciferous,
shortDescription: 'The meanest vegetable. Does not want to be eaten.',
shortDescription:
'The meanest vegetable. Does not want to be eaten.',
accentColor: const Color(0x40a86bd8),
seasons: [Season.winter, Season.autumn],
vitaminAPercentage: 133,
@@ -440,11 +470,15 @@ class LocalVeggieProvider {
'The first frost',
'Reading it a sad story',
], 1),
Trivia('Which of these isn\'t a color in which Kale can be found?', [
'Purple',
'White',
'Orange',
], 2),
Trivia(
'Which of these isn\'t a color in which Kale can be found?',
[
'Purple',
'White',
'Orange',
],
2,
),
Trivia(
'One serving of kale provides what percentage of a typical person\'s requirement for vitamin K?',
['100%', '300%', '900%'],
@@ -522,7 +556,8 @@ class LocalVeggieProvider {
name: 'Limes',
imageAssetPath: 'assets/images/lime.jpg',
category: VeggieCategory.citrus,
shortDescription: 'Couldn\'t have ceviche and margaritas without them.',
shortDescription:
'Couldn\'t have ceviche and margaritas without them.',
accentColor: const Color(0x4089b733),
seasons: [Season.winter],
vitaminAPercentage: 0,
@@ -552,7 +587,8 @@ class LocalVeggieProvider {
name: 'Mangos',
imageAssetPath: 'assets/images/mango.jpg',
category: VeggieCategory.tropical,
shortDescription: 'A fun orange fruit popular with smoothie enthusiasts.',
shortDescription:
'A fun orange fruit popular with smoothie enthusiasts.',
accentColor: const Color(0x40fcc93c),
seasons: [Season.summer, Season.autumn],
vitaminAPercentage: 72,
@@ -629,21 +665,29 @@ class LocalVeggieProvider {
servingSize: '1 medium nectarine',
caloriesPerServing: 60,
trivia: const [
Trivia('Nectarines are technically a variety of which other fruit?', [
'Peach',
'Plum',
'Cherry',
], 0),
Trivia(
'Nectarines are technically a variety of which other fruit?',
[
'Peach',
'Plum',
'Cherry',
],
0,
),
Trivia('Nectarines are sometimes called what?', [
'Neckless geese',
'Giant grapes',
'Shaved peaches',
], 2),
Trivia('Nectarines are thought to have originated in which country?', [
'China',
'Italy',
'Ethiopia',
], 0),
Trivia(
'Nectarines are thought to have originated in which country?',
[
'China',
'Italy',
'Ethiopia',
],
0,
),
],
),
Veggie(
@@ -651,7 +695,8 @@ class LocalVeggieProvider {
name: 'Persimmons',
imageAssetPath: 'assets/images/persimmon.jpg',
category: VeggieCategory.fruit,
shortDescription: 'It\'s like a plum and an apple had a baby together.',
shortDescription:
'It\'s like a plum and an apple had a baby together.',
accentColor: const Color(0x40979852),
seasons: [Season.winter, Season.autumn],
vitaminAPercentage: 0,
@@ -719,11 +764,15 @@ class LocalVeggieProvider {
servingSize: '1 medium spud',
caloriesPerServing: 110,
trivia: const [
Trivia('Which country consumes the most fried potatoes per capita?', [
'United States',
'Belgium',
'Ireland',
], 1),
Trivia(
'Which country consumes the most fried potatoes per capita?',
[
'United States',
'Belgium',
'Ireland',
],
1,
),
Trivia(
'Who is credited with introducing French Fries to the United States?',
['Thomas Jefferson', 'Betsy Ross', 'Alexander Hamilton'],
@@ -741,7 +790,8 @@ class LocalVeggieProvider {
name: 'Radicchio',
imageAssetPath: 'assets/images/radicchio.jpg',
category: VeggieCategory.leafy,
shortDescription: 'It\'s that bitter taste in the salad you\'re eating.',
shortDescription:
'It\'s that bitter taste in the salad you\'re eating.',
accentColor: const Color(0x40d75875),
seasons: [Season.spring, Season.autumn],
vitaminAPercentage: 0,
@@ -749,11 +799,15 @@ class LocalVeggieProvider {
servingSize: '2 cups shredded',
caloriesPerServing: 20,
trivia: const [
Trivia('Radicchio is a particuarly good source of which mineral?', [
'Manganese',
'Mercury',
'Molybdenum',
], 0),
Trivia(
'Radicchio is a particuarly good source of which mineral?',
[
'Manganese',
'Mercury',
'Molybdenum',
],
0,
),
Trivia('Radicchio should be stored at what temperature?', [
'Room temperature',
'Refrigerator temperature',
@@ -775,7 +829,8 @@ class LocalVeggieProvider {
name: 'Radishes',
imageAssetPath: 'assets/images/radish.jpg',
category: VeggieCategory.root,
shortDescription: 'Try roasting them in addition to slicing them up raw.',
shortDescription:
'Try roasting them in addition to slicing them up raw.',
accentColor: const Color(0x40819e4e),
seasons: [Season.spring, Season.autumn],
vitaminAPercentage: 0,
@@ -783,11 +838,15 @@ class LocalVeggieProvider {
servingSize: '7 radishes',
caloriesPerServing: 10,
trivia: const [
Trivia('Which ancient civilization is known to have used radish oil?', [
'Egyptian',
'Sumerian',
'Incan',
], 0),
Trivia(
'Which ancient civilization is known to have used radish oil?',
[
'Egyptian',
'Sumerian',
'Incan',
],
0,
),
Trivia(
'What\'s the name of the radish commonly used in Japanese cuisine?',
['Daisuki', 'Daijin', 'Daikon'],
@@ -805,7 +864,8 @@ class LocalVeggieProvider {
name: 'Squash',
imageAssetPath: 'assets/images/squash.jpg',
category: VeggieCategory.gourd,
shortDescription: 'Just slather them in butter and pop \'em in the oven.',
shortDescription:
'Just slather them in butter and pop \'em in the oven.',
accentColor: const Color(0x40dbb721),
seasons: [Season.winter, Season.autumn],
vitaminAPercentage: 297,
@@ -823,11 +883,15 @@ class LocalVeggieProvider {
'Furniture',
'Musical instruments',
], 0),
Trivia('Which country is the world\'s largest importer of squashes?', [
'China',
'United States',
'Russia',
], 1),
Trivia(
'Which country is the world\'s largest importer of squashes?',
[
'China',
'United States',
'Russia',
],
1,
),
],
),
Veggie(
@@ -849,11 +913,15 @@ class LocalVeggieProvider {
'100',
'200',
], 2),
Trivia('Strawberries are closely related to which type of flower?', [
'The rose',
'The daisy',
'The tulip',
], 0),
Trivia(
'Strawberries are closely related to which type of flower?',
[
'The rose',
'The daisy',
'The tulip',
],
0,
),
Trivia('Strawberries are unique among fruit for what reason?', [
'Their seeds are on the outside',
'Their flowers are striped',
@@ -866,7 +934,8 @@ class LocalVeggieProvider {
name: 'Tangelo',
imageAssetPath: 'assets/images/tangelo.jpg',
category: VeggieCategory.citrus,
shortDescription: 'No one\'s sure what they are or where they came from.',
shortDescription:
'No one\'s sure what they are or where they came from.',
accentColor: const Color(0x40f88c06),
seasons: [Season.winter, Season.autumn],
vitaminAPercentage: 6,
@@ -904,21 +973,29 @@ class LocalVeggieProvider {
servingSize: '1 medium tomato',
caloriesPerServing: 25,
trivia: const [
Trivia('French speakers sometimes refer to tomatoes with which name?', [
'Piet de terre',
'Mille-feuille',
'Pomme d\'amour',
], 2),
Trivia(
'French speakers sometimes refer to tomatoes with which name?',
[
'Piet de terre',
'Mille-feuille',
'Pomme d\'amour',
],
2,
),
Trivia(
'The largest tomato known to have been grown weighed in at how many pounds?',
['8', '10', '12'],
0,
),
Trivia('Which country is the world\'s largest producer of tomatoes?', [
'China',
'Italy',
'Ecuador',
], 0),
Trivia(
'Which country is the world\'s largest producer of tomatoes?',
[
'China',
'Italy',
'Ecuador',
],
0,
),
],
),
Veggie(
@@ -934,7 +1011,11 @@ class LocalVeggieProvider {
servingSize: '2 cups diced',
caloriesPerServing: 80,
trivia: const [
Trivia('How much of a watermelon is water?', ['50%', '75%', '90%'], 2),
Trivia('How much of a watermelon is water?', [
'50%',
'75%',
'90%',
], 2),
Trivia(
'Which nation is famous for growing watermelons in unsual shapes like cubes and hearts?',
['Armenia', 'Japan', 'Saudi Arabia'],
@@ -977,7 +1058,11 @@ class LocalVeggieProvider {
),
Trivia(
'Who is generally credited with giving bell peppers their peppery name?',
['Christopher Columbus', 'Benjamin Franklin', 'Eleanor Roosevelt'],
[
'Christopher Columbus',
'Benjamin Franklin',
'Eleanor Roosevelt',
],
0,
),
],

View File

@@ -6,7 +6,8 @@ import 'dart:io' show Platform;
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/services.dart' show DeviceOrientation, SystemChrome;
import 'package:flutter/services.dart'
show DeviceOrientation, SystemChrome;
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:window_size/window_size.dart';
@@ -30,14 +31,17 @@ void main() {
]);
setupWindow();
runApp(const RootRestorationScope(restorationId: 'root', child: VeggieApp()));
runApp(
const RootRestorationScope(restorationId: 'root', child: VeggieApp()),
);
}
const double windowWidth = 480;
const double windowHeight = 854;
void setupWindow() {
if (!kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS)) {
if (!kIsWeb &&
(Platform.isWindows || Platform.isLinux || Platform.isMacOS)) {
setWindowTitle('Veggie Seasons');
setWindowMinSize(const Size(windowWidth, windowHeight));
setWindowMaxSize(const Size(windowWidth, windowHeight));
@@ -143,7 +147,9 @@ class _VeggieAppState extends State<VeggieApp> with RestorationMixin {
return VeggieSeasonsPage(
key: state.pageKey,
restorationId: 'route.favorites',
child: const FavoritesScreen(restorationId: 'favorites'),
child: const FavoritesScreen(
restorationId: 'favorites',
),
);
},
routes: [_buildDetailsRoute()],
@@ -165,7 +171,9 @@ class _VeggieAppState extends State<VeggieApp> with RestorationMixin {
return VeggieSeasonsPage(
key: state.pageKey,
restorationId: 'route.settings',
child: const SettingsScreen(restorationId: 'settings'),
child: const SettingsScreen(
restorationId: 'settings',
),
);
},
routes: [

View File

@@ -21,7 +21,10 @@ class ServingInfoChart extends StatelessWidget {
// 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) {
Widget _buildVitaminText(
int standardPercentage,
Future<int> targetCalories,
) {
return FutureBuilder<int>(
future: targetCalories,
builder: (context, snapshot) {
@@ -62,7 +65,10 @@ class ServingInfoChart extends StatelessWidget {
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text('Calories', style: Styles.detailsServingLabelText(themeData)),
Text(
'Calories',
style: Styles.detailsServingLabelText(themeData),
),
const Spacer(),
Text(
'${veggie.caloriesPerServing} kCal',
@@ -75,18 +81,30 @@ class ServingInfoChart extends StatelessWidget {
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text('Vitamin A', style: Styles.detailsServingLabelText(themeData)),
Text(
'Vitamin A',
style: Styles.detailsServingLabelText(themeData),
),
const Spacer(),
_buildVitaminText(veggie.vitaminAPercentage, prefs.desiredCalories),
_buildVitaminText(
veggie.vitaminAPercentage,
prefs.desiredCalories,
),
],
),
const SizedBox(height: 24),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text('Vitamin C', style: Styles.detailsServingLabelText(themeData)),
Text(
'Vitamin C',
style: Styles.detailsServingLabelText(themeData),
),
const Spacer(),
_buildVitaminText(veggie.vitaminCPercentage, prefs.desiredCalories),
_buildVitaminText(
veggie.vitaminCPercentage,
prefs.desiredCalories,
),
],
),
Padding(
@@ -131,7 +149,10 @@ class InfoView extends StatelessWidget {
style: CupertinoTheme.of(context).textTheme.textStyle,
),
const SizedBox(height: 16),
Text('Seasons', style: Styles.detailsServingLabelText(themeData)),
Text(
'Seasons',
style: Styles.detailsServingLabelText(themeData),
),
const SizedBox(height: 12),
Row(
mainAxisSize: MainAxisSize.max,
@@ -143,10 +164,9 @@ class InfoView extends StatelessWidget {
children: [
Icon(
Styles.seasonIconData[season],
color:
veggie.seasons.contains(season)
? Styles.seasonColors[season]
: const Color.fromRGBO(128, 128, 128, 1),
color: veggie.seasons.contains(season)
? Styles.seasonColors[season]
: const Color.fromRGBO(128, 128, 128, 1),
size: 24,
),
const SizedBox(height: 4),

View File

@@ -25,26 +25,32 @@ class FavoritesScreen extends StatelessWidget {
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: CupertinoTheme.of(context).textTheme.textStyle,
),
)
: ListView(
restorationId: 'list',
children: [
const SizedBox(height: 24),
for (Veggie veggie in model.favoriteVeggies)
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 24),
child: VeggieHeadline(veggie),
),
],
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: CupertinoTheme.of(
context,
).textTheme.textStyle,
),
)
: ListView(
restorationId: 'list',
children: [
const SizedBox(height: 24),
for (Veggie veggie in model.favoriteVeggies)
Padding(
padding: const EdgeInsets.fromLTRB(
16,
0,
16,
24,
),
child: VeggieHeadline(veggie),
),
],
),
),
);
},

View File

@@ -21,7 +21,10 @@ class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final index = _getSelectedIndex(GoRouter.of(context).location);
final String location = GoRouter.of(
context,
).routerDelegate.currentConfiguration.uri.toString();
final index = _getSelectedIndex(location);
return RestorationScope(
restorationId: restorationId,
child: CupertinoPageScaffold(

View File

@@ -27,7 +27,11 @@ class ListScreen extends StatelessWidget {
future: prefs.preferredCategories,
builder: (context, snapshot) {
final data = snapshot.data ?? <VeggieCategory>{};
return VeggieCard(veggie, inSeason, data.contains(veggie.category));
return VeggieCard(
veggie,
inSeason,
data.contains(veggie.category),
);
},
),
);

View File

@@ -18,7 +18,8 @@ class SearchScreen extends StatefulWidget {
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> with RestorationMixin {
class _SearchScreenState extends State<SearchScreen>
with RestorationMixin {
final controller = RestorableTextEditingController();
final focusNode = FocusNode();
String? terms;
@@ -87,7 +88,11 @@ class _SearchScreenState extends State<SearchScreen> with RestorationMixin {
);
} else {
return Padding(
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 24),
padding: const EdgeInsets.only(
left: 16,
right: 16,
bottom: 24,
),
child: VeggieHeadline(veggies[i - 1]),
);
}
@@ -106,7 +111,9 @@ class _SearchScreenState extends State<SearchScreen> with RestorationMixin {
builder: (context) {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarBrightness: MediaQuery.platformBrightnessOf(context),
statusBarBrightness: MediaQuery.platformBrightnessOf(
context,
),
),
child: SafeArea(
bottom: false,

View File

@@ -58,7 +58,10 @@ class VeggieCategorySettingsScreen extends StatelessWidget {
},
);
} else {
toggle = const CupertinoSwitch(value: false, onChanged: null);
toggle = const CupertinoSwitch(
value: false,
onChanged: null,
);
}
tiles.add(
@@ -129,14 +132,13 @@ class CalorieSettingsScreen extends StatelessWidget {
icon: CupertinoIcons.check_mark,
foregroundColor:
snapshot.hasData && snapshot.data == cals
? CupertinoColors.activeBlue
: Styles.transparentColor,
? CupertinoColors.activeBlue
: Styles.transparentColor,
backgroundColor: Styles.transparentColor,
),
onTap:
snapshot.hasData
? () => model.setDesiredCalories(cals)
: null,
onTap: snapshot.hasData
? () => model.setDesiredCalories(cals)
: null,
),
);
}
@@ -227,29 +229,28 @@ class _SettingsScreenState extends State<SettingsScreen> {
onTap: () {
showCupertinoDialog<void>(
context: context,
builder:
(context) => CupertinoAlertDialog(
title: const Text('Are you sure?'),
content: const Text(
'Are you sure you want to reset the current settings?',
),
actions: [
CupertinoDialogAction(
isDestructiveAction: true,
child: const Text('Yes'),
onPressed: () async {
await prefs.restoreDefaults();
if (!context.mounted) return;
context.pop();
},
),
CupertinoDialogAction(
isDefaultAction: true,
child: const Text('No'),
onPressed: () => context.pop(),
),
],
builder: (context) => CupertinoAlertDialog(
title: const Text('Are you sure?'),
content: const Text(
'Are you sure you want to reset the current settings?',
),
actions: [
CupertinoDialogAction(
isDestructiveAction: true,
child: const Text('Yes'),
onPressed: () async {
await prefs.restoreDefaults();
if (!context.mounted) return;
context.pop();
},
),
CupertinoDialogAction(
isDefaultAction: true,
child: const Text('No'),
onPressed: () => context.pop(),
),
],
),
);
},
);

View File

@@ -43,35 +43,39 @@ abstract class Styles {
fontWeight: FontWeight.bold,
);
static TextStyle cardCategoryText(CupertinoThemeData themeData) => themeData
.textTheme
.textStyle
.copyWith(color: const Color.fromRGBO(255, 255, 255, 0.9));
static TextStyle cardCategoryText(CupertinoThemeData themeData) =>
themeData.textTheme.textStyle.copyWith(
color: const Color.fromRGBO(255, 255, 255, 0.9),
);
static TextStyle cardDescriptionText(CupertinoThemeData themeData) =>
themeData.textTheme.textStyle.copyWith(
color: const Color.fromRGBO(0, 0, 0, 0.9),
);
static TextStyle detailsTitleText(CupertinoThemeData themeData) => themeData
.textTheme
.textStyle
.copyWith(fontSize: 30, fontWeight: FontWeight.bold);
static TextStyle detailsPreferredCategoryText(CupertinoThemeData themeData) =>
themeData.textTheme.textStyle.copyWith(fontWeight: FontWeight.bold);
static TextStyle detailsBoldDescriptionText(CupertinoThemeData themeData) =>
static TextStyle detailsTitleText(CupertinoThemeData themeData) =>
themeData.textTheme.textStyle.copyWith(
color: const Color.fromRGBO(0, 0, 0, 0.9),
fontSize: 30,
fontWeight: FontWeight.bold,
);
static TextStyle detailsServingHeaderText(CupertinoThemeData themeData) =>
themeData.textTheme.textStyle.copyWith(
color: const Color.fromRGBO(176, 176, 176, 1),
fontWeight: FontWeight.bold,
);
static TextStyle detailsPreferredCategoryText(
CupertinoThemeData themeData,
) => themeData.textTheme.textStyle.copyWith(fontWeight: FontWeight.bold);
static TextStyle detailsBoldDescriptionText(
CupertinoThemeData themeData,
) => themeData.textTheme.textStyle.copyWith(
color: const Color.fromRGBO(0, 0, 0, 0.9),
fontWeight: FontWeight.bold,
);
static TextStyle detailsServingHeaderText(
CupertinoThemeData themeData,
) => themeData.textTheme.textStyle.copyWith(
color: const Color.fromRGBO(176, 176, 176, 1),
fontWeight: FontWeight.bold,
);
static TextStyle detailsServingLabelText(CupertinoThemeData themeData) =>
themeData.textTheme.textStyle.copyWith(fontWeight: FontWeight.bold);
@@ -103,8 +107,8 @@ abstract class Styles {
static Color? scaffoldBackground(Brightness brightness) =>
brightness == Brightness.light
? CupertinoColors.extraLightBackgroundGray
: null;
? CupertinoColors.extraLightBackgroundGray
: null;
static const frostedBackground = Color(0xccf8f8f8);
@@ -112,8 +116,12 @@ abstract class Styles {
static const closeButtonPressed = Color(0xff808080);
static TextStyle settingsItemSubtitleText(CupertinoThemeData themeData) =>
themeData.textTheme.textStyle.copyWith(fontSize: 12, letterSpacing: -0.2);
static TextStyle settingsItemSubtitleText(
CupertinoThemeData themeData,
) => themeData.textTheme.textStyle.copyWith(
fontSize: 12,
letterSpacing: -0.2,
);
static const Color searchCursorColor = Color.fromRGBO(0, 122, 255, 1);
@@ -177,13 +185,13 @@ abstract class Styles {
static Color settingsItemColor(Brightness brightness) =>
brightness == Brightness.light
? CupertinoColors.tertiarySystemBackground
: CupertinoColors.darkBackgroundGray;
? CupertinoColors.tertiarySystemBackground
: CupertinoColors.darkBackgroundGray;
static Color settingsLineation(Brightness brightness) =>
brightness == Brightness.light
? const Color(0xffbcbbc1)
: const Color(0xff4c4b4b);
? const Color(0xffbcbbc1)
: const Color(0xff4c4b4b);
static const Color settingsBackground = Color(0xffefeff4);
@@ -208,6 +216,6 @@ abstract class Styles {
static const servingInfoBorderColor = Color(0xffb0b0b0);
static const ColorFilter desaturatedColorFilter =
// 222222 is a random color that has low color saturation.
ColorFilter.mode(Color(0xff222222), BlendMode.saturation);
// 222222 is a random color that has low color saturation.
ColorFilter.mode(Color(0xff222222), BlendMode.saturation);
}

View File

@@ -86,11 +86,14 @@ class ShareButton extends _DetailPageButton {
/// A favorite button that invokes a callback when pressed.
class FavoriteButton extends _DetailPageButton {
const FavoriteButton(VoidCallback onPressed, bool isFavorite, {super.key})
: super(
onPressed,
isFavorite ? CupertinoIcons.heart_fill : CupertinoIcons.heart,
);
const FavoriteButton(
VoidCallback onPressed,
bool isFavorite, {
super.key,
}) : super(
onPressed,
isFavorite ? CupertinoIcons.heart_fill : CupertinoIcons.heart,
);
}
class _DetailPageButton extends StatefulWidget {
@@ -124,15 +127,16 @@ class _DetailPageButtonState extends State<_DetailPageButton> {
child: Container(
width: 30,
height: 30,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
),
child: Center(
child: ColorChangingIcon(
widget.icon,
duration: const Duration(milliseconds: 300),
color:
tapInProgress
? Styles.closeButtonPressed
: Styles.closeButtonUnpressed,
color: tapInProgress
? Styles.closeButtonPressed
: Styles.closeButtonUnpressed,
size: 20,
),
),

View File

@@ -93,8 +93,9 @@ class VeggieCard extends StatelessWidget {
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
colorFilter:
isInSeason ? null : Styles.desaturatedColorFilter,
colorFilter: isInSeason
? null
: Styles.desaturatedColorFilter,
image: AssetImage(veggie.imageAssetPath),
),
),

View File

@@ -67,6 +67,9 @@ class VeggieHeadline extends StatelessWidget {
@override
Widget build(BuildContext context) {
final themeData = CupertinoTheme.of(context);
final String location = GoRouter.of(
context,
).routerDelegate.currentConfiguration.uri.toString();
return GestureDetector(
onTap: () {
@@ -74,7 +77,7 @@ class VeggieHeadline extends StatelessWidget {
// so navigate to the absolute route, which can be either
// `/favorites/details/${veggie.id}` or `/search/details/${veggie.id}`
// see https://github.com/flutter/flutter/issues/108177
context.go('${GoRouter.of(context).location}/details/${veggie.id}');
context.go('$location/details/${veggie.id}');
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -93,7 +96,10 @@ class VeggieHeadline extends StatelessWidget {
children: [
Row(
children: [
Text(veggie.name, style: Styles.headlineName(themeData)),
Text(
veggie.name,
style: Styles.headlineName(themeData),
),
..._buildSeasonDots(veggie.seasons),
],
),

View File

@@ -19,7 +19,8 @@ class VeggieSeasonsPage<T> extends Page<T> {
}
class VeggieSeasonsPageRoute<T> extends PageRoute<T> {
VeggieSeasonsPageRoute(VeggieSeasonsPage<T> page) : super(settings: page);
VeggieSeasonsPageRoute(VeggieSeasonsPage<T> page)
: super(settings: page);
VeggieSeasonsPage<T> get _page => settings as VeggieSeasonsPage<T>;

View File

@@ -1,16 +1,15 @@
name: veggieseasons
description: An iOS app that shows the fruits and veggies currently in season.
publish_to: none
version: 1.2.0
resolution: workspace
environment:
sdk: ^3.7.0-0
sdk: ^3.9.0-0
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
font_awesome_flutter: ^10.1.0
intl: ^0.20.0
@@ -18,11 +17,11 @@ dependencies:
shared_preferences: ^2.0.14
window_size:
git:
url: https://github.com/google/flutter-desktop-embedding
url: https://github.com/google/flutter-desktop-embedding.git
path: plugins/window_size
# TODO: https://github.com/flutter/samples/issues/1838
# go_router ^7.1.0 is breaking the state restoration tests
go_router: 7.0.2
go_router: ^16.0.0
dev_dependencies:
analysis_defaults: