✨ Message translation
This commit is contained in:
parent
aecd04e0b9
commit
d2f4e7a969
@ -10,6 +10,7 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/providers/config.dart';
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/keypair.dart';
|
import 'package:surface/providers/keypair.dart';
|
||||||
|
import 'package:surface/providers/translation.dart';
|
||||||
import 'package:surface/providers/user_directory.dart';
|
import 'package:surface/providers/user_directory.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
import 'package:surface/types/chat.dart';
|
import 'package:surface/types/chat.dart';
|
||||||
@ -18,6 +19,7 @@ import 'package:surface/widgets/account/account_popover.dart';
|
|||||||
import 'package:surface/widgets/account/badge.dart';
|
import 'package:surface/widgets/account/badge.dart';
|
||||||
import 'package:surface/widgets/attachment/attachment_list.dart';
|
import 'package:surface/widgets/attachment/attachment_list.dart';
|
||||||
import 'package:surface/widgets/context_menu.dart';
|
import 'package:surface/widgets/context_menu.dart';
|
||||||
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/link_preview.dart';
|
import 'package:surface/widgets/link_preview.dart';
|
||||||
import 'package:surface/widgets/markdown_content.dart';
|
import 'package:surface/widgets/markdown_content.dart';
|
||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
@ -228,7 +230,7 @@ class ChatMessage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChatMessageText extends StatelessWidget {
|
class _ChatMessageText extends StatefulWidget {
|
||||||
final SnChatMessage data;
|
final SnChatMessage data;
|
||||||
final Function(SnChatMessage)? onReply;
|
final Function(SnChatMessage)? onReply;
|
||||||
final Function(SnChatMessage)? onEdit;
|
final Function(SnChatMessage)? onEdit;
|
||||||
@ -237,13 +239,38 @@ class _ChatMessageText extends StatelessWidget {
|
|||||||
const _ChatMessageText(
|
const _ChatMessageText(
|
||||||
{required this.data, this.onReply, this.onEdit, this.onDelete});
|
{required this.data, this.onReply, this.onEdit, this.onDelete});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_ChatMessageText> createState() => _ChatMessageTextState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChatMessageTextState extends State<_ChatMessageText> {
|
||||||
|
late String _displayText = widget.data.body['text'] ?? '';
|
||||||
|
bool _isTranslated = false;
|
||||||
|
|
||||||
|
Future<void> _translateText() async {
|
||||||
|
final ta = context.read<SnTranslator>();
|
||||||
|
try {
|
||||||
|
final to = EasyLocalization.of(context)!.locale.languageCode;
|
||||||
|
_displayText = await ta.translate(
|
||||||
|
widget.data.body['text'],
|
||||||
|
to: to,
|
||||||
|
);
|
||||||
|
_isTranslated = true;
|
||||||
|
if (mounted) setState(() {});
|
||||||
|
} catch (err) {
|
||||||
|
if (mounted) context.showErrorDialog(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ua = context.read<UserProvider>();
|
final ua = context.read<UserProvider>();
|
||||||
|
|
||||||
final isOwner = ua.isAuthorized && data.sender.accountId == ua.user?.id;
|
final isOwner =
|
||||||
|
ua.isAuthorized && widget.data.sender.accountId == ua.user?.id;
|
||||||
|
|
||||||
if (data.body['text'] != null && data.body['text'].isNotEmpty) {
|
if (widget.data.body['text'] != null &&
|
||||||
|
widget.data.body['text'].isNotEmpty) {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -252,38 +279,50 @@ class _ChatMessageText extends StatelessWidget {
|
|||||||
final List<ContextMenuButtonItem> items =
|
final List<ContextMenuButtonItem> items =
|
||||||
editableTextState.contextMenuButtonItems;
|
editableTextState.contextMenuButtonItems;
|
||||||
|
|
||||||
if (onReply != null) {
|
if (widget.onReply != null) {
|
||||||
items.insert(
|
items.insert(
|
||||||
0,
|
0,
|
||||||
ContextMenuButtonItem(
|
ContextMenuButtonItem(
|
||||||
label: 'reply'.tr(),
|
label: 'reply'.tr(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ContextMenuController.removeAny();
|
ContextMenuController.removeAny();
|
||||||
onReply?.call(data);
|
widget.onReply?.call(widget.data);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (isOwner && onEdit != null) {
|
if (isOwner && widget.onEdit != null) {
|
||||||
items.insert(
|
items.insert(
|
||||||
1,
|
1,
|
||||||
ContextMenuButtonItem(
|
ContextMenuButtonItem(
|
||||||
label: 'edit'.tr(),
|
label: 'edit'.tr(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ContextMenuController.removeAny();
|
ContextMenuController.removeAny();
|
||||||
onEdit?.call(data);
|
widget.onEdit?.call(widget.data);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (isOwner && onDelete != null) {
|
if (isOwner && widget.onDelete != null) {
|
||||||
items.insert(
|
items.insert(
|
||||||
2,
|
2,
|
||||||
ContextMenuButtonItem(
|
ContextMenuButtonItem(
|
||||||
label: 'delete'.tr(),
|
label: 'delete'.tr(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ContextMenuController.removeAny();
|
ContextMenuController.removeAny();
|
||||||
onDelete?.call(data);
|
widget.onDelete?.call(widget.data);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (widget.data.body['algorithm'] == 'plain') {
|
||||||
|
items.insert(
|
||||||
|
3,
|
||||||
|
ContextMenuButtonItem(
|
||||||
|
label: 'translate'.tr(),
|
||||||
|
onPressed: () {
|
||||||
|
ContextMenuController.removeAny();
|
||||||
|
_translateText();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -294,26 +333,37 @@ class _ChatMessageText extends StatelessWidget {
|
|||||||
buttonItems: items,
|
buttonItems: items,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: switch (data.body['algorithm']) {
|
child: switch (widget.data.body['algorithm']) {
|
||||||
'rsa' => _ChatDecryptMessage(message: data),
|
'rsa' => _ChatDecryptMessage(message: widget.data),
|
||||||
_ => MarkdownTextContent(
|
_ => MarkdownTextContent(
|
||||||
content: data.body['text'],
|
content: _displayText,
|
||||||
isAutoWarp: true,
|
isAutoWarp: true,
|
||||||
isEnlargeSticker:
|
isEnlargeSticker: RegExp(r"^:([-\w]+):$")
|
||||||
RegExp(r"^:([-\w]+):$").hasMatch(data.body['text'] ?? ''),
|
.hasMatch(widget.data.body['text'] ?? ''),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (data.updatedAt != data.createdAt)
|
if (widget.data.updatedAt != widget.data.createdAt)
|
||||||
Text('messageEditedHint'.tr()).fontSize(13).opacity(0.75),
|
Text('messageEditedHint'.tr()).fontSize(13).opacity(0.75),
|
||||||
|
if (_isTranslated)
|
||||||
|
InkWell(
|
||||||
|
child: Text('translated').tr().opacity(0.75),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_displayText = widget.data.body['text'] ?? '';
|
||||||
|
_isTranslated = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
} else if (data.body['attachments']?.isNotEmpty) {
|
} else if (widget.data.body['attachments']?.isNotEmpty) {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Symbols.file_present, size: 20),
|
const Icon(Symbols.file_present, size: 20),
|
||||||
const Gap(4),
|
const Gap(4),
|
||||||
Text('messageFileHint'.plural(data.body['attachments']!.length)),
|
Text('messageFileHint'
|
||||||
|
.plural(widget.data.body['attachments']!.length)),
|
||||||
],
|
],
|
||||||
).opacity(0.8);
|
).opacity(0.8);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user