mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-19 15:21:01 +10:00
allow disable repeater adverts
Adds checkbox to disable adverts and flood adverts Also updates flood avert range to new max of 168 hours
This commit is contained in:
@@ -41,7 +41,8 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
// Basic settings
|
// Basic settings
|
||||||
final TextEditingController _nameController = TextEditingController();
|
final TextEditingController _nameController = TextEditingController();
|
||||||
final TextEditingController _passwordController = TextEditingController();
|
final TextEditingController _passwordController = TextEditingController();
|
||||||
final TextEditingController _guestPasswordController = TextEditingController();
|
final TextEditingController _guestPasswordController =
|
||||||
|
TextEditingController();
|
||||||
|
|
||||||
// Radio settings
|
// Radio settings
|
||||||
final TextEditingController _freqController = TextEditingController();
|
final TextEditingController _freqController = TextEditingController();
|
||||||
@@ -60,7 +61,9 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
bool _privacyMode = false;
|
bool _privacyMode = false;
|
||||||
|
|
||||||
// Advertisement settings
|
// Advertisement settings
|
||||||
|
bool _advertEnable = true;
|
||||||
int _advertInterval = 120; // minutes/2
|
int _advertInterval = 120; // minutes/2
|
||||||
|
bool _floodAdvertEnable = true;
|
||||||
int _floodAdvertInterval = 12; // hours
|
int _floodAdvertInterval = 12; // hours
|
||||||
int _privAdvertInterval = 60; // minutes
|
int _privAdvertInterval = 60; // minutes
|
||||||
|
|
||||||
@@ -146,7 +149,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
if (_fetchedSettings.isEmpty) return;
|
if (_fetchedSettings.isEmpty) return;
|
||||||
|
|
||||||
final appLog = Provider.of<AppDebugLogService>(context, listen: false);
|
final appLog = Provider.of<AppDebugLogService>(context, listen: false);
|
||||||
appLog.info('Updating UI with keys: ${_fetchedSettings.keys.toList()}', tag: 'RadioSettings');
|
appLog.info(
|
||||||
|
'Updating UI with keys: ${_fetchedSettings.keys.toList()}',
|
||||||
|
tag: 'RadioSettings',
|
||||||
|
);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
// Update name
|
// Update name
|
||||||
@@ -161,7 +167,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
final radioStr = _fetchedSettings['radio']!;
|
final radioStr = _fetchedSettings['radio']!;
|
||||||
appLog.info('Raw radio string: "$radioStr"', tag: 'RadioSettings');
|
appLog.info('Raw radio string: "$radioStr"', tag: 'RadioSettings');
|
||||||
final parts = radioStr.split(',');
|
final parts = radioStr.split(',');
|
||||||
appLog.info('Split into ${parts.length} parts: $parts', tag: 'RadioSettings');
|
appLog.info(
|
||||||
|
'Split into ${parts.length} parts: $parts',
|
||||||
|
tag: 'RadioSettings',
|
||||||
|
);
|
||||||
|
|
||||||
if (parts.isNotEmpty) {
|
if (parts.isNotEmpty) {
|
||||||
final freqText = parts[0].replaceAll(RegExp(r'[^0-9.]'), '').trim();
|
final freqText = parts[0].replaceAll(RegExp(r'[^0-9.]'), '').trim();
|
||||||
@@ -193,7 +202,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
appLog.info('CR text: "$crText"', tag: 'RadioSettings');
|
appLog.info('CR text: "$crText"', tag: 'RadioSettings');
|
||||||
_codingRate = int.tryParse(crText) ?? _codingRate;
|
_codingRate = int.tryParse(crText) ?? _codingRate;
|
||||||
}
|
}
|
||||||
appLog.info('Final values: freq=${_freqController.text}, bw=$_bandwidth, sf=$_spreadingFactor, cr=$_codingRate', tag: 'RadioSettings');
|
appLog.info(
|
||||||
|
'Final values: freq=${_freqController.text}, bw=$_bandwidth, sf=$_spreadingFactor, cr=$_codingRate',
|
||||||
|
tag: 'RadioSettings',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_fetchedSettings.containsKey('tx')) {
|
if (_fetchedSettings.containsKey('tx')) {
|
||||||
@@ -207,11 +219,17 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_fetchedSettings.containsKey('lat')) {
|
if (_fetchedSettings.containsKey('lat')) {
|
||||||
appLog.info('Setting lat to: "${_fetchedSettings['lat']}"', tag: 'RadioSettings');
|
appLog.info(
|
||||||
|
'Setting lat to: "${_fetchedSettings['lat']}"',
|
||||||
|
tag: 'RadioSettings',
|
||||||
|
);
|
||||||
_latController.text = _fetchedSettings['lat']!;
|
_latController.text = _fetchedSettings['lat']!;
|
||||||
}
|
}
|
||||||
if (_fetchedSettings.containsKey('lon')) {
|
if (_fetchedSettings.containsKey('lon')) {
|
||||||
appLog.info('Setting lon to: "${_fetchedSettings['lon']}"', tag: 'RadioSettings');
|
appLog.info(
|
||||||
|
'Setting lon to: "${_fetchedSettings['lon']}"',
|
||||||
|
tag: 'RadioSettings',
|
||||||
|
);
|
||||||
_lonController.text = _fetchedSettings['lon']!;
|
_lonController.text = _fetchedSettings['lon']!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +286,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
|
|
||||||
void _applySettingResponse(String command, String response) {
|
void _applySettingResponse(String command, String response) {
|
||||||
final appLog = Provider.of<AppDebugLogService>(context, listen: false);
|
final appLog = Provider.of<AppDebugLogService>(context, listen: false);
|
||||||
appLog.info('Command: "$command", Raw response: "$response"', tag: 'RadioSettings');
|
appLog.info(
|
||||||
|
'Command: "$command", Raw response: "$response"',
|
||||||
|
tag: 'RadioSettings',
|
||||||
|
);
|
||||||
final value = _extractCliValue(response);
|
final value = _extractCliValue(response);
|
||||||
appLog.info('Extracted value: "$value"', tag: 'RadioSettings');
|
appLog.info('Extracted value: "$value"', tag: 'RadioSettings');
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
@@ -280,7 +301,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
// Validate response content matches expected format for the command
|
// Validate response content matches expected format for the command
|
||||||
// This prevents mismatched responses over LoRa where order isn't guaranteed
|
// This prevents mismatched responses over LoRa where order isn't guaranteed
|
||||||
if (!_validateResponseForCommand(key, value)) {
|
if (!_validateResponseForCommand(key, value)) {
|
||||||
appLog.warn('Response "$value" does not match expected format for "$key", ignoring', tag: 'RadioSettings');
|
appLog.warn(
|
||||||
|
'Response "$value" does not match expected format for "$key", ignoring',
|
||||||
|
tag: 'RadioSettings',
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +335,9 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
// Must have at least 3 commas and start with a frequency-like number
|
// Must have at least 3 commas and start with a frequency-like number
|
||||||
final parts = value.split(',');
|
final parts = value.split(',');
|
||||||
if (parts.length < 4) return false;
|
if (parts.length < 4) return false;
|
||||||
final freq = double.tryParse(parts[0].replaceAll(RegExp(r'[^0-9.]'), ''));
|
final freq = double.tryParse(
|
||||||
|
parts[0].replaceAll(RegExp(r'[^0-9.]'), ''),
|
||||||
|
);
|
||||||
// Frequency should be in reasonable LoRa range (300-2500 MHz)
|
// Frequency should be in reasonable LoRa range (300-2500 MHz)
|
||||||
return freq != null && freq >= 300 && freq <= 2500;
|
return freq != null && freq >= 300 && freq <= 2500;
|
||||||
|
|
||||||
@@ -339,7 +365,16 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
case 'privacy':
|
case 'privacy':
|
||||||
// Boolean values: on/off/true/false/1/0/enabled/disabled
|
// Boolean values: on/off/true/false/1/0/enabled/disabled
|
||||||
final lower = value.toLowerCase().trim();
|
final lower = value.toLowerCase().trim();
|
||||||
return ['on', 'off', 'true', 'false', '1', '0', 'enabled', 'disabled'].contains(lower);
|
return [
|
||||||
|
'on',
|
||||||
|
'off',
|
||||||
|
'true',
|
||||||
|
'false',
|
||||||
|
'1',
|
||||||
|
'0',
|
||||||
|
'enabled',
|
||||||
|
'disabled',
|
||||||
|
].contains(lower);
|
||||||
|
|
||||||
case 'advert.interval':
|
case 'advert.interval':
|
||||||
case 'flood.advert.interval':
|
case 'flood.advert.interval':
|
||||||
@@ -354,7 +389,8 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
if (value.isEmpty) return false;
|
if (value.isEmpty) return false;
|
||||||
// If it has 3+ commas and looks like numbers, probably radio data
|
// If it has 3+ commas and looks like numbers, probably radio data
|
||||||
final commaCount = ','.allMatches(value).length;
|
final commaCount = ','.allMatches(value).length;
|
||||||
if (commaCount >= 3 && RegExp(r'^[\d.,\s]+$').hasMatch(value)) return false;
|
if (commaCount >= 3 && RegExp(r'^[\d.,\s]+$').hasMatch(value))
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -551,7 +587,9 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
final freqMHz = double.tryParse(_freqController.text);
|
final freqMHz = double.tryParse(_freqController.text);
|
||||||
if (freqMHz != null) {
|
if (freqMHz != null) {
|
||||||
final bwKHz = _bandwidth! / 1000;
|
final bwKHz = _bandwidth! / 1000;
|
||||||
commands.add('set radio ${freqMHz.toStringAsFixed(1)} $bwKHz $_spreadingFactor $_codingRate');
|
commands.add(
|
||||||
|
'set radio ${freqMHz.toStringAsFixed(1)} $bwKHz $_spreadingFactor $_codingRate',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,7 +628,9 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
timestampSeconds: timestampSeconds,
|
timestampSeconds: timestampSeconds,
|
||||||
);
|
);
|
||||||
await connector.sendFrame(frame);
|
await connector.sendFrame(frame);
|
||||||
await Future.delayed(const Duration(milliseconds: 200)); // Delay between commands
|
await Future.delayed(
|
||||||
|
const Duration(milliseconds: 200),
|
||||||
|
); // Delay between commands
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -614,7 +654,9 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(context.l10n.repeater_errorSavingSettings(e.toString())),
|
content: Text(
|
||||||
|
context.l10n.repeater_errorSavingSettings(e.toString()),
|
||||||
|
),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -699,7 +741,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
Text(l10n.repeater_settingsTitle),
|
Text(l10n.repeater_settingsTitle),
|
||||||
Text(
|
Text(
|
||||||
repeater.name,
|
repeater.name,
|
||||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.normal),
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -723,12 +768,20 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
value: 'auto',
|
value: 'auto',
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.auto_mode, size: 20, color: !isFloodMode ? Theme.of(context).primaryColor : null),
|
Icon(
|
||||||
|
Icons.auto_mode,
|
||||||
|
size: 20,
|
||||||
|
color: !isFloodMode
|
||||||
|
? Theme.of(context).primaryColor
|
||||||
|
: null,
|
||||||
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
l10n.repeater_autoUseSavedPath,
|
l10n.repeater_autoUseSavedPath,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: !isFloodMode ? FontWeight.bold : FontWeight.normal,
|
fontWeight: !isFloodMode
|
||||||
|
? FontWeight.bold
|
||||||
|
: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -738,12 +791,20 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
value: 'flood',
|
value: 'flood',
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.waves, size: 20, color: isFloodMode ? Theme.of(context).primaryColor : null),
|
Icon(
|
||||||
|
Icons.waves,
|
||||||
|
size: 20,
|
||||||
|
color: isFloodMode
|
||||||
|
? Theme.of(context).primaryColor
|
||||||
|
: null,
|
||||||
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
l10n.repeater_forceFloodMode,
|
l10n.repeater_forceFloodMode,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: isFloodMode ? FontWeight.bold : FontWeight.normal,
|
fontWeight: isFloodMode
|
||||||
|
? FontWeight.bold
|
||||||
|
: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -754,7 +815,8 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.timeline),
|
icon: const Icon(Icons.timeline),
|
||||||
tooltip: l10n.repeater_pathManagement,
|
tooltip: l10n.repeater_pathManagement,
|
||||||
onPressed: () => PathManagementDialog.show(context, contact: repeater),
|
onPressed: () =>
|
||||||
|
PathManagementDialog.show(context, contact: repeater),
|
||||||
),
|
),
|
||||||
if (_hasChanges)
|
if (_hasChanges)
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
@@ -865,7 +927,9 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
suffixText: 'MHz',
|
suffixText: 'MHz',
|
||||||
),
|
),
|
||||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
keyboardType: const TextInputType.numberWithOptions(
|
||||||
|
decimal: true,
|
||||||
|
),
|
||||||
onChanged: (_) => _markChanged(),
|
onChanged: (_) => _markChanged(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
@@ -923,10 +987,7 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
items: _spreadingFactorOptions.map((sf) {
|
items: _spreadingFactorOptions.map((sf) {
|
||||||
return DropdownMenuItem(
|
return DropdownMenuItem(value: sf, child: Text('SF$sf'));
|
||||||
value: sf,
|
|
||||||
child: Text('SF$sf'),
|
|
||||||
);
|
|
||||||
}).toList(),
|
}).toList(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
@@ -945,10 +1006,7 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
items: _codingRateOptions.map((cr) {
|
items: _codingRateOptions.map((cr) {
|
||||||
return DropdownMenuItem(
|
return DropdownMenuItem(value: cr, child: Text('4/$cr'));
|
||||||
value: cr,
|
|
||||||
child: Text('4/$cr'),
|
|
||||||
);
|
|
||||||
}).toList(),
|
}).toList(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
@@ -988,7 +1046,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
helperText: l10n.repeater_latitudeHelper,
|
helperText: l10n.repeater_latitudeHelper,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true),
|
keyboardType: const TextInputType.numberWithOptions(
|
||||||
|
decimal: true,
|
||||||
|
signed: true,
|
||||||
|
),
|
||||||
onChanged: (_) => _markChanged(),
|
onChanged: (_) => _markChanged(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
@@ -999,7 +1060,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
helperText: l10n.repeater_longitudeHelper,
|
helperText: l10n.repeater_longitudeHelper,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true),
|
keyboardType: const TextInputType.numberWithOptions(
|
||||||
|
decimal: true,
|
||||||
|
signed: true,
|
||||||
|
),
|
||||||
onChanged: (_) => _markChanged(),
|
onChanged: (_) => _markChanged(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -1018,11 +1082,17 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.toggle_on, color: Theme.of(context).textTheme.headlineSmall?.color),
|
Icon(
|
||||||
|
Icons.toggle_on,
|
||||||
|
color: Theme.of(context).textTheme.headlineSmall?.color,
|
||||||
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
l10n.repeater_features,
|
l10n.repeater_features,
|
||||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -1102,7 +1172,7 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
width: 18,
|
width: 18,
|
||||||
height: 18,
|
height: 18,
|
||||||
child: CircularProgressIndicator(strokeWidth: 2),
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
)
|
)
|
||||||
: const Icon(Icons.refresh, size: 20),
|
: const Icon(Icons.refresh, size: 20),
|
||||||
onPressed: isRefreshing ? null : onRefresh,
|
onPressed: isRefreshing ? null : onRefresh,
|
||||||
tooltip: refreshTooltip,
|
tooltip: refreshTooltip,
|
||||||
@@ -1130,40 +1200,72 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
const Divider(),
|
const Divider(),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(l10n.repeater_localAdvertInterval),
|
title: Text(l10n.repeater_localAdvertInterval),
|
||||||
subtitle: Text(l10n.repeater_localAdvertIntervalMinutes(_advertInterval)),
|
subtitle: Text(
|
||||||
trailing: Text(l10n.repeater_localAdvertIntervalMinutes(_advertInterval)),
|
l10n.repeater_localAdvertIntervalMinutes(_advertInterval),
|
||||||
|
),
|
||||||
|
trailing: Checkbox(
|
||||||
|
value: _advertEnable,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_advertInterval = value! ? 60 : 0;
|
||||||
|
_advertEnable = value;
|
||||||
|
});
|
||||||
|
_markChanged();
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Slider(
|
Slider(
|
||||||
value: _advertInterval.toDouble(),
|
value: _advertInterval == 0
|
||||||
|
? 60.toDouble()
|
||||||
|
: _advertInterval.toDouble(),
|
||||||
min: 60,
|
min: 60,
|
||||||
max: 240,
|
max: 240,
|
||||||
divisions: 18,
|
divisions: 18,
|
||||||
label: l10n.repeater_localAdvertIntervalMinutes(_advertInterval),
|
label: l10n.repeater_localAdvertIntervalMinutes(_advertInterval),
|
||||||
onChanged: (value) {
|
onChanged: _advertEnable
|
||||||
setState(() {
|
? (value) {
|
||||||
_advertInterval = value.toInt();
|
setState(() {
|
||||||
});
|
_advertInterval = value.toInt();
|
||||||
_markChanged();
|
});
|
||||||
},
|
_markChanged();
|
||||||
|
}
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(l10n.repeater_floodAdvertInterval),
|
title: Text(l10n.repeater_floodAdvertInterval),
|
||||||
subtitle: Text(l10n.repeater_floodAdvertIntervalHours(_floodAdvertInterval)),
|
subtitle: Text(
|
||||||
trailing: Text(l10n.repeater_floodAdvertIntervalHours(_floodAdvertInterval)),
|
l10n.repeater_floodAdvertIntervalHours(_floodAdvertInterval),
|
||||||
|
),
|
||||||
|
trailing: Checkbox(
|
||||||
|
value: _floodAdvertEnable,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_floodAdvertInterval = value! ? 3 : 0;
|
||||||
|
_floodAdvertEnable = value;
|
||||||
|
});
|
||||||
|
_markChanged();
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Slider(
|
Slider(
|
||||||
value: _floodAdvertInterval.toDouble(),
|
value: _floodAdvertInterval == 0
|
||||||
|
? 3.toDouble()
|
||||||
|
: _floodAdvertInterval.toDouble(),
|
||||||
min: 3,
|
min: 3,
|
||||||
max: 48,
|
max: 168,
|
||||||
divisions: 45,
|
divisions: 165,
|
||||||
label: l10n.repeater_floodAdvertIntervalHours(_floodAdvertInterval),
|
label: l10n.repeater_floodAdvertIntervalHours(
|
||||||
onChanged: (value) {
|
_floodAdvertInterval,
|
||||||
setState(() {
|
),
|
||||||
_floodAdvertInterval = value.toInt();
|
onChanged: _floodAdvertEnable
|
||||||
});
|
? (value) {
|
||||||
_markChanged();
|
setState(() {
|
||||||
},
|
_floodAdvertInterval = value.toInt();
|
||||||
|
});
|
||||||
|
_markChanged();
|
||||||
|
}
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
// Encrypted advertisement interval - hidden until privacy mode is implemented
|
// Encrypted advertisement interval - hidden until privacy mode is implemented
|
||||||
// if (_privacyMode) ...[
|
// if (_privacyMode) ...[
|
||||||
@@ -1220,10 +1322,15 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
const Divider(),
|
const Divider(),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(Icons.refresh, color: colorScheme.onErrorContainer),
|
leading: Icon(Icons.refresh, color: colorScheme.onErrorContainer),
|
||||||
title: Text(l10n.repeater_rebootRepeater, style: TextStyle(color: colorScheme.onErrorContainer)),
|
title: Text(
|
||||||
|
l10n.repeater_rebootRepeater,
|
||||||
|
style: TextStyle(color: colorScheme.onErrorContainer),
|
||||||
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
l10n.repeater_rebootRepeaterSubtitle,
|
l10n.repeater_rebootRepeaterSubtitle,
|
||||||
style: TextStyle(color: colorScheme.onErrorContainer.withValues(alpha: 0.8)),
|
style: TextStyle(
|
||||||
|
color: colorScheme.onErrorContainer.withValues(alpha: 0.8),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onTap: () => _confirmAction(
|
onTap: () => _confirmAction(
|
||||||
l10n.repeater_rebootRepeater,
|
l10n.repeater_rebootRepeater,
|
||||||
@@ -1246,11 +1353,19 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(Icons.delete_forever, color: colorScheme.onErrorContainer),
|
leading: Icon(
|
||||||
title: Text(l10n.repeater_eraseFileSystem, style: TextStyle(color: colorScheme.onErrorContainer)),
|
Icons.delete_forever,
|
||||||
|
color: colorScheme.onErrorContainer,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
l10n.repeater_eraseFileSystem,
|
||||||
|
style: TextStyle(color: colorScheme.onErrorContainer),
|
||||||
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
l10n.repeater_eraseFileSystemSubtitle,
|
l10n.repeater_eraseFileSystemSubtitle,
|
||||||
style: TextStyle(color: colorScheme.onErrorContainer.withValues(alpha: 0.8)),
|
style: TextStyle(
|
||||||
|
color: colorScheme.onErrorContainer.withValues(alpha: 0.8),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onTap: () => _confirmAction(
|
onTap: () => _confirmAction(
|
||||||
l10n.repeater_eraseFileSystem,
|
l10n.repeater_eraseFileSystem,
|
||||||
@@ -1272,9 +1387,9 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
|
|||||||
|
|
||||||
if (command == 'erase') {
|
if (command == 'erase') {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(
|
||||||
SnackBar(content: Text(l10n.repeater_eraseSerialOnly)),
|
context,
|
||||||
);
|
).showSnackBar(SnackBar(content: Text(l10n.repeater_eraseSerialOnly)));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user