feat(#574): stock config export screen

Mirrors stock's Export Config screen: section list, Select All and Deselect
All, everything checked by default. The asymmetry with import, which will
start with nothing checked, is stock's own and is deliberate: opt out on the
way out, opt in on the way in.

A section the user ticked that could not be gathered is shown before the file
is written, with its specific reason, and the user chooses whether to export
anyway. Firmware-built-without-it reads differently from device-did-not-answer
because only one of them is worth retrying.

The screen also states plainly that this is the stock format and cannot carry
Offband-only data, so importing the file back will not restore it.

File naming follows stock, <name>_meshcore_config_<stamp>.json, and is
sanitized for the filesystem without touching the name written inside the
file, which has to round-trip exactly. Real device names in the reference
corpus contain emoji and a trailing space, both covered by tests.

Writing reuses LogExport for the per-platform mechanism (share sheet on
mobile, Save As on desktop, download on web) rather than adding a second
export path that could drift. The temp file can contain the node private key,
so it is written under the app's own temp directory.

The public key is abbreviated on screen; the private key is never rendered.

6 tests on the file name.
pull/701/head
Strycher 2 months ago committed by Benjamin Wiechel
parent ee1ba064ac
commit 0047ee0c8c

@ -2820,5 +2820,129 @@
"batteryOptimizationOpenFailed": "Couldn't open battery settings",
"@batteryOptimizationOpenFailed": {
"description": "Snackbar shown when the battery-optimization settings screen could not be opened (#443)."
},
"stockConfig_selectAll": "Select All",
"@stockConfig_selectAll": {
"description": "Button selecting every section on the stock config export/import screens (#568)."
},
"stockConfig_deselectAll": "Deselect All",
"@stockConfig_deselectAll": {
"description": "Button clearing every section on the stock config export/import screens (#568)."
},
"stockConfig_sectionName": "Name",
"@stockConfig_sectionName": {
"description": "Config section holding the device's display name (#568)."
},
"stockConfig_sectionIdentity": "Private Identity Key",
"@stockConfig_sectionIdentity": {
"description": "Config section holding the node's key pair (#568)."
},
"stockConfig_sectionRadio": "Radio Settings",
"@stockConfig_sectionRadio": {
"description": "Config section holding LoRa radio parameters (#568)."
},
"stockConfig_sectionPosition": "Position Settings",
"@stockConfig_sectionPosition": {
"description": "Config section holding the device's advertised position (#568)."
},
"stockConfig_sectionOther": "Other Settings",
"@stockConfig_sectionOther": {
"description": "Config section holding miscellaneous device preferences (#568)."
},
"stockConfig_sectionAutoAdd": "Auto Add Settings",
"@stockConfig_sectionAutoAdd": {
"description": "Config section holding automatic contact-add preferences (#568)."
},
"stockConfig_sectionChannels": "Channels ({count})",
"@stockConfig_sectionChannels": {
"description": "Config section holding channels, with how many there are (#568).",
"placeholders": { "count": { "type": "int" } }
},
"stockConfig_sectionContacts": "Contacts ({count})",
"@stockConfig_sectionContacts": {
"description": "Config section holding contacts, with how many there are (#568).",
"placeholders": { "count": { "type": "int" } }
},
"stockConfig_identityWarning": "Your private key must be kept secret. It should only be exported as a backup.",
"@stockConfig_identityWarning": {
"description": "Warning shown beside the identity section when exporting (#568)."
},
"stockConfig_publicKeyLabel": "Public Key: {key}",
"@stockConfig_publicKeyLabel": {
"description": "Abbreviated public key shown under the identity section (#568).",
"placeholders": { "key": { "type": "String" } }
},
"stockConfig_privateKeyHidden": "Private Key: hidden",
"@stockConfig_privateKeyHidden": {
"description": "Placeholder shown instead of the private key, which is never displayed (#568)."
},
"exportConfig_title": "Export Config",
"@exportConfig_title": {
"description": "Title of the stock config export screen (#574)."
},
"exportConfig_instruction": "Please select data to export.",
"@exportConfig_instruction": {
"description": "Banner instructing the user to pick sections to export (#574)."
},
"exportConfig_allChannels": "All channels will be exported.",
"@exportConfig_allChannels": {
"description": "Note that channels export as a whole, with no per-channel choice (#574)."
},
"exportConfig_allContacts": "All contacts will be exported.",
"@exportConfig_allContacts": {
"description": "Note that contacts export as a whole, with no per-contact choice (#574)."
},
"exportConfig_nothingSelected": "Select at least one section to export.",
"@exportConfig_nothingSelected": {
"description": "Shown when the user tries to export with every section unchecked (#574)."
},
"exportConfig_lossyNotice": "This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.",
"@exportConfig_lossyNotice": {
"description": "Explains that an export drops Offband-only contact fields (#574)."
},
"exportConfig_omittedTitle": "Some sections could not be exported",
"@exportConfig_omittedTitle": {
"description": "Title of the dialog listing sections that could not be gathered (#574)."
},
"exportConfig_omittedUnsupported": "{section}: this radio's firmware was built without it.",
"@exportConfig_omittedUnsupported": {
"description": "Reason line when firmware lacks the feature entirely, so retrying cannot help (#574).",
"placeholders": { "section": { "type": "String" } }
},
"exportConfig_omittedNoReply": "{section}: the device did not respond.",
"@exportConfig_omittedNoReply": {
"description": "Reason line when the device did not answer in time (#574).",
"placeholders": { "section": { "type": "String" } }
},
"exportConfig_omittedRejected": "{section}: the device refused the request.",
"@exportConfig_omittedRejected": {
"description": "Reason line when the device refused the request (#574).",
"placeholders": { "section": { "type": "String" } }
},
"exportConfig_omittedUnavailable": "{section}: the device has not reported this yet.",
"@exportConfig_omittedUnavailable": {
"description": "Reason line when the value is not known to the app yet (#574).",
"placeholders": { "section": { "type": "String" } }
},
"exportConfig_exportAnyway": "Export anyway",
"@exportConfig_exportAnyway": {
"description": "Confirms writing the file even though some sections are missing (#574)."
},
"exportConfig_cancel": "Cancel",
"@exportConfig_cancel": {
"description": "Dismisses the export without writing a file (#574)."
},
"exportConfig_shareSubject": "MeshCore config",
"@exportConfig_shareSubject": {
"description": "Subject line used when sharing an exported config file (#574)."
},
"exportConfig_failed": "Export failed: {message}",
"@exportConfig_failed": {
"description": "Snackbar shown when writing the export file failed (#574).",
"placeholders": { "message": { "type": "String" } }
},
"exportConfig_notConnected": "Connect to a device before exporting.",
"@exportConfig_notConnected": {
"description": "Shown when the export screen has no connected radio to read from (#574)."
}
}

