| // 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/foundation.dart'; |
| import 'package:flutter/material.dart'; |
| import 'package:flutter/rendering.dart'; |
| import 'package:flutter/services.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| void main() { |
| const appBarTheme = AppBarThemeData( |
| backgroundColor: Color(0xff00ff00), |
| foregroundColor: Color(0xff00ffff), |
| elevation: 4.0, |
| scrolledUnderElevation: 6.0, |
| shadowColor: Color(0xff1212ff), |
| shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(14.0))), |
| iconTheme: IconThemeData(color: Color(0xffff0000)), |
| actionsIconTheme: IconThemeData(color: Color(0xff0000ff)), |
| centerTitle: false, |
| titleSpacing: 10.0, |
| titleTextStyle: TextStyle(fontSize: 22.0, fontStyle: FontStyle.italic), |
| ); |
| |
| ScrollController primaryScrollController(WidgetTester tester) { |
| return PrimaryScrollController.of(tester.element(find.byType(CustomScrollView))); |
| } |
| |
| test('AppBarThemeData copyWith, ==, hashCode basics', () { |
| expect(const AppBarThemeData(), const AppBarThemeData().copyWith()); |
| expect(const AppBarThemeData().hashCode, const AppBarThemeData().copyWith().hashCode); |
| |
| expect(const AppBarThemeData().backgroundColor, null); |
| expect(const AppBarThemeData().foregroundColor, null); |
| expect(const AppBarThemeData().elevation, null); |
| expect(const AppBarThemeData().scrolledUnderElevation, null); |
| expect(const AppBarThemeData().shadowColor, null); |
| expect(const AppBarThemeData().surfaceTintColor, null); |
| expect(const AppBarThemeData().shape, null); |
| expect(const AppBarThemeData().iconTheme, null); |
| expect(const AppBarThemeData().actionsIconTheme, null); |
| expect(const AppBarThemeData().centerTitle, null); |
| expect(const AppBarThemeData().titleSpacing, null); |
| expect(const AppBarThemeData().leadingWidth, null); |
| expect(const AppBarThemeData().toolbarHeight, null); |
| expect(const AppBarThemeData().toolbarTextStyle, null); |
| expect(const AppBarThemeData().titleTextStyle, null); |
| expect(const AppBarThemeData().systemOverlayStyle, null); |
| expect(const AppBarThemeData().actionsPadding, null); |
| }); |
| |
| test('AppBarTheme lerp special cases', () { |
| const data = AppBarTheme(); |
| expect(identical(AppBarTheme.lerp(data, data, 0.5), data), true); |
| }); |
| |
| testWidgets('Material2 - Passing no AppBarTheme returns defaults', (WidgetTester tester) async { |
| final theme = ThemeData(useMaterial3: false); |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: theme, |
| home: Scaffold( |
| appBar: AppBar( |
| actions: <Widget>[IconButton(icon: const Icon(Icons.share), onPressed: () {})], |
| ), |
| ), |
| ), |
| ); |
| |
| final Material widget = _getAppBarMaterial(tester); |
| final IconTheme iconTheme = _getAppBarIconTheme(tester); |
| final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); |
| final RichText actionIconText = _getAppBarIconRichText(tester); |
| final DefaultTextStyle text = _getAppBarText(tester); |
| |
| expect( |
| SystemChrome.latestStyle!.statusBarBrightness, |
| SystemUiOverlayStyle.light.statusBarBrightness, |
| ); |
| expect(widget.color, Colors.blue); |
| expect(widget.elevation, 4.0); |
| expect(widget.shadowColor, Colors.black); |
| expect(widget.surfaceTintColor, null); |
| expect(widget.shape, null); |
| expect(iconTheme.data, const IconThemeData(color: Colors.white)); |
| expect(actionsIconTheme.data, const IconThemeData(color: Colors.white)); |
| expect(actionIconText.text.style!.color, Colors.white); |
| expect( |
| text.style, |
| Typography.material2014().englishLike.bodyMedium!.merge( |
| Typography.material2014().white.bodyMedium, |
| ), |
| ); |
| expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); |
| expect(tester.getSize(find.byType(AppBar)).width, 800); |
| }); |
| |
| testWidgets('Material3 - Passing no AppBarTheme returns defaults', (WidgetTester tester) async { |
| final theme = ThemeData(); |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: theme, |
| home: Scaffold( |
| appBar: AppBar( |
| actions: <Widget>[IconButton(icon: const Icon(Icons.share), onPressed: () {})], |
| ), |
| ), |
| ), |
| ); |
| |
| final Material widget = _getAppBarMaterial(tester); |
| final IconTheme iconTheme = _getAppBarIconTheme(tester); |
| final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); |
| final RichText actionIconText = _getAppBarIconRichText(tester); |
| final DefaultTextStyle text = _getAppBarText(tester); |
| |
| expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.light); |
| expect(widget.color, theme.colorScheme.surface); |
| expect(widget.elevation, 0); |
| expect(widget.shadowColor, Colors.transparent); |
| expect(widget.surfaceTintColor, theme.colorScheme.surfaceTint); |
| expect(widget.shape, null); |
| expect(iconTheme.data, IconThemeData(color: theme.colorScheme.onSurface, size: 24)); |
| expect( |
| actionsIconTheme.data, |
| IconThemeData(color: theme.colorScheme.onSurfaceVariant, size: 24), |
| ); |
| expect(actionIconText.text.style!.color, theme.colorScheme.onSurfaceVariant); |
| expect( |
| text.style, |
| Typography.material2021().englishLike.bodyMedium! |
| .merge(Typography.material2021().black.bodyMedium) |
| .copyWith( |
| color: theme.colorScheme.onSurface, |
| decorationColor: theme.colorScheme.onSurface, |
| ), |
| ); |
| expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); |
| expect(tester.getSize(find.byType(AppBar)).width, 800); |
| }); |
| |
| testWidgets('AppBar uses values from AppBarTheme', (WidgetTester tester) async { |
| final AppBarThemeData appBarTheme = _appBarTheme(); |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: appBarTheme), |
| home: Scaffold( |
| appBar: AppBar( |
| title: const Text('App Bar Title'), |
| actions: <Widget>[IconButton(icon: const Icon(Icons.share), onPressed: () {})], |
| ), |
| ), |
| ), |
| ); |
| |
| final Material widget = _getAppBarMaterial(tester); |
| final IconTheme iconTheme = _getAppBarIconTheme(tester); |
| final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); |
| final RichText actionIconText = _getAppBarIconRichText(tester); |
| final DefaultTextStyle text = _getAppBarText(tester); |
| |
| expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.light); |
| expect(widget.color, appBarTheme.backgroundColor); |
| expect(widget.elevation, appBarTheme.elevation); |
| expect(widget.shadowColor, appBarTheme.shadowColor); |
| expect(widget.surfaceTintColor, appBarTheme.surfaceTintColor); |
| expect(widget.shape, const StadiumBorder()); |
| expect(iconTheme.data, appBarTheme.iconTheme); |
| expect(actionsIconTheme.data, appBarTheme.actionsIconTheme); |
| expect(actionIconText.text.style!.color, appBarTheme.actionsIconTheme!.color); |
| expect(text.style, appBarTheme.toolbarTextStyle); |
| expect(tester.getSize(find.byType(AppBar)).height, appBarTheme.toolbarHeight); |
| expect(tester.getSize(find.byType(AppBar)).width, 800); |
| }); |
| |
| testWidgets('AppBar widget properties take priority over theme', (WidgetTester tester) async { |
| const Brightness brightness = Brightness.dark; |
| const SystemUiOverlayStyle systemOverlayStyle = SystemUiOverlayStyle.light; |
| const Color color = Colors.orange; |
| const elevation = 3.0; |
| const Color shadowColor = Colors.purple; |
| const Color surfaceTintColor = Colors.brown; |
| const ShapeBorder shape = RoundedRectangleBorder(); |
| const iconThemeData = IconThemeData(color: Colors.green); |
| const actionsIconThemeData = IconThemeData(color: Colors.lightBlue); |
| const toolbarTextStyle = TextStyle(color: Colors.pink); |
| const titleTextStyle = TextStyle(color: Colors.orange); |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData.from( |
| colorScheme: const ColorScheme.light(), |
| ).copyWith(appBarTheme: _appBarTheme()), |
| home: Scaffold( |
| appBar: AppBar( |
| backgroundColor: color, |
| systemOverlayStyle: systemOverlayStyle, |
| elevation: elevation, |
| shadowColor: shadowColor, |
| surfaceTintColor: surfaceTintColor, |
| shape: shape, |
| iconTheme: iconThemeData, |
| actionsIconTheme: actionsIconThemeData, |
| toolbarTextStyle: toolbarTextStyle, |
| titleTextStyle: titleTextStyle, |
| actions: <Widget>[IconButton(icon: const Icon(Icons.share), onPressed: () {})], |
| ), |
| ), |
| ), |
| ); |
| |
| final Material widget = _getAppBarMaterial(tester); |
| final IconTheme iconTheme = _getAppBarIconTheme(tester); |
| final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); |
| final RichText actionIconText = _getAppBarIconRichText(tester); |
| final DefaultTextStyle text = _getAppBarText(tester); |
| |
| expect(SystemChrome.latestStyle!.statusBarBrightness, brightness); |
| expect(widget.color, color); |
| expect(widget.elevation, elevation); |
| expect(widget.shadowColor, shadowColor); |
| expect(widget.surfaceTintColor, surfaceTintColor); |
| expect(widget.shape, shape); |
| expect(iconTheme.data, iconThemeData); |
| expect(actionsIconTheme.data, actionsIconThemeData); |
| expect(actionIconText.text.style!.color, actionsIconThemeData.color); |
| expect(text.style, toolbarTextStyle); |
| }); |
| |
| testWidgets('AppBar icon color takes priority over everything', (WidgetTester tester) async { |
| const Color color = Colors.lime; |
| const iconThemeData = IconThemeData(color: Colors.green); |
| const actionsIconThemeData = IconThemeData(color: Colors.lightBlue); |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData.from(colorScheme: const ColorScheme.light()), |
| home: Scaffold( |
| appBar: AppBar( |
| iconTheme: iconThemeData, |
| actionsIconTheme: actionsIconThemeData, |
| actions: <Widget>[ |
| IconButton(icon: const Icon(Icons.share), color: color, onPressed: () {}), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| final RichText actionIconText = _getAppBarIconRichText(tester); |
| expect(actionIconText.text.style!.color, color); |
| }); |
| |
| testWidgets('AppBarTheme properties take priority over ThemeData properties', ( |
| WidgetTester tester, |
| ) async { |
| final AppBarThemeData appBarTheme = _appBarTheme(); |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData.from( |
| colorScheme: const ColorScheme.light(), |
| ).copyWith(appBarTheme: _appBarTheme()), |
| home: Scaffold( |
| appBar: AppBar( |
| actions: <Widget>[IconButton(icon: const Icon(Icons.share), onPressed: () {})], |
| ), |
| ), |
| ), |
| ); |
| |
| final Material widget = _getAppBarMaterial(tester); |
| final IconTheme iconTheme = _getAppBarIconTheme(tester); |
| final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); |
| final RichText actionIconText = _getAppBarIconRichText(tester); |
| final DefaultTextStyle text = _getAppBarText(tester); |
| |
| expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.light); |
| expect(widget.color, appBarTheme.backgroundColor); |
| expect(widget.elevation, appBarTheme.elevation); |
| expect(widget.shadowColor, appBarTheme.shadowColor); |
| expect(widget.surfaceTintColor, appBarTheme.surfaceTintColor); |
| expect(iconTheme.data, appBarTheme.iconTheme); |
| expect(actionsIconTheme.data, appBarTheme.actionsIconTheme); |
| expect(actionIconText.text.style!.color, appBarTheme.actionsIconTheme!.color); |
| expect(text.style, appBarTheme.toolbarTextStyle); |
| }); |
| |
| testWidgets('Material2 - ThemeData colorScheme is used when no AppBarTheme is set', ( |
| WidgetTester tester, |
| ) async { |
| final lightTheme = ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: false); |
| final darkTheme = ThemeData.from(colorScheme: const ColorScheme.dark(), useMaterial3: false); |
| Widget buildFrame(ThemeData appTheme) { |
| return MaterialApp( |
| theme: appTheme, |
| home: Builder( |
| builder: (BuildContext context) { |
| return Scaffold( |
| appBar: AppBar( |
| actions: <Widget>[IconButton(icon: const Icon(Icons.share), onPressed: () {})], |
| ), |
| ); |
| }, |
| ), |
| ); |
| } |
| |
| // AppBar M2 defaults for light themes: |
| // - elevation: 4 |
| // - shadow color: black |
| // - surface tint color: null |
| // - background color: ColorScheme.primary |
| // - foreground color: ColorScheme.onPrimary |
| // - actions text: style bodyMedium, foreground color |
| // - status bar brightness: light (based on color scheme brightness) |
| await tester.pumpWidget(buildFrame(lightTheme)); |
| |
| Material widget = _getAppBarMaterial(tester); |
| IconTheme iconTheme = _getAppBarIconTheme(tester); |
| IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); |
| RichText actionIconText = _getAppBarIconRichText(tester); |
| DefaultTextStyle text = _getAppBarText(tester); |
| |
| expect( |
| SystemChrome.latestStyle!.statusBarBrightness, |
| SystemUiOverlayStyle.light.statusBarBrightness, |
| ); |
| expect(widget.color, lightTheme.colorScheme.primary); |
| expect(widget.elevation, 4.0); |
| expect(widget.shadowColor, Colors.black); |
| expect(widget.surfaceTintColor, null); |
| expect(iconTheme.data.color, lightTheme.colorScheme.onPrimary); |
| expect(actionsIconTheme.data.color, lightTheme.colorScheme.onPrimary); |
| expect(actionIconText.text.style!.color, lightTheme.colorScheme.onPrimary); |
| expect( |
| text.style, |
| Typography.material2014().englishLike.bodyMedium! |
| .merge(Typography.material2014().black.bodyMedium) |
| .copyWith(color: lightTheme.colorScheme.onPrimary), |
| ); |
| |
| // AppBar M2 defaults for dark themes: |
| // - elevation: 4 |
| // - shadow color: black |
| // - surface tint color: null |
| // - background color: ColorScheme.surface |
| // - foreground color: ColorScheme.onSurface |
| // - actions text: style bodyMedium, foreground color |
| // - status bar brightness: dark (based on background color) |
| await tester.pumpWidget(buildFrame(darkTheme)); |
| await tester.pumpAndSettle(); // Theme change animation |
| |
| widget = _getAppBarMaterial(tester); |
| iconTheme = _getAppBarIconTheme(tester); |
| actionsIconTheme = _getAppBarActionsIconTheme(tester); |
| actionIconText = _getAppBarIconRichText(tester); |
| text = _getAppBarText(tester); |
| |
| expect( |
| SystemChrome.latestStyle!.statusBarBrightness, |
| SystemUiOverlayStyle.light.statusBarBrightness, |
| ); |
| expect(widget.color, darkTheme.colorScheme.surface); |
| expect(widget.elevation, 4.0); |
| expect(widget.shadowColor, Colors.black); |
| expect(widget.surfaceTintColor, null); |
| expect(iconTheme.data.color, darkTheme.colorScheme.onSurface); |
| expect(actionsIconTheme.data.color, darkTheme.colorScheme.onSurface); |
| expect(actionIconText.text.style!.color, darkTheme.colorScheme.onSurface); |
| expect( |
| text.style, |
| Typography.material2014().englishLike.bodyMedium! |
| .merge(Typography.material2014().black.bodyMedium) |
| .copyWith(color: darkTheme.colorScheme.onSurface), |
| ); |
| }); |
| |
| testWidgets('Material3 - ThemeData colorScheme is used when no AppBarTheme is set', ( |
| WidgetTester tester, |
| ) async { |
| final lightTheme = ThemeData.from(colorScheme: const ColorScheme.light()); |
| final darkTheme = ThemeData.from(colorScheme: const ColorScheme.dark()); |
| Widget buildFrame(ThemeData appTheme) { |
| return MaterialApp( |
| theme: appTheme, |
| home: Builder( |
| builder: (BuildContext context) { |
| return Scaffold( |
| appBar: AppBar( |
| actions: <Widget>[IconButton(icon: const Icon(Icons.share), onPressed: () {})], |
| ), |
| ); |
| }, |
| ), |
| ); |
| } |
| |
| // M3 AppBar defaults for light themes: |
| // - elevation: 0 |
| // - shadow color: Colors.transparent |
| // - surface tint color: ColorScheme.surfaceTint |
| // - background color: ColorScheme.surface |
| // - foreground color: ColorScheme.onSurface |
| // - actions text: style bodyMedium, foreground color |
| // - status bar brightness: light (based on color scheme brightness) |
| await tester.pumpWidget(buildFrame(lightTheme)); |
| |
| Material widget = _getAppBarMaterial(tester); |
| IconTheme iconTheme = _getAppBarIconTheme(tester); |
| IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); |
| RichText actionIconText = _getAppBarIconRichText(tester); |
| DefaultTextStyle text = _getAppBarText(tester); |
| |
| expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.light); |
| expect(widget.color, lightTheme.colorScheme.surface); |
| expect(widget.elevation, 0); |
| expect(widget.shadowColor, Colors.transparent); |
| expect(widget.surfaceTintColor, lightTheme.colorScheme.surfaceTint); |
| expect(iconTheme.data.color, lightTheme.colorScheme.onSurface); |
| expect(actionsIconTheme.data.color, lightTheme.colorScheme.onSurface); |
| expect(actionIconText.text.style!.color, lightTheme.colorScheme.onSurface); |
| expect( |
| text.style, |
| Typography.material2021().englishLike.bodyMedium! |
| .merge(Typography.material2021().black.bodyMedium) |
| .copyWith(color: lightTheme.colorScheme.onSurface), |
| ); |
| |
| // M3 AppBar defaults for dark themes: |
| // - elevation: 0 |
| // - shadow color: Colors.transparent |
| // - surface tint color: ColorScheme.surfaceTint |
| // - background color: ColorScheme.surface |
| // - foreground color: ColorScheme.onSurface |
| // - actions text: style bodyMedium, foreground color |
| // - status bar brightness: dark (based on background color) |
| await tester.pumpWidget(buildFrame(darkTheme)); |
| await tester.pumpAndSettle(); // Theme change animation |
| |
| widget = _getAppBarMaterial(tester); |
| iconTheme = _getAppBarIconTheme(tester); |
| actionsIconTheme = _getAppBarActionsIconTheme(tester); |
| actionIconText = _getAppBarIconRichText(tester); |
| text = _getAppBarText(tester); |
| |
| expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.dark); |
| expect(widget.color, darkTheme.colorScheme.surface); |
| expect(widget.elevation, 0); |
| expect(widget.shadowColor, Colors.transparent); |
| expect(widget.surfaceTintColor, darkTheme.colorScheme.surfaceTint); |
| expect(iconTheme.data.color, darkTheme.colorScheme.onSurface); |
| expect(actionsIconTheme.data.color, darkTheme.colorScheme.onSurface); |
| expect(actionIconText.text.style!.color, darkTheme.colorScheme.onSurface); |
| expect( |
| text.style, |
| Typography.material2021().englishLike.bodyMedium! |
| .merge(Typography.material2021().black.bodyMedium) |
| .copyWith( |
| color: darkTheme.colorScheme.onSurface, |
| decorationColor: darkTheme.colorScheme.onSurface, |
| ), |
| ); |
| }); |
| |
| testWidgets('AppBar iconTheme with color=null defers to outer IconTheme', ( |
| WidgetTester tester, |
| ) async { |
| // Verify claim made in https://github.com/flutter/flutter/pull/71184#issuecomment-737419215 |
| |
| Widget buildFrame({Color? appIconColor, Color? appBarIconColor}) { |
| return MaterialApp( |
| theme: ThemeData.from(colorScheme: const ColorScheme.light()), |
| home: IconTheme( |
| data: IconThemeData(color: appIconColor), |
| child: Builder( |
| builder: (BuildContext context) { |
| return Scaffold( |
| appBar: AppBar( |
| iconTheme: IconThemeData(color: appBarIconColor), |
| actions: <Widget>[IconButton(icon: const Icon(Icons.share), onPressed: () {})], |
| ), |
| ); |
| }, |
| ), |
| ), |
| ); |
| } |
| |
| RichText getIconText() { |
| return tester.widget<RichText>( |
| find.descendant(of: find.byType(Icon), matching: find.byType(RichText)), |
| ); |
| } |
| |
| await tester.pumpWidget(buildFrame(appIconColor: Colors.lime)); |
| await tester.pumpAndSettle(); |
| expect(getIconText().text.style!.color, Colors.lime); |
| |
| await tester.pumpWidget(buildFrame(appIconColor: Colors.lime, appBarIconColor: Colors.purple)); |
| await tester.pumpAndSettle(); |
| expect(getIconText().text.style!.color, Colors.purple); |
| }); |
| |
| testWidgets('AppBar uses AppBarTheme.centerTitle when centerTitle is null', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(centerTitle: true)), |
| home: Scaffold(appBar: AppBar(title: const Text('Title'))), |
| ), |
| ); |
| |
| final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); |
| expect(navToolBar.centerMiddle, true); |
| }); |
| |
| testWidgets('AppBar.centerTitle takes priority over AppBarTheme.centerTitle', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(centerTitle: true)), |
| home: Scaffold(appBar: AppBar(title: const Text('Title'), centerTitle: false)), |
| ), |
| ); |
| |
| final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); |
| // The AppBar.centerTitle should be used instead of AppBarThemeData.centerTitle. |
| expect(navToolBar.centerMiddle, false); |
| }); |
| |
| testWidgets( |
| 'AppBar.centerTitle adapts to TargetPlatform when AppBarThemeData.centerTitle is null', |
| (WidgetTester tester) async { |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(platform: TargetPlatform.iOS), |
| home: Scaffold(appBar: AppBar(title: const Text('Title'))), |
| ), |
| ); |
| |
| final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); |
| // When ThemeData.platform is TargetPlatform.iOS, and AppBarThemeData is null, |
| // the value of NavigationToolBar.centerMiddle should be true. |
| expect(navToolBar.centerMiddle, true); |
| }, |
| ); |
| |
| testWidgets('AppBar.shadowColor takes priority over AppBarThemeData.shadowColor', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(shadowColor: Colors.red)), |
| home: Scaffold( |
| appBar: AppBar(title: const Text('Title'), shadowColor: Colors.yellow), |
| ), |
| ), |
| ); |
| |
| final AppBar appBar = tester.widget(find.byType(AppBar)); |
| // The AppBar.shadowColor should be used instead of AppBarThemeData.shadowColor. |
| expect(appBar.shadowColor, Colors.yellow); |
| }); |
| |
| testWidgets('AppBar.surfaceTintColor takes priority over AppBarThemeData.surfaceTintColor', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(surfaceTintColor: Colors.red)), |
| home: Scaffold( |
| appBar: AppBar(title: const Text('Title'), surfaceTintColor: Colors.yellow), |
| ), |
| ), |
| ); |
| |
| final AppBar appBar = tester.widget(find.byType(AppBar)); |
| // The AppBar.surfaceTintColor should be used instead of AppBarThemeData.surfaceTintColor. |
| expect(appBar.surfaceTintColor, Colors.yellow); |
| }); |
| |
| testWidgets( |
| 'Material3 - AppBarThemeData.iconTheme.color takes priority over IconButtonTheme.foregroundColor', |
| (WidgetTester tester) async { |
| const overallIconTheme = IconThemeData(color: Colors.yellow); |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData( |
| iconButtonTheme: IconButtonThemeData( |
| style: IconButton.styleFrom(foregroundColor: Colors.red), |
| ), |
| appBarTheme: const AppBarThemeData(iconTheme: overallIconTheme), |
| ), |
| home: Scaffold( |
| appBar: AppBar( |
| leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), |
| actions: <Widget>[IconButton(icon: const Icon(Icons.add), onPressed: () {})], |
| title: const Text('Title'), |
| ), |
| ), |
| ), |
| ); |
| |
| final Color? leadingIconButtonColor = _iconStyle(tester, Icons.menu)?.color; |
| final Color? actionIconButtonColor = _iconStyle(tester, Icons.add)?.color; |
| |
| expect(leadingIconButtonColor, overallIconTheme.color); |
| expect(actionIconButtonColor, overallIconTheme.color); |
| }, |
| ); |
| |
| testWidgets( |
| 'Material3 - AppBarThemeData.iconTheme.size takes priority over IconButtonTheme.iconSize', |
| (WidgetTester tester) async { |
| const overallIconTheme = IconThemeData(size: 30.0); |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData( |
| iconButtonTheme: IconButtonThemeData(style: IconButton.styleFrom(iconSize: 32.0)), |
| appBarTheme: const AppBarThemeData(iconTheme: overallIconTheme), |
| ), |
| home: Scaffold( |
| appBar: AppBar( |
| leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), |
| actions: <Widget>[IconButton(icon: const Icon(Icons.add), onPressed: () {})], |
| title: const Text('Title'), |
| ), |
| ), |
| ), |
| ); |
| |
| final double? leadingIconButtonSize = _iconStyle(tester, Icons.menu)?.fontSize; |
| final double? actionIconButtonSize = _iconStyle(tester, Icons.add)?.fontSize; |
| |
| expect(leadingIconButtonSize, overallIconTheme.size); |
| expect(actionIconButtonSize, overallIconTheme.size); |
| }, |
| ); |
| |
| testWidgets( |
| 'Material3 - AppBarThemeData.actionsIconTheme.color takes priority over IconButtonTheme.foregroundColor', |
| (WidgetTester tester) async { |
| const actionsIconTheme = IconThemeData(color: Colors.yellow); |
| final iconButtonTheme = IconButtonThemeData( |
| style: IconButton.styleFrom(foregroundColor: Colors.red), |
| ); |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData( |
| iconButtonTheme: iconButtonTheme, |
| appBarTheme: const AppBarThemeData(actionsIconTheme: actionsIconTheme), |
| ), |
| home: Scaffold( |
| appBar: AppBar( |
| leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), |
| actions: <Widget>[IconButton(icon: const Icon(Icons.add), onPressed: () {})], |
| title: const Text('Title'), |
| ), |
| ), |
| ), |
| ); |
| |
| final Color? leadingIconButtonColor = _iconStyle(tester, Icons.menu)?.color; |
| final Color? actionIconButtonColor = _iconStyle(tester, Icons.add)?.color; |
| |
| expect(leadingIconButtonColor, Colors.red); // leading color should come from iconButtonTheme |
| expect(actionIconButtonColor, actionsIconTheme.color); |
| }, |
| ); |
| |
| testWidgets( |
| 'Material3 - AppBarThemeData.actionsIconTheme.size takes priority over IconButtonTheme.iconSize', |
| (WidgetTester tester) async { |
| const actionsIconTheme = IconThemeData(size: 30.0); |
| final iconButtonTheme = IconButtonThemeData(style: IconButton.styleFrom(iconSize: 32.0)); |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData( |
| iconButtonTheme: iconButtonTheme, |
| appBarTheme: const AppBarThemeData(actionsIconTheme: actionsIconTheme), |
| ), |
| home: Scaffold( |
| appBar: AppBar( |
| leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), |
| actions: <Widget>[IconButton(icon: const Icon(Icons.add), onPressed: () {})], |
| title: const Text('Title'), |
| ), |
| ), |
| ), |
| ); |
| |
| final double? leadingIconButtonSize = _iconStyle(tester, Icons.menu)?.fontSize; |
| final double? actionIconButtonSize = _iconStyle(tester, Icons.add)?.fontSize; |
| |
| expect( |
| leadingIconButtonSize, |
| 32.0, |
| ); // The size of leading icon button should come from iconButtonTheme |
| expect(actionIconButtonSize, actionsIconTheme.size); |
| }, |
| ); |
| |
| testWidgets( |
| 'Material3 - AppBarThemeData.foregroundColor takes priority over IconButtonTheme.foregroundColor', |
| (WidgetTester tester) async { |
| final iconButtonTheme = IconButtonThemeData( |
| style: IconButton.styleFrom(foregroundColor: Colors.red), |
| ); |
| const appBarTheme = AppBarThemeData(foregroundColor: Colors.green); |
| final themeData = ThemeData(iconButtonTheme: iconButtonTheme, appBarTheme: appBarTheme); |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| appBar: AppBar( |
| title: const Text('title'), |
| leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), |
| actions: <Widget>[IconButton(icon: const Icon(Icons.add), onPressed: () {})], |
| ), |
| ), |
| ), |
| ); |
| |
| final Color? leadingIconButtonColor = _iconStyle(tester, Icons.menu)?.color; |
| final Color? actionIconButtonColor = _iconStyle(tester, Icons.add)?.color; |
| |
| expect(leadingIconButtonColor, appBarTheme.foregroundColor); |
| expect(actionIconButtonColor, appBarTheme.foregroundColor); |
| }, |
| ); |
| |
| testWidgets('AppBar uses AppBarThemeData.titleSpacing', (WidgetTester tester) async { |
| const double kTitleSpacing = 10; |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(titleSpacing: kTitleSpacing)), |
| home: Scaffold(appBar: AppBar(title: const Text('Title'))), |
| ), |
| ); |
| |
| final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); |
| expect(navToolBar.middleSpacing, kTitleSpacing); |
| }); |
| |
| testWidgets('AppBar.titleSpacing takes priority over AppBarThemeData.titleSpacing', ( |
| WidgetTester tester, |
| ) async { |
| const double kTitleSpacing = 10; |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(titleSpacing: kTitleSpacing)), |
| home: Scaffold(appBar: AppBar(title: const Text('Title'), titleSpacing: 40)), |
| ), |
| ); |
| |
| final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); |
| expect(navToolBar.middleSpacing, 40); |
| }); |
| |
| testWidgets('AppBar uses AppBarThemeData.leadingWidth', (WidgetTester tester) async { |
| const double kLeadingWidth = 80; |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(leadingWidth: kLeadingWidth)), |
| home: Scaffold(appBar: AppBar(leading: const Icon(Icons.chevron_left))), |
| ), |
| ); |
| |
| final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); |
| final BoxConstraints leadingConstraints = (navToolBar.leading! as ConstrainedBox).constraints; |
| expect(leadingConstraints.maxWidth, kLeadingWidth); |
| expect(leadingConstraints.minWidth, kLeadingWidth); |
| }); |
| |
| testWidgets('AppBar.leadingWidth takes priority over AppBarThemeData.leadingWidth', ( |
| WidgetTester tester, |
| ) async { |
| const double kLeadingWidth = 80; |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(leadingWidth: kLeadingWidth)), |
| home: Scaffold(appBar: AppBar(leading: const Icon(Icons.chevron_left), leadingWidth: 40)), |
| ), |
| ); |
| |
| final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); |
| final BoxConstraints leadingConstraints = (navToolBar.leading! as ConstrainedBox).constraints; |
| expect(leadingConstraints.maxWidth, 40); |
| expect(leadingConstraints.minWidth, 40); |
| }); |
| |
| testWidgets('SliverAppBar uses AppBarThemeData.titleSpacing', (WidgetTester tester) async { |
| const double kTitleSpacing = 10; |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(titleSpacing: kTitleSpacing)), |
| home: const CustomScrollView(slivers: <Widget>[SliverAppBar(title: Text('Title'))]), |
| ), |
| ); |
| |
| final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); |
| expect(navToolBar.middleSpacing, kTitleSpacing); |
| }); |
| |
| testWidgets('SliverAppBar.titleSpacing takes priority over AppBarThemeData.titleSpacing ', ( |
| WidgetTester tester, |
| ) async { |
| const double kTitleSpacing = 10; |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(titleSpacing: kTitleSpacing)), |
| home: const CustomScrollView( |
| slivers: <Widget>[SliverAppBar(title: Text('Title'), titleSpacing: 40)], |
| ), |
| ), |
| ); |
| |
| final NavigationToolbar navToolbar = tester.widget(find.byType(NavigationToolbar)); |
| expect(navToolbar.middleSpacing, 40); |
| }); |
| |
| testWidgets('SliverAppBar uses AppBarThemeData.leadingWidth', (WidgetTester tester) async { |
| const double kLeadingWidth = 80; |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(leadingWidth: kLeadingWidth)), |
| home: const CustomScrollView( |
| slivers: <Widget>[SliverAppBar(leading: Icon(Icons.chevron_left))], |
| ), |
| ), |
| ); |
| |
| final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); |
| final BoxConstraints leadingConstraints = (navToolBar.leading! as ConstrainedBox).constraints; |
| expect(leadingConstraints.maxWidth, kLeadingWidth); |
| expect(leadingConstraints.minWidth, kLeadingWidth); |
| }); |
| |
| testWidgets('SliverAppBar.leadingWidth takes priority over AppBarThemeData.leadingWidth ', ( |
| WidgetTester tester, |
| ) async { |
| const double kLeadingWidth = 80; |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: const AppBarThemeData(leadingWidth: kLeadingWidth)), |
| home: const CustomScrollView( |
| slivers: <Widget>[SliverAppBar(leading: Icon(Icons.chevron_left), leadingWidth: 40)], |
| ), |
| ), |
| ); |
| |
| final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); |
| final BoxConstraints leadingConstraints = (navToolBar.leading! as ConstrainedBox).constraints; |
| expect(leadingConstraints.maxWidth, 40); |
| expect(leadingConstraints.minWidth, 40); |
| }); |
| |
| testWidgets('SliverAppBar.medium uses AppBarThemeData properties', (WidgetTester tester) async { |
| const title = 'Medium App Bar'; |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: appBarTheme), |
| home: CustomScrollView( |
| primary: true, |
| slivers: <Widget>[ |
| SliverAppBar.medium( |
| leading: IconButton(onPressed: () {}, icon: const Icon(Icons.menu)), |
| title: const Text(title), |
| actions: <Widget>[IconButton(onPressed: () {}, icon: const Icon(Icons.search))], |
| ), |
| ], |
| ), |
| ), |
| ); |
| |
| // Test title. |
| final RichText titleText = tester.firstWidget(find.byType(RichText)); |
| expect(titleText.text.style!.fontSize, appBarTheme.titleTextStyle!.fontSize); |
| expect(titleText.text.style!.fontStyle, appBarTheme.titleTextStyle!.fontStyle); |
| |
| // Test background color, shadow color, and shape. |
| final Material material = tester.widget<Material>( |
| find.descendant(of: find.byType(SliverAppBar), matching: find.byType(Material).first), |
| ); |
| expect(material.color, appBarTheme.backgroundColor); |
| expect(material.shadowColor, appBarTheme.shadowColor); |
| expect(material.shape, appBarTheme.shape); |
| |
| final RichText actionIcon = tester.widget(find.byType(RichText).last); |
| expect(actionIcon.text.style!.color, appBarTheme.actionsIconTheme!.color); |
| |
| // Scroll to collapse the SliverAppBar. |
| final ScrollController controller = primaryScrollController(tester); |
| controller.jumpTo(120); |
| await tester.pumpAndSettle(); |
| |
| // Test title spacing. |
| final Finder collapsedTitle = find.text(title).last; |
| final Offset titleOffset = tester.getTopLeft(collapsedTitle); |
| final Offset iconOffset = tester.getTopRight( |
| find.ancestor( |
| of: find.widgetWithIcon(IconButton, Icons.menu), |
| matching: find.byType(ConstrainedBox), |
| ), |
| ); |
| expect(titleOffset.dx, iconOffset.dx + appBarTheme.titleSpacing!); |
| }); |
| |
| testWidgets('SliverAppBar.medium properties take priority over AppBarThemeData properties', ( |
| WidgetTester tester, |
| ) async { |
| const title = 'Medium App Bar'; |
| const backgroundColor = Color(0xff000099); |
| const foregroundColor = Color(0xff00ff98); |
| const shadowColor = Color(0xff00ff97); |
| const ShapeBorder shape = RoundedRectangleBorder( |
| borderRadius: BorderRadiusDirectional.only(bottomStart: Radius.circular(12.0)), |
| ); |
| const iconTheme = IconThemeData(color: Color(0xff00ff96)); |
| const actionsIconTheme = IconThemeData(color: Color(0xff00ff95)); |
| const titleSpacing = 18.0; |
| const titleTextStyle = TextStyle(fontSize: 22.9, fontStyle: FontStyle.italic); |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: appBarTheme), |
| home: CustomScrollView( |
| primary: true, |
| slivers: <Widget>[ |
| SliverAppBar.medium( |
| centerTitle: false, |
| backgroundColor: backgroundColor, |
| foregroundColor: foregroundColor, |
| shadowColor: shadowColor, |
| shape: shape, |
| iconTheme: iconTheme, |
| actionsIconTheme: actionsIconTheme, |
| titleSpacing: titleSpacing, |
| titleTextStyle: titleTextStyle, |
| leading: IconButton(onPressed: () {}, icon: const Icon(Icons.menu)), |
| title: const Text(title), |
| actions: <Widget>[IconButton(onPressed: () {}, icon: const Icon(Icons.search))], |
| ), |
| ], |
| ), |
| ), |
| ); |
| |
| // Test title. |
| final RichText titleText = tester.firstWidget(find.byType(RichText)); |
| expect(titleText.text.style, titleTextStyle); |
| |
| // Test background color, shadow color, and shape. |
| final Material material = tester.widget<Material>( |
| find.descendant(of: find.byType(SliverAppBar), matching: find.byType(Material).first), |
| ); |
| expect(material.color, backgroundColor); |
| expect(material.shadowColor, shadowColor); |
| expect(material.shape, shape); |
| |
| final RichText actionIcon = tester.widget(find.byType(RichText).last); |
| expect(actionIcon.text.style!.color, actionsIconTheme.color); |
| |
| // Scroll to collapse the SliverAppBar. |
| final ScrollController controller = primaryScrollController(tester); |
| controller.jumpTo(120); |
| await tester.pumpAndSettle(); |
| |
| // Test title spacing. |
| final Finder collapsedTitle = find.text(title).last; |
| final Offset titleOffset = tester.getTopLeft(collapsedTitle); |
| final Offset iconOffset = tester.getTopRight( |
| find.ancestor( |
| of: find.widgetWithIcon(IconButton, Icons.menu), |
| matching: find.byType(ConstrainedBox), |
| ), |
| ); |
| expect(titleOffset.dx, iconOffset.dx + titleSpacing); |
| }); |
| |
| testWidgets('SliverAppBar.large uses AppBarThemeData properties', (WidgetTester tester) async { |
| const title = 'Large App Bar'; |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: appBarTheme), |
| home: CustomScrollView( |
| primary: true, |
| slivers: <Widget>[ |
| SliverAppBar.large( |
| leading: IconButton(onPressed: () {}, icon: const Icon(Icons.menu)), |
| title: const Text(title), |
| actions: <Widget>[IconButton(onPressed: () {}, icon: const Icon(Icons.search))], |
| ), |
| ], |
| ), |
| ), |
| ); |
| |
| // Test title. |
| final RichText titleText = tester.firstWidget(find.byType(RichText)); |
| expect(titleText.text.style!.fontSize, appBarTheme.titleTextStyle!.fontSize); |
| expect(titleText.text.style!.fontStyle, appBarTheme.titleTextStyle!.fontStyle); |
| |
| // Test background color, shadow color, and shape. |
| final Material material = tester.widget<Material>( |
| find.descendant(of: find.byType(SliverAppBar), matching: find.byType(Material).first), |
| ); |
| expect(material.color, appBarTheme.backgroundColor); |
| expect(material.shadowColor, appBarTheme.shadowColor); |
| expect(material.shape, appBarTheme.shape); |
| |
| final RichText actionIcon = tester.widget(find.byType(RichText).last); |
| expect(actionIcon.text.style!.color, appBarTheme.actionsIconTheme!.color); |
| |
| // Scroll to collapse the SliverAppBar. |
| final ScrollController controller = primaryScrollController(tester); |
| controller.jumpTo(120); |
| await tester.pumpAndSettle(); |
| |
| // Test title spacing. |
| final Finder collapsedTitle = find.text(title).last; |
| final Offset titleOffset = tester.getTopLeft(collapsedTitle); |
| final Offset iconOffset = tester.getTopRight( |
| find.ancestor( |
| of: find.widgetWithIcon(IconButton, Icons.menu), |
| matching: find.byType(ConstrainedBox), |
| ), |
| ); |
| expect(titleOffset.dx, iconOffset.dx + appBarTheme.titleSpacing!); |
| }); |
| |
| testWidgets('SliverAppBar.large properties take priority over AppBarThemeData properties', ( |
| WidgetTester tester, |
| ) async { |
| const title = 'Large App Bar'; |
| const backgroundColor = Color(0xff000099); |
| const foregroundColor = Color(0xff00ff98); |
| const shadowColor = Color(0xff00ff97); |
| const ShapeBorder shape = RoundedRectangleBorder( |
| borderRadius: BorderRadiusDirectional.only(bottomStart: Radius.circular(12.0)), |
| ); |
| const iconTheme = IconThemeData(color: Color(0xff00ff96)); |
| const actionsIconTheme = IconThemeData(color: Color(0xff00ff95)); |
| const titleSpacing = 18.0; |
| const titleTextStyle = TextStyle(fontSize: 22.9, fontStyle: FontStyle.italic); |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: appBarTheme), |
| home: CustomScrollView( |
| primary: true, |
| slivers: <Widget>[ |
| SliverAppBar.large( |
| centerTitle: false, |
| backgroundColor: backgroundColor, |
| foregroundColor: foregroundColor, |
| shadowColor: shadowColor, |
| shape: shape, |
| iconTheme: iconTheme, |
| actionsIconTheme: actionsIconTheme, |
| titleSpacing: titleSpacing, |
| titleTextStyle: titleTextStyle, |
| leading: IconButton(onPressed: () {}, icon: const Icon(Icons.menu)), |
| title: const Text(title), |
| actions: <Widget>[IconButton(onPressed: () {}, icon: const Icon(Icons.search))], |
| ), |
| ], |
| ), |
| ), |
| ); |
| |
| // Test title. |
| final RichText titleText = tester.firstWidget(find.byType(RichText)); |
| expect(titleText.text.style, titleTextStyle); |
| |
| // Test background color, shadow color, and shape. |
| final Material material = tester.widget<Material>( |
| find.descendant(of: find.byType(SliverAppBar), matching: find.byType(Material).first), |
| ); |
| expect(material.color, backgroundColor); |
| expect(material.shadowColor, shadowColor); |
| expect(material.shape, shape); |
| |
| final RichText actionIcon = tester.widget(find.byType(RichText).last); |
| expect(actionIcon.text.style!.color, actionsIconTheme.color); |
| |
| // Scroll to collapse the SliverAppBar. |
| final ScrollController controller = primaryScrollController(tester); |
| controller.jumpTo(120); |
| await tester.pumpAndSettle(); |
| |
| // Test title spacing. |
| final Finder collapsedTitle = find.text(title).last; |
| final Offset titleOffset = tester.getTopLeft(collapsedTitle); |
| final Offset iconOffset = tester.getTopRight( |
| find.ancestor( |
| of: find.widgetWithIcon(IconButton, Icons.menu), |
| matching: find.byType(ConstrainedBox), |
| ), |
| ); |
| expect(titleOffset.dx, iconOffset.dx + titleSpacing); |
| }); |
| |
| testWidgets('SliverAppBar medium & large supports foregroundColor', (WidgetTester tester) async { |
| const title = 'AppBar title'; |
| const appBarTheme = AppBarThemeData(foregroundColor: Color(0xff00ff20)); |
| const foregroundColor = Color(0xff001298); |
| |
| Widget buildWidget({Color? color, AppBarThemeData? appBarTheme}) { |
| return MaterialApp( |
| theme: ThemeData(appBarTheme: appBarTheme), |
| home: CustomScrollView( |
| primary: true, |
| slivers: <Widget>[ |
| SliverAppBar.medium(foregroundColor: color, title: const Text(title)), |
| SliverAppBar.large(foregroundColor: color, title: const Text(title)), |
| ], |
| ), |
| ); |
| } |
| |
| await tester.pumpWidget(buildWidget(appBarTheme: appBarTheme)); |
| |
| // Test AppBarThemeData.foregroundColor parameter. |
| RichText mediumTitle = tester.widget(find.byType(RichText).first); |
| expect(mediumTitle.text.style!.color, appBarTheme.foregroundColor); |
| RichText largeTitle = tester.widget(find.byType(RichText).first); |
| expect(largeTitle.text.style!.color, appBarTheme.foregroundColor); |
| |
| await tester.pumpWidget(buildWidget(color: foregroundColor, appBarTheme: appBarTheme)); |
| |
| // Test foregroundColor parameter. |
| mediumTitle = tester.widget(find.byType(RichText).first); |
| expect(mediumTitle.text.style!.color, foregroundColor); |
| largeTitle = tester.widget(find.byType(RichText).first); |
| expect(largeTitle.text.style!.color, foregroundColor); |
| }); |
| |
| testWidgets('Default AppBarThemeData debugFillProperties', (WidgetTester tester) async { |
| final builder = DiagnosticPropertiesBuilder(); |
| const AppBarThemeData().debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect(description, <String>[]); |
| }); |
| |
| testWidgets('AppBarThemeData implements debugFillProperties', (WidgetTester tester) async { |
| final builder = DiagnosticPropertiesBuilder(); |
| const AppBarThemeData( |
| backgroundColor: Color(0xff000000), |
| foregroundColor: Color(0xff000001), |
| elevation: 8.0, |
| scrolledUnderElevation: 3, |
| shadowColor: Color(0xff000002), |
| surfaceTintColor: Color(0xff000003), |
| shape: StadiumBorder(), |
| iconTheme: IconThemeData(color: Color(0xff000004)), |
| actionsIconTheme: IconThemeData(color: Color(0xff000004)), |
| centerTitle: true, |
| titleSpacing: 40.0, |
| leadingWidth: 96, |
| toolbarHeight: 96, |
| toolbarTextStyle: TextStyle(color: Color(0xff000005)), |
| titleTextStyle: TextStyle(color: Color(0xff000006)), |
| systemOverlayStyle: SystemUiOverlayStyle(systemNavigationBarColor: Color(0xff000007)), |
| actionsPadding: EdgeInsets.symmetric(horizontal: 8.0), |
| ).debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect( |
| description, |
| equalsIgnoringHashCodes(<String>[ |
| 'backgroundColor: ${const Color(0xff000000)}', |
| 'foregroundColor: ${const Color(0xff000001)}', |
| 'elevation: 8.0', |
| 'scrolledUnderElevation: 3.0', |
| 'shadowColor: ${const Color(0xff000002)}', |
| 'surfaceTintColor: ${const Color(0xff000003)}', |
| 'shape: StadiumBorder(BorderSide(width: 0.0, style: none))', |
| 'iconTheme: IconThemeData#00000(color: ${const Color(0xff000004)})', |
| 'actionsIconTheme: IconThemeData#00000(color: ${const Color(0xff000004)})', |
| 'centerTitle: true', |
| 'titleSpacing: 40.0', |
| 'leadingWidth: 96.0', |
| 'toolbarHeight: 96.0', |
| 'toolbarTextStyle: TextStyle(inherit: true, color: ${const Color(0xff000005)})', |
| 'titleTextStyle: TextStyle(inherit: true, color: ${const Color(0xff000006)})', |
| 'systemOverlayStyle: SystemUiOverlayStyle(systemNavigationBarColor: ${const Color(0xff000007)})', |
| 'actionsPadding: EdgeInsets(8.0, 0.0, 8.0, 0.0)', |
| ]), |
| ); |
| |
| // On the web, Dart doubles and ints are backed by the same kind of object because |
| // JavaScript does not support integers. So, the Dart double "4.0" is identical |
| // to "4", which results in the web evaluating to the value "4" regardless of which |
| // one is used. This results in a difference for doubles in debugFillProperties between |
| // the web and the rest of Flutter's target platforms. |
| }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/87364 |
| |
| testWidgets('Local AppBarTheme overrides defaults', (WidgetTester tester) async { |
| const Color backgroundColor = Colors.blueAccent; |
| const Color foregroundColor = Colors.white; |
| const elevation = 1.0; |
| const scrolledUnderElevation = 2.0; |
| const Color shadowColor = Colors.black87; |
| const Color surfaceTintColor = Colors.transparent; |
| const ShapeBorder shape = RoundedRectangleBorder(); |
| const iconTheme = IconThemeData(color: Colors.red); |
| const actionsIconTheme = IconThemeData(color: Color(0xFF6750A4)); |
| const centerTitle = true; |
| const titleSpacing = 20.0; |
| const leadingWidth = 80.0; |
| const toolbarHeight = 100.0; |
| const toolbarTextStyle = TextStyle(color: Colors.yellow); |
| const titleTextStyle = TextStyle(color: Colors.orange); |
| const SystemUiOverlayStyle systemOverlayStyle = SystemUiOverlayStyle.dark; |
| const EdgeInsetsGeometry actionsPadding = EdgeInsets.all(8); |
| |
| const appbarThemeData = AppBarThemeData( |
| backgroundColor: backgroundColor, |
| foregroundColor: foregroundColor, |
| elevation: elevation, |
| scrolledUnderElevation: scrolledUnderElevation, |
| shadowColor: shadowColor, |
| surfaceTintColor: surfaceTintColor, |
| shape: shape, |
| iconTheme: iconTheme, |
| actionsIconTheme: actionsIconTheme, |
| centerTitle: centerTitle, |
| titleSpacing: titleSpacing, |
| leadingWidth: leadingWidth, |
| toolbarHeight: toolbarHeight, |
| toolbarTextStyle: toolbarTextStyle, |
| titleTextStyle: titleTextStyle, |
| systemOverlayStyle: systemOverlayStyle, |
| actionsPadding: actionsPadding, |
| ); |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| home: AppBarTheme( |
| data: appbarThemeData, |
| child: Scaffold( |
| appBar: AppBar( |
| title: const Text('Title'), |
| leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), |
| actions: <Widget>[IconButton(icon: const Icon(Icons.add), onPressed: () {})], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| final Material material = _getAppBarMaterial(tester); |
| expect(material.color, backgroundColor); |
| expect(material.elevation, elevation); |
| expect(material.shadowColor, shadowColor); |
| expect(material.surfaceTintColor, surfaceTintColor); |
| expect(material.shape, shape); |
| |
| final IconTheme leadingIconTheme = _getAppBarIconTheme(tester); |
| expect(leadingIconTheme.data, iconTheme); |
| |
| final IconTheme actionsIconThemeWidget = _getAppBarActionsIconTheme(tester); |
| expect(actionsIconThemeWidget.data.color, appbarThemeData.actionsIconTheme!.color); |
| expect(actionsIconThemeWidget.data.size, appbarThemeData.actionsIconTheme!.size); |
| |
| final NavigationToolbar navToolbar = tester.widget(find.byType(NavigationToolbar)); |
| expect(navToolbar.centerMiddle, centerTitle); |
| expect(navToolbar.middleSpacing, titleSpacing); |
| |
| final BoxConstraints leadingConstraints = (navToolbar.leading! as ConstrainedBox).constraints; |
| expect(leadingConstraints.maxWidth, leadingWidth); |
| expect(leadingConstraints.minWidth, leadingWidth); |
| |
| expect(tester.getSize(find.byType(AppBar)).height, toolbarHeight); |
| |
| final DefaultTextStyle text = _getAppBarText(tester); |
| expect(text.style, toolbarTextStyle); |
| |
| final RichText titleText = tester.widget<RichText>( |
| find.descendant(of: find.text('Title'), matching: find.byType(RichText)), |
| ); |
| expect(titleText.text.style, titleTextStyle); |
| |
| expect(SystemChrome.latestStyle, systemOverlayStyle); |
| |
| final Padding actionsPaddingWidget = tester.widget<Padding>( |
| find.descendant(of: find.byType(NavigationToolbar), matching: find.byType(Padding).last), |
| ); |
| expect(actionsPaddingWidget.padding, actionsPadding); |
| |
| final Size appBarSize = tester.getSize(find.byType(AppBar)); |
| expect(appBarSize.height, toolbarHeight); |
| }); |
| |
| testWidgets('Local AppBarTheme can override global AppBarTheme', (WidgetTester tester) async { |
| const Color backgroundColor = Colors.blueAccent; |
| const Color foregroundColor = Colors.white; |
| const elevation = 1.0; |
| const scrolledUnderElevation = 2.0; |
| const Color shadowColor = Colors.black87; |
| const Color surfaceTintColor = Colors.transparent; |
| const ShapeBorder shape = RoundedRectangleBorder(); |
| const iconTheme = IconThemeData(color: Colors.red); |
| const actionsIconTheme = IconThemeData(color: Color(0xFF6750A4)); |
| const centerTitle = true; |
| const titleSpacing = 20.0; |
| const leadingWidth = 80.0; |
| const toolbarHeight = 100.0; |
| const toolbarTextStyle = TextStyle(color: Colors.yellow); |
| const titleTextStyle = TextStyle(color: Colors.orange); |
| const SystemUiOverlayStyle systemOverlayStyle = SystemUiOverlayStyle.dark; |
| const EdgeInsetsGeometry actionsPadding = EdgeInsets.all(8); |
| |
| const appbarThemeData = AppBarThemeData( |
| backgroundColor: backgroundColor, |
| foregroundColor: foregroundColor, |
| elevation: elevation, |
| scrolledUnderElevation: scrolledUnderElevation, |
| shadowColor: shadowColor, |
| surfaceTintColor: surfaceTintColor, |
| shape: shape, |
| iconTheme: iconTheme, |
| actionsIconTheme: actionsIconTheme, |
| centerTitle: centerTitle, |
| titleSpacing: titleSpacing, |
| leadingWidth: leadingWidth, |
| toolbarHeight: toolbarHeight, |
| toolbarTextStyle: toolbarTextStyle, |
| titleTextStyle: titleTextStyle, |
| systemOverlayStyle: systemOverlayStyle, |
| actionsPadding: actionsPadding, |
| ); |
| const globalAppbarThemeData = AppBarThemeData( |
| backgroundColor: Colors.red, |
| foregroundColor: Colors.green, |
| elevation: 0.0, |
| scrolledUnderElevation: 0.0, |
| shadowColor: Colors.blue, |
| surfaceTintColor: Colors.yellow, |
| shape: RoundedRectangleBorder(), |
| iconTheme: IconThemeData(color: Colors.black), |
| actionsIconTheme: IconThemeData(color: Colors.purple), |
| centerTitle: false, |
| titleSpacing: 10.0, |
| leadingWidth: 50.0, |
| toolbarHeight: 50.0, |
| toolbarTextStyle: TextStyle(color: Colors.white), |
| titleTextStyle: TextStyle(color: Colors.black), |
| systemOverlayStyle: SystemUiOverlayStyle.light, |
| actionsPadding: EdgeInsets.zero, |
| ); |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: ThemeData(appBarTheme: globalAppbarThemeData), |
| home: AppBarTheme( |
| data: appbarThemeData, |
| child: Scaffold( |
| appBar: AppBar( |
| title: const Text('Title'), |
| leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), |
| actions: <Widget>[IconButton(icon: const Icon(Icons.add), onPressed: () {})], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| final Material material = _getAppBarMaterial(tester); |
| expect(material.color, backgroundColor); |
| expect(material.elevation, elevation); |
| expect(material.shadowColor, shadowColor); |
| expect(material.surfaceTintColor, surfaceTintColor); |
| expect(material.shape, shape); |
| |
| final IconTheme leadingIconTheme = _getAppBarIconTheme(tester); |
| expect(leadingIconTheme.data, iconTheme); |
| |
| final IconTheme actionsIconThemeWidget = _getAppBarActionsIconTheme(tester); |
| expect(actionsIconThemeWidget.data.color, appbarThemeData.actionsIconTheme!.color); |
| expect(actionsIconThemeWidget.data.size, appbarThemeData.actionsIconTheme!.size); |
| |
| final NavigationToolbar navToolbar = tester.widget(find.byType(NavigationToolbar)); |
| expect(navToolbar.centerMiddle, centerTitle); |
| expect(navToolbar.middleSpacing, titleSpacing); |
| |
| final BoxConstraints leadingConstraints = (navToolbar.leading! as ConstrainedBox).constraints; |
| expect(leadingConstraints.maxWidth, leadingWidth); |
| expect(leadingConstraints.minWidth, leadingWidth); |
| |
| expect(tester.getSize(find.byType(AppBar)).height, toolbarHeight); |
| |
| final DefaultTextStyle text = _getAppBarText(tester); |
| expect(text.style, toolbarTextStyle); |
| |
| final RichText titleText = tester.widget<RichText>( |
| find.descendant(of: find.text('Title'), matching: find.byType(RichText)), |
| ); |
| expect(titleText.text.style, titleTextStyle); |
| |
| expect(SystemChrome.latestStyle, systemOverlayStyle); |
| |
| final Padding actionsPaddingWidget = tester.widget<Padding>( |
| find.descendant(of: find.byType(NavigationToolbar), matching: find.byType(Padding).last), |
| ); |
| expect(actionsPaddingWidget.padding, actionsPadding); |
| |
| final Size appBarSize = tester.getSize(find.byType(AppBar)); |
| expect(appBarSize.height, toolbarHeight); |
| }); |
| |
| // This is a regression test for https://github.com/flutter/flutter/issues/130485. |
| testWidgets( |
| 'Material3 - AppBarThemeData.iconTheme correctly applies custom white color in dark mode', |
| (WidgetTester tester) async { |
| final themeData = ThemeData( |
| brightness: Brightness.dark, |
| appBarTheme: const AppBarThemeData(iconTheme: IconThemeData(color: Colors.white)), |
| ); |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| appBar: AppBar( |
| leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), |
| actions: <Widget>[IconButton(icon: const Icon(Icons.add), onPressed: () {})], |
| ), |
| ), |
| ), |
| ); |
| |
| Color? leadingIconButtonColor() => _iconStyle(tester, Icons.menu)?.color; |
| Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; |
| |
| expect(leadingIconButtonColor(), Colors.white); |
| expect(actionIconButtonColor(), Colors.white); |
| }, |
| ); |
| } |
| |
| AppBarThemeData _appBarTheme() { |
| const SystemUiOverlayStyle systemOverlayStyle = SystemUiOverlayStyle.dark; |
| const Color backgroundColor = Colors.lightBlue; |
| const elevation = 6.0; |
| const Color shadowColor = Colors.red; |
| const Color surfaceTintColor = Colors.green; |
| const iconThemeData = IconThemeData(color: Colors.black); |
| const actionsIconThemeData = IconThemeData(color: Colors.pink); |
| return const AppBarThemeData( |
| actionsIconTheme: actionsIconThemeData, |
| systemOverlayStyle: systemOverlayStyle, |
| backgroundColor: backgroundColor, |
| elevation: elevation, |
| shadowColor: shadowColor, |
| surfaceTintColor: surfaceTintColor, |
| shape: StadiumBorder(), |
| iconTheme: iconThemeData, |
| toolbarHeight: 96, |
| toolbarTextStyle: TextStyle(color: Colors.yellow), |
| titleTextStyle: TextStyle(color: Colors.pink), |
| ); |
| } |
| |
| Material _getAppBarMaterial(WidgetTester tester) { |
| return tester.widget<Material>( |
| find.descendant(of: find.byType(AppBar), matching: find.byType(Material)).first, |
| ); |
| } |
| |
| IconTheme _getAppBarIconTheme(WidgetTester tester) { |
| return tester.widget<IconTheme>( |
| find.descendant(of: find.byType(AppBar), matching: find.byType(IconTheme)).first, |
| ); |
| } |
| |
| IconTheme _getAppBarActionsIconTheme(WidgetTester tester) { |
| return tester.widget<IconTheme>( |
| find.descendant(of: find.byType(NavigationToolbar), matching: find.byType(IconTheme)).first, |
| ); |
| } |
| |
| RichText _getAppBarIconRichText(WidgetTester tester) { |
| return tester.widget<RichText>( |
| find.descendant(of: find.byType(Icon), matching: find.byType(RichText)).first, |
| ); |
| } |
| |
| DefaultTextStyle _getAppBarText(WidgetTester tester) { |
| return tester.widget<DefaultTextStyle>( |
| find |
| .descendant( |
| of: find.byType(CustomSingleChildLayout), |
| matching: find.byType(DefaultTextStyle), |
| ) |
| .first, |
| ); |
| } |
| |
| TextStyle? _iconStyle(WidgetTester tester, IconData icon) { |
| final RichText iconRichText = tester.widget<RichText>( |
| find.descendant(of: find.byIcon(icon).first, matching: find.byType(RichText)), |
| ); |
| return iconRichText.text.style; |
| } |