Line data Source code
1 : import 'package:flutter/material.dart';
2 :
3 : import 'package:fast_immutable_collections/fast_immutable_collections.dart';
4 : import 'package:flutter_redux/flutter_redux.dart';
5 :
6 : import '../../../../types.dart';
7 : import '../../../auth/actions/sign_out_action.dart';
8 : import '../../../navigation/actions/push_page_action.dart';
9 : import '../../../redux/extensions/build_context_extensions.dart';
10 : import '../profile_avatar.dart';
11 :
12 : /// Class extends [StatefulWidget] so we can keep a global key as state.
13 : ///
14 : /// The button actually consists of two buttons in a stack. A [PopupMenuButton]
15 : /// and our custom-made [ProfileAvatar].
16 : ///
17 : /// The [PopupMenuButton] is disabled but the [ProfileAvatar] is setup to open
18 : /// the [PopupMenuButton]'s menu.
19 : ///
20 : /// The global key is used as the [PopupMenuButton]'s key and given to the
21 : /// [ProfileAvatar] so it can pop the menu.
22 : ///
23 : class AccountButton<T extends RedFireState> extends StatefulWidget {
24 0 : const AccountButton({ISet<AccountButtonOption>? options, Key? key})
25 : : _options = options ?? const ISetConst({}),
26 0 : super(key: key);
27 :
28 : final ISet<AccountButtonOption> _options;
29 :
30 0 : @override
31 0 : State<AccountButton> createState() => _AccountButtonState<T>();
32 : }
33 :
34 : class _AccountButtonState<T extends RedFireState> extends State<AccountButton> {
35 : final _popupKey = GlobalKey<PopupMenuButtonState>();
36 :
37 0 : @override
38 : Widget build(BuildContext context) {
39 0 : return StoreConnector<T, AuthUserData?>(
40 : distinct: true,
41 0 : converter: (store) => store.state.auth.userData,
42 0 : builder: (context, userData) {
43 0 : return Stack(
44 0 : children: [
45 0 : HiddenPopupMenuButton<T>(_popupKey, widget._options),
46 0 : Padding(
47 : padding: const EdgeInsets.all(8.0),
48 0 : child: ProfileAvatar(
49 0 : userData?.photoURL,
50 0 : onPressed: () => _popupKey.currentState?.showButtonMenu(),
51 : ),
52 : ),
53 : ],
54 : );
55 : },
56 : );
57 : }
58 : }
59 :
60 : class AccountButtonOption {
61 0 : AccountButtonOption(this.name, this.callback);
62 : final String name;
63 : final Function(BuildContext) callback;
64 : }
65 :
66 : class HiddenPopupMenuButton<T extends RedFireState> extends StatelessWidget {
67 0 : HiddenPopupMenuButton(this._key, ISet<AccountButtonOption> options,
68 : {Key? key})
69 0 : : super(key: key) {
70 0 : _options = options.addAll([
71 0 : AccountButtonOption(
72 : 'Account Details',
73 0 : (context) =>
74 0 : context.dispatch<T>(const PushPageAction(ProfilePageData()))),
75 0 : AccountButtonOption('Sign Out',
76 0 : (BuildContext context) => context.dispatch<T>(const SignOutAction()))
77 : ]);
78 : }
79 :
80 : final Key _key;
81 : late final ISet<AccountButtonOption> _options;
82 :
83 0 : @override
84 : Widget build(BuildContext context) {
85 0 : return PopupMenuButton<AccountButtonOption>(
86 0 : key: _key,
87 0 : child: Container(color: Colors.red),
88 : enabled: false,
89 0 : onSelected: (option) => option.callback(context),
90 0 : itemBuilder: (context) => _options
91 0 : .map<PopupMenuEntry<AccountButtonOption>>(
92 0 : (option) => PopupMenuItem<AccountButtonOption>(
93 : value: option,
94 0 : child: Text(option.name),
95 : ))
96 0 : .toList(),
97 : );
98 : }
99 : }
|