Updated Material 3 Progress Indicators Samples (#158925)

Fixes [Update both `ProgressIndicator` for Material 3
redesign](https://github.com/flutter/flutter/issues/141340)

> [!IMPORTANT]  
> ~~This to be merged after
https://github.com/flutter/flutter/pull/158104.~~ Merged.

### Description 

This updates progress indicator samples to include toggle to opt in to
the updated Material 3 appearance .

### Preview

<img width="753" alt="Screenshot 2024-12-04 at 15 54 50"
src="https://github.com/user-attachments/assets/285f2803-1a12-470a-9afe-2abcf0548ff4">

<img width="753" alt="Screenshot 2024-12-04 at 15 58 35"
src="https://github.com/user-attachments/assets/9caebec9-f65e-4baa-8e39-9a4a4a72b205">


## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
Taha Tesser 2024-12-05 19:54:54 +02:00 committed by GitHub
parent 1856940f66
commit a6d3bb5cb4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 153 additions and 69 deletions

View File

@ -6,10 +6,10 @@ import 'package:flutter/material.dart';
/// Flutter code sample for [CircularProgressIndicator].
void main() => runApp(const ProgressIndicatorApp());
void main() => runApp(const ProgressIndicatorExampleApp());
class ProgressIndicatorApp extends StatelessWidget {
const ProgressIndicatorApp({super.key});
class ProgressIndicatorExampleApp extends StatelessWidget {
const ProgressIndicatorExampleApp({super.key});
@override
Widget build(BuildContext context) {
@ -28,19 +28,18 @@ class ProgressIndicatorExample extends StatefulWidget {
class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample> with TickerProviderStateMixin {
late AnimationController controller;
bool year2023 = true;
@override
void initState() {
super.initState();
controller = AnimationController(
/// [AnimationController]s can be created with `vsync: this` because of
/// [TickerProviderStateMixin].
vsync: this,
duration: const Duration(seconds: 5),
)..addListener(() {
setState(() {});
});
controller.repeat(reverse: true);
super.initState();
setState(() {});
})
..repeat(reverse: true);
}
@override
@ -52,18 +51,32 @@ class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample> wit
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(20.0),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
spacing: 16.0,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Circular progress indicator with a fixed color',
style: Theme.of(context).textTheme.titleLarge,
const Text('Determinate CircularProgressIndicator'),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: CircularProgressIndicator(
year2023: year2023,
value: controller.value,
),
),
CircularProgressIndicator(
value: controller.value,
semanticsLabel: 'Circular progress indicator',
const Text('Indeterminate CircularProgressIndicator'),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: CircularProgressIndicator(year2023: year2023),
),
SwitchListTile(
value: year2023,
title: year2023 ? const Text('Switch to latest M3 style') : const Text('Switch to year2023 M3 style'),
onChanged: (bool value) {
setState(() {
year2023 = !year2023;
});
},
),
],
),

View File

@ -6,10 +6,10 @@ import 'package:flutter/material.dart';
/// Flutter code sample for [CircularProgressIndicator].
void main() => runApp(const ProgressIndicatorApp());
void main() => runApp(const ProgressIndicatorExampleApp());
class ProgressIndicatorApp extends StatelessWidget {
const ProgressIndicatorApp({super.key});
class ProgressIndicatorExampleApp extends StatelessWidget {
const ProgressIndicatorExampleApp({super.key});
@override
Widget build(BuildContext context) {
@ -57,18 +57,17 @@ class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample> wit
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
spacing: 16.0,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Circular progress indicator',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 30),
CircularProgressIndicator(
value: controller.value,
semanticsLabel: 'Circular progress indicator',
),
const SizedBox(height: 10),
Row(
children: <Widget>[
Expanded(

View File

@ -27,9 +27,9 @@ class ProgressIndicatorExample extends StatefulWidget {
_ProgressIndicatorExampleState();
}
class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample>
with TickerProviderStateMixin {
class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample> with TickerProviderStateMixin {
late AnimationController controller;
bool year2023 = true;
@override
void initState() {
@ -54,18 +54,33 @@ class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample>
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
spacing: 16.0,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Determinate LinearProgressIndicator'),
LinearProgressIndicator(value: controller.value),
const Text('Indeterminate LinearProgressIndicator'),
const LinearProgressIndicator(),
],
),
body: Column(
spacing: 16.0,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Determinate LinearProgressIndicator'),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: LinearProgressIndicator(
year2023: year2023,
value: controller.value,
),
),
const Text('Indeterminate LinearProgressIndicator'),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: LinearProgressIndicator(year2023: year2023),
),
SwitchListTile(
value: year2023,
title: year2023 ? const Text('Switch to latest M3 style') : const Text('Switch to year2023 M3 style'),
onChanged: (bool value) {
setState(() {
year2023 = !year2023;
});
},
),
],
),
);
}

View File

@ -58,18 +58,17 @@ class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample>
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
spacing: 16.0,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'Linear progress indicator',
style: TextStyle(fontSize: 20),
),
const SizedBox(height: 30),
LinearProgressIndicator(
value: determinate ? controller.value : null,
semanticsLabel: 'Linear progress indicator',
),
const SizedBox(height: 10),
Row(
children: <Widget>[
Expanded(

View File

@ -2,23 +2,58 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter_api_samples/material/progress_indicator/circular_progress_indicator.0.dart'
as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Finds CircularProgressIndicator', (WidgetTester tester) async {
testWidgets('Determinate CircularProgressIndicator uses the provided value', (WidgetTester tester) async {
await tester.pumpWidget(
const example.ProgressIndicatorApp(),
const example.ProgressIndicatorExampleApp(),
);
await tester.pump(const Duration(milliseconds: 2500));
final Finder indicatorFinder = find.byType(CircularProgressIndicator).first;
final CircularProgressIndicator progressIndicator = tester.widget(indicatorFinder);
expect(progressIndicator.value, equals(0.5));
});
testWidgets('Indeterminate CircularProgressIndicator does not have a value', (WidgetTester tester) async {
await tester.pumpWidget(
const example.ProgressIndicatorExampleApp(),
);
await tester.pump(const Duration(milliseconds: 2500));
final Finder indicatorFinder = find.byType(CircularProgressIndicator).last;
final CircularProgressIndicator progressIndicator = tester.widget(indicatorFinder);
expect(progressIndicator.value, null);
});
testWidgets('Progress indicators year2023 flag can be toggled', (WidgetTester tester) async {
await tester.pumpWidget(
const example.ProgressIndicatorExampleApp(),
);
expect(
find.bySemanticsLabel('Circular progress indicator'),
findsOneWidget,
CircularProgressIndicator determinateIndicator = tester.widget<CircularProgressIndicator>(
find.byType(CircularProgressIndicator).first,
);
expect(determinateIndicator.year2023, true);
CircularProgressIndicator indeterminateIndicator = tester.widget<CircularProgressIndicator>(
find.byType(CircularProgressIndicator).last,
);
expect(indeterminateIndicator.year2023, true);
// Test if CircularProgressIndicator is animating.
await tester.pump(const Duration(seconds: 2));
expect(tester.hasRunningAnimations, isTrue);
await tester.tap(find.byType(SwitchListTile));
await tester.pump();
determinateIndicator = tester.widget<CircularProgressIndicator>(
find.byType(CircularProgressIndicator).first,
);
expect(determinateIndicator.year2023, false);
indeterminateIndicator = tester.widget<CircularProgressIndicator>(
find.byType(CircularProgressIndicator).last,
);
expect(indeterminateIndicator.year2023, false);
});
}

View File

@ -10,7 +10,7 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Finds CircularProgressIndicator', (WidgetTester tester) async {
await tester.pumpWidget(
const example.ProgressIndicatorApp(),
const example.ProgressIndicatorExampleApp(),
);
expect(

View File

@ -8,33 +8,52 @@ import 'package:flutter_api_samples/material/progress_indicator/linear_progress_
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Determinate and Indeterminate LinearProgressIndicators',
(WidgetTester tester) async {
testWidgets('Determinate LinearProgressIndicator uses the provided value', (WidgetTester tester) async {
await tester.pumpWidget(
const example.ProgressIndicatorExampleApp(),
);
await tester.pump(const Duration(milliseconds: 2500));
final Finder indicatorFinder = find.byType(LinearProgressIndicator).first;
final LinearProgressIndicator progressIndicator = tester.widget(indicatorFinder);
expect(progressIndicator.value, equals(0.5));
});
testWidgets('Indeterminate LinearProgressIndicator does not have a value', (WidgetTester tester) async {
await tester.pumpWidget(
const example.ProgressIndicatorExampleApp(),
);
await tester.pump(const Duration(milliseconds: 2500));
final Finder indicatorFinder = find.byType(LinearProgressIndicator).last;
final LinearProgressIndicator progressIndicator = tester.widget(indicatorFinder);
expect(progressIndicator.value, null);
});
testWidgets('Progress indicators year2023 flag can be toggled', (WidgetTester tester) async {
await tester.pumpWidget(
const example.ProgressIndicatorExampleApp(),
);
expect(find.text('Determinate LinearProgressIndicator'), findsOneWidget);
expect(find.text('Indeterminate LinearProgressIndicator'), findsOneWidget);
expect(find.byType(LinearProgressIndicator), findsNWidgets(2));
// Test determinate LinearProgressIndicator.
LinearProgressIndicator determinateIndicator = tester.firstWidget(
LinearProgressIndicator determinateIndicator = tester.widget<LinearProgressIndicator>(
find.byType(LinearProgressIndicator).first,
);
expect(determinateIndicator.value, equals(0.0));
// Advance the animation by 2 seconds.
await tester.pump(const Duration(seconds: 2));
determinateIndicator = tester.firstWidget(
find.byType(LinearProgressIndicator).first,
);
expect(determinateIndicator.value, equals(0.4));
// Test indeterminate LinearProgressIndicator.
final LinearProgressIndicator indeterminateIndicator = tester.firstWidget(
expect(determinateIndicator.year2023, true);
LinearProgressIndicator indeterminateIndicator = tester.widget<LinearProgressIndicator>(
find.byType(LinearProgressIndicator).last,
);
expect(indeterminateIndicator.value, null);
expect(indeterminateIndicator.year2023, true);
await tester.tap(find.byType(SwitchListTile));
await tester.pump();
determinateIndicator = tester.widget<LinearProgressIndicator>(
find.byType(LinearProgressIndicator).first,
);
expect(determinateIndicator.year2023, false);
indeterminateIndicator = tester.widget<LinearProgressIndicator>(
find.byType(LinearProgressIndicator).last,
);
expect(indeterminateIndicator.year2023, false);
});
}

View File

@ -312,6 +312,8 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
///
/// {@tool dartpad}
/// This example showcases determinate and indeterminate [LinearProgressIndicator]s.
/// The [LinearProgressIndicator]s will use the ![updated Material 3 Design appearance](https://m3.material.io/components/progress-indicators/overview)
/// when setting the [LinearProgressIndicator.year2023] flag to false.
///
/// ** See code in examples/api/lib/material/progress_indicator/linear_progress_indicator.0.dart **
/// {@end-tool}
@ -704,7 +706,9 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
/// specify a constant color use: `AlwaysStoppedAnimation<Color>(color)`.
///
/// {@tool dartpad}
/// This example shows a [CircularProgressIndicator] with a changing value.
/// This example showcases determinate and indeterminate [CircularProgressIndicator]s.
/// The [CircularProgressIndicator]s will use the ![updated Material 3 Design appearance](https://m3.material.io/components/progress-indicators/overview)
/// when setting the [CircularProgressIndicator.year2023] flag to false.
///
/// ** See code in examples/api/lib/material/progress_indicator/circular_progress_indicator.0.dart **
/// {@end-tool}