user_accounts_drawer_header.dart 6.25 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 7 8 9
import 'package:flutter/material.dart';

import 'debug.dart';

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
class _AccountPictures extends StatelessWidget {
  _AccountPictures({
    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>[
        new Positioned(
          top: 0.0,
          right: 0.0,
          child: new Row(
            children: (otherAccountsPictures ?? <Widget>[]).take(3).map((Widget picture) {
              return new Container(
                margin: const EdgeInsets.only(left: 16.0),
                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 {
  _AccountDetails({
    Key key,
54 55
    @required this.accountName,
    @required this.accountEmail,
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 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
    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(
        alignment: FractionalOffset.centerRight,
        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,
    );
  }
}

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

145 146
  /// The header's background. If decoration is null then a [BoxDecoration]
  /// with its background color set to the current theme's primaryColor is used.
147
  final Decoration decoration;
148

149 150
  /// A widget placed in the upper-left corner that represents the current
  /// user's account. Normally a [CircleAvatar].
151 152
  final Widget currentAccountPicture;

153 154 155
  /// 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.
156 157
  final List<Widget> otherAccountsPictures;

158 159
  /// A widget that represents the user's current account name. It is
  /// displayed on the left, below the [currentAccountPicture].
160 161
  final Widget accountName;

162 163
  /// A widget that represents the email address of the user's current account.
  /// It is displayed on the left, below the [accountName].
164 165
  final Widget accountEmail;

166 167 168 169
  /// A callback that is called when the horizontal area which contains the
  /// [accountName] and [accountEmail] is tapped.
  final VoidCallback onDetailsPressed;

170
  @override
171
  _UserAccountsDrawerHeaderState createState() => new _UserAccountsDrawerHeaderState();
172 173 174
}

class _UserAccountsDrawerHeaderState extends State<UserAccountsDrawerHeader> {
175
  bool _isOpen = false;
176 177 178 179 180

  @override
  Widget build(BuildContext context) {
    assert(debugCheckHasMaterial(context));
    return new DrawerHeader(
181 182 183
      decoration: config.decoration ?? new BoxDecoration(
        backgroundColor: Theme.of(context).primaryColor,
      ),
184
      child: new Column(
185
        crossAxisAlignment: CrossAxisAlignment.stretch,
186
        children: <Widget>[
187
          new Expanded(
188 189 190
            child: new _AccountPictures(
              currentAccountPicture: config.currentAccountPicture,
              otherAccountsPictures: config.otherAccountsPictures,
191 192
            )
          ),
193 194 195 196 197 198 199 200 201 202 203 204 205
          new _AccountDetails(
            accountName: config.accountName,
            accountEmail: config.accountEmail,
            isOpen: _isOpen,
            onTap: config.onDetailsPressed == null ? null : () {
              setState(() {
                _isOpen = !_isOpen;
              });
              config.onDetailsPressed();
            },
          ),
        ],
      ),
206 207 208
    );
  }
}