diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 2d339d4..b9bef0f 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -16,6 +16,9 @@ "ignoreUser": "Ignore user", "normalUser": "Normal user", "pinCode": "PIN code", + "displayNavigationRail": "Display navigation rail on mobile", + "enableGradient": "Enable bubble background gradient", + "translationDisabledInE2e": "Cloud translation is disabled in encrypted rooms to preserve privacy. Select specific words and use system context menu to translate with apps that support it.", "remove": "Remove", "@remove": { "type": "String", diff --git a/assets/l10n/intl_ru.arb b/assets/l10n/intl_ru.arb index dbdc681..72934ea 100644 --- a/assets/l10n/intl_ru.arb +++ b/assets/l10n/intl_ru.arb @@ -23,6 +23,9 @@ "importNow": "Импортировать сейчас", "@importNow": {}, "importEmojis": "Импортировать эмодзи", + "displayNavigationRail": "Всегда показывать боковую панель", + "enableGradient": "Фоновый градиент для сообщений", + "translationDisabledInE2e": "Облачные переводы недоступны в зашифрованных комнатах для защиты конфиденциальности. Выбирайте отдельные слова и переводите их через другие приложения.", "@importEmojis": {}, "importFromZipFile": "Импортировать из ZIP-файла", "@importFromZipFile": {}, diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index e8d1ac3..be6757e 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -12,6 +12,7 @@ abstract class AppConfig { static String _defaultHomeserver = 'extera.xyz'; static bool displayNavigationRail = true; + static bool enableGradient = true; static String get defaultHomeserver => _defaultHomeserver; static double fontSizeFactor = 1; @@ -113,5 +114,8 @@ abstract class AppConfig { if (json['hide_unknown_events'] is bool) { hideUnknownEvents = json['hide_unknown_events']; } + if (json['enable_gradient'] is bool) { + enableGradient = json['enable_gradient']; + } } } diff --git a/lib/config/setting_keys.dart b/lib/config/setting_keys.dart index 00332ee..a45036b 100644 --- a/lib/config/setting_keys.dart +++ b/lib/config/setting_keys.dart @@ -35,6 +35,7 @@ abstract class SettingKeys { 'chat.fluffy.swipeRightToLeftToReply'; static const String experimentalVoip = 'chat.fluffy.experimental_voip'; static const String showPresences = 'chat.fluffy.show_presences'; + static const String enableGradient = 'xyz.extera.next.enableGradient'; } enum AppSettings { @@ -45,6 +46,7 @@ enum AppSettings { audioRecordingBitRate('audioRecordingBitRate', 64000), audioRecordingSamplingRate('audioRecordingSamplingRate', 44100), enableSoftLogout('enableSoftLogout', false), + enableGradient('enableGradient', true), pushNotificationsGatewayUrl( 'pushNotificationsGatewayUrl', 'https://push.fluffychat.im/_matrix/push/v1/notify', diff --git a/lib/config/themes.dart b/lib/config/themes.dart index 87b383b..abed6dc 100644 --- a/lib/config/themes.dart +++ b/lib/config/themes.dart @@ -46,11 +46,11 @@ abstract class FluffyThemes { ? { 'surface': const Color.fromARGB(255, 0, 0, 0), 'surfaceBright': const Color.fromARGB(255, 0, 0, 0), - 'surfaceContainer': const Color.fromARGB(255, 22, 22, 22), - 'surfaceContainerHigh': const Color.fromARGB(255, 33, 33, 33), - 'surfaceContainerHighest': const Color.fromARGB(255, 33, 33, 33), - 'surfaceContainerLow': const Color.fromARGB(255, 22, 22, 22), - 'surfaceContainerLowest': const Color.fromARGB(255, 22, 22, 22), + 'surfaceContainer': const Color.fromARGB(255, 11, 11, 11), + 'surfaceContainerHigh': const Color.fromARGB(255, 22, 22, 22), + 'surfaceContainerHighest': const Color.fromARGB(255, 22, 22, 22), + 'surfaceContainerLow': const Color.fromARGB(255, 11, 11, 11), + 'surfaceContainerLowest': const Color.fromARGB(255, 8, 8, 8), 'surfaceDim': const Color.fromARGB(255, 0, 0, 0), 'surfaceTint': const Color.fromARGB(255, 11, 11, 11), 'surfaceVariant': const Color.fromARGB(255, 0, 0, 0), diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 4d1a375..73a4e7b 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -761,6 +761,12 @@ class ChatController extends State } void translateEventAction() async { + if (room.encrypted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(L10n.of(context).translationDisabledInE2e)), + ); + return; + } final event = selectedEvents.single; var text = event.isRichMessage ? event.formattedText : event.text; if (text == null) { diff --git a/lib/pages/chat/chat_event_list.dart b/lib/pages/chat/chat_event_list.dart index 01feeae..e9e89f0 100644 --- a/lib/pages/chat/chat_event_list.dart +++ b/lib/pages/chat/chat_event_list.dart @@ -1,3 +1,4 @@ +import 'package:fluffychat/config/app_config.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -150,6 +151,7 @@ class ChatEventList extends StatelessWidget { wallpaperMode: hasWallpaper, scrollController: controller.scrollController, colors: colors, + gradient: AppConfig.enableGradient, ), ); }, diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index a524871..2125b23 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -41,6 +41,7 @@ class Message extends StatelessWidget { final bool wallpaperMode; final ScrollController? scrollController; final List colors; + final bool gradient; const Message( this.event, { @@ -48,6 +49,7 @@ class Message extends StatelessWidget { this.previousEvent, this.displayReadMarker = false, this.longPressSelect = false, + this.gradient = false, required this.onSelect, required this.onInfoTab, required this.scrollToEventId, @@ -328,7 +330,7 @@ class Message extends StatelessWidget { clipBehavior: Clip.antiAlias, child: BubbleBackground( colors: colors, - ignore: noBubble || !ownMessage, + ignore: noBubble || !ownMessage || !gradient, scrollController: scrollController, child: Container( decoration: BoxDecoration( @@ -638,7 +640,7 @@ class BubblePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { - if (!(context.widget is ScrollView || context.widget is SingleChildScrollView)) return; + // if (!(context.widget is ScrollView || context.widget is SingleChildScrollView)) return; final scrollable = _scrollable ??= Scrollable.of(context); final scrollableBox = scrollable.context.findRenderObject() as RenderBox; final scrollableRect = Offset.zero & scrollableBox.size; diff --git a/lib/pages/chat/events/poll_content.dart b/lib/pages/chat/events/poll_content.dart index ccbc216..0a062ae 100644 --- a/lib/pages/chat/events/poll_content.dart +++ b/lib/pages/chat/events/poll_content.dart @@ -30,7 +30,15 @@ class PollWidgetState extends State { padding: EdgeInsetsGeometry.all(16), child: Column( children: [ - Text(content?['question']['m.text'] as String, style: TextStyle(fontWeight: FontWeight.bold)) + Text(content?['question']['m.text'] as String, style: TextStyle(fontWeight: FontWeight.bold)), + Padding( + padding: EdgeInsets.fromLTRB(4, 4, 4, 2), + child: Column( + children: [ + + ], + ), + ) ], ), ); diff --git a/lib/pages/chat/translated_event_dialog.dart b/lib/pages/chat/translated_event_dialog.dart index 879c828..a0b61df 100644 --- a/lib/pages/chat/translated_event_dialog.dart +++ b/lib/pages/chat/translated_event_dialog.dart @@ -49,6 +49,7 @@ class TranslatedEventDialogState extends State { longPressSelect: false, selected: false, wallpaperMode: false, + gradient: false ); return Scaffold( diff --git a/lib/pages/chat_list/chat_list_view.dart b/lib/pages/chat_list/chat_list_view.dart index 8f41281..cd62a12 100644 --- a/lib/pages/chat_list/chat_list_view.dart +++ b/lib/pages/chat_list/chat_list_view.dart @@ -1,3 +1,4 @@ +import 'package:fluffychat/config/app_config.dart'; import 'package:flutter/material.dart'; import 'package:fluffychat/generated/l10n/l10n.dart'; @@ -30,8 +31,7 @@ class ChatListView extends StatelessWidget { }, child: Row( children: [ - if (FluffyThemes.isColumnMode(context) && - controller.widget.displayNavigationRail) ...[ + if (FluffyThemes.isColumnMode(context) || AppConfig.displayNavigationRail) ...[ SpacesNavigationRail( activeSpaceId: controller.activeSpaceId, onGoToChats: controller.clearActiveSpace, diff --git a/lib/pages/image_viewer/image_viewer.dart b/lib/pages/image_viewer/image_viewer.dart index d42a845..28da2c4 100644 --- a/lib/pages/image_viewer/image_viewer.dart +++ b/lib/pages/image_viewer/image_viewer.dart @@ -56,10 +56,10 @@ class ImageViewerController extends State { void onKeyEvent(KeyEvent event) { switch (event.logicalKey) { - case LogicalKeyboardKey.arrowLeft: + case LogicalKeyboardKey.arrowUp: if (canGoBack) prevImage(); break; - case LogicalKeyboardKey.arrowRight: + case LogicalKeyboardKey.arrowDown: if (canGoNext) nextImage(); break; } @@ -119,4 +119,4 @@ class ImageViewerController extends State { @override Widget build(BuildContext context) => ImageViewerView(this); -} +} \ No newline at end of file diff --git a/lib/pages/image_viewer/image_viewer_view.dart b/lib/pages/image_viewer/image_viewer_view.dart index df4486e..45c27a7 100644 --- a/lib/pages/image_viewer/image_viewer_view.dart +++ b/lib/pages/image_viewer/image_viewer_view.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:fluffychat/generated/l10n/l10n.dart'; import 'package:matrix/matrix.dart'; +import 'package:fluffychat/generated/l10n/l10n.dart'; import 'package:fluffychat/pages/image_viewer/video_player.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/hover_builder.dart'; @@ -75,6 +75,7 @@ class ImageViewerView extends StatelessWidget { focusNode: controller.focusNode, onKeyEvent: controller.onKeyEvent, child: PageView.builder( + scrollDirection: Axis.vertical, controller: controller.pageController, itemCount: controller.allEvents.length, itemBuilder: (context, i) { @@ -119,30 +120,33 @@ class ImageViewerView extends StatelessWidget { }, ), ), - if (hovered && controller.canGoBack) - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.all(12.0), - child: IconButton( - style: iconButtonStyle, - tooltip: L10n.of(context).previous, - icon: const Icon(Icons.chevron_left_outlined), - onPressed: controller.prevImage, - ), - ), - ), - if (hovered && controller.canGoNext) + if (hovered) Align( alignment: Alignment.centerRight, - child: Padding( - padding: const EdgeInsets.all(12.0), - child: IconButton( - style: iconButtonStyle, - tooltip: L10n.of(context).next, - icon: const Icon(Icons.chevron_right_outlined), - onPressed: controller.nextImage, - ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (controller.canGoBack) + Padding( + padding: const EdgeInsets.all(12.0), + child: IconButton( + style: iconButtonStyle, + tooltip: L10n.of(context).previous, + icon: const Icon(Icons.arrow_upward_outlined), + onPressed: controller.prevImage, + ), + ), + if (controller.canGoNext) + Padding( + padding: const EdgeInsets.all(12.0), + child: IconButton( + style: iconButtonStyle, + tooltip: L10n.of(context).next, + icon: const Icon(Icons.arrow_downward_outlined), + onPressed: controller.nextImage, + ), + ), + ], ), ), ], diff --git a/lib/pages/settings_style/settings_style_view.dart b/lib/pages/settings_style/settings_style_view.dart index 27663dd..e02bd6e 100644 --- a/lib/pages/settings_style/settings_style_view.dart +++ b/lib/pages/settings_style/settings_style_view.dart @@ -233,7 +233,7 @@ class SettingsStyleView extends StatelessWidget { vertical: 8, ), child: Text( - 'Рассказать шутку?', + 'Я такой угарный анекдот про зайца вспомнил, го расскажу прямо на странице настроек?', style: TextStyle( color: theme.onBubbleColor, fontSize: AppConfig.messageFontSize * @@ -314,6 +314,12 @@ class SettingsStyleView extends StatelessWidget { ], ), ), + SettingsSwitchListTile.adaptive( + title: L10n.of(context).enableGradient, + onChanged: (b) => AppConfig.enableGradient = b, + storeKey: SettingKeys.enableGradient, + defaultValue: AppConfig.enableGradient, + ), Divider( color: theme.dividerColor, ), @@ -398,6 +404,12 @@ class SettingsStyleView extends StatelessWidget { storeKey: SettingKeys.separateChatTypes, defaultValue: AppConfig.separateChatTypes, ), + SettingsSwitchListTile.adaptive( + title: L10n.of(context).displayNavigationRail, + onChanged: (b) => AppConfig.displayNavigationRail = b, + storeKey: SettingKeys.displayNavigationRail, + defaultValue: AppConfig.displayNavigationRail, + ), ], ), ), diff --git a/lib/widgets/matrix.dart b/lib/widgets/matrix.dart index b643c49..7b737bd 100644 --- a/lib/widgets/matrix.dart +++ b/lib/widgets/matrix.dart @@ -442,6 +442,10 @@ class MatrixState extends State with WidgetsBindingObserver { AppConfig.displayNavigationRail = store.getBool(SettingKeys.displayNavigationRail) ?? AppConfig.displayNavigationRail; + + AppConfig.enableGradient = + store.getBool(SettingKeys.enableGradient) ?? + AppConfig.enableGradient; } @override diff --git a/lib/widgets/member_actions_popup_menu_button.dart b/lib/widgets/member_actions_popup_menu_button.dart index 6ad6879..341bfa8 100644 --- a/lib/widgets/member_actions_popup_menu_button.dart +++ b/lib/widgets/member_actions_popup_menu_button.dart @@ -137,7 +137,7 @@ void showMemberActionsPopupMenu({ ], ), ), - if (user.canBan) + if (user.canBan && user.membership != Membership.ban) PopupMenuItem( value: _MemberActions.ban, child: Row( diff --git a/lib/widgets/navigation_rail.dart b/lib/widgets/navigation_rail.dart index 00b0672..ed5402e 100644 --- a/lib/widgets/navigation_rail.dart +++ b/lib/widgets/navigation_rail.dart @@ -32,7 +32,10 @@ class SpacesNavigationRail extends StatelessWidget { .value .uri .path - .startsWith('/rooms/settings'); + .startsWith('/rooms/settings') + && FluffyThemes.isColumnMode(context); + // workaround on settings button remaining selected. + // who will even see it selected on mobile? return StreamBuilder( key: ValueKey( client.userID.toString(),