chore: Adjust power level UX

This commit is contained in:
Christian Kußowski 2026-02-25 13:12:47 +01:00
commit 47934a3378
No known key found for this signature in database
GPG key ID: E067ECD60F1A0652
4 changed files with 186 additions and 106 deletions

View file

@ -43,13 +43,7 @@ Future<void> showMemberActionsPopupMenu({
child: Row(
spacing: 12.0,
children: [
Avatar(
name: displayname,
size: 30,
mxContent: user.avatarUrl,
presenceUserId: user.id,
presenceBackgroundColor: theme.colorScheme.surfaceContainer,
),
Avatar(name: displayname, size: 30, mxContent: user.avatarUrl),
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 200),
child: Text(
@ -83,31 +77,71 @@ Future<void> showMemberActionsPopupMenu({
],
),
),
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: .min,
crossAxisAlignment: .start,
if (user.canChangeUserPowerLevel) ...[
if (user.powerLevel < 100)
PopupMenuItem(
value: _MemberActions.makeAdmin,
child: Row(
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),
),
const Icon(Icons.admin_panel_settings_outlined),
const SizedBox(width: 18),
Text(L10n.of(context).makeAdmin),
],
),
],
),
if (user.powerLevel < 50)
PopupMenuItem(
value: _MemberActions.makeModerator,
child: Row(
children: [
const Icon(Icons.add_moderator_outlined),
const SizedBox(width: 18),
Text(L10n.of(context).makeModerator),
],
),
),
if (user.powerLevel >= 100)
PopupMenuItem(
value: _MemberActions.removeAdmin,
child: Row(
children: [
const Icon(Icons.remove_moderator_outlined),
const SizedBox(width: 18),
Text(L10n.of(context).removeAdminRights),
],
),
)
else if (user.powerLevel >= 50)
PopupMenuItem(
value: _MemberActions.removeModerator,
child: Row(
children: [
const Icon(Icons.remove_moderator_outlined),
const SizedBox(width: 18),
Text(L10n.of(context).removeModeratorRights),
],
),
),
],
if (user.canChangeUserPowerLevel ||
!{0, 50, 100}.contains(user.powerLevel))
PopupMenuItem(
value: _MemberActions.setPowerLevel,
enabled: user.canChangeUserPowerLevel,
child: Row(
children: [
const Icon(Icons.manage_accounts_outlined),
const SizedBox(width: 18),
Text(
user.canChangeUserPowerLevel
? L10n.of(context).setPowerLevel
: L10n.of(context).powerLevel,
),
if (!{0, 50, 100}.contains(user.powerLevel))
Text(' (${user.powerLevel})'),
],
),
),
),
if (user.canKick)
PopupMenuItem(
value: _MemberActions.kick,
@ -179,7 +213,7 @@ Future<void> showMemberActionsPopupMenu({
case _MemberActions.mention:
onMention?.call();
return;
case _MemberActions.setRole:
case _MemberActions.setPowerLevel:
final power = await showPermissionChooser(
context,
currentLevel: user.powerLevel,
@ -280,13 +314,48 @@ Future<void> showMemberActionsPopupMenu({
future: () => user.unban(),
);
}
case _MemberActions.makeAdmin:
if (user.room.ownPowerLevel <= 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(100),
);
case _MemberActions.makeModerator:
await showFutureLoadingDialog(
context: context,
future: () => user.setPower(50),
);
case _MemberActions.removeAdmin:
case _MemberActions.removeModerator:
final defaultUserLevel =
user.room
.getState(EventTypes.RoomPowerLevels)
?.content
.tryGet<int>('users_default') ??
0;
await showFutureLoadingDialog(
context: context,
future: () => user.setPower(defaultUserLevel),
);
}
}
enum _MemberActions {
info,
mention,
setRole,
setPowerLevel,
makeAdmin,
makeModerator,
removeAdmin,
removeModerator,
kick,
ban,
approve,

View file

@ -9,7 +9,7 @@ Future<int?> showPermissionChooser(
int currentLevel = 0,
int maxLevel = 100,
}) async {
final controller = TextEditingController();
final controller = TextEditingController(text: currentLevel.toString());
final error = ValueNotifier<String?>(null);
return await showAdaptiveDialog<int>(
context: context,
@ -22,7 +22,7 @@ Future<int?> showPermissionChooser(
crossAxisAlignment: .stretch,
spacing: 12.0,
children: [
Text(L10n.of(context).setPermissionsLevelDescription),
Text(L10n.of(context).setPowerLevelDescription),
ValueListenableBuilder(
valueListenable: error,
builder: (context, errorText, _) => DialogTextField(
@ -38,8 +38,6 @@ Future<int?> showPermissionChooser(
),
actions: [
AdaptiveDialogAction(
bigButtons: true,
borderRadius: AdaptiveDialogAction.topRadius,
onPressed: () {
final level = int.tryParse(controller.text.trim());
if (level == null) {
@ -52,31 +50,12 @@ Future<int?> showPermissionChooser(
}
Navigator.of(context).pop<int>(level);
},
child: Text(L10n.of(context).setCustomPermissionLevel),
child: Text(L10n.of(context).setPowerLevel),
),
AdaptiveDialogAction(
onPressed: () => Navigator.of(context).pop<int>(null),
child: Text(L10n.of(context).cancel),
),
if (maxLevel >= 100 && currentLevel != 100)
AdaptiveDialogAction(
borderRadius: AdaptiveDialogAction.centerRadius,
bigButtons: true,
onPressed: () => Navigator.of(context).pop<int>(100),
child: Text(L10n.of(context).admin),
),
if (maxLevel >= 50 && currentLevel != 50)
AdaptiveDialogAction(
borderRadius: maxLevel != 0
? AdaptiveDialogAction.centerRadius
: AdaptiveDialogAction.bottomRadius,
bigButtons: true,
onPressed: () => Navigator.of(context).pop<int>(50),
child: Text(L10n.of(context).moderator),
),
if (currentLevel != 0)
AdaptiveDialogAction(
borderRadius: AdaptiveDialogAction.bottomRadius,
bigButtons: true,
onPressed: () => Navigator.of(context).pop<int>(0),
child: Text(L10n.of(context).normalUser),
),
],
),
);