refactor: Better UX for accepting declining invite

pull/2024/head
krille-chan 3 months ago
parent 80997b44cf
commit 0e1874b226
No known key found for this signature in database

@ -3241,5 +3241,6 @@
"commandHint_logoutall": "Logout all active devices",
"displayNavigationRail": "Show navigation rail on mobile",
"customReaction": "Custom reaction",
"moreEvents": "More events"
"moreEvents": "More events",
"declineInvitation": "Decline invitation"
}

@ -20,7 +20,6 @@ import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/show_scaffold_dialog.dart';
import 'package:fluffychat/utils/show_update_snackbar.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart';
@ -114,82 +113,6 @@ class ChatListController extends State<ChatList>
void onChatTap(Room room) async {
if (room.membership == Membership.invite) {
final theme = Theme.of(context);
final inviteEvent = room.getState(
EventTypes.RoomMember,
room.client.userID!,
);
final matrixLocals = MatrixLocals(L10n.of(context));
final action = await showAdaptiveDialog<InviteAction>(
context: context,
builder: (context) => AlertDialog.adaptive(
title: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 256),
child: Center(
child: Text(
room.getLocalizedDisplayname(matrixLocals),
textAlign: TextAlign.center,
),
),
),
content: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256),
child: Text(
inviteEvent == null
? L10n.of(context).inviteForMe
: inviteEvent.content.tryGet<String>('reason') ??
L10n.of(context).youInvitedBy(
room
.unsafeGetUserFromMemoryOrFallback(
inviteEvent.senderId,
)
.calcDisplayname(i18n: matrixLocals),
),
textAlign: TextAlign.center,
),
),
actions: [
AdaptiveDialogAction(
onPressed: () => Navigator.of(context).pop(InviteAction.accept),
bigButtons: true,
child: Text(L10n.of(context).accept),
),
AdaptiveDialogAction(
onPressed: () => Navigator.of(context).pop(InviteAction.decline),
bigButtons: true,
child: Text(
L10n.of(context).decline,
style: TextStyle(color: theme.colorScheme.error),
),
),
AdaptiveDialogAction(
onPressed: () => Navigator.of(context).pop(InviteAction.block),
bigButtons: true,
child: Text(
L10n.of(context).block,
style: TextStyle(color: theme.colorScheme.error),
),
),
],
),
);
switch (action) {
case null:
return;
case InviteAction.accept:
break;
case InviteAction.decline:
await showFutureLoadingDialog(
context: context,
future: () => room.leave(),
);
return;
case InviteAction.block:
final userId = inviteEvent?.senderId;
context.go('/rooms/settings/security/ignorelist', extra: userId);
return;
}
if (!mounted) return;
final joinResult = await showFutureLoadingDialog(
context: context,
future: () async {
@ -680,6 +603,26 @@ class ChatListController extends State<ChatList>
],
),
),
if (room.membership == Membership.invite)
PopupMenuItem(
value: ChatContextAction.block,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.block_outlined,
color: Theme.of(context).colorScheme.onErrorContainer,
),
const SizedBox(width: 12),
Text(
L10n.of(context).block,
style: TextStyle(
color: Theme.of(context).colorScheme.onErrorContainer,
),
),
],
),
),
],
);
@ -715,6 +658,15 @@ class ChatListController extends State<ChatList>
),
);
return;
case ChatContextAction.block:
final inviteEvent = room.getState(
EventTypes.RoomMember,
room.client.userID!,
);
context.go(
'/rooms/settings/security/ignorelist',
extra: inviteEvent?.senderId,
);
case ChatContextAction.leave:
final confirmed = await showOkCancelAlertDialog(
context: context,
@ -981,6 +933,5 @@ enum ChatContextAction {
mute,
leave,
addToSpace,
block,
}
enum InviteAction { accept, decline, block }

@ -35,32 +35,6 @@ class ChatListItem extends StatelessWidget {
super.key,
});
Future<bool> archiveAction(BuildContext context) async {
{
if ([Membership.leave, Membership.ban].contains(room.membership)) {
final forgetResult = await showFutureLoadingDialog(
context: context,
future: () => room.forget(),
);
return forgetResult.isValue;
}
final confirmed = await showOkCancelAlertDialog(
context: context,
title: L10n.of(context).areYouSure,
okLabel: L10n.of(context).leave,
cancelLabel: L10n.of(context).cancel,
message: L10n.of(context).archiveRoomDescription,
isDestructive: true,
);
if (confirmed != OkCancelResult.ok) return false;
final leaveResult = await showFutureLoadingDialog(
context: context,
future: () => room.leave(),
);
return leaveResult.isValue;
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
@ -69,7 +43,7 @@ class ChatListItem extends StatelessWidget {
final typingText = room.getLocalizedTypingText(context);
final lastEvent = room.lastEvent;
final ownMessage = lastEvent?.senderId == room.client.userID;
final unread = room.isUnread || room.membership == Membership.invite;
final unread = room.isUnread;
final directChatMatrixId = room.directChatMatrixID;
final isDirectChat = directChatMatrixId != null;
final unreadBubbleSize = unread || room.hasNewMessages
@ -357,8 +331,7 @@ class ChatListItem extends StatelessWidget {
room.notificationCount.toString().length +
9,
decoration: BoxDecoration(
color: room.highlightCount > 0 ||
room.membership == Membership.invite
color: room.highlightCount > 0
? theme.colorScheme.error
: hasNotifications || room.markedUnread
? theme.colorScheme.primary
@ -369,8 +342,7 @@ class ChatListItem extends StatelessWidget {
? Text(
room.notificationCount.toString(),
style: TextStyle(
color: room.highlightCount > 0 ||
room.membership == Membership.invite
color: room.highlightCount > 0
? theme.colorScheme.onError
: hasNotifications
? theme.colorScheme.onPrimary
@ -386,7 +358,28 @@ class ChatListItem extends StatelessWidget {
),
onTap: onTap,
trailing: onForget == null
? null
? room.membership == Membership.invite
? IconButton(
tooltip: L10n.of(context).declineInvitation,
icon: const Icon(Icons.delete_forever_outlined),
color: theme.colorScheme.error,
onPressed: () async {
final consent = await showOkCancelAlertDialog(
context: context,
title: L10n.of(context).declineInvitation,
message: L10n.of(context).areYouSure,
okLabel: L10n.of(context).yes,
isDestructive: true,
);
if (consent != OkCancelResult.ok) return;
if (!context.mounted) return;
await showFutureLoadingDialog(
context: context,
future: room.leave,
);
},
)
: null
: IconButton(
icon: const Icon(Icons.delete_outlined),
onPressed: onForget,

Loading…
Cancel
Save