@ -8451,6 +8451,180 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Couldn\'t open battery settings'**
String get batteryOptimizationOpenFailed;
/// Button selecting every section on the stock config export/import screens (#568).
///
/// In en, this message translates to:
/// **'Select All'**
String get stockConfig_selectAll;
/// Button clearing every section on the stock config export/import screens (#568).
///
/// In en, this message translates to:
/// **'Deselect All'**
String get stockConfig_deselectAll;
/// Config section holding the device's display name (#568).
///
/// In en, this message translates to:
/// **'Name'**
String get stockConfig_sectionName;
/// Config section holding the node's key pair (#568).
///
/// In en, this message translates to:
/// **'Private Identity Key'**
String get stockConfig_sectionIdentity;
/// Config section holding LoRa radio parameters (#568).
///
/// In en, this message translates to:
/// **'Radio Settings'**
String get stockConfig_sectionRadio;
/// Config section holding the device's advertised position (#568).
///
/// In en, this message translates to:
/// **'Position Settings'**
String get stockConfig_sectionPosition;
/// Config section holding miscellaneous device preferences (#568).
///
/// In en, this message translates to:
/// **'Other Settings'**
String get stockConfig_sectionOther;
/// Config section holding automatic contact-add preferences (#568).
///
/// In en, this message translates to:
/// **'Auto Add Settings'**
String get stockConfig_sectionAutoAdd;
/// Config section holding channels, with how many there are (#568).
///
/// In en, this message translates to:
/// **'Channels ({count})'**
String stockConfig_sectionChannels(int count);
/// Config section holding contacts, with how many there are (#568).
///
/// In en, this message translates to:
/// **'Contacts ({count})'**
String stockConfig_sectionContacts(int count);
/// Warning shown beside the identity section when exporting (#568).
///
/// In en, this message translates to:
/// **'Your private key must be kept secret. It should only be exported as a backup.'**
String get stockConfig_identityWarning;
/// Abbreviated public key shown under the identity section (#568).
///
/// In en, this message translates to:
/// **'Public Key: {key}'**
String stockConfig_publicKeyLabel(String key);
/// Placeholder shown instead of the private key, which is never displayed (#568).
///
/// In en, this message translates to:
/// **'Private Key: hidden'**
String get stockConfig_privateKeyHidden;
/// Title of the stock config export screen (#574).
///
/// In en, this message translates to:
/// **'Export Config'**
String get exportConfig_title;
/// Banner instructing the user to pick sections to export (#574).
///
/// In en, this message translates to:
/// **'Please select data to export.'**
String get exportConfig_instruction;
/// Note that channels export as a whole, with no per-channel choice (#574).
///
/// In en, this message translates to:
/// **'All channels will be exported.'**
String get exportConfig_allChannels;
/// Note that contacts export as a whole, with no per-contact choice (#574).
///
/// In en, this message translates to:
/// **'All contacts will be exported.'**
String get exportConfig_allContacts;
/// Shown when the user tries to export with every section unchecked (#574).
///
/// In en, this message translates to:
/// **'Select at least one section to export.'**
String get exportConfig_nothingSelected;
/// Explains that an export drops Offband-only contact fields (#574).
///
/// In en, this message translates to:
/// **'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.'**
String get exportConfig_lossyNotice;
/// Title of the dialog listing sections that could not be gathered (#574).
///
/// In en, this message translates to:
/// **'Some sections could not be exported'**
String get exportConfig_omittedTitle;
/// Reason line when firmware lacks the feature entirely, so retrying cannot help (#574).
///
/// In en, this message translates to:
/// **'{section}: this radio\'s firmware was built without it.'**
String exportConfig_omittedUnsupported(String section);
/// Reason line when the device did not answer in time (#574).
///
/// In en, this message translates to:
/// **'{section}: the device did not respond.'**
String exportConfig_omittedNoReply(String section);
/// Reason line when the device refused the request (#574).
///
/// In en, this message translates to:
/// **'{section}: the device refused the request.'**
String exportConfig_omittedRejected(String section);
/// Reason line when the value is not known to the app yet (#574).
///
/// In en, this message translates to:
/// **'{section}: the device has not reported this yet.'**
String exportConfig_omittedUnavailable(String section);
/// Confirms writing the file even though some sections are missing (#574).
///
/// In en, this message translates to:
/// **'Export anyway'**
String get exportConfig_exportAnyway;
/// Dismisses the export without writing a file (#574).
///
/// In en, this message translates to:
/// **'Cancel'**
String get exportConfig_cancel;
/// Subject line used when sharing an exported config file (#574).
///
/// In en, this message translates to:
/// **'MeshCore config'**
String get exportConfig_shareSubject;
/// Snackbar shown when writing the export file failed (#574).
///
/// In en, this message translates to:
/// **'Export failed: {message}'**
String exportConfig_failed(String message);
/// Shown when the export screen has no connected radio to read from (#574).
///
/// In en, this message translates to:
/// **'Connect to a device before exporting.'**
String get exportConfig_notConnected;
}
class _AppLocalizationsDelegate

