user_accounts_drawer_header.dart 6.56 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:flutter/foundation.dart';
6
import 'package:flutter/widgets.dart';
7

8
import 'colors.dart';
9
import 'debug.dart';
10 11 12 13
import 'drawer_header.dart';
import 'icons.dart';
import 'ink_well.dart';
import 'theme.dart';
14

15
class _AccountPictures extends StatelessWidget {
16
  const _AccountPictures({
17 18 19 20 21 22 23 24 25 26 27 28
    Key key,
    this.currentAccountPicture,
    this.otherAccountsPictures,
  }) : super(key: key);

  final Widget currentAccountPicture;
  final List<Widget> otherAccountsPictures;

  @override
  Widget build(BuildContext context) {
    return new Stack(
      children: <Widget>[
29
        new PositionedDirectional(
30
          top: 0.0,
31
          end: 0.0,
32 33 34
          child: new Row(
            children: (otherAccountsPictures ?? <Widget>[]).take(3).map((Widget picture) {
              return new Container(
35
                margin: const EdgeInsetsDirectional.only(start: 16.0),
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
                width: 40.0,
                height: 40.0,
                child: picture
              );
            }).toList(),
          ),
        ),
        new Positioned(
          top: 0.0,
          child: new SizedBox(
            width: 72.0,
            height: 72.0,
            child: currentAccountPicture
          ),
        ),
      ],
    );
  }
}

class _AccountDetails extends StatelessWidget {
57
  const _AccountDetails({
58
    Key key,
59 60
    @required this.accountName,
    @required this.accountEmail,
61 62 63 64 65 66 67 68 69 70 71 72
    this.onTap,
    this.isOpen,
  }) : super(key: key);

  final Widget accountName;
  final Widget accountEmail;
  final VoidCallback onTap;
  final bool isOpen;

  Widget addDropdownIcon(Widget line) {
    final Widget icon = new Expanded(
      child: new Align(
73
        alignment: AlignmentDirectional.centerEnd,
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
        child: new Icon(
          isOpen ? Icons.arrow_drop_up : Icons.arrow_drop_down,
          color: Colors.white
        ),
      ),
    );
    return new Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: line == null ? <Widget>[icon] : <Widget>[line, icon],
    );
  }

  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    Widget accountNameLine = accountName == null ? null : new DefaultTextStyle(
      style: theme.primaryTextTheme.body2,
      child: accountName,
    );
    Widget accountEmailLine = accountEmail == null ? null : new DefaultTextStyle(
      style: theme.primaryTextTheme.body1,
      child: accountEmail,
    );
    if (onTap != null) {
      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)
            ? <Widget>[accountNameLine, accountEmailLine]
            : <Widget>[accountNameLine ?? accountEmailLine]
        ),
      );
    }

    if (onTap != null)
      accountDetails = new InkWell(onTap: onTap, child: accountDetails);

    return new SizedBox(
      height: 56.0,
      child: accountDetails,
    );
  }
}

128 129 130 131 132 133
/// A material design [Drawer] header that identifies the app's user.
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// See also:
///
134
///  * [DrawerHeader], for a drawer header that doesn't show user accounts
135
///  * <https://material.google.com/patterns/navigation-drawer.html>
136 137 138 139
class UserAccountsDrawerHeader extends StatefulWidget {
  /// Creates a material design drawer header.
  ///
  /// Requires one of its ancestors to be a [Material] widget.
140
  const UserAccountsDrawerHeader({
141 142
    Key key,
    this.decoration,
143
    this.margin: const EdgeInsets.only(bottom: 8.0),
144 145
    this.currentAccountPicture,
    this.otherAccountsPictures,
146 147
    @required this.accountName,
    @required this.accountEmail,
148 149 150
    this.onDetailsPressed
  }) : super(key: key);

151 152
  /// The header's background. If decoration is null then a [BoxDecoration]
  /// with its background color set to the current theme's primaryColor is used.
153
  final Decoration decoration;
154

155
  /// The margin around the drawer header.
156
  final EdgeInsetsGeometry margin;
157

158 159
  /// A widget placed in the upper-left corner that represents the current
  /// user's account. Normally a [CircleAvatar].
160 161
  final Widget currentAccountPicture;

162 163 164
  /// A list of widgets that represent the current user's other accounts.
  /// Up to three of these widgets will be arranged in a row in the header's
  /// upper-right corner. Normally a list of [CircleAvatar] widgets.
165 166
  final List<Widget> otherAccountsPictures;

167 168
  /// A widget that represents the user's current account name. It is
  /// displayed on the left, below the [currentAccountPicture].
169 170
  final Widget accountName;

171 172
  /// A widget that represents the email address of the user's current account.
  /// It is displayed on the left, below the [accountName].
173 174
  final Widget accountEmail;

175 176 177 178
  /// A callback that is called when the horizontal area which contains the
  /// [accountName] and [accountEmail] is tapped.
  final VoidCallback onDetailsPressed;

179
  @override
180
  _UserAccountsDrawerHeaderState createState() => new _UserAccountsDrawerHeaderState();
181 182 183
}

class _UserAccountsDrawerHeaderState extends State<UserAccountsDrawerHeader> {
184
  bool _isOpen = false;
185

186 187 188 189 190 191 192
  void _handleDetailsPressed() {
    setState(() {
      _isOpen = !_isOpen;
    });
    widget.onDetailsPressed();
  }

193 194 195 196
  @override
  Widget build(BuildContext context) {
    assert(debugCheckHasMaterial(context));
    return new DrawerHeader(
197
      decoration: widget.decoration ?? new BoxDecoration(
198
        color: Theme.of(context).primaryColor,
199
      ),
200
      margin: widget.margin,
201
      child: new Column(
202
        crossAxisAlignment: CrossAxisAlignment.stretch,
203
        children: <Widget>[
204
          new Expanded(
205
            child: new _AccountPictures(
206 207
              currentAccountPicture: widget.currentAccountPicture,
              otherAccountsPictures: widget.otherAccountsPictures,
208 209
            )
          ),
210
          new _AccountDetails(
211 212
            accountName: widget.accountName,
            accountEmail: widget.accountEmail,
213
            isOpen: _isOpen,
214
            onTap: widget.onDetailsPressed == null ? null : _handleDetailsPressed,
215 216 217
          ),
        ],
      ),
218 219 220
    );
  }
}