You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
317 lines
9.5 KiB
Dart
317 lines
9.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'package:matrix/matrix.dart';
|
|
|
|
import 'package:fluffychat/l10n/l10n.dart';
|
|
import 'package:fluffychat/widgets/permission_slider_dialog.dart';
|
|
import 'adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
|
|
import 'adaptive_dialogs/show_text_input_dialog.dart';
|
|
import 'adaptive_dialogs/user_dialog.dart';
|
|
import 'avatar.dart';
|
|
import 'future_loading_dialog.dart';
|
|
|
|
void showMemberActionsPopupMenu({
|
|
required BuildContext context,
|
|
required User user,
|
|
void Function()? onMention,
|
|
}) async {
|
|
final theme = Theme.of(context);
|
|
final displayname = user.calcDisplayname();
|
|
final isMe = user.room.client.userID == user.id;
|
|
|
|
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
|
|
|
|
final button = context.findRenderObject() as RenderBox;
|
|
|
|
final position = RelativeRect.fromRect(
|
|
Rect.fromPoints(
|
|
button.localToGlobal(const Offset(0, -65), ancestor: overlay),
|
|
button.localToGlobal(
|
|
button.size.bottomRight(Offset.zero) + const Offset(-50, 0),
|
|
ancestor: overlay,
|
|
),
|
|
),
|
|
Offset.zero & overlay.size,
|
|
);
|
|
|
|
final action = await showMenu<_MemberActions>(
|
|
context: context,
|
|
position: position,
|
|
items: <PopupMenuEntry<_MemberActions>>[
|
|
PopupMenuItem(
|
|
value: _MemberActions.info,
|
|
child: Row(
|
|
spacing: 12.0,
|
|
children: [
|
|
Avatar(
|
|
name: displayname,
|
|
mxContent: user.avatarUrl,
|
|
presenceUserId: user.id,
|
|
presenceBackgroundColor: theme.colorScheme.surfaceContainer,
|
|
),
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
ConstrainedBox(
|
|
constraints: const BoxConstraints(maxWidth: 128),
|
|
child: Text(
|
|
displayname,
|
|
textAlign: TextAlign.center,
|
|
style: theme.textTheme.labelLarge,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
ConstrainedBox(
|
|
constraints: const BoxConstraints(maxWidth: 128),
|
|
child: Text(
|
|
user.id,
|
|
textAlign: TextAlign.center,
|
|
style: const TextStyle(fontSize: 10),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const PopupMenuDivider(),
|
|
if (onMention != null)
|
|
PopupMenuItem(
|
|
value: _MemberActions.mention,
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.alternate_email_outlined),
|
|
const SizedBox(width: 18),
|
|
Text(L10n.of(context).mention),
|
|
],
|
|
),
|
|
),
|
|
if (user.membership == Membership.knock)
|
|
PopupMenuItem(
|
|
value: _MemberActions.approve,
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.how_to_reg_outlined),
|
|
const SizedBox(width: 18),
|
|
Text(L10n.of(context).approve),
|
|
],
|
|
),
|
|
),
|
|
PopupMenuItem(
|
|
enabled: user.room.canChangePowerLevel && user.canChangeUserPowerLevel,
|
|
value: _MemberActions.setRole,
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.admin_panel_settings_outlined),
|
|
const SizedBox(width: 18),
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(L10n.of(context).chatPermissions),
|
|
Text(
|
|
user.powerLevel < 50
|
|
? L10n.of(context).userLevel(user.powerLevel)
|
|
: user.powerLevel < 100
|
|
? L10n.of(context).moderatorLevel(user.powerLevel)
|
|
: L10n.of(context).adminLevel(user.powerLevel),
|
|
style: const TextStyle(fontSize: 10),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (user.canKick)
|
|
PopupMenuItem(
|
|
value: _MemberActions.kick,
|
|
child: Row(
|
|
children: [
|
|
Icon(
|
|
Icons.person_remove_outlined,
|
|
color: theme.colorScheme.onErrorContainer,
|
|
),
|
|
const SizedBox(width: 18),
|
|
Text(
|
|
L10n.of(context).kickFromChat,
|
|
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (user.canBan && user.membership != Membership.ban)
|
|
PopupMenuItem(
|
|
value: _MemberActions.ban,
|
|
child: Row(
|
|
children: [
|
|
Icon(
|
|
Icons.block_outlined,
|
|
color: theme.colorScheme.onErrorContainer,
|
|
),
|
|
const SizedBox(width: 18),
|
|
Text(
|
|
L10n.of(context).banFromChat,
|
|
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (user.canBan && user.membership == Membership.ban)
|
|
PopupMenuItem(
|
|
value: _MemberActions.unban,
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.warning),
|
|
const SizedBox(width: 18),
|
|
Text(L10n.of(context).unbanFromChat),
|
|
],
|
|
),
|
|
),
|
|
if (!isMe)
|
|
PopupMenuItem(
|
|
value: _MemberActions.report,
|
|
child: Row(
|
|
children: [
|
|
Icon(
|
|
Icons.gavel_outlined,
|
|
color: theme.colorScheme.onErrorContainer,
|
|
),
|
|
const SizedBox(width: 18),
|
|
Text(
|
|
L10n.of(context).reportUser,
|
|
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
if (action == null) return;
|
|
if (!context.mounted) return;
|
|
|
|
switch (action) {
|
|
case _MemberActions.mention:
|
|
onMention?.call();
|
|
return;
|
|
case _MemberActions.setRole:
|
|
final power = await showPermissionChooser(
|
|
context,
|
|
currentLevel: user.powerLevel,
|
|
maxLevel: user.room.ownPowerLevel,
|
|
);
|
|
if (power == null) return;
|
|
if (!context.mounted) return;
|
|
if (power >= 100) {
|
|
final consent = await showOkCancelAlertDialog(
|
|
context: context,
|
|
title: L10n.of(context).areYouSure,
|
|
message: L10n.of(context).makeAdminDescription,
|
|
);
|
|
if (consent != OkCancelResult.ok) return;
|
|
if (!context.mounted) return;
|
|
}
|
|
await showFutureLoadingDialog(
|
|
context: context,
|
|
future: () => user.setPower(power),
|
|
);
|
|
return;
|
|
case _MemberActions.approve:
|
|
await showFutureLoadingDialog(
|
|
context: context,
|
|
future: () => user.room.invite(user.id),
|
|
);
|
|
return;
|
|
case _MemberActions.kick:
|
|
if (await showOkCancelAlertDialog(
|
|
context: context,
|
|
title: L10n.of(context).areYouSure,
|
|
okLabel: L10n.of(context).yes,
|
|
cancelLabel: L10n.of(context).no,
|
|
message: L10n.of(context).kickUserDescription,
|
|
) ==
|
|
OkCancelResult.ok) {
|
|
await showFutureLoadingDialog(
|
|
context: context,
|
|
future: () => user.kick(),
|
|
);
|
|
}
|
|
return;
|
|
case _MemberActions.ban:
|
|
if (await showOkCancelAlertDialog(
|
|
context: context,
|
|
title: L10n.of(context).areYouSure,
|
|
okLabel: L10n.of(context).yes,
|
|
cancelLabel: L10n.of(context).no,
|
|
message: L10n.of(context).banUserDescription,
|
|
) ==
|
|
OkCancelResult.ok) {
|
|
await showFutureLoadingDialog(
|
|
context: context,
|
|
future: () => user.ban(),
|
|
);
|
|
}
|
|
return;
|
|
case _MemberActions.report:
|
|
final reason = await showTextInputDialog(
|
|
context: context,
|
|
title: L10n.of(context).whyDoYouWantToReportThis,
|
|
okLabel: L10n.of(context).report,
|
|
cancelLabel: L10n.of(context).cancel,
|
|
hintText: L10n.of(context).reason,
|
|
);
|
|
if (reason == null || reason.isEmpty) return;
|
|
|
|
final result = await showFutureLoadingDialog(
|
|
context: context,
|
|
future: () => user.room.client.reportUser(
|
|
user.id,
|
|
reason,
|
|
),
|
|
);
|
|
if (result.error != null) return;
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(content: Text(L10n.of(context).contentHasBeenReported)),
|
|
);
|
|
return;
|
|
case _MemberActions.info:
|
|
await UserDialog.show(
|
|
context: context,
|
|
profile: Profile(
|
|
userId: user.id,
|
|
displayName: user.displayName,
|
|
avatarUrl: user.avatarUrl,
|
|
),
|
|
);
|
|
return;
|
|
case _MemberActions.unban:
|
|
if (await showOkCancelAlertDialog(
|
|
context: context,
|
|
title: L10n.of(context).areYouSure,
|
|
okLabel: L10n.of(context).yes,
|
|
cancelLabel: L10n.of(context).no,
|
|
message: L10n.of(context).unbanUserDescription,
|
|
) ==
|
|
OkCancelResult.ok) {
|
|
await showFutureLoadingDialog(
|
|
context: context,
|
|
future: () => user.unban(),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
enum _MemberActions {
|
|
info,
|
|
mention,
|
|
setRole,
|
|
kick,
|
|
ban,
|
|
approve,
|
|
unban,
|
|
report,
|
|
}
|