fix(#483): restore strict capability gating, remove the diagnostics screen

A radio without the caps bits has no button and no buzzer to configure,
so it gets nothing: no tile, no screen, no command.

I had changed the tile to appear whenever a radio was connected and
added a diagnostics pane showing its raw caps byte 2. Nobody asked for
that. I added it on my own initiative because a silently absent screen
looked like a broken client, and it broke the negative test #474
specifies verbatim:

  "A device that does not advertise the bit shows no screen and the
   client emits no command."
  "Settings screen appears ONLY when the device advertises the
   capability bit"

That negative test is the reason client code ships ahead of firmware:
cross-compatibility with radios that lack the bits can only be exercised
if the client is out in front. My change would have made it fail on
something I invented rather than on anything real.

The tile is now gated on supportsButtonMatrix || supportsNotifyScope.
The pane keeps a matching guard as belt and braces, not a reachable
path. The no-command-emitted half was already correct and is unchanged.

Full suite 740 pass, analyze clean, format clean.

Epic: #474, #475
Agent: CalmBay (session d14220d9)
feat/483-button-buzzer-ui
Strycher 2 months ago
parent a659cd1672
commit 9cd35ca54c

@ -40,49 +40,12 @@ class _DeviceUiViewState extends State<DeviceUiView> {
builder: (context, connector, _) {
final showButtons = connector.supportsButtonMatrix;
final showScope = connector.supportsNotifyScope;
// A radio that advertises nothing gets a diagnosis, not a blank screen.
// Silence used to be indistinguishable from a broken client, which is
// exactly the failure this pane is meant to make visible.
// A radio advertising neither bit has no button and no buzzer to
// configure, so it gets nothing. The tile that leads here is gated the
// same way, so this is a belt-and-braces guard rather than a path a
// user can reach. (#474 negative test)
if (!showButtons && !showScope) {
final caps2 = connector.offbandCaps2;
return ListView(
children: [
const _SectionHeader('Not advertised by this radio'),
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 12),
child: Text(
caps2 == null
? 'This radio sends no capability byte 2 at all, which '
'means its firmware predates the feature. Nothing '
'is wrong with the app; the radio needs newer '
'firmware.'
: 'This radio sends capability byte 2 as 0x'
'${caps2.toRadixString(16).padLeft(2, '0')}, with '
'neither the notification-scope bit (0x01) nor the '
'button-matrix bit (0x02) set. Its firmware knows '
'about byte 2 but does not claim these features, '
'for example a board with no buzzer.',
),
),
ListTile(
leading: const Icon(Icons.memory_outlined),
title: const Text('Capability byte 2'),
subtitle: Text(
caps2 == null
? 'absent (frame shorter than 85 bytes)'
: '0x${caps2.toRadixString(16).padLeft(2, '0')}',
),
),
const ListTile(
leading: Icon(Icons.block_outlined),
title: Text('No command will be sent'),
subtitle: Text(
'The app never emits this command to a radio that has not '
'advertised support for it.',
),
),
],
);
return const SizedBox.shrink();
}
// The radio advertises the capability but shipped firmware has no
// get/set command yet, so it can be detected and not queried. Say that

@ -272,7 +272,14 @@ class _SettingsScreenState extends State<SettingsScreen> {
// Button and buzzer: device UI config (#474/#475). Owner-placed
// under Node Settings, appended last so nothing already here
// moves.
if (connector.isConnected) ...[
//
// Gated STRICTLY on the capability bits. A radio without the
// hardware has no button to configure, so it gets no tile, no
// screen and no command. This is the negative test in #474:
// "A device that does not advertise the bit shows no screen and
// the client emits no command."
if (connector.supportsButtonMatrix ||
connector.supportsNotifyScope) ...[
const Divider(height: 1),
ListTile(
leading: const Icon(Icons.radio_button_checked_outlined),

Loading…
Cancel
Save

Powered by TurnKey Linux.