chore: Follow up dialog themes
Signed-off-by: Krille <c.kussowski@famedly.com>
This commit is contained in:
parent
8db9a05071
commit
eeb630b5fc
5 changed files with 397 additions and 387 deletions
|
|
@ -1,12 +1,5 @@
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|
||||||
import 'package:matrix/matrix.dart';
|
|
||||||
import 'package:swipe_to_action/swipe_to_action.dart';
|
|
||||||
|
|
||||||
import 'package:fluffychat/config/themes.dart';
|
import 'package:fluffychat/config/themes.dart';
|
||||||
import 'package:fluffychat/pages/chat/events/room_creation_state_event.dart';
|
import 'package:fluffychat/pages/chat/events/room_creation_state_event.dart';
|
||||||
import 'package:fluffychat/utils/date_time_extension.dart';
|
import 'package:fluffychat/utils/date_time_extension.dart';
|
||||||
|
|
@ -15,6 +8,12 @@ import 'package:fluffychat/utils/string_color.dart';
|
||||||
import 'package:fluffychat/widgets/avatar.dart';
|
import 'package:fluffychat/widgets/avatar.dart';
|
||||||
import 'package:fluffychat/widgets/matrix.dart';
|
import 'package:fluffychat/widgets/matrix.dart';
|
||||||
import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart';
|
import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
|
import 'package:matrix/matrix.dart';
|
||||||
|
import 'package:swipe_to_action/swipe_to_action.dart';
|
||||||
|
|
||||||
import '../../../config/app_config.dart';
|
import '../../../config/app_config.dart';
|
||||||
import 'message_content.dart';
|
import 'message_content.dart';
|
||||||
import 'message_reactions.dart';
|
import 'message_reactions.dart';
|
||||||
|
|
@ -237,16 +236,17 @@ class Message extends StatelessWidget {
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final user = snapshot.data ??
|
final user = snapshot.data ??
|
||||||
event.senderFromMemoryOrFallback;
|
event.senderFromMemoryOrFallback;
|
||||||
return MemberActionsPopupMenuButton(
|
return Avatar(
|
||||||
onMention: onMention,
|
mxContent: user.avatarUrl,
|
||||||
user: user,
|
name: user.calcDisplayname(),
|
||||||
child: Avatar(
|
onTap: () => showMemberActionsPopupMenu(
|
||||||
mxContent: user.avatarUrl,
|
context: context,
|
||||||
name: user.calcDisplayname(),
|
user: user,
|
||||||
presenceUserId: user.stateKey,
|
onMention: onMention,
|
||||||
presenceBackgroundColor:
|
|
||||||
wallpaperMode ? Colors.transparent : null,
|
|
||||||
),
|
),
|
||||||
|
presenceUserId: user.stateKey,
|
||||||
|
presenceBackgroundColor:
|
||||||
|
wallpaperMode ? Colors.transparent : null,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
|
import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/config/app_config.dart';
|
|
||||||
import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart';
|
|
||||||
import '../../widgets/avatar.dart';
|
import '../../widgets/avatar.dart';
|
||||||
|
|
||||||
class ParticipantListItem extends StatelessWidget {
|
class ParticipantListItem extends StatelessWidget {
|
||||||
|
|
@ -32,68 +31,66 @@ class ParticipantListItem extends StatelessWidget {
|
||||||
|
|
||||||
return Opacity(
|
return Opacity(
|
||||||
opacity: user.membership == Membership.join ? 1 : 0.5,
|
opacity: user.membership == Membership.join ? 1 : 0.5,
|
||||||
child: MemberActionsPopupMenuButton(
|
child: ListTile(
|
||||||
user: user,
|
onTap: () => showMemberActionsPopupMenu(context: context, user: user),
|
||||||
child: ListTile(
|
title: Row(
|
||||||
title: Row(
|
children: <Widget>[
|
||||||
children: <Widget>[
|
Expanded(
|
||||||
Expanded(
|
child: Text(
|
||||||
|
user.calcDisplayname(),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (permissionBatch.isNotEmpty)
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: user.powerLevel >= 100
|
||||||
|
? theme.colorScheme.tertiary
|
||||||
|
: theme.colorScheme.tertiaryContainer,
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
AppConfig.borderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
user.calcDisplayname(),
|
permissionBatch,
|
||||||
overflow: TextOverflow.ellipsis,
|
style: theme.textTheme.labelSmall?.copyWith(
|
||||||
|
color: user.powerLevel >= 100
|
||||||
|
? theme.colorScheme.onTertiary
|
||||||
|
: theme.colorScheme.onTertiaryContainer,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (permissionBatch.isNotEmpty)
|
membershipBatch == null
|
||||||
Container(
|
? const SizedBox.shrink()
|
||||||
padding: const EdgeInsets.symmetric(
|
: Container(
|
||||||
horizontal: 12,
|
padding: const EdgeInsets.all(4),
|
||||||
vertical: 6,
|
margin: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
),
|
decoration: BoxDecoration(
|
||||||
decoration: BoxDecoration(
|
color: theme.secondaryHeaderColor,
|
||||||
color: user.powerLevel >= 100
|
borderRadius: BorderRadius.circular(8),
|
||||||
? theme.colorScheme.tertiary
|
|
||||||
: theme.colorScheme.tertiaryContainer,
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
AppConfig.borderRadius,
|
|
||||||
),
|
),
|
||||||
),
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
permissionBatch,
|
membershipBatch,
|
||||||
style: theme.textTheme.labelSmall?.copyWith(
|
style: theme.textTheme.labelSmall,
|
||||||
color: user.powerLevel >= 100
|
|
||||||
? theme.colorScheme.onTertiary
|
|
||||||
: theme.colorScheme.onTertiaryContainer,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
membershipBatch == null
|
|
||||||
? const SizedBox.shrink()
|
|
||||||
: Container(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: theme.secondaryHeaderColor,
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
membershipBatch,
|
|
||||||
style: theme.textTheme.labelSmall,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
subtitle: Text(
|
),
|
||||||
user.id,
|
subtitle: Text(
|
||||||
maxLines: 1,
|
user.id,
|
||||||
overflow: TextOverflow.ellipsis,
|
maxLines: 1,
|
||||||
),
|
overflow: TextOverflow.ellipsis,
|
||||||
leading: Avatar(
|
),
|
||||||
mxContent: user.avatarUrl,
|
leading: Avatar(
|
||||||
name: user.calcDisplayname(),
|
mxContent: user.avatarUrl,
|
||||||
presenceUserId: user.stateKey,
|
name: user.calcDisplayname(),
|
||||||
),
|
presenceUserId: user.stateKey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ class UserDialog extends StatelessWidget {
|
||||||
}) =>
|
}) =>
|
||||||
showAdaptiveDialog(
|
showAdaptiveDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
barrierDismissible: true,
|
||||||
builder: (context) => UserDialog(
|
builder: (context) => UserDialog(
|
||||||
profile,
|
profile,
|
||||||
noProfileWarning: noProfileWarning,
|
noProfileWarning: noProfileWarning,
|
||||||
|
|
@ -49,34 +50,35 @@ class UserDialog extends StatelessWidget {
|
||||||
child: Center(child: Text(displayname, textAlign: TextAlign.center)),
|
child: Center(child: Text(displayname, textAlign: TextAlign.center)),
|
||||||
),
|
),
|
||||||
content: ConstrainedBox(
|
content: ConstrainedBox(
|
||||||
constraints: const BoxConstraints(maxWidth: 256),
|
constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256),
|
||||||
child: SelectionArea(
|
child: SelectionArea(
|
||||||
child: Center(
|
child: PresenceBuilder(
|
||||||
child: PresenceBuilder(
|
userId: profile.userId,
|
||||||
userId: profile.userId,
|
client: Matrix.of(context).client,
|
||||||
client: Matrix.of(context).client,
|
builder: (context, presence) {
|
||||||
builder: (context, presence) {
|
if (presence == null) return const SizedBox.shrink();
|
||||||
if (presence == null) return const SizedBox.shrink();
|
final statusMsg = presence.statusMsg;
|
||||||
final statusMsg = presence.statusMsg;
|
final lastActiveTimestamp = presence.lastActiveTimestamp;
|
||||||
final lastActiveTimestamp = presence.lastActiveTimestamp;
|
final presenceText = presence.currentlyActive == true
|
||||||
final presenceText = presence.currentlyActive == true
|
? L10n.of(context).currentlyActive
|
||||||
? L10n.of(context).currentlyActive
|
: lastActiveTimestamp != null
|
||||||
: lastActiveTimestamp != null
|
? L10n.of(context).lastActiveAgo(
|
||||||
? L10n.of(context).lastActiveAgo(
|
lastActiveTimestamp.localizedTimeShort(context),
|
||||||
lastActiveTimestamp.localizedTimeShort(context),
|
)
|
||||||
)
|
: null;
|
||||||
: null;
|
return SingleChildScrollView(
|
||||||
return Column(
|
child: Column(
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
HoverBuilder(
|
HoverBuilder(
|
||||||
builder: (context, hovered) => StatefulBuilder(
|
builder: (context, hovered) => StatefulBuilder(
|
||||||
builder: (context, setState) => GestureDetector(
|
builder: (context, setState) => GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Clipboard.setData(
|
Clipboard.setData(
|
||||||
ClipboardData(text: profile.userId));
|
ClipboardData(text: profile.userId),
|
||||||
|
);
|
||||||
setState(() {
|
setState(() {
|
||||||
copied = true;
|
copied = true;
|
||||||
});
|
});
|
||||||
|
|
@ -115,15 +117,18 @@ class UserDialog extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Avatar(
|
Center(
|
||||||
mxContent: profile.avatarUrl,
|
child: Avatar(
|
||||||
name: displayname,
|
mxContent: profile.avatarUrl,
|
||||||
size: Avatar.defaultSize * 2,
|
name: displayname,
|
||||||
|
size: Avatar.defaultSize * 2,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (presenceText != null)
|
if (presenceText != null)
|
||||||
Text(
|
Text(
|
||||||
presenceText,
|
presenceText,
|
||||||
style: const TextStyle(fontSize: 10),
|
style: const TextStyle(fontSize: 10),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
if (statusMsg != null)
|
if (statusMsg != null)
|
||||||
Linkify(
|
Linkify(
|
||||||
|
|
@ -139,48 +144,49 @@ class UserDialog extends StatelessWidget {
|
||||||
UrlLauncher(context, url.url).launchUrl(),
|
UrlLauncher(context, url.url).launchUrl(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
if (client.userID != profile.userId) ...[],
|
if (client.userID != profile.userId) ...[
|
||||||
AdaptiveDialogAction(
|
AdaptiveDialogAction(
|
||||||
bigButtons: true,
|
bigButtons: true,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final router = GoRouter.of(context);
|
final router = GoRouter.of(context);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
final roomIdResult = await showFutureLoadingDialog(
|
final roomIdResult = await showFutureLoadingDialog(
|
||||||
context: context,
|
context: context,
|
||||||
future: () => client.startDirectChat(profile.userId),
|
future: () => client.startDirectChat(profile.userId),
|
||||||
);
|
);
|
||||||
final roomId = roomIdResult.result;
|
final roomId = roomIdResult.result;
|
||||||
if (roomId == null) return;
|
if (roomId == null) return;
|
||||||
router.go('/rooms/$roomId');
|
router.go('/rooms/$roomId');
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
dmRoomId == null
|
dmRoomId == null
|
||||||
? L10n.of(context).startConversation
|
? L10n.of(context).startConversation
|
||||||
: L10n.of(context).sendAMessage,
|
: L10n.of(context).sendAMessage,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
AdaptiveDialogAction(
|
||||||
AdaptiveDialogAction(
|
bigButtons: true,
|
||||||
bigButtons: true,
|
onPressed: () {
|
||||||
onPressed: () {
|
final router = GoRouter.of(context);
|
||||||
final router = GoRouter.of(context);
|
Navigator.of(context).pop();
|
||||||
Navigator.of(context).pop();
|
router.go(
|
||||||
router.go(
|
'/rooms/settings/security/ignorelist',
|
||||||
'/rooms/settings/security/ignorelist',
|
extra: profile.userId,
|
||||||
extra: profile.userId,
|
);
|
||||||
);
|
},
|
||||||
},
|
child: Text(
|
||||||
child: Text(
|
L10n.of(context).ignoreUser,
|
||||||
L10n.of(context).ignoreUser,
|
style: TextStyle(color: theme.colorScheme.error),
|
||||||
style: TextStyle(color: theme.colorScheme.error),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
AdaptiveDialogAction(
|
AdaptiveDialogAction(
|
||||||
bigButtons: true,
|
bigButtons: true,
|
||||||
onPressed: Navigator.of(context).pop,
|
onPressed: Navigator.of(context).pop,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
|
import 'package:fluffychat/widgets/permission_slider_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/widgets/permission_slider_dialog.dart';
|
|
||||||
import 'adaptive_dialogs/show_modal_action_popup.dart';
|
import 'adaptive_dialogs/show_modal_action_popup.dart';
|
||||||
import 'adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
|
import 'adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
|
||||||
import 'adaptive_dialogs/show_text_input_dialog.dart';
|
import 'adaptive_dialogs/show_text_input_dialog.dart';
|
||||||
|
|
@ -11,278 +10,284 @@ import 'adaptive_dialogs/user_dialog.dart';
|
||||||
import 'avatar.dart';
|
import 'avatar.dart';
|
||||||
import 'future_loading_dialog.dart';
|
import 'future_loading_dialog.dart';
|
||||||
|
|
||||||
class MemberActionsPopupMenuButton extends StatelessWidget {
|
void showMemberActionsPopupMenu({
|
||||||
final Widget child;
|
required BuildContext context,
|
||||||
final User user;
|
required User user,
|
||||||
final void Function()? onMention;
|
void Function()? onMention,
|
||||||
|
}) async {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final displayname = user.calcDisplayname();
|
||||||
|
final isMe = user.room.client.userID == user.id;
|
||||||
|
|
||||||
const MemberActionsPopupMenuButton({
|
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
required this.child,
|
|
||||||
required this.user,
|
|
||||||
this.onMention,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
final button = context.findRenderObject() as RenderBox;
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final theme = Theme.of(context);
|
|
||||||
final displayname = user.calcDisplayname();
|
|
||||||
final isMe = user.room.client.userID == user.id;
|
|
||||||
return PopupMenuButton(
|
|
||||||
onSelected: (action) async {
|
|
||||||
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.kick:
|
|
||||||
if (await showOkCancelAlertDialog(
|
|
||||||
useRootNavigator: false,
|
|
||||||
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(
|
|
||||||
useRootNavigator: false,
|
|
||||||
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 score = await showModalActionPopup<int>(
|
|
||||||
context: context,
|
|
||||||
title: L10n.of(context).reportUser,
|
|
||||||
message: L10n.of(context).howOffensiveIsThisContent,
|
|
||||||
cancelLabel: L10n.of(context).cancel,
|
|
||||||
actions: [
|
|
||||||
AdaptiveModalAction(
|
|
||||||
value: -100,
|
|
||||||
label: L10n.of(context).extremeOffensive,
|
|
||||||
),
|
|
||||||
AdaptiveModalAction(
|
|
||||||
value: -50,
|
|
||||||
label: L10n.of(context).offensive,
|
|
||||||
),
|
|
||||||
AdaptiveModalAction(
|
|
||||||
value: 0,
|
|
||||||
label: L10n.of(context).inoffensive,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
if (score == null) return;
|
|
||||||
final reason = await showTextInputDialog(
|
|
||||||
useRootNavigator: false,
|
|
||||||
context: context,
|
|
||||||
title: L10n.of(context).whyDoYouWantToReportThis,
|
|
||||||
okLabel: L10n.of(context).ok,
|
|
||||||
cancelLabel: L10n.of(context).cancel,
|
|
||||||
hintText: L10n.of(context).reason,
|
|
||||||
);
|
|
||||||
if (reason == null || reason.isEmpty) return;
|
|
||||||
|
|
||||||
final result = await showFutureLoadingDialog(
|
final position = RelativeRect.fromRect(
|
||||||
context: context,
|
Rect.fromPoints(
|
||||||
future: () => user.room.client.reportEvent(
|
button.localToGlobal(const Offset(0, -65), ancestor: overlay),
|
||||||
user.room.id,
|
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: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Avatar(
|
||||||
|
name: displayname,
|
||||||
|
mxContent: user.avatarUrl,
|
||||||
|
presenceUserId: user.id,
|
||||||
|
presenceBackgroundColor: theme.colorScheme.surfaceContainer,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
displayname,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: theme.textTheme.labelLarge,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
user.id,
|
user.id,
|
||||||
reason: reason,
|
textAlign: TextAlign.center,
|
||||||
score: score,
|
style: const TextStyle(fontSize: 10),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
);
|
],
|
||||||
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(
|
|
||||||
useRootNavigator: false,
|
|
||||||
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(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
itemBuilder: (context) => <PopupMenuEntry<_MemberActions>>[
|
|
||||||
PopupMenuItem(
|
|
||||||
value: _MemberActions.info,
|
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Avatar(
|
|
||||||
name: displayname,
|
|
||||||
mxContent: user.avatarUrl,
|
|
||||||
presenceUserId: user.id,
|
|
||||||
presenceBackgroundColor: theme.colorScheme.surfaceContainer,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
displayname,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: theme.textTheme.labelLarge,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
user.id,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(fontSize: 10),
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const PopupMenuDivider(),
|
),
|
||||||
if (onMention != null)
|
const PopupMenuDivider(),
|
||||||
PopupMenuItem(
|
if (onMention != null)
|
||||||
value: _MemberActions.mention,
|
|
||||||
child: ListTile(
|
|
||||||
leading: const Icon(Icons.alternate_email_outlined),
|
|
||||||
title: Text(L10n.of(context).mention),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
enabled:
|
value: _MemberActions.mention,
|
||||||
user.room.canChangePowerLevel && user.canChangeUserPowerLevel,
|
|
||||||
value: _MemberActions.setRole,
|
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: const Icon(Icons.admin_panel_settings_outlined),
|
leading: const Icon(Icons.alternate_email_outlined),
|
||||||
title: Text(L10n.of(context).chatPermissions),
|
title: Text(L10n.of(context).mention),
|
||||||
subtitle: Text(
|
),
|
||||||
user.powerLevel < 50
|
),
|
||||||
? L10n.of(context).userLevel(user.powerLevel)
|
PopupMenuItem(
|
||||||
: user.powerLevel < 100
|
enabled: user.room.canChangePowerLevel && user.canChangeUserPowerLevel,
|
||||||
? L10n.of(context).moderatorLevel(user.powerLevel)
|
value: _MemberActions.setRole,
|
||||||
: L10n.of(context).adminLevel(user.powerLevel),
|
child: ListTile(
|
||||||
style: const TextStyle(fontSize: 10),
|
leading: const Icon(Icons.admin_panel_settings_outlined),
|
||||||
|
title: Text(L10n.of(context).chatPermissions),
|
||||||
|
subtitle: 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: ListTile(
|
||||||
|
leading: Icon(
|
||||||
|
Icons.person_remove_outlined,
|
||||||
|
color: theme.colorScheme.onErrorContainer,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
L10n.of(context).kickFromChat,
|
||||||
|
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (user.canKick)
|
if (user.canBan)
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
value: _MemberActions.kick,
|
value: _MemberActions.ban,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(
|
leading: Icon(
|
||||||
Icons.person_remove_outlined,
|
Icons.block_outlined,
|
||||||
color: theme.colorScheme.onErrorContainer,
|
color: theme.colorScheme.onErrorContainer,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
L10n.of(context).kickFromChat,
|
L10n.of(context).banFromChat,
|
||||||
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (user.canBan)
|
),
|
||||||
PopupMenuItem(
|
if (user.canBan && user.membership == Membership.ban)
|
||||||
value: _MemberActions.ban,
|
PopupMenuItem(
|
||||||
child: ListTile(
|
value: _MemberActions.ban,
|
||||||
leading: Icon(
|
child: ListTile(
|
||||||
Icons.block_outlined,
|
leading: const Icon(Icons.warning),
|
||||||
color: theme.colorScheme.onErrorContainer,
|
title: Text(
|
||||||
),
|
L10n.of(context).unbanFromChat,
|
||||||
title: Text(
|
|
||||||
L10n.of(context).banFromChat,
|
|
||||||
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (user.canBan && user.membership == Membership.ban)
|
),
|
||||||
PopupMenuItem(
|
if (user.canBan && user.membership == Membership.ban)
|
||||||
value: _MemberActions.ban,
|
PopupMenuItem(
|
||||||
child: ListTile(
|
value: _MemberActions.unban,
|
||||||
leading: const Icon(Icons.warning),
|
child: ListTile(
|
||||||
title: Text(
|
leading: const Icon(Icons.warning_outlined),
|
||||||
L10n.of(context).unbanFromChat,
|
title: Text(L10n.of(context).unbanFromChat),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
if (!isMe)
|
||||||
|
PopupMenuItem(
|
||||||
|
value: _MemberActions.report,
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(
|
||||||
|
Icons.gavel_outlined,
|
||||||
|
color: theme.colorScheme.onErrorContainer,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
L10n.of(context).reportUser,
|
||||||
|
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (user.canBan && user.membership == Membership.ban)
|
),
|
||||||
PopupMenuItem(
|
],
|
||||||
value: _MemberActions.unban,
|
);
|
||||||
child: ListTile(
|
if (action == null) return;
|
||||||
leading: const Icon(Icons.warning_outlined),
|
if (!context.mounted) return;
|
||||||
title: Text(L10n.of(context).unbanFromChat),
|
|
||||||
),
|
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.kick:
|
||||||
|
if (await showOkCancelAlertDialog(
|
||||||
|
useRootNavigator: false,
|
||||||
|
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(
|
||||||
|
useRootNavigator: false,
|
||||||
|
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 score = await showModalActionPopup<int>(
|
||||||
|
context: context,
|
||||||
|
title: L10n.of(context).reportUser,
|
||||||
|
message: L10n.of(context).howOffensiveIsThisContent,
|
||||||
|
cancelLabel: L10n.of(context).cancel,
|
||||||
|
actions: [
|
||||||
|
AdaptiveModalAction(
|
||||||
|
value: -100,
|
||||||
|
label: L10n.of(context).extremeOffensive,
|
||||||
),
|
),
|
||||||
if (!isMe)
|
AdaptiveModalAction(
|
||||||
PopupMenuItem(
|
value: -50,
|
||||||
value: _MemberActions.report,
|
label: L10n.of(context).offensive,
|
||||||
child: ListTile(
|
|
||||||
leading: Icon(
|
|
||||||
Icons.gavel_outlined,
|
|
||||||
color: theme.colorScheme.onErrorContainer,
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
L10n.of(context).reportUser,
|
|
||||||
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
AdaptiveModalAction(
|
||||||
child: child,
|
value: 0,
|
||||||
);
|
label: L10n.of(context).inoffensive,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
if (score == null) return;
|
||||||
|
final reason = await showTextInputDialog(
|
||||||
|
useRootNavigator: false,
|
||||||
|
context: context,
|
||||||
|
title: L10n.of(context).whyDoYouWantToReportThis,
|
||||||
|
okLabel: L10n.of(context).ok,
|
||||||
|
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.reportEvent(
|
||||||
|
user.room.id,
|
||||||
|
user.id,
|
||||||
|
reason: reason,
|
||||||
|
score: score,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
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(
|
||||||
|
useRootNavigator: false,
|
||||||
|
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(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
|
import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
|
||||||
import 'package:fluffychat/widgets/adaptive_dialogs/dialog_text_field.dart';
|
import 'package:fluffychat/widgets/adaptive_dialogs/dialog_text_field.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|
||||||
|
|
||||||
Future<int?> showPermissionChooser(
|
Future<int?> showPermissionChooser(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue