diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index f787f2b4f..c90ca6d55 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -677,7 +677,7 @@ "type": "text", "placeholders": {} }, - "defaultPermissionLevel": "Default permission level", + "defaultPermissionLevel": "Default permission level for new users", "@defaultPermissionLevel": { "type": "text", "placeholders": {} @@ -4152,5 +4152,33 @@ "type": "text", "space": {} }, - "markAsUnread": "Mark as unread" + "markAsUnread": "Mark as unread", + "userLevel": "{level} - User", + "@userLevel": { + "type": "text", + "placeholders": { + "level": {} + } + }, + "moderatorLevel": "{level} - Moderator", + "@moderatorLevel": { + "type": "text", + "placeholders": { + "level": {} + } + }, + "adminLevel": "{level} - Admin", + "@adminLevel": { + "type": "text", + "placeholders": { + "level": {} + } + }, + "changeGeneralChatSettings": "Change general chat settings", + "inviteOtherUsers": "Invite other users to this chat", + "changeTheChatPermissions": "Change the chat permissions", + "changeTheVisibilityOfChatHistory": "Change the visibility of the chat history", + "changeTheCanonicalRoomAlias": "Change the main public chat address", + "sendRoomNotifications": "Send a @room notifications", + "changeTheDescriptionOfTheGroup": "Change the description of the chat" } \ No newline at end of file diff --git a/lib/pages/chat/send_file_dialog.dart b/lib/pages/chat/send_file_dialog.dart index b50a7d19e..f97a4f2c6 100644 --- a/lib/pages/chat/send_file_dialog.dart +++ b/lib/pages/chat/send_file_dialog.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -6,7 +8,7 @@ import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/utils/localized_exception_extension.dart'; +import 'package:fluffychat/utils/error_reporter.dart'; import 'package:fluffychat/utils/size_string.dart'; import '../../utils/resize_image.dart'; @@ -42,19 +44,20 @@ class SendFileDialogState extends State { }, ); } - final scaffoldMessenger = ScaffoldMessenger.of(context); - widget.room - .sendFileEvent( - file, - thumbnail: thumbnail, - shrinkImageMaxDimension: origImage ? null : 1600, - ) - .catchError((e) { - scaffoldMessenger.showSnackBar( - SnackBar(content: Text((e as Object).toLocalizedString(context))), + try { + await widget.room.sendFileEvent( + file, + thumbnail: thumbnail, + shrinkImageMaxDimension: origImage ? null : 1600, ); - return null; - }); + } on IOException catch (_) { + } on FileTooBigMatrixException catch (_) { + } catch (e, s) { + if (mounted) { + ErrorReporter(context, 'Unable to send file').onErrorCallback(e, s); + } + rethrow; + } } Navigator.of(context, rootNavigator: false).pop(); diff --git a/lib/pages/chat_access_settings/chat_access_settings_controller.dart b/lib/pages/chat_access_settings/chat_access_settings_controller.dart index c0ab1fa7a..fd7624790 100644 --- a/lib/pages/chat_access_settings/chat_access_settings_controller.dart +++ b/lib/pages/chat_access_settings/chat_access_settings_controller.dart @@ -24,6 +24,36 @@ class ChatAccessSettingsController extends State { bool guestAccessLoading = false; Room get room => Matrix.of(context).client.getRoomById(widget.roomId)!; + String get roomVersion => + room + .getState(EventTypes.RoomCreate)! + .content + .tryGet('room_version') ?? + 'Unknown'; + + /// Calculates which join rules are available based on the information on + /// https://spec.matrix.org/v1.11/rooms/#feature-matrix + List get availableJoinRules { + final joinRules = Set.from(JoinRules.values); + + final roomVersionInt = int.tryParse(roomVersion); + + // Knock is only supported for rooms up from version 7: + if (roomVersionInt != null && roomVersionInt <= 6) { + joinRules.remove(JoinRules.knock); + } + + // Not yet supported in FluffyChat: + joinRules.remove(JoinRules.restricted); + joinRules.remove(JoinRules.knockRestricted); + + // If an unsupported join rule is the current join rule, display it: + final currentJoinRule = room.joinRules; + if (currentJoinRule != null) joinRules.add(currentJoinRule); + + return joinRules.toList(); + } + void setJoinRule(JoinRules? newJoinRules) async { if (newJoinRules == null) return; setState(() { diff --git a/lib/pages/chat_access_settings/chat_access_settings_page.dart b/lib/pages/chat_access_settings/chat_access_settings_page.dart index 7de6f3793..c23d9dc6b 100644 --- a/lib/pages/chat_access_settings/chat_access_settings_page.dart +++ b/lib/pages/chat_access_settings/chat_access_settings_page.dart @@ -66,7 +66,7 @@ class ChatAccessSettingsPageView extends StatelessWidget { ), ), ), - for (final joinRule in JoinRules.values) + for (final joinRule in controller.availableJoinRules) if (joinRule != JoinRules.private) RadioListTile.adaptive( title: Text( diff --git a/lib/pages/chat_permissions_settings/permission_list_tile.dart b/lib/pages/chat_permissions_settings/permission_list_tile.dart index 04a2d3a60..e319e7467 100644 --- a/lib/pages/chat_permissions_settings/permission_list_tile.dart +++ b/lib/pages/chat_permissions_settings/permission_list_tile.dart @@ -1,6 +1,4 @@ import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/pangea/extensions/client_extension/client_extension.dart'; -import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; @@ -29,7 +27,7 @@ class PermissionsListTile extends StatelessWidget { case 'events_default': return L10n.of(context)!.sendMessages; case 'state_default': - return L10n.of(context)!.configureChat; + return L10n.of(context)!.changeGeneralChatSettings; case 'ban': return L10n.of(context)!.banFromChat; case 'kick': @@ -37,23 +35,25 @@ class PermissionsListTile extends StatelessWidget { case 'redact': return L10n.of(context)!.deleteMessage; case 'invite': - return L10n.of(context)!.inviteContact; + return L10n.of(context)!.inviteOtherUsers; } } else if (category == 'notifications') { switch (permissionKey) { case 'rooms': - return L10n.of(context)!.notifications; + return L10n.of(context)!.sendRoomNotifications; } } else if (category == 'events') { switch (permissionKey) { case EventTypes.RoomName: return L10n.of(context)!.changeTheNameOfTheGroup; + case EventTypes.RoomTopic: + return L10n.of(context)!.changeTheDescriptionOfTheGroup; case EventTypes.RoomPowerLevels: - return L10n.of(context)!.chatPermissions; + return L10n.of(context)!.changeTheChatPermissions; case EventTypes.HistoryVisibility: - return L10n.of(context)!.visibilityOfTheChatHistory; + return L10n.of(context)!.changeTheVisibilityOfChatHistory; case EventTypes.RoomCanonicalAlias: - return L10n.of(context)!.setInvitationLink; + return L10n.of(context)!.changeTheCanonicalRoomAlias; case EventTypes.RoomAvatar: return L10n.of(context)!.editRoomAvatar; case EventTypes.RoomTombstone: @@ -69,41 +69,40 @@ class PermissionsListTile extends StatelessWidget { @override Widget build(BuildContext context) { + final color = permission >= 100 + ? Colors.orangeAccent + : permission >= 50 + ? Colors.blueAccent + : Colors.greenAccent; return ListTile( - title: Text(getLocalizedPowerLevelString(context)), - subtitle: Text( - // #Pangea - // L10n.of(context)!.minimumPowerLevel(permission.toString()), - L10n.of(context)!.minimumPowerLevel( - Matrix.of(context).client.powerLevelName( - permission, - L10n.of(context)!, - ) ?? - permission.toString(), - ), - // Pangea# + title: Text( + getLocalizedPowerLevelString(context), + style: Theme.of(context).textTheme.titleSmall, ), trailing: Material( - borderRadius: BorderRadius.circular(AppConfig.borderRadius / 2), - color: Theme.of(context).colorScheme.onInverseSurface, + color: color.withAlpha(64), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(AppConfig.borderRadius / 2), + side: BorderSide(color: color), + ), child: DropdownButton( padding: const EdgeInsets.symmetric(horizontal: 8.0), borderRadius: BorderRadius.circular(AppConfig.borderRadius / 2), underline: const SizedBox.shrink(), onChanged: canEdit ? onChanged : null, - value: {0, 50, 100}.contains(permission) ? permission : null, + value: permission, items: [ DropdownMenuItem( - value: 0, - child: Text(L10n.of(context)!.user), + value: permission < 50 ? permission : 0, + child: Text(L10n.of(context)!.userLevel(permission)), ), DropdownMenuItem( - value: 50, - child: Text(L10n.of(context)!.moderator), + value: permission < 100 && permission >= 50 ? permission : 50, + child: Text(L10n.of(context)!.moderatorLevel(permission)), ), DropdownMenuItem( - value: 100, - child: Text(L10n.of(context)!.admin), + value: permission >= 100 ? permission : 100, + child: Text(L10n.of(context)!.adminLevel(permission)), ), DropdownMenuItem( value: null,