diff --git a/lib/main.dart b/lib/main.dart index d29edca..17fc5e0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -262,9 +262,9 @@ class LinkBar extends StatelessWidget { ), if (b.state == LinkState.up && b.hello?['boot_id'] is String) TextButton.icon( - onPressed: () => shutDownOrin(context, b), + onPressed: () => orinPowerOptions(context, b), icon: const Icon(Icons.power_settings_new), - label: const Text('Shut down Orin'), + label: const Text('Orin power options'), ), ], ), @@ -276,33 +276,42 @@ class LinkBar extends StatelessWidget { /// Confirm, then send `poweroff` once (contracts BOUNDARY.md): it carries this /// connection's boot id, so it can never take effect on a later boot. -Future shutDownOrin(BuildContext context, Boundary b) async { +/// Power off or reboot the Orin: one confirmation that is also the choice. Sent once, +/// never resent (contracts BOUNDARY.md: the ack cache does not survive the restart). +Future orinPowerOptions(BuildContext context, Boundary b) async { final host = b.hello?['host'] ?? 'the Orin'; - final yes = await showDialog( + final verb = await showDialog( context: context, builder: (context) => AlertDialog( - title: Text('Shut down $host?'), + title: Text('Power options: $host'), content: const Text( - 'Recording stops and the session is closed cleanly. ' - 'The Orin stays off until its power button is pressed.', + 'Either way, recording stops and the session is closed cleanly.\n\n' + 'Power off: the Orin stays off until its power button is pressed.\n' + 'Reboot: it is back in about a minute; this screen reconnects by itself.', ), actions: [ TextButton( - onPressed: () => Navigator.of(context).pop(false), + onPressed: () => Navigator.of(context).pop(), child: const Text('Cancel'), ), - FilledButton( + OutlinedButton.icon( + onPressed: () => Navigator.of(context).pop('reboot'), + icon: const Icon(Icons.restart_alt), + label: const Text('Reboot'), + ), + FilledButton.icon( style: FilledButton.styleFrom(backgroundColor: Colors.red.shade700), - onPressed: () => Navigator.of(context).pop(true), - child: const Text('Shut down'), + onPressed: () => Navigator.of(context).pop('poweroff'), + icon: const Icon(Icons.power_settings_new), + label: const Text('Power off'), ), ], ), ); - if (yes != true || !context.mounted) return; + if (verb == null || !context.mounted) return; final messenger = ScaffoldMessenger.of(context); - final id = b.commandOnce('poweroff', { - 'confirm': 'poweroff', + final id = b.commandOnce(verb, { + 'confirm': verb, 'boot_id': b.hello?['boot_id'], }); if (id == null) { @@ -312,11 +321,12 @@ Future shutDownOrin(BuildContext context, Boundary b) async { return; } final ack = await b.ackFor(id); + final what = verb == 'reboot' ? 'rebooting' : 'shutting down'; messenger.showSnackBar( SnackBar( content: Text( ack == null - ? 'No reply: the Orin may or may not be shutting down' + ? 'No reply: the Orin may or may not be $what' : ack.ok ? 'Orin: ${ack.detail}' : 'Refused: ${ack.detail}',