From 804457c761046fd057622c1726b6e9a19d39276c Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Sat, 2 May 2020 15:30:19 +0200 Subject: [PATCH] Create pick user dialog --- lib/ui/dialogs/pick_user_dialog.dart | 63 +++++++++++++++++++ lib/ui/screens/group_members_screen.dart | 31 ++++++++- .../widgets/dialogs/cancel_dialog_button.dart | 17 +++++ .../dialogs/confirm_dialog_button.dart | 27 ++++++++ lib/ui/widgets/pick_user_widget.dart | 30 +++++---- 5 files changed, 153 insertions(+), 15 deletions(-) create mode 100644 lib/ui/dialogs/pick_user_dialog.dart create mode 100644 lib/ui/widgets/dialogs/cancel_dialog_button.dart create mode 100644 lib/ui/widgets/dialogs/confirm_dialog_button.dart diff --git a/lib/ui/dialogs/pick_user_dialog.dart b/lib/ui/dialogs/pick_user_dialog.dart new file mode 100644 index 0000000..42e463f --- /dev/null +++ b/lib/ui/dialogs/pick_user_dialog.dart @@ -0,0 +1,63 @@ +import 'package:comunic/models/user.dart'; +import 'package:comunic/ui/widgets/dialogs/cancel_dialog_button.dart'; +import 'package:comunic/ui/widgets/dialogs/confirm_dialog_button.dart'; +import 'package:comunic/ui/widgets/pick_user_widget.dart'; +import 'package:comunic/ui/widgets/safe_state.dart'; +import 'package:comunic/utils/intl_utils.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// Pick user dialog +/// +/// @author Pierre HUBERT + +/// Ask the user to pick a user +/// +/// Returns null if no user was selected +Future showPickUserDialog(BuildContext context) async { + return await showDialog(context: context, builder: (c) => _PickUserDialog()); +} + +class _PickUserDialog extends StatefulWidget { + @override + __PickUserDialogState createState() => __PickUserDialogState(); +} + +class __PickUserDialogState extends SafeState<_PickUserDialog> { + User _user; + + bool get _isValid => _user != null; + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text(tr("Choose a user")), + content: _buildContent(), + actions: [ + CancelDialogButton(), + ConfirmDialogButton( + value: _isValid ? _user.id : null, + enabled: _isValid, + ), + ], + ); + } + + Widget _buildContent() { + final size = MediaQuery.of(context).size; + print(size); + return Container( + width: size.width, + height: size.height, + child: Column( + children: [ + PickUserWidget( + onSelectUser: (u) => setState(() => _user = u), + label: tr("Search user..."), + onValueChange: (u) => setState(() => _user = null), + ), + ], + ), + ); + } +} diff --git a/lib/ui/screens/group_members_screen.dart b/lib/ui/screens/group_members_screen.dart index 427e233..4cf4b1f 100644 --- a/lib/ui/screens/group_members_screen.dart +++ b/lib/ui/screens/group_members_screen.dart @@ -6,6 +6,7 @@ import 'package:comunic/models/group.dart'; import 'package:comunic/models/group_membership.dart'; import 'package:comunic/models/user.dart'; import 'package:comunic/ui/dialogs/multi_choices_dialog.dart'; +import 'package:comunic/ui/dialogs/pick_user_dialog.dart'; import 'package:comunic/ui/widgets/account_image_widget.dart'; import 'package:comunic/ui/widgets/async_screen_widget.dart'; import 'package:comunic/ui/widgets/comunic_back_button_widget.dart'; @@ -61,8 +62,11 @@ class _GroupMembersScreenState extends State { ); Widget _buildBodyContent() { - return ListView( - children: _members.map(_buildGroupMemberTile).toList(), + return Stack( + children: [ + ListView(children: _members.map(_buildGroupMemberTile).toList()), + _buildInvitationFAB() + ], ); } @@ -75,6 +79,29 @@ class _GroupMembersScreenState extends State { onUpdated: () => _key.currentState.refresh(), ); } + + Widget _buildInvitationFAB() { + return Positioned( + right: 20, + bottom: 20, + child: FloatingActionButton( + onPressed: _inviteMember, + child: Icon(Icons.add), + ), + ); + } + + void _inviteMember() async { + try { + final userID = await showPickUserDialog(context); + if (userID == null) return; + + print("Invite user: $userID"); + } catch (e, s) { + print("Could not invite a user! $e\n$s"); + showSimpleSnack(context, tr("Could not invite a user!")); + } + } } List> get _membershipLevels => [ diff --git a/lib/ui/widgets/dialogs/cancel_dialog_button.dart b/lib/ui/widgets/dialogs/cancel_dialog_button.dart new file mode 100644 index 0000000..b174608 --- /dev/null +++ b/lib/ui/widgets/dialogs/cancel_dialog_button.dart @@ -0,0 +1,17 @@ +import 'package:comunic/utils/intl_utils.dart'; +import 'package:flutter/material.dart'; + +/// Render a cancel button for an alert dialog +/// +/// @author Pierre HUBERT + +class CancelDialogButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialButton( + onPressed: () => Navigator.of(context).pop(), + child: Text(tr("Cancel").toUpperCase()), + textColor: Colors.red, + ); + } +} diff --git a/lib/ui/widgets/dialogs/confirm_dialog_button.dart b/lib/ui/widgets/dialogs/confirm_dialog_button.dart new file mode 100644 index 0000000..2ab8ca6 --- /dev/null +++ b/lib/ui/widgets/dialogs/confirm_dialog_button.dart @@ -0,0 +1,27 @@ +import 'package:comunic/utils/intl_utils.dart'; +import 'package:flutter/material.dart'; + +/// Confirm dialog button +/// +/// @author Pierre HUBERT + +class ConfirmDialogButton extends StatelessWidget { + final bool enabled; + final T value; + + const ConfirmDialogButton({ + Key key, + this.enabled = true, + @required this.value, + }) : assert(enabled != null), + super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialButton( + onPressed: enabled ? () => Navigator.of(context).pop(value) : null, + child: Text(tr("Confirm").toUpperCase()), + textColor: Colors.green, + ); + } +} diff --git a/lib/ui/widgets/pick_user_widget.dart b/lib/ui/widgets/pick_user_widget.dart index 538df04..a67b381 100644 --- a/lib/ui/widgets/pick_user_widget.dart +++ b/lib/ui/widgets/pick_user_widget.dart @@ -15,19 +15,21 @@ typedef OnSelectUserCallback = void Function(User); class PickUserWidget extends StatefulWidget { final OnSelectUserCallback onSelectUser; + final void Function(String) onValueChange; final String label; final bool resetOnChoose; final bool keepFocusOnChoose; final bool enabled; - const PickUserWidget( - {Key key, - @required this.onSelectUser, - @required this.label, - this.resetOnChoose = false, - this.keepFocusOnChoose = false, - this.enabled = true}) - : assert(onSelectUser != null), + const PickUserWidget({ + Key key, + @required this.onSelectUser, + @required this.label, + this.resetOnChoose = false, + this.keepFocusOnChoose = false, + this.onValueChange, + this.enabled = true, + }) : assert(onSelectUser != null), assert(label != null), assert(resetOnChoose != null), assert(keepFocusOnChoose != null), @@ -93,9 +95,9 @@ class _PickUserWidgetState extends State { shrinkWrap: true, itemCount: _suggestions == null ? 0 : _suggestions.length, itemBuilder: (c, i) => SimpleUserTile( - user: _suggestions[i], - onTap: _userTapped, - ), + user: _suggestions[i], + onTap: _userTapped, + ), ), ), ); @@ -116,9 +118,11 @@ class _PickUserWidgetState extends State { /// This method get called each time the input value is updated Future _updateSuggestions() async { - if (_controller.value.text.length == 0) return _removeOverlay(); + if (widget.onValueChange != null) widget.onValueChange(_controller.text); - final results = await _searchHelper.searchUser(_controller.value.text); + if (_controller.text.length == 0) return _removeOverlay(); + + final results = await _searchHelper.searchUser(_controller.text); if (results == null) return;