@ -4966,4 +4966,111 @@ class AppLocalizationsBg extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4983,4 +4983,111 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4889,4 +4889,111 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4971,4 +4971,111 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4999,4 +4999,111 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4988,4 +4988,111 @@ class AppLocalizationsHu extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4976,4 +4976,111 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4742,4 +4742,111 @@ class AppLocalizationsJa extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4743,4 +4743,111 @@ class AppLocalizationsKo extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4951,4 +4951,111 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4988,4 +4988,111 @@ class AppLocalizationsPl extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4964,4 +4964,111 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4982,4 +4982,111 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4948,4 +4948,111 @@ class AppLocalizationsSk extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4946,4 +4946,111 @@ class AppLocalizationsSl extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4921,4 +4921,111 @@ class AppLocalizationsSv extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4983,4 +4983,111 @@ class AppLocalizationsUk extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -4616,4 +4616,111 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get batteryOptimizationOpenFailed => 'Couldn\'t open battery settings';
@override
String get stockConfig_selectAll => 'Select All';
@override
String get stockConfig_deselectAll => 'Deselect All';
@override
String get stockConfig_sectionName => 'Name';
@override
String get stockConfig_sectionIdentity => 'Private Identity Key';
@override
String get stockConfig_sectionRadio => 'Radio Settings';
@override
String get stockConfig_sectionPosition => 'Position Settings';
@override
String get stockConfig_sectionOther => 'Other Settings';
@override
String get stockConfig_sectionAutoAdd => 'Auto Add Settings';
@override
String stockConfig_sectionChannels(int count) {
return 'Channels ($count)';
}
@override
String stockConfig_sectionContacts(int count) {
return 'Contacts ($count)';
}
@override
String get stockConfig_identityWarning =>
'Your private key must be kept secret. It should only be exported as a backup.';
@override
String stockConfig_publicKeyLabel(String key) {
return 'Public Key: $key';
}
@override
String get stockConfig_privateKeyHidden => 'Private Key: hidden';
@override
String get exportConfig_title => 'Export Config';
@override
String get exportConfig_instruction => 'Please select data to export.';
@override
String get exportConfig_allChannels => 'All channels will be exported.';
@override
String get exportConfig_allContacts => 'All contacts will be exported.';
@override
String get exportConfig_nothingSelected =>
'Select at least one section to export.';
@override
String get exportConfig_lossyNotice =>
'This is the MeshCore stock format, so it cannot carry Offband-only data such as path overrides. Importing this file back into Offband will not restore that data.';
@override
String get exportConfig_omittedTitle => 'Some sections could not be exported';
@override
String exportConfig_omittedUnsupported(String section) {
return '$section: this radio\'s firmware was built without it.';
}
@override
String exportConfig_omittedNoReply(String section) {
return '$section: the device did not respond.';
}
@override
String exportConfig_omittedRejected(String section) {
return '$section: the device refused the request.';
}
@override
String exportConfig_omittedUnavailable(String section) {
return '$section: the device has not reported this yet.';
}
@override
String get exportConfig_exportAnyway => 'Export anyway';
@override
String get exportConfig_cancel => 'Cancel';
@override
String get exportConfig_shareSubject => 'MeshCore config';
@override
String exportConfig_failed(String message) {
return 'Export failed: $message';
}
@override
String get exportConfig_notConnected =>
'Connect to a device before exporting.';
}

@ -0,0 +1,310 @@
/// Stock-compatible config export (#574, epic #568).
///
/// Mirrors the stock app's Export Config screen: a list of sections, Select All
/// and Deselect All, and **everything checked by default**. The asymmetry with
/// the import screen (which starts with nothing checked) is deliberate and
/// copied from stock: opt out on the way out, opt in on the way in.
library;
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../connector/meshcore_connector.dart';
import '../l10n/l10n.dart';
import '../services/stock_config_export_service.dart';
import '../utils/stock_config_file.dart';
import '../widgets/adaptive_app_bar_title.dart';
class ExportConfigScreen extends StatefulWidget {
const ExportConfigScreen({super.key});
@override
State<ExportConfigScreen> createState() => _ExportConfigScreenState();
}
class _ExportConfigScreenState extends State<ExportConfigScreen> {
/// Every section starts selected, matching stock.
final Set<StockConfigSection> _selected = StockConfigSection.values.toSet();
bool _busy = false;
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final connector = context.watch<MeshCoreConnector>();
return Scaffold(
appBar: AppBar(
title: AdaptiveAppBarTitle(l10n.exportConfig_title),
centerTitle: true,
actions: [
IconButton(
icon: const Icon(Icons.check),
onPressed: _busy ? null : () => _export(connector),
tooltip: l10n.exportConfig_title,
),
],
),
body: ListView(
children: [
_Banner(text: l10n.exportConfig_instruction),
_Banner(text: l10n.exportConfig_lossyNotice, subdued: true),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () =>
setState(() => _selected.addAll(StockConfigSection.values)),
child: Text(l10n.stockConfig_selectAll),
),
TextButton(
onPressed: () => setState(_selected.clear),
child: Text(l10n.stockConfig_deselectAll),
),
],
),
for (final section in StockConfigSection.values)
_SectionTile(
title: sectionLabel(context, section, connector),
subtitle: _subtitleFor(section, connector),
selected: _selected.contains(section),
onChanged: (value) => setState(() {
if (value) {
_selected.add(section);
} else {
_selected.remove(section);
}
}),
),
],
),
);
}
String? _subtitleFor(
StockConfigSection section,
MeshCoreConnector connector,
) {
final l10n = context.l10n;
switch (section) {
case StockConfigSection.name:
return connector.selfName;
case StockConfigSection.identity:
final key = connector.selfPublicKeyHex;
final abbreviated = key.length > 12
? '${key.substring(0, 6)}...${key.substring(key.length - 6)}'
: key;
// The private key is never rendered, not even abbreviated.
return '${l10n.stockConfig_identityWarning}\n'
'${l10n.stockConfig_publicKeyLabel(abbreviated)}\n'
'${l10n.stockConfig_privateKeyHidden}';
case StockConfigSection.radioSettings:
final freq = connector.currentFreqHz;
final bw = connector.currentBwHz;
if (freq == null || bw == null) return null;
// currentFreqHz is kHz despite its name; currentBwHz really is Hz.
return '${l10n.settings_frequency}: ${freq / 1000} MHz\n'
'${l10n.settings_bandwidth}: ${bw / 1000} kHz\n'
'${l10n.settings_spreadingFactor}: ${connector.currentSf}\n'
'${l10n.settings_codingRate}: ${connector.currentCr}\n'
'${l10n.settings_txPower}: ${connector.currentTxPower}';
case StockConfigSection.positionSettings:
return '${connector.selfLatitude ?? 0}, ${connector.selfLongitude ?? 0}';
case StockConfigSection.otherSettings:
return null;
case StockConfigSection.autoAddSettings:
return null;
case StockConfigSection.channels:
return l10n.exportConfig_allChannels;
case StockConfigSection.contacts:
return l10n.exportConfig_allContacts;
}
}
Future<void> _export(MeshCoreConnector connector) async {
final l10n = context.l10n;
final messenger = ScaffoldMessenger.of(context);
if (!connector.isConnected) {
messenger.showSnackBar(
SnackBar(content: Text(l10n.exportConfig_notConnected)),
);
return;
}
if (_selected.isEmpty) {
messenger.showSnackBar(
SnackBar(content: Text(l10n.exportConfig_nothingSelected)),
);
return;
}
setState(() => _busy = true);
try {
final result = await StockConfigExportService(
connector,
).build(sections: Set.of(_selected));
// A section the user asked for that could not be gathered is surfaced
// before the file is written, never dropped quietly.
if (!result.isComplete) {
if (!mounted) return;
final proceed = await _confirmOmissions(result);
if (proceed != true) return;
}
if (!mounted) return;
await saveStockConfigFile(
context,
json: result.config.encode(),
fileName: stockConfigFileName(connector.selfName, DateTime.now()),
subject: l10n.exportConfig_shareSubject,
);
} catch (e) {
messenger.showSnackBar(
SnackBar(content: Text(l10n.exportConfig_failed('$e'))),
);
} finally {
if (mounted) setState(() => _busy = false);
}
}
Future<bool?> _confirmOmissions(StockConfigExportResult result) {
final l10n = context.l10n;
final connector = context.read<MeshCoreConnector>();
return showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text(l10n.exportConfig_omittedTitle),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (final entry in result.omitted.entries)
Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Text(
_omissionText(
context,
sectionLabel(context, entry.key, connector),
entry.value,
),
),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text(l10n.exportConfig_cancel),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text(l10n.exportConfig_exportAnyway),
),
],
),
);
}
}
String _omissionText(
BuildContext context,
String section,
StockConfigOmission reason,
) {
final l10n = context.l10n;
switch (reason) {
case StockConfigOmission.unsupported:
return l10n.exportConfig_omittedUnsupported(section);
case StockConfigOmission.noReply:
return l10n.exportConfig_omittedNoReply(section);
case StockConfigOmission.rejected:
return l10n.exportConfig_omittedRejected(section);
case StockConfigOmission.unavailable:
return l10n.exportConfig_omittedUnavailable(section);
}
}
/// Section titles, shared with the import screen so the two cannot drift.
String sectionLabel(
BuildContext context,
StockConfigSection section,
MeshCoreConnector connector,
) {
final l10n = context.l10n;
switch (section) {
case StockConfigSection.name:
return l10n.stockConfig_sectionName;
case StockConfigSection.identity:
return l10n.stockConfig_sectionIdentity;
case StockConfigSection.radioSettings:
return l10n.stockConfig_sectionRadio;
case StockConfigSection.positionSettings:
return l10n.stockConfig_sectionPosition;
case StockConfigSection.otherSettings:
return l10n.stockConfig_sectionOther;
case StockConfigSection.autoAddSettings:
return l10n.stockConfig_sectionAutoAdd;
case StockConfigSection.channels:
return l10n.stockConfig_sectionChannels(
connector.channels.where((c) => !c.isEmpty).length,
);
case StockConfigSection.contacts:
return l10n.stockConfig_sectionContacts(connector.contacts.length);
}
}
class _SectionTile extends StatelessWidget {
const _SectionTile({
required this.title,
required this.selected,
required this.onChanged,
this.subtitle,
});
final String title;
final String? subtitle;
final bool selected;
final ValueChanged<bool> onChanged;
@override
Widget build(BuildContext context) {
return CheckboxListTile(
value: selected,
onChanged: (value) => onChanged(value ?? false),
controlAffinity: ListTileControlAffinity.trailing,
isThreeLine: subtitle != null,
title: Text(title),
subtitle: subtitle == null ? null : Text(subtitle!),
);
}
}
class _Banner extends StatelessWidget {
const _Banner({required this.text, this.subdued = false});
final String text;
final bool subdued;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Container(
width: double.infinity,
color: theme.colorScheme.surfaceContainerHighest,
padding: const EdgeInsets.all(12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.info_outline, size: 18, color: theme.colorScheme.primary),
const SizedBox(width: 8),
Expanded(
child: Text(
text,
style: subdued ? theme.textTheme.bodySmall : null,
),
),
],
),
);
}
}

@ -0,0 +1,70 @@
/// Naming and writing of stock-compatible config files (#574, epic #568).
library;
import 'dart:io' show File;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'log_export.dart';
import 'log_web_download.dart';
/// Characters Windows forbids in a file name, plus the path separators.
final _illegalFileNameChars = RegExp(r'[<>:"/\\|?*\x00-\x1F]');
/// Builds the file name stock uses: `<device name>_meshcore_config_<stamp>`.
///
/// Real device names contain emoji and, in at least one observed case, a
/// trailing space, so the name is sanitized for the filesystem here. The name
/// written *inside* the file is never touched: it must round-trip exactly.
String stockConfigFileName(String? deviceName, DateTime at) {
final safeName = _sanitizeForFileName(deviceName ?? '');
final stamp = [
at.year.toString().padLeft(4, '0'),
at.month.toString().padLeft(2, '0'),
at.day.toString().padLeft(2, '0'),
].join('-');
final time = [
at.hour.toString().padLeft(2, '0'),
at.minute.toString().padLeft(2, '0'),
at.second.toString().padLeft(2, '0'),
].join();
final prefix = safeName.isEmpty ? '' : '${safeName}_';
return '${prefix}meshcore_config_$stamp-$time.json';
}
String _sanitizeForFileName(String name) {
final cleaned = name.replaceAll(_illegalFileNameChars, '');
// Windows also rejects names ending in a space or a dot.
return cleaned.replaceAll(RegExp(r'[ .]+$'), '').trim();
}
/// Writes [json] out as [fileName], using each platform's normal mechanism:
/// the share sheet on mobile, a Save As dialog on desktop, a browser download
/// on web. Reuses [LogExport], which already owns that per-platform logic, so
/// there is only one place where export behavior can drift.
Future<void> saveStockConfigFile(
BuildContext context, {
required String json,
required String fileName,
String? subject,
}) async {
if (kIsWeb) {
downloadTextFile(fileName, json);
return;
}
// A temp file is the handoff format LogExport works in. It holds the node's
// private key when the identity section was included, so it is written under
// the app's own temp directory and never anywhere shared.
final dir = await getTemporaryDirectory();
final file = File('${dir.path}/$fileName');
await file.writeAsString(json, flush: true);
if (!context.mounted) return;
await LogExport.shareFile(
context,
file,
subject: subject,
fileName: fileName,
);
}

