mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
WIP Commits separated as follows: - Update lints in analysis_options files - Run `dart fix --apply` - Clean up leftover analysis issues - Run `dart format .` in the right places. Local analysis and testing passes. Checking CI now. Part of https://github.com/flutter/flutter/issues/178827 - Adoption of flutter_lints in examples/api coming in a separate change (cc @loic-sharma) ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] 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. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- 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
681 lines
24 KiB
Dart
681 lines
24 KiB
Dart
// Copyright 2014 The Flutter Authors. 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/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
testWidgets('Theme.wrap()', (WidgetTester tester) async {
|
|
const primaryColor = Color(0xFF00FF00);
|
|
final Key primaryContainerKey = UniqueKey();
|
|
|
|
// Effectively the same as a StatelessWidget subclass.
|
|
final Widget primaryBox = Builder(
|
|
builder: (BuildContext context) {
|
|
return Container(key: primaryContainerKey, color: Theme.of(context).primaryColor);
|
|
},
|
|
);
|
|
|
|
late BuildContext navigatorContext;
|
|
|
|
Widget buildFrame() {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
body: Builder(
|
|
// Introduce a context so the app's Theme is visible.
|
|
builder: (BuildContext context) {
|
|
navigatorContext = context;
|
|
return Theme(
|
|
data: Theme.of(context).copyWith(primaryColor: primaryColor),
|
|
child: Builder(
|
|
// Introduce a context so the shadow Theme is visible to captureAll().
|
|
builder: (BuildContext context) {
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
ElevatedButton(
|
|
child: const Text('push unwrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// The primaryBox will see the default Theme when built.
|
|
builder: (BuildContext _) => primaryBox,
|
|
),
|
|
);
|
|
},
|
|
),
|
|
ElevatedButton(
|
|
child: const Text('push wrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// Capture the shadow Theme.
|
|
builder: (BuildContext _) =>
|
|
InheritedTheme.captureAll(context, primaryBox),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Color containerColor() {
|
|
return tester.widget<Container>(find.byKey(primaryContainerKey)).color!;
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame());
|
|
|
|
// Show the route which contains primaryBox which was wrapped with
|
|
// InheritedTheme.captureAll().
|
|
await tester.tap(find.text('push wrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
expect(containerColor(), primaryColor);
|
|
|
|
Navigator.of(navigatorContext).pop();
|
|
await tester.pumpAndSettle(); // route animation
|
|
|
|
// Show the route which contains primaryBox
|
|
await tester.tap(find.text('push unwrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
expect(containerColor(), isNot(primaryColor));
|
|
});
|
|
|
|
testWidgets('Material2 - PopupMenuTheme.wrap()', (WidgetTester tester) async {
|
|
const double menuFontSize = 24;
|
|
const menuTextColor = Color(0xFF0000FF);
|
|
|
|
Widget buildFrame() {
|
|
return MaterialApp(
|
|
theme: ThemeData(useMaterial3: false),
|
|
home: Scaffold(
|
|
body: PopupMenuTheme(
|
|
data: const PopupMenuThemeData(
|
|
// The menu route's elevation, shape, and color are defined by the
|
|
// current context, so they're not affected by ThemeData.captureAll().
|
|
textStyle: TextStyle(fontSize: menuFontSize, color: menuTextColor),
|
|
),
|
|
child: Center(
|
|
child: PopupMenuButton<int>(
|
|
// The appearance of the menu items' text is defined by the
|
|
// PopupMenuTheme defined above. Popup menus use
|
|
// InheritedTheme.captureAll() by default.
|
|
child: const Text('show popupmenu'),
|
|
onSelected: (int result) {},
|
|
itemBuilder: (BuildContext context) {
|
|
return const <PopupMenuEntry<int>>[
|
|
PopupMenuItem<int>(value: 1, child: Text('One')),
|
|
PopupMenuItem<int>(value: 2, child: Text('Two')),
|
|
];
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
TextStyle itemTextStyle(String text) {
|
|
return tester
|
|
.widget<RichText>(find.descendant(of: find.text(text), matching: find.byType(RichText)))
|
|
.text
|
|
.style!;
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame());
|
|
|
|
await tester.tap(find.text('show popupmenu'));
|
|
await tester.pumpAndSettle(); // menu route animation
|
|
expect(itemTextStyle('One').fontSize, menuFontSize);
|
|
expect(itemTextStyle('One').color, menuTextColor);
|
|
expect(itemTextStyle('Two').fontSize, menuFontSize);
|
|
expect(itemTextStyle('Two').color, menuTextColor);
|
|
|
|
// Dismiss the menu
|
|
await tester.tap(find.text('One'));
|
|
await tester.pumpAndSettle(); // menu route animation
|
|
});
|
|
|
|
testWidgets('Material3 - PopupMenuTheme.wrap()', (WidgetTester tester) async {
|
|
const textStyle = TextStyle(fontSize: 24.0, color: Color(0xFF0000FF));
|
|
|
|
Widget buildFrame() {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
body: PopupMenuTheme(
|
|
data: const PopupMenuThemeData(
|
|
// The menu route's elevation, shape, and color are defined by the
|
|
// current context, so they're not affected by ThemeData.captureAll().
|
|
labelTextStyle: MaterialStatePropertyAll<TextStyle>(textStyle),
|
|
),
|
|
child: Center(
|
|
child: PopupMenuButton<int>(
|
|
// The appearance of the menu items' text is defined by the
|
|
// PopupMenuTheme defined above. Popup menus use
|
|
// InheritedTheme.captureAll() by default.
|
|
child: const Text('show popupmenu'),
|
|
onSelected: (int result) {},
|
|
itemBuilder: (BuildContext context) {
|
|
return const <PopupMenuEntry<int>>[
|
|
PopupMenuItem<int>(value: 1, child: Text('One')),
|
|
PopupMenuItem<int>(value: 2, child: Text('Two')),
|
|
];
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
TextStyle itemTextStyle(String text) {
|
|
return tester
|
|
.widget<RichText>(find.descendant(of: find.text(text), matching: find.byType(RichText)))
|
|
.text
|
|
.style!;
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame());
|
|
|
|
await tester.tap(find.text('show popupmenu'));
|
|
await tester.pumpAndSettle(); // menu route animation
|
|
expect(itemTextStyle('One').fontSize, textStyle.fontSize);
|
|
expect(itemTextStyle('One').color, textStyle.color);
|
|
expect(itemTextStyle('Two').fontSize, textStyle.fontSize);
|
|
expect(itemTextStyle('Two').color, textStyle.color);
|
|
|
|
// Dismiss the menu
|
|
await tester.tap(find.text('One'));
|
|
await tester.pumpAndSettle(); // menu route animation
|
|
});
|
|
|
|
testWidgets('BannerTheme.wrap()', (WidgetTester tester) async {
|
|
const bannerBackgroundColor = Color(0xFF0000FF);
|
|
const double bannerFontSize = 48;
|
|
const bannerTextColor = Color(0xFF00FF00);
|
|
|
|
final Widget banner = MaterialBanner(
|
|
content: const Text('hello'),
|
|
actions: <Widget>[TextButton(child: const Text('action'), onPressed: () {})],
|
|
);
|
|
|
|
late BuildContext navigatorContext;
|
|
|
|
Widget buildFrame() {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
body: MaterialBannerTheme(
|
|
data: const MaterialBannerThemeData(
|
|
backgroundColor: bannerBackgroundColor,
|
|
contentTextStyle: TextStyle(fontSize: bannerFontSize, color: bannerTextColor),
|
|
),
|
|
child: Builder(
|
|
// Introduce a context so the shadow BannerTheme is visible to captureAll().
|
|
builder: (BuildContext context) {
|
|
navigatorContext = context;
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
ElevatedButton(
|
|
child: const Text('push unwrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// The Banner will see the default BannerTheme when built.
|
|
builder: (BuildContext _) => banner,
|
|
),
|
|
);
|
|
},
|
|
),
|
|
ElevatedButton(
|
|
child: const Text('push wrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// Capture the shadow BannerTheme.
|
|
builder: (BuildContext _) =>
|
|
InheritedTheme.captureAll(context, banner),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Color bannerColor() {
|
|
return tester
|
|
.widget<Material>(
|
|
find.descendant(of: find.byType(MaterialBanner), matching: find.byType(Material)).first,
|
|
)
|
|
.color!;
|
|
}
|
|
|
|
TextStyle getTextStyle(String text) {
|
|
return tester
|
|
.widget<RichText>(find.descendant(of: find.text(text), matching: find.byType(RichText)))
|
|
.text
|
|
.style!;
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame());
|
|
|
|
// Show the route which contains the banner.
|
|
await tester.tap(find.text('push wrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
expect(bannerColor(), bannerBackgroundColor);
|
|
expect(getTextStyle('hello').fontSize, bannerFontSize);
|
|
expect(getTextStyle('hello').color, bannerTextColor);
|
|
|
|
Navigator.of(navigatorContext).pop();
|
|
await tester.pumpAndSettle(); // route animation
|
|
|
|
await tester.tap(find.text('push unwrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
expect(bannerColor(), isNot(bannerBackgroundColor));
|
|
expect(getTextStyle('hello').fontSize, isNot(bannerFontSize));
|
|
expect(getTextStyle('hello').color, isNot(bannerTextColor));
|
|
});
|
|
|
|
testWidgets('DividerTheme.wrap()', (WidgetTester tester) async {
|
|
const dividerColor = Color(0xFF0000FF);
|
|
const double dividerSpace = 13;
|
|
const double dividerThickness = 7;
|
|
const Widget divider = Center(child: Divider());
|
|
|
|
late BuildContext navigatorContext;
|
|
|
|
Widget buildFrame() {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
body: DividerTheme(
|
|
data: const DividerThemeData(
|
|
color: dividerColor,
|
|
space: dividerSpace,
|
|
thickness: dividerThickness,
|
|
),
|
|
child: Builder(
|
|
// Introduce a context so the shadow DividerTheme is visible to captureAll().
|
|
builder: (BuildContext context) {
|
|
navigatorContext = context;
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
ElevatedButton(
|
|
child: const Text('push unwrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// The Banner will see the default BannerTheme when built.
|
|
builder: (BuildContext _) => divider,
|
|
),
|
|
);
|
|
},
|
|
),
|
|
ElevatedButton(
|
|
child: const Text('push wrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// Capture the shadow BannerTheme.
|
|
builder: (BuildContext _) =>
|
|
InheritedTheme.captureAll(context, divider),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
BorderSide dividerBorder() {
|
|
final decoration =
|
|
tester
|
|
.widget<Container>(
|
|
find
|
|
.descendant(of: find.byType(Divider), matching: find.byType(Container))
|
|
.first,
|
|
)
|
|
.decoration!
|
|
as BoxDecoration;
|
|
return decoration.border!.bottom;
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame());
|
|
|
|
// Show a route which contains a divider.
|
|
await tester.tap(find.text('push wrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
expect(tester.getSize(find.byType(Divider)).height, dividerSpace);
|
|
expect(dividerBorder().color, dividerColor);
|
|
expect(dividerBorder().width, dividerThickness);
|
|
|
|
Navigator.of(navigatorContext).pop();
|
|
await tester.pumpAndSettle(); // route animation
|
|
|
|
await tester.tap(find.text('push unwrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
expect(tester.getSize(find.byType(Divider)).height, isNot(dividerSpace));
|
|
expect(dividerBorder().color, isNot(dividerColor));
|
|
expect(dividerBorder().width, isNot(dividerThickness));
|
|
});
|
|
|
|
testWidgets('ListTileTheme.wrap()', (WidgetTester tester) async {
|
|
const tileSelectedColor = Color(0xFF00FF00);
|
|
const tileIconColor = Color(0xFF0000FF);
|
|
const tileTextColor = Color(0xFFFF0000);
|
|
|
|
final Key selectedIconKey = UniqueKey();
|
|
final Key unselectedIconKey = UniqueKey();
|
|
|
|
final Widget listTiles = Scaffold(
|
|
body: Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
ListTile(
|
|
leading: Icon(Icons.computer, key: selectedIconKey),
|
|
title: const Text('selected'),
|
|
selected: true,
|
|
),
|
|
ListTile(
|
|
leading: Icon(Icons.add, key: unselectedIconKey),
|
|
title: const Text('unselected'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
late BuildContext navigatorContext;
|
|
|
|
Widget buildFrame() {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
body: ListTileTheme(
|
|
selectedColor: tileSelectedColor,
|
|
textColor: tileTextColor,
|
|
iconColor: tileIconColor,
|
|
child: Builder(
|
|
// Introduce a context so the shadow ListTileTheme is visible to captureAll().
|
|
builder: (BuildContext context) {
|
|
navigatorContext = context;
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
ElevatedButton(
|
|
child: const Text('push unwrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// The Banner will see the default BannerTheme when built.
|
|
builder: (BuildContext _) => listTiles,
|
|
),
|
|
);
|
|
},
|
|
),
|
|
ElevatedButton(
|
|
child: const Text('push wrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// Capture the shadow BannerTheme.
|
|
builder: (BuildContext _) =>
|
|
InheritedTheme.captureAll(context, listTiles),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
TextStyle getTextStyle(String text) {
|
|
return tester
|
|
.widget<RichText>(find.descendant(of: find.text(text), matching: find.byType(RichText)))
|
|
.text
|
|
.style!;
|
|
}
|
|
|
|
TextStyle getIconStyle(Key key) {
|
|
return tester
|
|
.widget<RichText>(find.descendant(of: find.byKey(key), matching: find.byType(RichText)))
|
|
.text
|
|
.style!;
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame());
|
|
|
|
// Show a route which contains listTiles.
|
|
await tester.tap(find.text('push wrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
expect(getTextStyle('unselected').color, tileTextColor);
|
|
expect(getTextStyle('selected').color, tileSelectedColor);
|
|
expect(getIconStyle(selectedIconKey).color, tileSelectedColor);
|
|
expect(getIconStyle(unselectedIconKey).color, tileIconColor);
|
|
|
|
Navigator.of(navigatorContext).pop();
|
|
await tester.pumpAndSettle(); // route animation
|
|
|
|
await tester.tap(find.text('push unwrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
expect(getTextStyle('unselected').color, isNot(tileTextColor));
|
|
expect(getTextStyle('selected').color, isNot(tileSelectedColor));
|
|
expect(getIconStyle(selectedIconKey).color, isNot(tileSelectedColor));
|
|
expect(getIconStyle(unselectedIconKey).color, isNot(tileIconColor));
|
|
});
|
|
|
|
testWidgets('SliderTheme.wrap()', (WidgetTester tester) async {
|
|
const activeTrackColor = Color(0xFF00FF00);
|
|
const inactiveTrackColor = Color(0xFF0000FF);
|
|
const thumbColor = Color(0xFFFF0000);
|
|
|
|
final Widget slider = Scaffold(
|
|
body: Center(child: Slider(value: 0.5, onChanged: (double value) {})),
|
|
);
|
|
|
|
late BuildContext navigatorContext;
|
|
|
|
Widget buildFrame() {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
body: SliderTheme(
|
|
data: const SliderThemeData(
|
|
activeTrackColor: activeTrackColor,
|
|
inactiveTrackColor: inactiveTrackColor,
|
|
thumbColor: thumbColor,
|
|
),
|
|
child: Builder(
|
|
// Introduce a context so the shadow SliderTheme is visible to captureAll().
|
|
builder: (BuildContext context) {
|
|
navigatorContext = context;
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
ElevatedButton(
|
|
child: const Text('push unwrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// The slider will see the default SliderTheme when built.
|
|
builder: (BuildContext _) => slider,
|
|
),
|
|
);
|
|
},
|
|
),
|
|
ElevatedButton(
|
|
child: const Text('push wrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// Capture the shadow SliderTheme.
|
|
builder: (BuildContext _) =>
|
|
InheritedTheme.captureAll(context, slider),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame());
|
|
|
|
// Show a route which contains listTiles.
|
|
await tester.tap(find.text('push wrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
|
|
expect(
|
|
sliderBox,
|
|
paints
|
|
..rrect(color: inactiveTrackColor)
|
|
..rrect(color: activeTrackColor),
|
|
);
|
|
expect(sliderBox, paints..circle(color: thumbColor));
|
|
|
|
Navigator.of(navigatorContext).pop();
|
|
await tester.pumpAndSettle(); // route animation
|
|
|
|
await tester.tap(find.text('push unwrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
|
|
expect(
|
|
sliderBox,
|
|
isNot(
|
|
paints
|
|
..rrect(color: inactiveTrackColor)
|
|
..rrect(color: activeTrackColor),
|
|
),
|
|
);
|
|
expect(sliderBox, isNot(paints..circle(color: thumbColor)));
|
|
});
|
|
|
|
testWidgets('ToggleButtonsTheme.wrap()', (WidgetTester tester) async {
|
|
const buttonColor = Color(0xFF00FF00);
|
|
const selectedButtonColor = Color(0xFFFF0000);
|
|
|
|
final Widget toggleButtons = Scaffold(
|
|
body: Center(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[true, false],
|
|
children: const <Widget>[Text('selected'), Text('unselected')],
|
|
onPressed: (int index) {},
|
|
),
|
|
),
|
|
);
|
|
|
|
late BuildContext navigatorContext;
|
|
|
|
Widget buildFrame() {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
body: ToggleButtonsTheme(
|
|
data: const ToggleButtonsThemeData(
|
|
color: buttonColor,
|
|
selectedColor: selectedButtonColor,
|
|
),
|
|
child: Builder(
|
|
// Introduce a context so the shadow ToggleButtonsTheme is visible to captureAll().
|
|
builder: (BuildContext context) {
|
|
navigatorContext = context;
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
ElevatedButton(
|
|
child: const Text('push unwrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// The slider will see the default ToggleButtonsTheme when built.
|
|
builder: (BuildContext _) => toggleButtons,
|
|
),
|
|
);
|
|
},
|
|
),
|
|
ElevatedButton(
|
|
child: const Text('push wrapped'),
|
|
onPressed: () {
|
|
Navigator.of(context).push<void>(
|
|
MaterialPageRoute<void>(
|
|
// Capture the shadow toggleButtons.
|
|
builder: (BuildContext _) =>
|
|
InheritedTheme.captureAll(context, toggleButtons),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Color getTextColor(String text) {
|
|
return tester
|
|
.widget<RichText>(find.descendant(of: find.text(text), matching: find.byType(RichText)))
|
|
.text
|
|
.style!
|
|
.color!;
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame());
|
|
|
|
// Show a route which contains toggleButtons.
|
|
await tester.tap(find.text('push wrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
expect(getTextColor('selected'), selectedButtonColor);
|
|
expect(getTextColor('unselected'), buttonColor);
|
|
|
|
Navigator.of(navigatorContext).pop();
|
|
await tester.pumpAndSettle(); // route animation
|
|
|
|
await tester.tap(find.text('push unwrapped'));
|
|
await tester.pumpAndSettle(); // route animation
|
|
expect(getTextColor('selected'), isNot(selectedButtonColor));
|
|
expect(getTextColor('unselected'), isNot(buttonColor));
|
|
});
|
|
}
|