feat: disable cloud translations in Encrypted Rooms
feat: follow with fluffychat's image viewer feat: navigation rail on mobile feat: bring back bubble gradient as an option feat: darker amoled colors
This commit is contained in:
parent
6316dda939
commit
01f13723f5
|
|
@ -16,6 +16,9 @@
|
||||||
"ignoreUser": "Ignore user",
|
"ignoreUser": "Ignore user",
|
||||||
"normalUser": "Normal user",
|
"normalUser": "Normal user",
|
||||||
"pinCode": "PIN code",
|
"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": "Remove",
|
||||||
"@remove": {
|
"@remove": {
|
||||||
"type": "String",
|
"type": "String",
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@
|
||||||
"importNow": "Импортировать сейчас",
|
"importNow": "Импортировать сейчас",
|
||||||
"@importNow": {},
|
"@importNow": {},
|
||||||
"importEmojis": "Импортировать эмодзи",
|
"importEmojis": "Импортировать эмодзи",
|
||||||
|
"displayNavigationRail": "Всегда показывать боковую панель",
|
||||||
|
"enableGradient": "Фоновый градиент для сообщений",
|
||||||
|
"translationDisabledInE2e": "Облачные переводы недоступны в зашифрованных комнатах для защиты конфиденциальности. Выбирайте отдельные слова и переводите их через другие приложения.",
|
||||||
"@importEmojis": {},
|
"@importEmojis": {},
|
||||||
"importFromZipFile": "Импортировать из ZIP-файла",
|
"importFromZipFile": "Импортировать из ZIP-файла",
|
||||||
"@importFromZipFile": {},
|
"@importFromZipFile": {},
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ abstract class AppConfig {
|
||||||
static String _defaultHomeserver = 'extera.xyz';
|
static String _defaultHomeserver = 'extera.xyz';
|
||||||
|
|
||||||
static bool displayNavigationRail = true;
|
static bool displayNavigationRail = true;
|
||||||
|
static bool enableGradient = true;
|
||||||
|
|
||||||
static String get defaultHomeserver => _defaultHomeserver;
|
static String get defaultHomeserver => _defaultHomeserver;
|
||||||
static double fontSizeFactor = 1;
|
static double fontSizeFactor = 1;
|
||||||
|
|
@ -113,5 +114,8 @@ abstract class AppConfig {
|
||||||
if (json['hide_unknown_events'] is bool) {
|
if (json['hide_unknown_events'] is bool) {
|
||||||
hideUnknownEvents = json['hide_unknown_events'];
|
hideUnknownEvents = json['hide_unknown_events'];
|
||||||
}
|
}
|
||||||
|
if (json['enable_gradient'] is bool) {
|
||||||
|
enableGradient = json['enable_gradient'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ abstract class SettingKeys {
|
||||||
'chat.fluffy.swipeRightToLeftToReply';
|
'chat.fluffy.swipeRightToLeftToReply';
|
||||||
static const String experimentalVoip = 'chat.fluffy.experimental_voip';
|
static const String experimentalVoip = 'chat.fluffy.experimental_voip';
|
||||||
static const String showPresences = 'chat.fluffy.show_presences';
|
static const String showPresences = 'chat.fluffy.show_presences';
|
||||||
|
static const String enableGradient = 'xyz.extera.next.enableGradient';
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AppSettings<T> {
|
enum AppSettings<T> {
|
||||||
|
|
@ -45,6 +46,7 @@ enum AppSettings<T> {
|
||||||
audioRecordingBitRate<int>('audioRecordingBitRate', 64000),
|
audioRecordingBitRate<int>('audioRecordingBitRate', 64000),
|
||||||
audioRecordingSamplingRate<int>('audioRecordingSamplingRate', 44100),
|
audioRecordingSamplingRate<int>('audioRecordingSamplingRate', 44100),
|
||||||
enableSoftLogout<bool>('enableSoftLogout', false),
|
enableSoftLogout<bool>('enableSoftLogout', false),
|
||||||
|
enableGradient<bool>('enableGradient', true),
|
||||||
pushNotificationsGatewayUrl<String>(
|
pushNotificationsGatewayUrl<String>(
|
||||||
'pushNotificationsGatewayUrl',
|
'pushNotificationsGatewayUrl',
|
||||||
'https://push.fluffychat.im/_matrix/push/v1/notify',
|
'https://push.fluffychat.im/_matrix/push/v1/notify',
|
||||||
|
|
|
||||||
|
|
@ -46,11 +46,11 @@ abstract class FluffyThemes {
|
||||||
? {
|
? {
|
||||||
'surface': const Color.fromARGB(255, 0, 0, 0),
|
'surface': const Color.fromARGB(255, 0, 0, 0),
|
||||||
'surfaceBright': const Color.fromARGB(255, 0, 0, 0),
|
'surfaceBright': const Color.fromARGB(255, 0, 0, 0),
|
||||||
'surfaceContainer': const Color.fromARGB(255, 22, 22, 22),
|
'surfaceContainer': const Color.fromARGB(255, 11, 11, 11),
|
||||||
'surfaceContainerHigh': const Color.fromARGB(255, 33, 33, 33),
|
'surfaceContainerHigh': const Color.fromARGB(255, 22, 22, 22),
|
||||||
'surfaceContainerHighest': const Color.fromARGB(255, 33, 33, 33),
|
'surfaceContainerHighest': const Color.fromARGB(255, 22, 22, 22),
|
||||||
'surfaceContainerLow': const Color.fromARGB(255, 22, 22, 22),
|
'surfaceContainerLow': const Color.fromARGB(255, 11, 11, 11),
|
||||||
'surfaceContainerLowest': const Color.fromARGB(255, 22, 22, 22),
|
'surfaceContainerLowest': const Color.fromARGB(255, 8, 8, 8),
|
||||||
'surfaceDim': const Color.fromARGB(255, 0, 0, 0),
|
'surfaceDim': const Color.fromARGB(255, 0, 0, 0),
|
||||||
'surfaceTint': const Color.fromARGB(255, 11, 11, 11),
|
'surfaceTint': const Color.fromARGB(255, 11, 11, 11),
|
||||||
'surfaceVariant': const Color.fromARGB(255, 0, 0, 0),
|
'surfaceVariant': const Color.fromARGB(255, 0, 0, 0),
|
||||||
|
|
|
||||||
|
|
@ -761,6 +761,12 @@ class ChatController extends State<ChatPageWithRoom>
|
||||||
}
|
}
|
||||||
|
|
||||||
void translateEventAction() async {
|
void translateEventAction() async {
|
||||||
|
if (room.encrypted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(L10n.of(context).translationDisabledInE2e)),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
final event = selectedEvents.single;
|
final event = selectedEvents.single;
|
||||||
var text = event.isRichMessage ? event.formattedText : event.text;
|
var text = event.isRichMessage ? event.formattedText : event.text;
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
@ -150,6 +151,7 @@ class ChatEventList extends StatelessWidget {
|
||||||
wallpaperMode: hasWallpaper,
|
wallpaperMode: hasWallpaper,
|
||||||
scrollController: controller.scrollController,
|
scrollController: controller.scrollController,
|
||||||
colors: colors,
|
colors: colors,
|
||||||
|
gradient: AppConfig.enableGradient,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ class Message extends StatelessWidget {
|
||||||
final bool wallpaperMode;
|
final bool wallpaperMode;
|
||||||
final ScrollController? scrollController;
|
final ScrollController? scrollController;
|
||||||
final List<Color> colors;
|
final List<Color> colors;
|
||||||
|
final bool gradient;
|
||||||
|
|
||||||
const Message(
|
const Message(
|
||||||
this.event, {
|
this.event, {
|
||||||
|
|
@ -48,6 +49,7 @@ class Message extends StatelessWidget {
|
||||||
this.previousEvent,
|
this.previousEvent,
|
||||||
this.displayReadMarker = false,
|
this.displayReadMarker = false,
|
||||||
this.longPressSelect = false,
|
this.longPressSelect = false,
|
||||||
|
this.gradient = false,
|
||||||
required this.onSelect,
|
required this.onSelect,
|
||||||
required this.onInfoTab,
|
required this.onInfoTab,
|
||||||
required this.scrollToEventId,
|
required this.scrollToEventId,
|
||||||
|
|
@ -328,7 +330,7 @@ class Message extends StatelessWidget {
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: BubbleBackground(
|
child: BubbleBackground(
|
||||||
colors: colors,
|
colors: colors,
|
||||||
ignore: noBubble || !ownMessage,
|
ignore: noBubble || !ownMessage || !gradient,
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|
@ -638,7 +640,7 @@ class BubblePainter extends CustomPainter {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
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 scrollable = _scrollable ??= Scrollable.of(context);
|
||||||
final scrollableBox = scrollable.context.findRenderObject() as RenderBox;
|
final scrollableBox = scrollable.context.findRenderObject() as RenderBox;
|
||||||
final scrollableRect = Offset.zero & scrollableBox.size;
|
final scrollableRect = Offset.zero & scrollableBox.size;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,15 @@ class PollWidgetState extends State<PollWidget> {
|
||||||
padding: EdgeInsetsGeometry.all(16),
|
padding: EdgeInsetsGeometry.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
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: [
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ class TranslatedEventDialogState extends State<TranslatedEventDialog> {
|
||||||
longPressSelect: false,
|
longPressSelect: false,
|
||||||
selected: false,
|
selected: false,
|
||||||
wallpaperMode: false,
|
wallpaperMode: false,
|
||||||
|
gradient: false
|
||||||
);
|
);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/generated/l10n/l10n.dart';
|
import 'package:fluffychat/generated/l10n/l10n.dart';
|
||||||
|
|
@ -30,8 +31,7 @@ class ChatListView extends StatelessWidget {
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
if (FluffyThemes.isColumnMode(context) &&
|
if (FluffyThemes.isColumnMode(context) || AppConfig.displayNavigationRail) ...[
|
||||||
controller.widget.displayNavigationRail) ...[
|
|
||||||
SpacesNavigationRail(
|
SpacesNavigationRail(
|
||||||
activeSpaceId: controller.activeSpaceId,
|
activeSpaceId: controller.activeSpaceId,
|
||||||
onGoToChats: controller.clearActiveSpace,
|
onGoToChats: controller.clearActiveSpace,
|
||||||
|
|
|
||||||
|
|
@ -56,10 +56,10 @@ class ImageViewerController extends State<ImageViewer> {
|
||||||
|
|
||||||
void onKeyEvent(KeyEvent event) {
|
void onKeyEvent(KeyEvent event) {
|
||||||
switch (event.logicalKey) {
|
switch (event.logicalKey) {
|
||||||
case LogicalKeyboardKey.arrowLeft:
|
case LogicalKeyboardKey.arrowUp:
|
||||||
if (canGoBack) prevImage();
|
if (canGoBack) prevImage();
|
||||||
break;
|
break;
|
||||||
case LogicalKeyboardKey.arrowRight:
|
case LogicalKeyboardKey.arrowDown:
|
||||||
if (canGoNext) nextImage();
|
if (canGoNext) nextImage();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -119,4 +119,4 @@ class ImageViewerController extends State<ImageViewer> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => ImageViewerView(this);
|
Widget build(BuildContext context) => ImageViewerView(this);
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/generated/l10n/l10n.dart';
|
|
||||||
import 'package:matrix/matrix.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/pages/image_viewer/video_player.dart';
|
||||||
import 'package:fluffychat/utils/platform_infos.dart';
|
import 'package:fluffychat/utils/platform_infos.dart';
|
||||||
import 'package:fluffychat/widgets/hover_builder.dart';
|
import 'package:fluffychat/widgets/hover_builder.dart';
|
||||||
|
|
@ -75,6 +75,7 @@ class ImageViewerView extends StatelessWidget {
|
||||||
focusNode: controller.focusNode,
|
focusNode: controller.focusNode,
|
||||||
onKeyEvent: controller.onKeyEvent,
|
onKeyEvent: controller.onKeyEvent,
|
||||||
child: PageView.builder(
|
child: PageView.builder(
|
||||||
|
scrollDirection: Axis.vertical,
|
||||||
controller: controller.pageController,
|
controller: controller.pageController,
|
||||||
itemCount: controller.allEvents.length,
|
itemCount: controller.allEvents.length,
|
||||||
itemBuilder: (context, i) {
|
itemBuilder: (context, i) {
|
||||||
|
|
@ -119,30 +120,33 @@ class ImageViewerView extends StatelessWidget {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (hovered && controller.canGoBack)
|
if (hovered)
|
||||||
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)
|
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: Padding(
|
child: Column(
|
||||||
padding: const EdgeInsets.all(12.0),
|
mainAxisSize: MainAxisSize.min,
|
||||||
child: IconButton(
|
children: [
|
||||||
style: iconButtonStyle,
|
if (controller.canGoBack)
|
||||||
tooltip: L10n.of(context).next,
|
Padding(
|
||||||
icon: const Icon(Icons.chevron_right_outlined),
|
padding: const EdgeInsets.all(12.0),
|
||||||
onPressed: controller.nextImage,
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ class SettingsStyleView extends StatelessWidget {
|
||||||
vertical: 8,
|
vertical: 8,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Рассказать шутку?',
|
'Я такой угарный анекдот про зайца вспомнил, го расскажу прямо на странице настроек?',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: theme.onBubbleColor,
|
color: theme.onBubbleColor,
|
||||||
fontSize: AppConfig.messageFontSize *
|
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(
|
Divider(
|
||||||
color: theme.dividerColor,
|
color: theme.dividerColor,
|
||||||
),
|
),
|
||||||
|
|
@ -398,6 +404,12 @@ class SettingsStyleView extends StatelessWidget {
|
||||||
storeKey: SettingKeys.separateChatTypes,
|
storeKey: SettingKeys.separateChatTypes,
|
||||||
defaultValue: AppConfig.separateChatTypes,
|
defaultValue: AppConfig.separateChatTypes,
|
||||||
),
|
),
|
||||||
|
SettingsSwitchListTile.adaptive(
|
||||||
|
title: L10n.of(context).displayNavigationRail,
|
||||||
|
onChanged: (b) => AppConfig.displayNavigationRail = b,
|
||||||
|
storeKey: SettingKeys.displayNavigationRail,
|
||||||
|
defaultValue: AppConfig.displayNavigationRail,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -442,6 +442,10 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
||||||
AppConfig.displayNavigationRail =
|
AppConfig.displayNavigationRail =
|
||||||
store.getBool(SettingKeys.displayNavigationRail) ??
|
store.getBool(SettingKeys.displayNavigationRail) ??
|
||||||
AppConfig.displayNavigationRail;
|
AppConfig.displayNavigationRail;
|
||||||
|
|
||||||
|
AppConfig.enableGradient =
|
||||||
|
store.getBool(SettingKeys.enableGradient) ??
|
||||||
|
AppConfig.enableGradient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ void showMemberActionsPopupMenu({
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (user.canBan)
|
if (user.canBan && user.membership != Membership.ban)
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
value: _MemberActions.ban,
|
value: _MemberActions.ban,
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,10 @@ class SpacesNavigationRail extends StatelessWidget {
|
||||||
.value
|
.value
|
||||||
.uri
|
.uri
|
||||||
.path
|
.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(
|
return StreamBuilder(
|
||||||
key: ValueKey(
|
key: ValueKey(
|
||||||
client.userID.toString(),
|
client.userID.toString(),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue