diff --git a/packages/flutter/lib/src/material/user_accounts_drawer_header.dart b/packages/flutter/lib/src/material/user_accounts_drawer_header.dart index 1558929c456..d793a8515a0 100644 --- a/packages/flutter/lib/src/material/user_accounts_drawer_header.dart +++ b/packages/flutter/lib/src/material/user_accounts_drawer_header.dart @@ -10,7 +10,6 @@ import 'debug.dart'; import 'drawer_header.dart'; import 'icons.dart'; import 'ink_well.dart'; -import 'material_localizations.dart'; import 'theme.dart'; class _AccountPictures extends StatelessWidget { @@ -36,10 +35,7 @@ class _AccountPictures extends StatelessWidget { margin: const EdgeInsetsDirectional.only(start: 16.0), width: 40.0, height: 40.0, - child: new Semantics( - container: true, - child: picture, - ), + child: picture ); }).toList(), ), @@ -49,7 +45,7 @@ class _AccountPictures extends StatelessWidget { child: new SizedBox( width: 72.0, height: 72.0, - child: currentAccountPicture, + child: currentAccountPicture ), ), ], @@ -71,72 +67,62 @@ class _AccountDetails extends StatelessWidget { final VoidCallback onTap; final bool isOpen; + Widget addDropdownIcon(Widget line) { + final Widget icon = new Icon( + isOpen ? Icons.arrow_drop_up : Icons.arrow_drop_down, + color: Colors.white + ); + return new Expanded( + child: new Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: line == null ? [icon] : [ + new Expanded(child: line), + icon, + ], + ), + ); + } + @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - final MaterialLocalizations localizations = MaterialLocalizations.of(context); - final Widget accountNameLine = accountName == null ? null : new DefaultTextStyle( + Widget accountNameLine = accountName == null ? null : new DefaultTextStyle( style: theme.primaryTextTheme.body2, overflow: TextOverflow.ellipsis, child: accountName, ); - final Widget accountEmailLine = accountEmail == null ? null : new DefaultTextStyle( + Widget accountEmailLine = accountEmail == null ? null : new DefaultTextStyle( style: theme.primaryTextTheme.body1, overflow: TextOverflow.ellipsis, child: accountEmail, ); - - final List rowChildren = []; - - if (accountEmailLine != null || accountNameLine != null) { - rowChildren.add( - new Expanded( - flex: 1, - child: new Padding( - padding: const EdgeInsets.fromLTRB(16.0, 8.0, 0.0, 8.0), - child: new Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: (accountEmailLine != null && accountNameLine != null) - ? [accountNameLine, accountEmailLine] - : [accountNameLine ?? accountEmailLine], - ), - ), - ), - ); - } - - const double kAccountDetailsHeight = 56.0; - if (onTap != null) { - rowChildren.add( - new InkWell( - onTap: onTap, - child: new Semantics( - button: true, - child: new SizedBox( - height: kAccountDetailsHeight, - width: kAccountDetailsHeight, // make it a square - child: new Center( - child: new Icon( - isOpen ? Icons.arrow_drop_up : Icons.arrow_drop_down, - color: Colors.white, - semanticLabel: isOpen - ? localizations.hideAccountsLabel - : localizations.showAccountsLabel, - ), - ), - ), - ), + if (accountEmailLine != null) + accountEmailLine = addDropdownIcon(accountEmailLine); + else + accountNameLine = addDropdownIcon(accountNameLine); + } + + Widget accountDetails; + if (accountEmailLine != null || accountNameLine != null) { + accountDetails = new Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: (accountEmailLine != null && accountNameLine != null) + ? [accountNameLine, accountEmailLine] + : [accountNameLine ?? accountEmailLine] ), ); } + if (onTap != null) + accountDetails = new InkWell(onTap: onTap, child: accountDetails); + return new SizedBox( - height: kAccountDetailsHeight, - child: new Row( - children: rowChildren, - ), + height: 56.0, + child: accountDetails, ); } } @@ -161,7 +147,7 @@ class UserAccountsDrawerHeader extends StatefulWidget { this.otherAccountsPictures, @required this.accountName, @required this.accountEmail, - this.onDetailsPressed, + this.onDetailsPressed }) : super(key: key); /// The header's background. If decoration is null then a [BoxDecoration] @@ -214,32 +200,24 @@ class _UserAccountsDrawerHeaderState extends State { color: Theme.of(context).primaryColor, ), margin: widget.margin, - padding: EdgeInsets.zero, child: new SafeArea( bottom: false, - child: new Semantics( - container: true, - label: 'Signed in', - child: new Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - new Expanded( - child: new Padding( - padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0), - child: new _AccountPictures( - currentAccountPicture: widget.currentAccountPicture, - otherAccountsPictures: widget.otherAccountsPictures, - ), - ), - ), - new _AccountDetails( - accountName: widget.accountName, - accountEmail: widget.accountEmail, - isOpen: _isOpen, - onTap: widget.onDetailsPressed == null ? null : _handleDetailsPressed, - ), - ], - ), + child: new Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + new Expanded( + child: new _AccountPictures( + currentAccountPicture: widget.currentAccountPicture, + otherAccountsPictures: widget.otherAccountsPictures, + ) + ), + new _AccountDetails( + accountName: widget.accountName, + accountEmail: widget.accountEmail, + isOpen: _isOpen, + onTap: widget.onDetailsPressed == null ? null : _handleDetailsPressed, + ), + ], ), ), ); diff --git a/packages/flutter/test/material/user_accounts_drawer_header_test.dart b/packages/flutter/test/material/user_accounts_drawer_header_test.dart index a68288a371f..f18956eb12a 100644 --- a/packages/flutter/test/material/user_accounts_drawer_header_test.dart +++ b/packages/flutter/test/material/user_accounts_drawer_header_test.dart @@ -2,71 +2,58 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui'; - import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter_test/flutter_test.dart' hide TypeMatcher; +import 'package:flutter_test/flutter_test.dart'; -import '../widgets/semantics_tester.dart'; +void main() { + testWidgets('UserAccountsDrawerHeader test', (WidgetTester tester) async { + final Key avatarA = const Key('A'); + final Key avatarC = const Key('C'); + final Key avatarD = const Key('D'); -const Key avatarA = const Key('A'); -const Key avatarC = const Key('C'); -const Key avatarD = const Key('D'); - -Future pumpTestWidget(WidgetTester tester, { - bool withName: true, - bool withEmail: true, - bool withOnDetailsPressedHandler: true, -}) async { - await tester.pumpWidget( - new MaterialApp( - home: new MediaQuery( - data: const MediaQueryData( - padding: const EdgeInsets.only( - left: 10.0, - top: 20.0, - right: 30.0, - bottom: 40.0, + await tester.pumpWidget( + new MaterialApp( + home: new MediaQuery( + data: const MediaQueryData( + padding: const EdgeInsets.only( + left: 10.0, + top: 20.0, + right: 30.0, + bottom: 40.0, + ), ), - ), - child: new Material( - child: new Center( - child: new UserAccountsDrawerHeader( - onDetailsPressed: withOnDetailsPressedHandler ? () {} : null, - currentAccountPicture: const CircleAvatar( - key: avatarA, - child: const Text('A'), + child: new Material( + child: new Center( + child: new UserAccountsDrawerHeader( + currentAccountPicture: new CircleAvatar( + key: avatarA, + child: const Text('A'), + ), + otherAccountsPictures: [ + const CircleAvatar( + child: const Text('B'), + ), + new CircleAvatar( + key: avatarC, + child: const Text('C'), + ), + new CircleAvatar( + key: avatarD, + child: const Text('D'), + ), + const CircleAvatar( + child: const Text('E'), + ) + ], + accountName: const Text('name'), + accountEmail: const Text('email'), ), - otherAccountsPictures: [ - const CircleAvatar( - child: const Text('B'), - ), - const CircleAvatar( - key: avatarC, - child: const Text('C'), - ), - const CircleAvatar( - key: avatarD, - child: const Text('D'), - ), - const CircleAvatar( - child: const Text('E'), - ) - ], - accountName: withName ? const Text('name') : null, - accountEmail: withEmail ? const Text('email') : null, ), ), ), ), - ), - ); -} - -void main() { - testWidgets('UserAccountsDrawerHeader layout', (WidgetTester tester) async { - await pumpTestWidget(tester); + ); expect(find.text('A'), findsOneWidget); expect(find.text('B'), findsOneWidget); @@ -139,8 +126,6 @@ void main() { )); expect(find.byType(Icon), findsOneWidget); - // When either email or account name (but not both!) are present, the icon - // is center aligned with the text displaying the email/name. await tester.pumpWidget(buildFrame( accountName: const Text('accountName'), onDetailsPressed: () { }, @@ -159,16 +144,13 @@ void main() { tester.getCenter(find.byType(Icon)).dy ); - // When _both_ email and account name are present, the icon is placed in the - // center of the entire row. It's not aligned with text any more. await tester.pumpWidget(buildFrame( accountName: const Text('accountName'), accountEmail: const Text('accountEmail'), onDetailsPressed: () { }, )); - final RenderFlex row = tester.element(find.text('accountEmail')).ancestorRenderObjectOfType(const TypeMatcher()); expect( - row.localToGlobal(row.size.center(Offset.zero)).dy, + tester.getCenter(find.text('accountEmail')).dy, tester.getCenter(find.byType(Icon)).dy ); expect( @@ -204,83 +186,4 @@ void main() { greaterThan(tester.getBottomLeft(find.byKey(avatarA)).dy) ); }); - - testWidgets('UserAccountsDrawerHeader provides semantics', (WidgetTester tester) async { - final SemanticsTester semantics = new SemanticsTester(tester); - await pumpTestWidget(tester); - expect( - semantics, - hasSemantics( - new TestSemantics( - children: [ - new TestSemantics( - label: 'Signed in\nA\nname\nemail', - textDirection: TextDirection.ltr, - children: [ - new TestSemantics( - label: r'B', - textDirection: TextDirection.ltr, - ), - new TestSemantics( - label: r'C', - textDirection: TextDirection.ltr, - ), - new TestSemantics( - label: r'D', - textDirection: TextDirection.ltr, - ), - new TestSemantics( - flags: [SemanticsFlags.isButton], - actions: [SemanticsAction.tap], - label: r'Show accounts', - textDirection: TextDirection.ltr, - ), - ], - ), - ], - ), - ignoreId: true, ignoreTransform: true, ignoreRect: true, - ), - ); - semantics.dispose(); - }); - - testWidgets('UserAccountsDrawerHeader provides semantics with missing properties', (WidgetTester tester) async { - final SemanticsTester semantics = new SemanticsTester(tester); - await pumpTestWidget( - tester, - withEmail: false, - withName: false, - withOnDetailsPressedHandler: false, - ); - expect( - semantics, - hasSemantics( - new TestSemantics( - children: [ - new TestSemantics( - label: 'Signed in\nA', - textDirection: TextDirection.ltr, - children: [ - new TestSemantics( - label: r'B', - textDirection: TextDirection.ltr, - ), - new TestSemantics( - label: r'C', - textDirection: TextDirection.ltr, - ), - new TestSemantics( - label: r'D', - textDirection: TextDirection.ltr, - ), - ], - ), - ], - ), - ignoreId: true, ignoreTransform: true, ignoreRect: true, - ), - ); - semantics.dispose(); - }); }