mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-02 15:10:36 +10:00
Added Cyr2Lat compression by replacing 2-byte cyrillic chars by 1-byte latin
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -60,6 +61,8 @@ class AppSettingsScreen extends StatelessWidget {
|
||||
const SizedBox(height: 16),
|
||||
_buildMapSettingsCard(context, settingsService),
|
||||
const SizedBox(height: 16),
|
||||
_buildCyr2LatCard(context, settingsService),
|
||||
const SizedBox(height: 16),
|
||||
_buildDebugCard(context, settingsService),
|
||||
],
|
||||
);
|
||||
@@ -1255,6 +1258,116 @@ class AppSettingsScreen extends StatelessWidget {
|
||||
return '${sizeMb.toStringAsFixed(1)} MB • $source';
|
||||
}
|
||||
|
||||
Widget _buildCyr2LatCard(
|
||||
BuildContext context,
|
||||
AppSettingsService settingsService,
|
||||
) {
|
||||
return Card(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
child: Text(
|
||||
context.l10n.channels_cyr2latSettingsHeading,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.translate),
|
||||
|
||||
title: Text(context.l10n.channels_cyr2latSettingsSubheading),
|
||||
subtitle: Text(context.l10n.channels_cyr2latSettingsDscr),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () => _showCyr2LatDialog(context, settingsService),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showCyr2LatDialog(
|
||||
BuildContext context,
|
||||
AppSettingsService settingsService,
|
||||
) {
|
||||
final controller = TextEditingController(
|
||||
text: const JsonEncoder.withIndent(
|
||||
' ',
|
||||
).convert(settingsService.settings.cyr2latCharMap),
|
||||
);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(context.l10n.channels_cyr2latSettingsDscr),
|
||||
content: SingleChildScrollView(
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
maxLines: 20,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
hintText: context.l10n.channels_cyr2latSettingsDialogHint,
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(context.l10n.common_cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
try {
|
||||
final json =
|
||||
jsonDecode(controller.text) as Map<String, dynamic>;
|
||||
final map = json.map(
|
||||
(key, value) => MapEntry(key, value.toString()),
|
||||
);
|
||||
final newSettings = settingsService.settings.copyWith(
|
||||
cyr2latCharMap: map,
|
||||
);
|
||||
settingsService.updateSettings(newSettings);
|
||||
Navigator.pop(context);
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(
|
||||
context.l10n.channels_cyr2latSettingsDialogSuccess,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(
|
||||
context.l10n.channels_cyr2latSettingsDialogWrongJSON(
|
||||
e.toString(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(context.l10n.common_save),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
final newSettings = settingsService.settings.copyWith(
|
||||
cyr2latCharMap: defaultCyr2LatCharMap,
|
||||
);
|
||||
settingsService.updateSettings(newSettings);
|
||||
Navigator.pop(context);
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(
|
||||
context.l10n.channels_cyr2latSettingsDialogResetted,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(context.l10n.channels_cyr2latSettingsDialogReset),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDebugCard(
|
||||
BuildContext context,
|
||||
AppSettingsService settingsService,
|
||||
|
||||
@@ -11,6 +11,7 @@ import '../connector/meshcore_connector.dart';
|
||||
import '../utils/platform_info.dart';
|
||||
import '../helpers/chat_scroll_controller.dart';
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../helpers/cyr2lat.dart';
|
||||
import '../helpers/gif_helper.dart';
|
||||
import '../helpers/reaction_helper.dart';
|
||||
import '../helpers/snack_bar_builder.dart';
|
||||
@@ -1100,7 +1101,12 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
||||
hintText: context.l10n.chat_typeMessage,
|
||||
onSubmitted: (_) => _sendMessage(),
|
||||
encoder:
|
||||
connector.isChannelSmazEnabled(widget.channel.index)
|
||||
(connector.isChannelSmazEnabled(
|
||||
widget.channel.index,
|
||||
) ||
|
||||
connector.isChannelCyr2LatEnabled(
|
||||
widget.channel.index,
|
||||
))
|
||||
? (text) => connector.prepareChannelOutboundText(
|
||||
widget.channel.index,
|
||||
text,
|
||||
@@ -1213,6 +1219,15 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
||||
return;
|
||||
}
|
||||
|
||||
// When messageText is transformed with cyr2lat, it (generally) hasn't visual differences,
|
||||
// but we getting messages doubles in chat screen (source text and transformed).
|
||||
// To prevent, we'll perform transform of source before pass to main sender logic.
|
||||
// We can pass whole text, senderName will be kept intact
|
||||
if (connector.isChannelCyr2LatEnabled(widget.channel.index)) {
|
||||
messageText = Cyr2Lat.encode(messageText);
|
||||
}
|
||||
// end transform
|
||||
|
||||
_textController.clear();
|
||||
_cancelReply();
|
||||
_textFieldFocusNode.requestFocus();
|
||||
|
||||
@@ -1404,6 +1404,7 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
||||
final nameController = TextEditingController(text: channel.name);
|
||||
final pskController = TextEditingController(text: channel.pskHex);
|
||||
bool smazEnabled = connector.isChannelSmazEnabled(channel.index);
|
||||
bool cyr2latEnabled = connector.isChannelCyr2LatEnabled(channel.index);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
@@ -1449,7 +1450,26 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(dialogContext.l10n.channels_smazCompression),
|
||||
value: smazEnabled,
|
||||
onChanged: (value) => setState(() => smazEnabled = value),
|
||||
onChanged: (value) => setState(() {
|
||||
smazEnabled = value;
|
||||
if (smazEnabled) {
|
||||
cyr2latEnabled = false;
|
||||
}
|
||||
}),
|
||||
),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(dialogContext.l10n.channels_cyr2latCompression),
|
||||
subtitle: Text(
|
||||
dialogContext.l10n.channels_cyr2latCompressionDscr,
|
||||
),
|
||||
value: cyr2latEnabled,
|
||||
onChanged: (value) => setState(() {
|
||||
cyr2latEnabled = value;
|
||||
if (cyr2latEnabled) {
|
||||
smazEnabled = false;
|
||||
}
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -1482,6 +1502,10 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
||||
channel.index,
|
||||
smazEnabled,
|
||||
);
|
||||
await connector.setChannelCyr2LatEnabled(
|
||||
channel.index,
|
||||
cyr2latEnabled,
|
||||
);
|
||||
if (!context.mounted) return;
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
|
||||
@@ -13,6 +13,7 @@ import 'package:latlong2/latlong.dart';
|
||||
|
||||
import '../connector/meshcore_connector.dart';
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../helpers/cyr2lat.dart';
|
||||
import '../helpers/reaction_helper.dart';
|
||||
import '../widgets/message_status_icon.dart';
|
||||
import '../helpers/chat_scroll_controller.dart';
|
||||
@@ -574,9 +575,12 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
hintText: context.l10n.chat_typeMessage,
|
||||
onSubmitted: (_) => _sendMessage(connector),
|
||||
encoder:
|
||||
connector.isContactSmazEnabled(
|
||||
widget.contact.publicKeyHex,
|
||||
)
|
||||
(connector.isContactSmazEnabled(
|
||||
widget.contact.publicKeyHex,
|
||||
) ||
|
||||
connector.isContactCyr2LatEnabled(
|
||||
widget.contact.publicKeyHex,
|
||||
))
|
||||
? (text) => connector.prepareContactOutboundText(
|
||||
widget.contact,
|
||||
text,
|
||||
@@ -695,6 +699,18 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is only for cyr2lat compression - to see the message being sent in the same format as the other person will receive
|
||||
try {
|
||||
if (connector.isContactCyr2LatEnabled(
|
||||
_resolveContact(connector).publicKeyHex,
|
||||
)) {
|
||||
outgoingText = Cyr2Lat.encode(outgoingText);
|
||||
}
|
||||
} catch (_) {
|
||||
// TODO maybe log
|
||||
}
|
||||
// end transform
|
||||
|
||||
_textController.clear();
|
||||
_textFieldFocusNode.requestFocus();
|
||||
connector.sendMessage(
|
||||
@@ -1196,8 +1212,12 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
void _showContactSettings(BuildContext context) {
|
||||
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
|
||||
connector.ensureContactSmazSettingLoaded(widget.contact.publicKeyHex);
|
||||
connector.ensureContactCyr2LatSettingLoaded(widget.contact.publicKeyHex);
|
||||
final contact = widget.contact;
|
||||
bool smazEnabled = connector.isContactSmazEnabled(contact.publicKeyHex);
|
||||
bool cyr2latEnabled = connector.isContactCyr2LatEnabled(
|
||||
contact.publicKeyHex,
|
||||
);
|
||||
bool teleBaseEnabled = contact.teleBaseEnabled;
|
||||
bool teleLocEnabled = contact.teleLocEnabled;
|
||||
bool teleEnvEnabled = contact.teleEnvEnabled;
|
||||
@@ -1228,7 +1248,39 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
contact.publicKeyHex,
|
||||
value,
|
||||
);
|
||||
setDialogState(() => smazEnabled = value);
|
||||
connector.setContactCyr2LatEnabled(
|
||||
contact.publicKeyHex,
|
||||
false,
|
||||
);
|
||||
setDialogState(() {
|
||||
smazEnabled = value;
|
||||
if (smazEnabled) {
|
||||
cyr2latEnabled = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
const Divider(height: 8),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(context.l10n.channels_cyr2latCompression),
|
||||
subtitle: Text(context.l10n.channels_cyr2latCompressionDscr),
|
||||
value: cyr2latEnabled,
|
||||
onChanged: (value) {
|
||||
connector.setContactCyr2LatEnabled(
|
||||
contact.publicKeyHex,
|
||||
value,
|
||||
);
|
||||
connector.setContactSmazEnabled(
|
||||
contact.publicKeyHex,
|
||||
false,
|
||||
);
|
||||
setDialogState(() {
|
||||
cyr2latEnabled = value;
|
||||
if (cyr2latEnabled) {
|
||||
smazEnabled = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
const Divider(height: 8),
|
||||
|
||||
Reference in New Issue
Block a user