@ -0,0 +1,56 @@
// #574 (epic #568): the export file name has to match stock's convention and
// survive real device names, which contain emoji and trailing spaces.
import 'package:flutter_test/flutter_test.dart';
import 'package:meshcore_open/utils/stock_config_file.dart';
void main() {
final at = DateTime(2026, 8, 12, 22, 16, 25);
test('matches stock: name, then meshcore_config, then a stamp', () {
expect(
stockConfigFileName('Strycher-RAK-CAR', at),
'Strycher-RAK-CAR_meshcore_config_2026-08-12-221625.json',
);
});
test('single-digit months, days and times are zero padded', () {
expect(
stockConfigFileName('Node', DateTime(2026, 1, 2, 3, 4, 5)),
'Node_meshcore_config_2026-01-02-030405.json',
);
});
test('emoji in a device name are kept, as stock keeps them', () {
expect(
stockConfigFileName('Strycher T1000\u{1F6F0}️', at),
startsWith('Strycher T1000\u{1F6F0}️_meshcore_config_'),
);
});
test('a trailing space is dropped, since Windows rejects it', () {
// Observed in a real export: the device name ended in a space.
expect(
stockConfigFileName('Strycher-Wio-L1 ', at),
'Strycher-Wio-L1_meshcore_config_2026-08-12-221625.json',
);
});
test('path separators and reserved characters are stripped', () {
expect(
stockConfigFileName(r'a/b\c:d*e?f"g<h>i|j', at),
'abcdefghij_meshcore_config_2026-08-12-221625.json',
);
});
test('a device with no name still produces a usable file name', () {
expect(
stockConfigFileName(null, at),
'meshcore_config_2026-08-12-221625.json',
);
expect(
stockConfigFileName(' ', at),
'meshcore_config_2026-08-12-221625.json',
);
});
}

