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

@@ -21,7 +21,8 @@ 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)) {
WidgetsFlutterBinding.ensureInitialized();
setWindowTitle('Animation Samples');
setWindowMinSize(const Size(windowWidth, windowHeight));
@@ -43,7 +44,11 @@ class Demo {
final String route;
final WidgetBuilder builder;
const Demo({required this.name, required this.route, required this.builder});
const Demo({
required this.name,
required this.route,
required this.builder,
});
}
final basicDemos = [

View File

@@ -49,7 +49,9 @@ class _AnimatedBuilderDemoState extends State<AnimatedBuilderDemo>
animation: animation,
builder: (context, child) {
return ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: animation.value),
style: ElevatedButton.styleFrom(
backgroundColor: animation.value,
),
child: child,
onPressed: () {
switch (controller.status) {

View File

@@ -49,18 +49,21 @@ class _FadeTransitionDemoState extends State<FadeTransitionDemo>
children: [
FadeTransition(
opacity: _animation,
child: const Icon(Icons.star, color: Colors.amber, size: 300),
child: const Icon(
Icons.star,
color: Colors.amber,
size: 300,
),
),
ElevatedButton(
child: const Text('animate'),
onPressed:
() => setState(() {
_controller
.animateTo(1.0)
.then<TickerFuture>(
(value) => _controller.animateBack(0.0),
);
}),
onPressed: () => setState(() {
_controller
.animateTo(1.0)
.then<TickerFuture>(
(value) => _controller.animateBack(0.0),
);
}),
),
],
),

View File

@@ -74,7 +74,10 @@ class _TweenSequenceDemoState extends State<TweenSequenceDemo>
child: child,
);
},
child: const Text('Animate', style: TextStyle(color: Colors.white)),
child: const Text(
'Animate',
style: TextStyle(color: Colors.white),
),
),
),
);

View File

