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

@@ -67,26 +67,24 @@ class ActivitiesViewModel extends ChangeNotifier {
switch (resultActivities) {
case Ok():
{
_daytimeActivities =
resultActivities.value
.where(
(activity) => [
TimeOfDay.any,
TimeOfDay.morning,
TimeOfDay.afternoon,
].contains(activity.timeOfDay),
)
.toList();
_daytimeActivities = resultActivities.value
.where(
(activity) => [
TimeOfDay.any,
TimeOfDay.morning,
TimeOfDay.afternoon,
].contains(activity.timeOfDay),
)
.toList();
_eveningActivities =
resultActivities.value
.where(
(activity) => [
TimeOfDay.evening,
TimeOfDay.night,
].contains(activity.timeOfDay),
)
.toList();
_eveningActivities = resultActivities.value
.where(
(activity) => [
TimeOfDay.evening,
TimeOfDay.night,
].contains(activity.timeOfDay),
)
.toList();
_log.fine(
'Activities (daytime: ${_daytimeActivities.length}, '

View File

@@ -71,10 +71,9 @@ class _ActivitiesScreenState extends State<ActivitiesScreen> {
Expanded(
child: Center(
child: ErrorIndicator(
title:
AppLocalization.of(
context,
).errorWhileLoadingActivities,
title: AppLocalization.of(
context,
).errorWhileLoadingActivities,
label: AppLocalization.of(context).tryAgain,
onPressed: widget.viewModel.loadActivities.execute,
),
@@ -171,10 +170,9 @@ class _BottomArea extends StatelessWidget {
),
FilledButton(
key: const Key(confirmButtonKey),
onPressed:
viewModel.selectedActivities.isNotEmpty
? viewModel.saveActivities.execute
: null,
onPressed: viewModel.selectedActivities.isNotEmpty
? viewModel.saveActivities.execute
: null,
child: Text(AppLocalization.of(context).confirm),
),
],

View File

@@ -101,11 +101,10 @@ class _LoginScreenState extends State<LoginScreen> {
content: Text(AppLocalization.of(context).errorWhileLogin),
action: SnackBarAction(
label: AppLocalization.of(context).tryAgain,
onPressed:
() => widget.viewModel.login.execute((
_email.value.text,
_password.value.text,
)),
onPressed: () => widget.viewModel.login.execute((
_email.value.text,
_password.value.text,
)),
),
),
);

View File

@@ -50,8 +50,8 @@ class BookingViewModel extends ChangeNotifier {
Future<Result<void>> _createBooking() async {
_log.fine('Loading booking');
final itineraryConfig =
await _itineraryConfigRepository.getItineraryConfig();
final itineraryConfig = await _itineraryConfigRepository
.getItineraryConfig();
switch (itineraryConfig) {
case Ok<ItineraryConfig>():
_log.fine('Loaded stored ItineraryConfig');

View File

@@ -90,18 +90,17 @@ class _Tags extends StatelessWidget {
child: Wrap(
spacing: 6,
runSpacing: 6,
children:
booking.destination.tags
.map(
(tag) => TagChip(
tag: tag,
fontSize: 16,
height: 32,
chipColor: chipColor,
onChipColor: Theme.of(context).colorScheme.onSurface,
),
)
.toList(),
children: booking.destination.tags
.map(
(tag) => TagChip(
tag: tag,
fontSize: 16,
height: 32,
chipColor: chipColor,
onChipColor: Theme.of(context).colorScheme.onSurface,
),
)
.toList(),
),
);
}

View File

@@ -44,18 +44,16 @@ class _BookingScreenState extends State<BookingScreen> {
child: Scaffold(
floatingActionButton: ListenableBuilder(
listenable: widget.viewModel,
builder:
(context, _) => FloatingActionButton.extended(
// Workaround for https://github.com/flutter/flutter/issues/115358#issuecomment-2117157419
heroTag: null,
key: const ValueKey('share-button'),
onPressed:
widget.viewModel.booking != null
? widget.viewModel.shareBooking.execute
: null,
label: Text(AppLocalization.of(context).shareTrip),
icon: const Icon(Icons.share_outlined),
),
builder: (context, _) => FloatingActionButton.extended(
// Workaround for https://github.com/flutter/flutter/issues/115358#issuecomment-2117157419
heroTag: null,
key: const ValueKey('share-button'),
onPressed: widget.viewModel.booking != null
? widget.viewModel.shareBooking.execute
: null,
label: Text(AppLocalization.of(context).shareTrip),
icon: const Icon(Icons.share_outlined),
),
),
body: ListenableBuilder(
// Listen to changes in both commands

View File

@@ -35,12 +35,11 @@ abstract final class Dimens {
static const Dimens mobile = _DimensMobile();
/// Get dimensions definition based on screen size
factory Dimens.of(BuildContext context) => switch (MediaQuery.sizeOf(
context,
).width) {
> 600 && < 840 => desktop,
_ => mobile,
};
factory Dimens.of(BuildContext context) =>
switch (MediaQuery.sizeOf(context).width) {
> 600 && < 840 => desktop,
_ => mobile,
};
}
/// Mobile dimensions

View File

@@ -28,10 +28,9 @@ class CustomCheckbox extends StatelessWidget {
),
child: Material(
borderRadius: BorderRadius.circular(24),
color:
value
? Theme.of(context).colorScheme.primary
: Colors.transparent,
color: value
? Theme.of(context).colorScheme.primary
: Colors.transparent,
child: SizedBox(
width: 24,
height: 24,

View File

@@ -93,31 +93,29 @@ class _HomeScreenState extends State<HomeScreen> {
),
SliverList.builder(
itemCount: widget.viewModel.bookings.length,
itemBuilder:
(_, index) => _Booking(
key: ValueKey(widget.viewModel.bookings[index].id),
booking: widget.viewModel.bookings[index],
onTap:
() => context.push(
Routes.bookingWithId(
widget.viewModel.bookings[index].id,
),
),
confirmDismiss: (_) async {
// wait for command to complete
await widget.viewModel.deleteBooking.execute(
widget.viewModel.bookings[index].id,
);
// if command completed successfully, return true
if (widget.viewModel.deleteBooking.completed) {
// removes the dismissable from the list
return true;
} else {
// the dismissable stays in the list
return false;
}
},
itemBuilder: (_, index) => _Booking(
key: ValueKey(widget.viewModel.bookings[index].id),
booking: widget.viewModel.bookings[index],
onTap: () => context.push(
Routes.bookingWithId(
widget.viewModel.bookings[index].id,
),
),
confirmDismiss: (_) async {
// wait for command to complete
await widget.viewModel.deleteBooking.execute(
widget.viewModel.bookings[index].id,
);
// if command completed successfully, return true
if (widget.viewModel.deleteBooking.completed) {
// removes the dismissable from the list
return true;
} else {
// the dismissable stays in the list
return false;
}
},
),
),
],
);

View File

@@ -61,12 +61,11 @@ class _Title extends StatelessWidget {
Widget build(BuildContext context) {
return ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback:
(bounds) => RadialGradient(
center: Alignment.bottomLeft,
radius: 2,
colors: [Colors.purple.shade700, Colors.purple.shade400],
).createShader(Rect.fromLTWH(0, 0, bounds.width, bounds.height)),
shaderCallback: (bounds) => RadialGradient(
center: Alignment.bottomLeft,
radius: 2,
colors: [Colors.purple.shade700, Colors.purple.shade400],
).createShader(Rect.fromLTWH(0, 0, bounds.width, bounds.height)),
child: Text(
text,
style: GoogleFonts.rubik(

View File

@@ -67,13 +67,12 @@ class ResultsViewModel extends ChangeNotifier {
case Ok():
{
// If the result is Ok, update the list of destinations
_destinations =
result.value
.where(
(destination) =>
destination.continent == _itineraryConfig!.continent,
)
.toList();
_destinations = result.value
.where(
(destination) =>
destination.continent == _itineraryConfig!.continent,
)
.toList();
_log.fine('Destinations (${_destinations.length}) loaded');
}
case Error():

View File

@@ -42,8 +42,9 @@ class ResultCard extends StatelessWidget {
spacing: 4.0,
runSpacing: 4.0,
direction: Axis.horizontal,
children:
destination.tags.map((e) => TagChip(tag: e)).toList(),
children: destination.tags
.map((e) => TagChip(tag: e))
.toList(),
),
],
),

View File

@@ -67,10 +67,9 @@ class _ResultsScreenState extends State<ResultsScreen> {
Expanded(
child: Center(
child: ErrorIndicator(
title:
AppLocalization.of(
context,
).errorWhileLoadingDestinations,
title: AppLocalization.of(
context,
).errorWhileLoadingDestinations,
label: AppLocalization.of(context).tryAgain,
onPressed: widget.viewModel.search.execute,
),

View File

@@ -75,14 +75,12 @@ class _QuantitySelector extends StatelessWidget {
),
ListenableBuilder(
listenable: viewModel,
builder:
(context, _) => Text(
viewModel.guests.toString(),
style:
viewModel.guests == 0
? Theme.of(context).inputDecorationTheme.hintStyle
: Theme.of(context).textTheme.bodyMedium,
),
builder: (context, _) => Text(
viewModel.guests.toString(),
style: viewModel.guests == 0
? Theme.of(context).inputDecorationTheme.hintStyle
: Theme.of(context).textTheme.bodyMedium,
),
),
InkWell(
key: const ValueKey(addGuestsKey),

View File

@@ -65,10 +65,9 @@ class _SearchFormSubmitState extends State<SearchFormSubmit> {
builder: (context, child) {
return FilledButton(
key: const ValueKey(searchFormSubmitButtonKey),
onPressed:
widget.viewModel.valid
? widget.viewModel.updateItineraryConfig.execute
: null,
onPressed: widget.viewModel.valid
? widget.viewModel.updateItineraryConfig.execute
: null,
child: child,
);
},