@ -143,7 +143,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"de": [
@ -290,7 +319,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"es": [
@ -437,7 +495,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"fr": [
@ -584,7 +671,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"hu": [
@ -731,7 +847,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"it": [
@ -878,7 +1023,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"ja": [
@ -1025,7 +1199,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"ko": [
@ -1172,7 +1375,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"nl": [
@ -1319,7 +1551,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"pl": [
@ -1466,7 +1727,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"pt": [
@ -1613,7 +1903,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"ru": [
@ -1760,7 +2079,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"sk": [
@ -1907,7 +2255,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"sl": [
@ -2054,7 +2431,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"sv": [
@ -2201,7 +2607,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"uk": [
@ -2348,7 +2783,36 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
],
"zh": [
@ -2495,6 +2959,35 @@
"batteryOptimizationBody",
"batteryOptimizationOpenSettings",
"batteryOptimizationDismiss",
"batteryOptimizationOpenFailed"
"batteryOptimizationOpenFailed",
"stockConfig_selectAll",
"stockConfig_deselectAll",
"stockConfig_sectionName",
"stockConfig_sectionIdentity",
"stockConfig_sectionRadio",
"stockConfig_sectionPosition",
"stockConfig_sectionOther",
"stockConfig_sectionAutoAdd",
"stockConfig_sectionChannels",
"stockConfig_sectionContacts",
"stockConfig_identityWarning",
"stockConfig_publicKeyLabel",
"stockConfig_privateKeyHidden",
"exportConfig_title",
"exportConfig_instruction",
"exportConfig_allChannels",
"exportConfig_allContacts",
"exportConfig_nothingSelected",
"exportConfig_lossyNotice",
"exportConfig_omittedTitle",
"exportConfig_omittedUnsupported",
"exportConfig_omittedNoReply",
"exportConfig_omittedRejected",
"exportConfig_omittedUnavailable",
"exportConfig_exportAnyway",
"exportConfig_cancel",
"exportConfig_shareSubject",
"exportConfig_failed",
"exportConfig_notConnected"
]
}

Loading…
Cancel
Save

Powered by TurnKey Linux.