feat(#18): inline Radio Settings form into its pane

Bring radio config up a level: render the form directly in the Radio Settings pane with a full-width Save button, instead of a tile that opens a dialog. _RadioSettingsDialog -> _RadioSettingsForm; build returns an inline Column of the (verbatim) fields + Save; _saveSettings drops the Navigator.pop (no dialog), which also resolves the unguarded-pop-after-await finding. Removed _showRadioSettings. Field widgets, controllers, preset matching, and off-grid snapshot logic unchanged.

Key the form on the device's current radio values (freq/bw/sf/cr/txpower/clientRepeat) so a device-reported change re-seeds it -- the dialog got this for free by reopening; the persistent inline form needs the key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pull/36/head
Strycher 1 month ago
parent eb2888162e
commit 413e47563e

@ -138,21 +138,33 @@ class _SettingsScreenState extends State<SettingsScreen> {
padding: const EdgeInsets.all(16),
children: [
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
leading: const Icon(Icons.radio),
title: Text(l10n.settings_radioSettings),
subtitle: Text(l10n.settings_radioSettingsSubtitle),
trailing: const Icon(Icons.chevron_right),
onTap: () => _showRadioSettings(context, connector),
Text(
l10n.settings_radioSettings,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
_RadioSettingsForm(
key: ValueKey(
'${connector.currentFreqHz}-${connector.currentBwHz}-'
'${connector.currentSf}-${connector.currentCr}-'
'${connector.currentTxPower}-${connector.clientRepeat}',
),
connector: connector,
),
const Divider(height: 1),
_PathHashSizeTile(connector: connector),
],
),
),
),
const SizedBox(height: 16),
Card(child: _PathHashSizeTile(connector: connector)),
],
);
}
@ -663,13 +675,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
);
}
void _showRadioSettings(BuildContext context, MeshCoreConnector connector) {
showDialog(
context: context,
builder: (context) => _RadioSettingsDialog(connector: connector),
);
}
void _editLocation(BuildContext context, MeshCoreConnector connector) {
final l10n = context.l10n;
final latController = TextEditingController();
@ -1367,16 +1372,16 @@ class _AutoAddSectionState extends State<_AutoAddSection> {
}
}
class _RadioSettingsDialog extends StatefulWidget {
class _RadioSettingsForm extends StatefulWidget {
final MeshCoreConnector connector;
const _RadioSettingsDialog({required this.connector});
const _RadioSettingsForm({super.key, required this.connector});
@override
State<_RadioSettingsDialog> createState() => _RadioSettingsDialogState();
State<_RadioSettingsForm> createState() => _RadioSettingsFormState();
}
class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
class _RadioSettingsFormState extends State<_RadioSettingsForm> {
final _frequencyController = TextEditingController();
LoRaBandwidth _bandwidth = LoRaBandwidth.bw125;
LoRaSpreadingFactor _spreadingFactor = LoRaSpreadingFactor.sf7;
@ -1763,7 +1768,6 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
content: Text(l10n.settings_error(e.toString())),
);
}
Navigator.pop(context);
}
String _presetLabel(int? index) {
@ -1803,10 +1807,7 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return AlertDialog(
title: Text(l10n.settings_radioSettings),
content: SingleChildScrollView(
child: Column(
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -1839,9 +1840,7 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
border: const OutlineInputBorder(),
helperText: l10n.settings_frequencyHelper,
),
keyboardType: const TextInputType.numberWithOptions(
decimal: true,
),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
),
const SizedBox(height: 16),
DropdownButtonFormField<LoRaBandwidth>(
@ -1851,9 +1850,7 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
border: const OutlineInputBorder(),
),
items: LoRaBandwidth.values
.map(
(bw) => DropdownMenuItem(value: bw, child: Text(bw.label)),
)
.map((bw) => DropdownMenuItem(value: bw, child: Text(bw.label)))
.toList(),
onChanged: (value) {
if (value != null) {
@ -1873,9 +1870,7 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
border: const OutlineInputBorder(),
),
items: LoRaSpreadingFactor.values
.map(
(sf) => DropdownMenuItem(value: sf, child: Text(sf.label)),
)
.map((sf) => DropdownMenuItem(value: sf, child: Text(sf.label)))
.toList(),
onChanged: (value) {
if (value != null) {
@ -1883,9 +1878,7 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
_spreadingFactor = value;
_syncPresetSelection();
});
_logRadioSettingsState(
'Manual settings edit: spreading factor',
);
_logRadioSettingsState('Manual settings edit: spreading factor');
}
},
),
@ -1897,9 +1890,7 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
border: const OutlineInputBorder(),
),
items: LoRaCodingRate.values
.map(
(cr) => DropdownMenuItem(value: cr, child: Text(cr.label)),
)
.map((cr) => DropdownMenuItem(value: cr, child: Text(cr.label)))
.toList(),
onChanged: (value) {
if (value != null) {
@ -1934,15 +1925,15 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
contentPadding: EdgeInsets.zero,
),
],
],
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: FilledButton.icon(
onPressed: _saveSettings,
icon: const Icon(Icons.save_outlined),
label: Text(l10n.common_save),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(l10n.common_cancel),
),
FilledButton(onPressed: _saveSettings, child: Text(l10n.common_save)),
],
);
}

Loading…
Cancel
Save

Powered by TurnKey Linux.