mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-01 22:50:37 +10:00
synced with last dev, added profiles for cyr2lat replacement dictionaries
This commit is contained in:
@@ -1262,6 +1262,7 @@ class AppSettingsScreen extends StatelessWidget {
|
||||
BuildContext context,
|
||||
AppSettingsService settingsService,
|
||||
) {
|
||||
final selectedProfile = settingsService.getSelectedCyr2LatProfile();
|
||||
return Card(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -1273,41 +1274,109 @@ class AppSettingsScreen extends StatelessWidget {
|
||||
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),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DropdownButtonFormField<String>(
|
||||
initialValue: settingsService.settings.selectedCyr2latProfileId,
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.channels_cyr2latSettingsSubheading,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
items: settingsService.settings.cyr2latProfiles.map((profile) {
|
||||
return DropdownMenuItem(
|
||||
value: profile.id,
|
||||
child: Text(profile.name),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
settingsService.setSelectedCyr2LatProfile(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () =>
|
||||
_showAddCyr2LatProfileDialog(context, settingsService),
|
||||
icon: const Icon(Icons.add),
|
||||
label: Text(context.l10n.common_add),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () => _showEditCyr2LatProfileDialog(
|
||||
context,
|
||||
settingsService,
|
||||
selectedProfile,
|
||||
),
|
||||
icon: const Icon(Icons.edit),
|
||||
label: Text(context.l10n.common_edit),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
onPressed:
|
||||
settingsService.settings.cyr2latProfiles.length > 1
|
||||
? () => _showDeleteCyr2LatProfileDialog(
|
||||
context,
|
||||
settingsService,
|
||||
selectedProfile,
|
||||
)
|
||||
: null,
|
||||
icon: const Icon(Icons.delete),
|
||||
label: Text(context.l10n.common_delete),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showCyr2LatDialog(
|
||||
void _showAddCyr2LatProfileDialog(
|
||||
BuildContext context,
|
||||
AppSettingsService settingsService,
|
||||
) {
|
||||
final controller = TextEditingController(
|
||||
text: const JsonEncoder.withIndent(
|
||||
' ',
|
||||
).convert(settingsService.settings.cyr2latCharMap),
|
||||
final nameController = TextEditingController();
|
||||
final jsonController = TextEditingController(
|
||||
text: const JsonEncoder.withIndent(' ').convert(defaultCyr2LatCharMap),
|
||||
);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(context.l10n.channels_cyr2latSettingsDscr),
|
||||
title: Text(context.l10n.settings_cyr2latProfileAdd),
|
||||
content: SingleChildScrollView(
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
maxLines: 20,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
hintText: context.l10n.channels_cyr2latSettingsDialogHint,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: nameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.settings_cyr2latProfileName,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
controller: jsonController,
|
||||
maxLines: 15,
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.channels_cyr2latSettingsDialogHint,
|
||||
border: const OutlineInputBorder(),
|
||||
hintText: context.l10n.channels_cyr2latSettingsDscr,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
@@ -1316,23 +1385,31 @@ class AppSettingsScreen extends StatelessWidget {
|
||||
child: Text(context.l10n.common_cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
if (nameController.text.isEmpty) {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.settings_cyr2latProfileNameEmpty),
|
||||
);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final json =
|
||||
jsonDecode(controller.text) as Map<String, dynamic>;
|
||||
jsonDecode(jsonController.text) as Map<String, dynamic>;
|
||||
final map = json.map(
|
||||
(key, value) => MapEntry(key, value.toString()),
|
||||
);
|
||||
final newSettings = settingsService.settings.copyWith(
|
||||
cyr2latCharMap: map,
|
||||
final profile = Cyr2LatProfile(
|
||||
id: DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
name: nameController.text,
|
||||
charMap: map,
|
||||
);
|
||||
settingsService.updateSettings(newSettings);
|
||||
await settingsService.addCyr2LatProfile(profile);
|
||||
if (!context.mounted) return;
|
||||
Navigator.pop(context);
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(
|
||||
context.l10n.channels_cyr2latSettingsDialogSuccess,
|
||||
),
|
||||
content: Text(context.l10n.settings_cyr2latProfileAdded),
|
||||
);
|
||||
} catch (e) {
|
||||
showDismissibleSnackBar(
|
||||
@@ -1347,21 +1424,126 @@ class AppSettingsScreen extends StatelessWidget {
|
||||
},
|
||||
child: Text(context.l10n.common_save),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showEditCyr2LatProfileDialog(
|
||||
BuildContext context,
|
||||
AppSettingsService settingsService,
|
||||
Cyr2LatProfile profile,
|
||||
) {
|
||||
final nameController = TextEditingController(text: profile.name);
|
||||
final jsonController = TextEditingController(
|
||||
text: const JsonEncoder.withIndent(' ').convert(profile.charMap),
|
||||
);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(context.l10n.settings_cyr2latProfileEdit),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: nameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.settings_cyr2latProfileName,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
controller: jsonController,
|
||||
maxLines: 15,
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.channels_cyr2latSettingsDialogHint,
|
||||
border: const OutlineInputBorder(),
|
||||
hintText: context.l10n.channels_cyr2latSettingsDscr,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
final newSettings = settingsService.settings.copyWith(
|
||||
cyr2latCharMap: defaultCyr2LatCharMap,
|
||||
);
|
||||
settingsService.updateSettings(newSettings);
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(context.l10n.common_cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
if (nameController.text.isEmpty) {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.settings_cyr2latProfileNameEmpty),
|
||||
);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final json =
|
||||
jsonDecode(jsonController.text) as Map<String, dynamic>;
|
||||
final map = json.map(
|
||||
(key, value) => MapEntry(key, value.toString()),
|
||||
);
|
||||
final updatedProfile = profile.copyWith(
|
||||
name: nameController.text,
|
||||
charMap: map,
|
||||
);
|
||||
await settingsService.updateCyr2LatProfile(updatedProfile);
|
||||
if (!context.mounted) return;
|
||||
Navigator.pop(context);
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(context.l10n.settings_cyr2latProfileUpdated),
|
||||
);
|
||||
} catch (e) {
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(
|
||||
context.l10n.channels_cyr2latSettingsDialogWrongJSON(
|
||||
e.toString(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(context.l10n.common_save),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showDeleteCyr2LatProfileDialog(
|
||||
BuildContext context,
|
||||
AppSettingsService settingsService,
|
||||
Cyr2LatProfile profile,
|
||||
) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(context.l10n.settings_cyr2latProfileDelete),
|
||||
content: Text(
|
||||
context.l10n.settings_cyr2latProfileDeleteDscr(profile.name),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(context.l10n.common_cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await settingsService.removeCyr2LatProfile(profile.id);
|
||||
if (!context.mounted) return;
|
||||
Navigator.pop(context);
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
content: Text(
|
||||
context.l10n.channels_cyr2latSettingsDialogResetted,
|
||||
),
|
||||
content: Text(context.l10n.settings_cyr2latProfileDeleted),
|
||||
);
|
||||
},
|
||||
child: Text(context.l10n.channels_cyr2latSettingsDialogReset),
|
||||
child: Text(context.l10n.common_delete),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1401,10 +1401,17 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
||||
MeshCoreConnector connector,
|
||||
Channel channel,
|
||||
) {
|
||||
final appSettingsService = Provider.of<AppSettingsService>(
|
||||
context,
|
||||
listen: false,
|
||||
);
|
||||
final nameController = TextEditingController(text: channel.name);
|
||||
final pskController = TextEditingController(text: channel.pskHex);
|
||||
bool smazEnabled = connector.isChannelSmazEnabled(channel.index);
|
||||
bool cyr2latEnabled = connector.isChannelCyr2LatEnabled(channel.index);
|
||||
String? selectedCyr2LatProfileId = connector.getChannelCyr2LatProfileId(
|
||||
channel.index,
|
||||
);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
@@ -1471,6 +1478,31 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
||||
}
|
||||
}),
|
||||
),
|
||||
if (cyr2latEnabled) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 8, 0, 8),
|
||||
child: DropdownButtonFormField<String>(
|
||||
initialValue: selectedCyr2LatProfileId,
|
||||
decoration: InputDecoration(
|
||||
labelText: dialogContext
|
||||
.l10n
|
||||
.channels_cyr2latSettingsSubheading,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
items: appSettingsService.settings.cyr2latProfiles.map((
|
||||
profile,
|
||||
) {
|
||||
return DropdownMenuItem(
|
||||
value: profile.id,
|
||||
child: Text(profile.name),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) => setState(() {
|
||||
selectedCyr2LatProfileId = value;
|
||||
}),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -1506,6 +1538,10 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
||||
channel.index,
|
||||
cyr2latEnabled,
|
||||
);
|
||||
await connector.setChannelCyr2LatProfileId(
|
||||
channel.index,
|
||||
selectedCyr2LatProfileId,
|
||||
);
|
||||
if (!context.mounted) return;
|
||||
showDismissibleSnackBar(
|
||||
context,
|
||||
|
||||
@@ -1211,6 +1211,10 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
|
||||
void _showContactSettings(BuildContext context) {
|
||||
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
|
||||
final appSettingsService = Provider.of<AppSettingsService>(
|
||||
context,
|
||||
listen: false,
|
||||
);
|
||||
connector.ensureContactSmazSettingLoaded(widget.contact.publicKeyHex);
|
||||
connector.ensureContactCyr2LatSettingLoaded(widget.contact.publicKeyHex);
|
||||
final contact = widget.contact;
|
||||
@@ -1218,6 +1222,9 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
bool cyr2latEnabled = connector.isContactCyr2LatEnabled(
|
||||
contact.publicKeyHex,
|
||||
);
|
||||
String? selectedCyr2LatProfileId = connector.getContactCyr2LatProfileId(
|
||||
contact.publicKeyHex,
|
||||
);
|
||||
bool teleBaseEnabled = contact.teleBaseEnabled;
|
||||
bool teleLocEnabled = contact.teleLocEnabled;
|
||||
bool teleEnvEnabled = contact.teleEnvEnabled;
|
||||
@@ -1283,6 +1290,36 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
});
|
||||
},
|
||||
),
|
||||
if (cyr2latEnabled) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 8, 0, 8),
|
||||
child: DropdownButtonFormField<String>(
|
||||
initialValue: selectedCyr2LatProfileId,
|
||||
decoration: InputDecoration(
|
||||
labelText:
|
||||
context.l10n.channels_cyr2latSettingsSubheading,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
items: appSettingsService.settings.cyr2latProfiles.map((
|
||||
profile,
|
||||
) {
|
||||
return DropdownMenuItem(
|
||||
value: profile.id,
|
||||
child: Text(profile.name),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
connector.setContactCyr2LatProfileId(
|
||||
contact.publicKeyHex,
|
||||
value,
|
||||
);
|
||||
setDialogState(() {
|
||||
selectedCyr2LatProfileId = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
const Divider(height: 8),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
|
||||
Reference in New Issue
Block a user