@@ -75,7 +75,9 @@ class _AnimatedListDemoState extends State<AnimatedListDemo> {
return Scaffold(
appBar: AppBar(
title: const Text('AnimatedList'),
actions: [IconButton(icon: const Icon(Icons.add), onPressed: addUser)],
actions: [
IconButton(icon: const Icon(Icons.add), onPressed: addUser),
],
),
body: SafeArea(
child: AnimatedList(

View File

@@ -11,7 +11,8 @@ class AnimatedPositionedDemo extends StatefulWidget {
static String routeName = 'misc/animated_positioned';
@override
State<AnimatedPositionedDemo> createState() => _AnimatedPositionedDemoState();
State<AnimatedPositionedDemo> createState() =>
_AnimatedPositionedDemoState();
}
class _AnimatedPositionedDemoState extends State<AnimatedPositionedDemo> {
@@ -54,12 +55,11 @@ class _AnimatedPositionedDemoState extends State<AnimatedPositionedDemo> {
left: leftPosition,
duration: const Duration(seconds: 1),
child: InkWell(
onTap:
() => changePosition(
size.height -
(appBar.preferredSize.height + topPadding + 50),
size.width - 150,
),
onTap: () => changePosition(
size.height -
(appBar.preferredSize.height + topPadding + 50),
size.width - 150,
),
child: Container(
alignment: Alignment.center,
width: 150,
@@ -68,8 +68,9 @@ class _AnimatedPositionedDemoState extends State<AnimatedPositionedDemo> {
child: Text(
'Click Me',
style: TextStyle(
color:
Theme.of(context).buttonTheme.colorScheme!.onPrimary,
color: Theme.of(
context,
).buttonTheme.colorScheme!.onPrimary,
),
),
),

View File

@@ -48,8 +48,8 @@ class _AnimatedSwitcherDemoState extends State<AnimatedSwitcherDemo> {
title: const Text('AnimatedSwitcher'),
actions: [
TextButton(
onPressed:
() => setState(() => container = generateContainer(++keyCount)),
onPressed: () =>
setState(() => container = generateContainer(++keyCount)),
child: const Text('Change Widget'),
),
],
@@ -61,9 +61,8 @@ class _AnimatedSwitcherDemoState extends State<AnimatedSwitcherDemo> {
child: AnimatedSwitcher(
duration: const Duration(seconds: 1),
child: container,
transitionBuilder:
(child, animation) =>
ScaleTransition(scale: animation, child: child),
transitionBuilder: (child, animation) =>
ScaleTransition(scale: animation, child: child),
),
),
);

View File

@@ -15,8 +15,9 @@ class CarouselDemo extends StatelessWidget {
'assets/eat_sydney_sm.jpg',
];
final List<Widget> images =
fileNames.map((file) => Image.asset(file, fit: BoxFit.cover)).toList();
final List<Widget> images = fileNames
.map((file) => Image.asset(file, fit: BoxFit.cover))
.toList();
@override
Widget build(context) {
@@ -77,29 +78,32 @@ class _CarouselState extends State<Carousel> {
},
controller: _controller,
scrollBehavior: ScrollConfiguration.of(context).copyWith(
dragDevices: {ui.PointerDeviceKind.touch, ui.PointerDeviceKind.mouse},
dragDevices: {
ui.PointerDeviceKind.touch,
ui.PointerDeviceKind.mouse,
},
),
itemBuilder:
(context, index) => AnimatedBuilder(
animation: _controller,
builder: (context, child) {
var result =
_pageHasChanged ? _controller.page! : _currentPage * 1.0;
itemBuilder: (context, index) => AnimatedBuilder(
animation: _controller,
builder: (context, child) {
var result = _pageHasChanged
? _controller.page!
: _currentPage * 1.0;
// The horizontal position of the page between a 1 and 0
var value = result - index;
value = (1 - (value.abs() * .5)).clamp(0.0, 1.0);
// The horizontal position of the page between a 1 and 0
var value = result - index;
value = (1 - (value.abs() * .5)).clamp(0.0, 1.0);
return Center(
child: SizedBox(
height: Curves.easeOut.transform(value) * size.height,
width: Curves.easeOut.transform(value) * size.width,
child: child,
),
);
},
child: widget.itemBuilder(context, index),
),
return Center(
child: SizedBox(
height: Curves.easeOut.transform(value) * size.height,
width: Curves.easeOut.transform(value) * size.width,
child: child,
),
);
},
child: widget.itemBuilder(context, index),
),
);
}

View File

@@ -91,13 +91,12 @@ class _CurvedAnimationDemoState extends State<CurvedAnimationDemo>
style: Theme.of(context).textTheme.titleLarge,
),
DropdownButton<CurveChoice>(
items:
curves.map((curve) {
return DropdownMenuItem<CurveChoice>(
value: curve,
child: Text(curve.name),
);
}).toList(),
items: curves.map((curve) {
return DropdownMenuItem<CurveChoice>(
value: curve,
child: Text(curve.name),
);
}).toList(),
onChanged: (newCurve) {
if (newCurve != null) {
setState(() {
@@ -114,13 +113,12 @@ class _CurvedAnimationDemoState extends State<CurvedAnimationDemo>
style: Theme.of(context).textTheme.titleLarge,
),
DropdownButton<CurveChoice>(
items:
curves.map((curve) {
return DropdownMenuItem<CurveChoice>(
value: curve,
child: Text(curve.name),
);
}).toList(),
items: curves.map((curve) {
return DropdownMenuItem<CurveChoice>(
value: curve,
child: Text(curve.name),
);
}).toList(),
onChanged: (newCurve) {
if (newCurve != null) {
setState(() {

View File

@@ -52,26 +52,24 @@ class _ExpandCardState extends State<ExpandCard>
duration: duration,
firstCurve: Curves.easeInOutCubic,
secondCurve: Curves.easeInOutCubic,
crossFadeState:
selected
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
crossFadeState: selected
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
// Use Positioned.fill() to pass the constraints to its children.
// This allows the Images to use BoxFit.cover to cover the correct
// size
layoutBuilder: (
topChild,
topChildKey,
bottomChild,
bottomChildKey,
) {
return Stack(
children: [
Positioned.fill(key: bottomChildKey, child: bottomChild),
Positioned.fill(key: topChildKey, child: topChild),
],
);
},
layoutBuilder:
(topChild, topChildKey, bottomChild, bottomChildKey) {
return Stack(
children: [
Positioned.fill(
key: bottomChildKey,
child: bottomChild,
),
Positioned.fill(key: topChildKey, child: topChild),
],
);
},
firstChild: Image.asset(
'assets/eat_cape_town_sm.jpg',
fit: BoxFit.cover,

View File

@@ -18,20 +18,21 @@ class FlutterAnimateDemo extends StatelessWidget {
body: Center(
child: Padding(
padding: const EdgeInsets.all(16),
child: Text(
"Hello Flutter Animate",
style: Theme.of(context).textTheme.headlineLarge,
)
.animate(onPlay: (controller) => controller.repeat())
.then(delay: 250.ms)
.fadeIn(duration: 500.ms)
.then(delay: 250.ms)
.shimmer(duration: 400.ms)
.then(delay: 250.ms)
.slide()
.then(delay: 250.ms)
.blur(duration: 500.ms)
.then(delay: 100.ms),
child:
Text(
"Hello Flutter Animate",
style: Theme.of(context).textTheme.headlineLarge,
)
.animate(onPlay: (controller) => controller.repeat())
.then(delay: 250.ms)
.fadeIn(duration: 500.ms)
.then(delay: 250.ms)
.shimmer(duration: 400.ms)
.then(delay: 250.ms)
.slide()
.then(delay: 250.ms)
.blur(duration: 500.ms)
.then(delay: 100.ms),
),
),
);

View File

@@ -29,10 +29,12 @@ class Grid extends StatelessWidget {
),
itemBuilder: (context, index) {
return (index >= 20)
? const SmallCard(imageAssetName: 'assets/eat_cape_town_sm.jpg')
? const SmallCard(
imageAssetName: 'assets/eat_cape_town_sm.jpg',
)
: const SmallCard(
imageAssetName: 'assets/eat_new_orleans_sm.jpg',
);
imageAssetName: 'assets/eat_new_orleans_sm.jpg',
);
},
),
);
@@ -50,7 +52,9 @@ Route _createRoute(BuildContext parentContext, String image) {
).chain(CurveTween(curve: Curves.ease)).animate(animation);
return Stack(
children: [PositionedTransition(rect: rectAnimation, child: child)],
children: [
PositionedTransition(rect: rectAnimation, child: child),
],
);
},
);

View File

@@ -15,10 +15,15 @@ class HeroAnimationDemo extends StatelessWidget {
body: GestureDetector(
child: Hero(
tag: 'hero-page-child',
child: _createHeroContainer(size: 50.0, color: Colors.grey.shade300),
child: _createHeroContainer(
size: 50.0,
color: Colors.grey.shade300,
),
),
onTap:
() => Navigator.of(context).push<void>(
onTap: () =>
Navigator.of(
context,
).push<void>(
MaterialPageRoute(builder: (context) => const HeroPage()),
),
),
@@ -52,7 +57,9 @@ StatelessWidget _createHeroContainer({
height: size,
width: size,
padding: const EdgeInsets.all(10.0),
margin: size < 100.0 ? const EdgeInsets.all(10.0) : const EdgeInsets.all(0),
margin: size < 100.0
? const EdgeInsets.all(10.0)
: const EdgeInsets.all(0),
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
child: const FlutterLogo(),
);

View File

@@ -78,7 +78,9 @@ class _DraggableCardState extends State<DraggableCard>
void initState() {
super.initState();
_controller = AnimationController.unbounded(vsync: this)
..addListener(() => setState(() => _dragAlignment = _animation.value));
..addListener(
() => setState(() => _dragAlignment = _animation.value),
);
}
@override
@@ -92,17 +94,18 @@ class _DraggableCardState extends State<DraggableCard>
final size = MediaQuery.of(context).size;
return GestureDetector(
onPanStart: (details) => _controller.stop(canceled: true),
onPanUpdate:
(details) => setState(
() =>
_dragAlignment += Alignment(
details.delta.dx / (size.width / 2),
details.delta.dy / (size.height / 2),
),
),
onPanEnd:
(details) => _runAnimation(details.velocity.pixelsPerSecond, size),
child: Align(alignment: _dragAlignment, child: Card(child: widget.child)),
onPanUpdate: (details) => setState(
() => _dragAlignment += Alignment(
details.delta.dx / (size.width / 2),
details.delta.dy / (size.height / 2),
),
),
onPanEnd: (details) =>
_runAnimation(details.velocity.pixelsPerSecond, size),
child: Align(
alignment: _dragAlignment,
child: Card(child: widget.child),
),
);
}
}

View File

@@ -9,7 +9,8 @@ class RepeatingAnimationDemo extends StatefulWidget {
static String routeName = 'misc/repeating_animation';
@override
State<RepeatingAnimationDemo> createState() => _RepeatingAnimationDemoState();
State<RepeatingAnimationDemo> createState() =>
_RepeatingAnimationDemoState();
}
class _RepeatingAnimationDemoState extends State<RepeatingAnimationDemo>

View File

@@ -2,15 +2,16 @@ name: animations
description: A new Flutter project.
version: 1.0.0+1
publish_to: none
resolution: workspace
environment:
sdk: ^3.7.0-0
sdk: ^3.9.0-0
dependencies:
flutter:
sdk: flutter
flutter_animate: ^4.1.0
go_router: ^16.1.0
go_router: ^16.0.0
window_size: # plugin is not yet part of the flutter framework
git:
url: https://github.com/google/flutter-desktop-embedding.git
@@ -22,7 +23,6 @@ dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
assets:

View File

@@ -16,7 +16,8 @@ void main() {
// Get the initial color of the button.
ElevatedButton button = tester.widget(find.byType(ElevatedButton));
WidgetStateProperty<Color?>? initialColor = button.style!.backgroundColor;
WidgetStateProperty<Color?>? initialColor =
button.style!.backgroundColor;
// Tap the button.
await tester.tap(find.byType(ElevatedButton));
@@ -24,7 +25,8 @@ void main() {
// Get the updated color of the button.
button = tester.widget(find.byType(ElevatedButton));
WidgetStateProperty<Color?>? updatedColor = button.style!.backgroundColor;
WidgetStateProperty<Color?>? updatedColor =
button.style!.backgroundColor;
// Check if the color has changed.
expect(initialColor, isNot(updatedColor));
@@ -35,7 +37,8 @@ void main() {
// Get the initial color of the button.
ElevatedButton button = tester.widget(find.byType(ElevatedButton));
WidgetStateProperty<Color?>? initialColor = button.style!.backgroundColor;
WidgetStateProperty<Color?>? initialColor =
button.style!.backgroundColor;
// Tap the button to trigger the animation but don't wait for it to finish.
await tester.tap(find.byType(ElevatedButton));
@@ -44,7 +47,8 @@ void main() {
// Check that the color has changed but not to the final color.
button = tester.widget(find.byType(ElevatedButton));
WidgetStateProperty<Color?>? changedColor = button.style!.backgroundColor;
WidgetStateProperty<Color?>? changedColor =
button.style!.backgroundColor;
expect(initialColor, isNot(changedColor));
// Wait for the animation to finish.

View File

@@ -24,7 +24,10 @@ void main() {
await tester.pumpAndSettle();
// Check if removed properly.
expect(tester.widgetList(find.byType(Card)).length, lessThan(totalCards));
expect(
tester.widgetList(find.byType(Card)).length,
lessThan(totalCards),
);
});
testWidgets('All cards swiped out', (tester) async {
@@ -36,7 +39,10 @@ void main() {
// Swipe out all cards.
for (var i = 0; i < totalCards; i++) {
// Swipe out one by one.
await tester.drag(find.byType(Card).last, const Offset(100.0, 0.0));
await tester.drag(
find.byType(Card).last,
const Offset(100.0, 0.0),
);
await tester.pumpAndSettle();
}

View File

@@ -18,7 +18,11 @@ void main() {
expect(imageList.length, 2);
// Swipe the Carousel.
await tester.fling(find.byType(CarouselDemo), const Offset(-400, 0), 800);
await tester.fling(
find.byType(CarouselDemo),
const Offset(-400, 0),
800,
);
await tester.pumpAndSettle();
// Get the images available on the screen after swipe.

View File

@@ -22,7 +22,10 @@ void main() {
// The size of ExpandCard must change once tapped.
// The initialSize should be less than current ExpandCard size.
expect(initialSize, lessThan(tester.getSize(find.byType(ExpandCard))));
expect(
initialSize,
lessThan(tester.getSize(find.byType(ExpandCard))),
);
});
testWidgets('ExpandCard changes image on tap', (tester) async {

View File

@@ -33,7 +33,9 @@ void main() {
expect(finalSize, greaterThan(initialSize));
});
testWidgets('Final inkwell on tap goes back to the grid', (tester) async {
testWidgets('Final inkwell on tap goes back to the grid', (
tester,
) async {
await tester.pumpWidget(createFocusImageScreen());
// Tap on the ink well at index 0.

View File

@@ -58,7 +58,9 @@ void main() {
// Final color should not be same as initial color.
expect(
(finalContainer.decoration as BoxDecoration).color,
isNot(equals((initialContainer.decoration as BoxDecoration).color)),
isNot(
equals((initialContainer.decoration as BoxDecoration).color),
),
);
});
@@ -66,7 +68,9 @@ void main() {
await tester.pumpWidget(createHeroAnimationDemoScreen());
// Get the initial Screen.
final initialScreen = tester.firstWidget(find.byType(HeroAnimationDemo));
final initialScreen = tester.firstWidget(
find.byType(HeroAnimationDemo),
);
// Tap on the GestureDetector.
await tester.tap(find.byType(GestureDetector));