diff --git a/lib/helpers/conversations_helper.dart b/lib/helpers/conversations_helper.dart index 40fa6d2..8662c48 100644 --- a/lib/helpers/conversations_helper.dart +++ b/lib/helpers/conversations_helper.dart @@ -49,6 +49,15 @@ class ConversationsHelper { return response.getObject()["conversationID"]; } + /// Remove a member from a conversation. + /// + /// Throws in case of failure + static Future removeMember(int convID, int userID) async => + await APIRequest.withLogin("conversations/removeMember") + .addInt("convID", convID) + .addInt("userID", userID) + .execWithThrow(); + /// Update an existing conversation /// /// Throws in case of failure diff --git a/lib/ui/screens/update_conversation_screen.dart b/lib/ui/screens/update_conversation_screen.dart index 66dd145..1f9a21d 100644 --- a/lib/ui/screens/update_conversation_screen.dart +++ b/lib/ui/screens/update_conversation_screen.dart @@ -10,6 +10,7 @@ import 'package:comunic/ui/tiles/simple_user_tile.dart'; import 'package:comunic/ui/widgets/async_screen_widget.dart'; import 'package:comunic/ui/widgets/comunic_back_button_widget.dart'; import 'package:comunic/ui/widgets/pick_user_widget.dart'; +import 'package:comunic/utils/account_utils.dart'; import 'package:comunic/utils/color_utils.dart'; import 'package:comunic/utils/dart_color.dart'; import 'package:comunic/utils/intl_utils.dart'; @@ -21,7 +22,7 @@ import 'package:flutter/material.dart'; /// /// @author Pierre HUBERT -enum _MembersMenuChoices { REMOVE } +enum _MembersMenuChoices { TOGGLE_ADMIN_STATUS, REMOVE } class UpdateConversationScreen extends StatefulWidget { final convID; @@ -67,13 +68,17 @@ class _UpdateConversationScreen extends State { get _isValid => _members.length > 0; Future _init() async { - if (!isUpdating) return; + if (!isUpdating) { + _admins.add(userID()); + return; + } + _conversation = await ConversationsHelper().getSingle(widget.convID, force: true); _nameController.text = _conversation.name ?? ""; _colorController.text = - _conversationColor == null ? "" : "#${_conversation.color}"; + _conversationColor == null ? "" : "#${colorToHex(_conversation.color)}"; _members = await UsersHelper().getList(_conversation.membersID); _admins = _conversation.adminsID; _followConversation = _conversation.following; @@ -172,29 +177,7 @@ class _UpdateConversationScreen extends State { //Conversation members Column( - children: _members - .map((f) => SimpleUserTile( - user: f, - trailing: _canAddMembers - ? PopupMenuButton<_MembersMenuChoices>( - captureInheritedThemes: false, - onSelected: (choice) => - _membersMenuItemSelected(f, choice), - itemBuilder: (c) => - >[ - PopupMenuItem( - child: Text(tr("Remove")), - value: _MembersMenuChoices.REMOVE, - enabled: isAdmin || - (_canEveryoneAddMembers && - !_conversation.membersID - .contains(f.id)), - ) - ], - ) - : null, - )) - .toList(), + children: _members.map((f) => _buildMemberTile(f)).toList(), ), ], ), @@ -202,6 +185,29 @@ class _UpdateConversationScreen extends State { ); } + Widget _buildMemberTile(User user) => SimpleUserTile( + user: user, + subtitle: _admins.contains(user.id) ? tr("Admin") : tr("Member"), + trailing: _canAddMembers + ? PopupMenuButton<_MembersMenuChoices>( + captureInheritedThemes: false, + onSelected: (choice) => _membersMenuItemSelected(user, choice), + itemBuilder: (c) => >[ + PopupMenuItem( + child: Text(tr("Toggle admin status")), + value: _MembersMenuChoices.TOGGLE_ADMIN_STATUS, + enabled: isUpdating && isAdmin && user.id != userID(), + ), + PopupMenuItem( + child: Text(tr("Remove")), + value: _MembersMenuChoices.REMOVE, + enabled: isAdmin && user.id != userID(), + ), + ], + ) + : null, + ); + void _pickColor() async { final color = await showColorPickerDialog(context, _color); setState(() => @@ -212,10 +218,30 @@ class _UpdateConversationScreen extends State { void _membersMenuItemSelected(User user, _MembersMenuChoices choice) { if (choice == null) return; - if (choice == _MembersMenuChoices.REMOVE) + switch (choice) { + case _MembersMenuChoices.REMOVE: + _removeMember(user); + break; + + case _MembersMenuChoices.TOGGLE_ADMIN_STATUS: + // TODO: Handle this case. + break; + } + } + + void _removeMember(User user) async { + try { + if (isUpdating) + await ConversationsHelper.removeMember(_conversation.id, user.id); + setState(() { _members.removeWhere((u) => u.id == user.id); + _admins.remove(user.id); }); + } catch (e, s) { + logError(e, s); + snack(context, tr("Failed to remove member!")); + } } /// Submit the conversation diff --git a/lib/ui/tiles/simple_user_tile.dart b/lib/ui/tiles/simple_user_tile.dart index 026fbd3..e694bb3 100644 --- a/lib/ui/tiles/simple_user_tile.dart +++ b/lib/ui/tiles/simple_user_tile.dart @@ -14,9 +14,15 @@ class SimpleUserTile extends StatelessWidget { final User user; final OnUserTap onTap; final Widget trailing; + final String subtitle; - const SimpleUserTile({Key key, this.user, this.onTap, this.trailing}) - : assert(user != null), + const SimpleUserTile({ + Key key, + this.user, + this.onTap, + this.trailing, + this.subtitle, + }) : assert(user != null), super(key: key); @override @@ -27,6 +33,7 @@ class SimpleUserTile extends StatelessWidget { user: user, ), title: Text(user.fullName), + subtitle: subtitle == null ? null : Text(subtitle), trailing: trailing, ); }