chore: Adjust power level UX
This commit is contained in:
parent
1ea607f633
commit
47934a3378
4 changed files with 186 additions and 106 deletions
|
|
@ -3126,5 +3126,12 @@
|
||||||
"theProcessWasCanceled": "The process was canceled.",
|
"theProcessWasCanceled": "The process was canceled.",
|
||||||
"join": "Join",
|
"join": "Join",
|
||||||
"searchOrEnterHomeserverAddress": "Search or enter homeserver address",
|
"searchOrEnterHomeserverAddress": "Search or enter homeserver address",
|
||||||
"matrixId": "Matrix ID"
|
"matrixId": "Matrix ID",
|
||||||
|
"setPowerLevel": "Set power level",
|
||||||
|
"makeModerator": "Make moderator",
|
||||||
|
"makeAdmin": "Make admin",
|
||||||
|
"removeModeratorRights": "Remove moderator rights",
|
||||||
|
"removeAdminRights": "Remove admin rights",
|
||||||
|
"powerLevel": "Power level",
|
||||||
|
"setPowerLevelDescription": "Power levels define what a member is allowed to do in this room and usually range between 0 and 100."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,7 @@ class Message extends StatelessWidget {
|
||||||
singleSelected && event.room.canSendDefaultMessages;
|
singleSelected && event.room.canSendDefaultMessages;
|
||||||
|
|
||||||
final enterThread = this.enterThread;
|
final enterThread = this.enterThread;
|
||||||
|
final sender = event.senderFromMemoryOrFallback;
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: Swipeable(
|
child: Swipeable(
|
||||||
|
|
@ -358,9 +359,7 @@ class Message extends StatelessWidget {
|
||||||
FutureBuilder<User?>(
|
FutureBuilder<User?>(
|
||||||
future: event.fetchSenderUser(),
|
future: event.fetchSenderUser(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final user =
|
final user = snapshot.data ?? sender;
|
||||||
snapshot.data ??
|
|
||||||
event.senderFromMemoryOrFallback;
|
|
||||||
return Avatar(
|
return Avatar(
|
||||||
mxContent: user.avatarUrl,
|
mxContent: user.avatarUrl,
|
||||||
name: user.calcDisplayname(),
|
name: user.calcDisplayname(),
|
||||||
|
|
@ -392,52 +391,78 @@ class Message extends StatelessWidget {
|
||||||
ownMessage ||
|
ownMessage ||
|
||||||
event.room.isDirectChat
|
event.room.isDirectChat
|
||||||
? const SizedBox(height: 12)
|
? const SizedBox(height: 12)
|
||||||
: FutureBuilder<User?>(
|
: Row(
|
||||||
future: event
|
children: [
|
||||||
.fetchSenderUser(),
|
if (sender.powerLevel >=
|
||||||
builder: (context, snapshot) {
|
50)
|
||||||
final displayname =
|
Padding(
|
||||||
snapshot.data
|
padding:
|
||||||
?.calcDisplayname() ??
|
const EdgeInsets.only(
|
||||||
event
|
right: 2.0,
|
||||||
.senderFromMemoryOrFallback
|
),
|
||||||
.calcDisplayname();
|
child: Icon(
|
||||||
return Text(
|
sender.powerLevel >=
|
||||||
displayname,
|
100
|
||||||
style: TextStyle(
|
? Icons
|
||||||
fontSize: 11,
|
.admin_panel_settings
|
||||||
fontWeight:
|
: Icons
|
||||||
FontWeight.bold,
|
.add_moderator_outlined,
|
||||||
color:
|
size: 14,
|
||||||
(theme.brightness ==
|
color: theme
|
||||||
Brightness
|
.colorScheme
|
||||||
.light
|
.onPrimaryContainer,
|
||||||
? displayname
|
),
|
||||||
.color
|
|
||||||
: displayname
|
|
||||||
.lightColorText),
|
|
||||||
shadows:
|
|
||||||
!wallpaperMode
|
|
||||||
? null
|
|
||||||
: [
|
|
||||||
const Shadow(
|
|
||||||
offset:
|
|
||||||
Offset(
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
),
|
|
||||||
blurRadius:
|
|
||||||
3,
|
|
||||||
color: Colors
|
|
||||||
.black,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
maxLines: 1,
|
Expanded(
|
||||||
overflow: TextOverflow
|
child: FutureBuilder<User?>(
|
||||||
.ellipsis,
|
future: event
|
||||||
);
|
.fetchSenderUser(),
|
||||||
},
|
builder: (context, snapshot) {
|
||||||
|
final displayname =
|
||||||
|
snapshot.data
|
||||||
|
?.calcDisplayname() ??
|
||||||
|
sender
|
||||||
|
.calcDisplayname();
|
||||||
|
return Text(
|
||||||
|
displayname,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight:
|
||||||
|
FontWeight
|
||||||
|
.bold,
|
||||||
|
color:
|
||||||
|
(theme.brightness ==
|
||||||
|
Brightness
|
||||||
|
.light
|
||||||
|
? displayname
|
||||||
|
.color
|
||||||
|
: displayname
|
||||||
|
.lightColorText),
|
||||||
|
shadows:
|
||||||
|
!wallpaperMode
|
||||||
|
? null
|
||||||
|
: [
|
||||||
|
const Shadow(
|
||||||
|
offset: Offset(
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
),
|
||||||
|
blurRadius:
|
||||||
|
3,
|
||||||
|
color:
|
||||||
|
Colors.black,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow:
|
||||||
|
TextOverflow
|
||||||
|
.ellipsis,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
|
|
|
||||||
|
|
@ -43,13 +43,7 @@ Future<void> showMemberActionsPopupMenu({
|
||||||
child: Row(
|
child: Row(
|
||||||
spacing: 12.0,
|
spacing: 12.0,
|
||||||
children: [
|
children: [
|
||||||
Avatar(
|
Avatar(name: displayname, size: 30, mxContent: user.avatarUrl),
|
||||||
name: displayname,
|
|
||||||
size: 30,
|
|
||||||
mxContent: user.avatarUrl,
|
|
||||||
presenceUserId: user.id,
|
|
||||||
presenceBackgroundColor: theme.colorScheme.surfaceContainer,
|
|
||||||
),
|
|
||||||
ConstrainedBox(
|
ConstrainedBox(
|
||||||
constraints: const BoxConstraints(maxWidth: 200),
|
constraints: const BoxConstraints(maxWidth: 200),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
@ -83,31 +77,71 @@ Future<void> showMemberActionsPopupMenu({
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem(
|
if (user.canChangeUserPowerLevel) ...[
|
||||||
enabled: user.room.canChangePowerLevel && user.canChangeUserPowerLevel,
|
if (user.powerLevel < 100)
|
||||||
value: _MemberActions.setRole,
|
PopupMenuItem(
|
||||||
child: Row(
|
value: _MemberActions.makeAdmin,
|
||||||
children: [
|
child: Row(
|
||||||
const Icon(Icons.admin_panel_settings_outlined),
|
|
||||||
const SizedBox(width: 18),
|
|
||||||
Column(
|
|
||||||
mainAxisSize: .min,
|
|
||||||
crossAxisAlignment: .start,
|
|
||||||
children: [
|
children: [
|
||||||
Text(L10n.of(context).chatPermissions),
|
const Icon(Icons.admin_panel_settings_outlined),
|
||||||
Text(
|
const SizedBox(width: 18),
|
||||||
user.powerLevel < 50
|
Text(L10n.of(context).makeAdmin),
|
||||||
? 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.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)
|
if (user.canKick)
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
value: _MemberActions.kick,
|
value: _MemberActions.kick,
|
||||||
|
|
@ -179,7 +213,7 @@ Future<void> showMemberActionsPopupMenu({
|
||||||
case _MemberActions.mention:
|
case _MemberActions.mention:
|
||||||
onMention?.call();
|
onMention?.call();
|
||||||
return;
|
return;
|
||||||
case _MemberActions.setRole:
|
case _MemberActions.setPowerLevel:
|
||||||
final power = await showPermissionChooser(
|
final power = await showPermissionChooser(
|
||||||
context,
|
context,
|
||||||
currentLevel: user.powerLevel,
|
currentLevel: user.powerLevel,
|
||||||
|
|
@ -280,13 +314,48 @@ Future<void> showMemberActionsPopupMenu({
|
||||||
future: () => user.unban(),
|
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 {
|
enum _MemberActions {
|
||||||
info,
|
info,
|
||||||
mention,
|
mention,
|
||||||
setRole,
|
setPowerLevel,
|
||||||
|
makeAdmin,
|
||||||
|
makeModerator,
|
||||||
|
removeAdmin,
|
||||||
|
removeModerator,
|
||||||
kick,
|
kick,
|
||||||
ban,
|
ban,
|
||||||
approve,
|
approve,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ Future<int?> showPermissionChooser(
|
||||||
int currentLevel = 0,
|
int currentLevel = 0,
|
||||||
int maxLevel = 100,
|
int maxLevel = 100,
|
||||||
}) async {
|
}) async {
|
||||||
final controller = TextEditingController();
|
final controller = TextEditingController(text: currentLevel.toString());
|
||||||
final error = ValueNotifier<String?>(null);
|
final error = ValueNotifier<String?>(null);
|
||||||
return await showAdaptiveDialog<int>(
|
return await showAdaptiveDialog<int>(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
@ -22,7 +22,7 @@ Future<int?> showPermissionChooser(
|
||||||
crossAxisAlignment: .stretch,
|
crossAxisAlignment: .stretch,
|
||||||
spacing: 12.0,
|
spacing: 12.0,
|
||||||
children: [
|
children: [
|
||||||
Text(L10n.of(context).setPermissionsLevelDescription),
|
Text(L10n.of(context).setPowerLevelDescription),
|
||||||
ValueListenableBuilder(
|
ValueListenableBuilder(
|
||||||
valueListenable: error,
|
valueListenable: error,
|
||||||
builder: (context, errorText, _) => DialogTextField(
|
builder: (context, errorText, _) => DialogTextField(
|
||||||
|
|
@ -38,8 +38,6 @@ Future<int?> showPermissionChooser(
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
AdaptiveDialogAction(
|
AdaptiveDialogAction(
|
||||||
bigButtons: true,
|
|
||||||
borderRadius: AdaptiveDialogAction.topRadius,
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final level = int.tryParse(controller.text.trim());
|
final level = int.tryParse(controller.text.trim());
|
||||||
if (level == null) {
|
if (level == null) {
|
||||||
|
|
@ -52,31 +50,12 @@ Future<int?> showPermissionChooser(
|
||||||
}
|
}
|
||||||
Navigator.of(context).pop<int>(level);
|
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),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue