You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 05d7092
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/specifications/App/TDD.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -324,7 +324,7 @@ the host `file` classifier reports as `script text executable` (BLD-11).
324
324
-**Neutral scan seam (`lib/pble`).**`class ScanHit { final String id; final String name; final int rssi; }` — the advertised board, retyped 1:1 off `BleScanResult` (`name` is the advertised name **verbatim**: the user-set label, else `PyBLE-XXXX`; value equality by `id`). `abstract interface class Scanner { Stream<List<ScanHit>> scan({Duration? timeout}); Future<void> stopScan(); }` — emits an **accumulating, deduped-by-`id`, latest-RSSI snapshot list** (accumulation lives in `lib/pble`, not the UI). A shipped `FakeScanner implements Scanner` scripts snapshots for tests. **This supersedes the illustrative `DiscoveredBoard`/`Scanner`-in-`lib/connect` sketch** — the seam is a neutral `lib/pble` type, exported through the `pble` barrel.
325
325
-**Readiness seam.**`BleReadinessSource` (`BleReadiness current` + `Stream<BleReadiness> readiness`, [§7.4](#74-permissions--platform-quirks)) is **re-exported through the `pble` barrel** (the enum already is), so the connect UI observes adapter/permission transitions without importing `lib/ble`.
326
326
- **`ConnectionManager` (neutral, `lib/pble`).** Holds the session; composes a `Scanner`, a `BleReadinessSource`, and a `ConnectionFactory` (`typedef ConnectionFactory = Future<Connection> Function(String deviceId)`). Surface: `Connection get connection` (the **stable facade**, [§6.2](#62-binding-pattern)); `Stream<List<ScanHit>> get scanResults`; `BleReadinessSource get readiness`; `ValueListenable<ConnectPhase> get phase`; `ScanHit? get selected`; `Object? get lastError`; and `startScan({Duration? timeout})` / `stopScan()` / `connect(String id)` / `disconnect()` / `dispose()`. `enum ConnectPhase { idle, scanning, connecting, connected, failed }` is the **connect-flow session phase — distinct from `ConnState`** (`scanning`/`connected` are deliberately not `ConnState` members, [§5.2](#52-shared-types)). `connect(id)` calls the `ConnectionFactory`, publishes the resulting `Connection`, and lets `PbleConnection.fromLink`'s link observation drive `connecting → ready`. The production `PbleConnectionManager.production({required String appName, required String appVersion})` wires the real `flutter_blue_plus` stack (`FbpBleAdapter` as scan source **and** connector, `FbpBleReadinessSource`) **internally**, so `main.dart` names no `lib/ble` type ([§6.2](#62-binding-pattern)).
327
-
- **Connect controller + view (`lib/connect`).** A `ConnectController` (Riverpod `Notifier`, ADR-0007) projects the manager into an immutable `ConnectState { ConnectPhase phase, BleReadiness readiness, List<ScanHit> hits, ScanHit? selected, DeviceInfo? deviceInfo, Object? error }` (with `int get hitCount`), exposing `startScan`/`stopScan`/`connect(id)`/`disconnect`. On reaching `connected` it reads `connection.deviceInfo()` and stores it — the **DeviceInfo proof** the UI shows. `ConnectScreen` (the surface, hosted by `lib/app/pages/connect_page.dart` as a thin delegator) renders: the readiness banner (adapter-off / unauthorized / unsupported with localized rationale, FR-CONNECT-3); the scan CTA → live `ScanHit` list (name + RSSI, FR-CONNECT-1) → connecting indicator → connected `DeviceInfo` card (board ID / PyBLE firmware / chip / mpy / free-mem, FR-CONNECT-2) → disconnect; the unsupported-`proto_version` update prompt (FR-CONNECT-6); and a **live diagnostics panel** (adapter state, scanning yes/no, hit count, last-error detail) for on-hardware debugging (FR-CONN-6). The board-ID row reads only `DeviceInfo.deviceId` (never `ScanHit.id`); board ID and agent version are verbatim technical values. Empty compatibility defaults render localized **Not reported** rows and do not gate the connection. Because ADR-0011 replaces the Connect surface with the IDE at `ready`, the connected shell's `ConnectionStatusPill` also watches `connectControllerProvider`; this keeps the auto-disposed controller alive, defensively fetches `deviceInfo()` for an already-attached board, and appends its board ID + agent version to the state signal. The pill shows state alone while the fetch is pending, preserves the full state word under width pressure, and exposes the complete labeled summary through semantics.
327
+
- **Connect controller + view (`lib/connect`).** A `ConnectController` (Riverpod `Notifier`, ADR-0007) projects the manager into an immutable `ConnectState { ConnectPhase phase, BleReadiness readiness, List<ScanHit> hits, ScanHit? selected, DeviceInfo? deviceInfo, Object? error }` (with `int get hitCount`), exposing `startScan`/`stopScan`/`connect(id)`/`disconnect`. On reaching `connected` it reads `connection.deviceInfo()` and stores it — the **DeviceInfo proof** the UI shows. `ConnectScreen` (the surface, hosted by `lib/app/pages/connect_page.dart` as a thin delegator) renders: the readiness banner (adapter-off / unauthorized / unsupported with localized rationale, FR-CONNECT-3); the scan CTA → live `ScanHit` list (name + RSSI, FR-CONNECT-1) → connecting indicator → connected `DeviceInfo` card (board ID / PyBLE firmware / chip / mpy / free-mem, FR-CONNECT-2) → disconnect; the unsupported-`proto_version` update prompt (FR-CONNECT-6); and a **live diagnostics panel** (adapter state, scanning yes/no, hit count, last-error detail) for on-hardware debugging (FR-CONN-6). The board-ID row reads only `DeviceInfo.deviceId` (never `ScanHit.id`); board ID and agent version are verbatim technical values. Empty compatibility defaults render localized **Not reported** rows and do not gate the connection. Because ADR-0011 replaces the Connect surface with the IDE at `ready`, the connected shell's `ConnectionStatusPill` also watches `connectControllerProvider`; this keeps the auto-disposed controller alive, defensively fetches `deviceInfo()` for an already-attached board, and appends its board ID + agent version to the state signal. Each fetch captures `connectionSessionStampOf(manager.connection)` and may publish its result only while that opaque local stamp is still current; a late prior-session result is discarded, and a replacement session may fetch concurrently rather than being suppressed by the old request. The pill shows state alone while the current-session fetch is pending, preserves the full state word under width pressure, and exposes the complete labeled summary through semantics.
328
328
-**Scope of this freeze.** Delivers FR-CONNECT-1/2/3/5/6 + FR-CONN-6. **Saved-boards persistence** (FR-CONNECT-4 list/reconnect-by-remembered-id) depends on Drift `board_ref` (`lib/data`, A-24) which does not exist yet — auto-reattempt on an *unexpected* drop works today (A-03 `ReconnectingBleLink` + re-HELLO), but the persisted saved-board **list** is A-24/S5. The **screenless-identity UX** (rename / Identify, `setLabel`/`setIdentifyLed`/`identify`) is A-36/A-37/S7 and is **not** in this increment.
329
329
330
330
**Public API (sketch):**`ConnectController` (Riverpod `Notifier`) over the neutral `ConnectionManager` above; plus (A-36/A-37) `renameBoard(String label)`, `configureIdentifyLed(IdentifyLed)`, and `identify()` delegating to `Connection`.
Copy file name to clipboardExpand all lines: docs/specifications/App/design-system.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -253,7 +253,7 @@ The primary state signal. Binds to `connStateProvider` (read-only, `ValueListena
253
253
|`running`|`Icons.play_circle` (live) |
254
254
255
255
The glyph is the state color at full strength (≥ 3:1 graphic).
256
-
-**Contents** (row, `SignalSpacing.sm` gap, `EdgeInsets.symmetric(horizontal: SignalSpacing.md, vertical: SignalSpacing.xs)`): the state glyph + the **localized state label** in **`colorScheme.onSurface`** (`labelMedium`, scaler ≤ 1.3). On `ready`/`running`, once `DeviceInfo` is available, a localized compact pattern appends its verbatim board ID + PyBLE agent version (English: `Ready · 5646 · 0.6.0`); empty values use the localized **Not reported** fallback. The label uses `onSurface` (not the state color) so text is AA-safe at any hue (§1.3). The full **state word never ellipsizes** — under width pressure only the appended identity summary may ellipsize, and the pill's minimum content remains glyph + full word (§7.1 shrink order).
256
+
-**Contents** (row, `SignalSpacing.sm` gap, `EdgeInsets.symmetric(horizontal: SignalSpacing.md, vertical: SignalSpacing.xs)`): the state glyph + the **localized state label** in **`colorScheme.onSurface`** (`labelMedium`, scaler ≤ 1.3). On `ready`/`running`, once the current connection session's `DeviceInfo` is available, a localized compact pattern appends its verbatim board ID + PyBLE agent version (English: `Ready · 5646 · 0.6.0`); empty values use the localized **Not reported** fallback. A late result from a detached session is never rendered. The label uses `onSurface` (not the state color) so text is AA-safe at any hue (§1.3). The full **state word never ellipsizes** — under width pressure only the appended identity summary may ellipsize, and the pill's minimum content remains glyph + full word (§7.1 shrink order).
257
257
-**Motion:**`connecting`/`running` glyphs pulse (`SignalMotion.pulse`, opacity 0.55↔1.0) under the reduced-motion gate (§6). Color transitions animate over `SignalMotion.standard`.
258
258
-**Screen reader (folded from review):** wrap the pill in one `Semantics` node. Without live metadata its label remains `l10n.connStatusSemanticLabel(stateWord)` → "Connection status: {state}". With metadata it uses a localized label that announces the complete state, **Board ID**, and **PyBLE firmware** values with context; visual ellipsis never truncates semantics.
259
259
- Hit area ≥ 48 dp tall (transparent padding) so it can later become a tappable connection summary.
Copy file name to clipboardExpand all lines: docs/specifications/App/specs.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -822,6 +822,7 @@ implementation:
822
822
-**AC-3 (additive compatibility)** — When either additive field is empty, its row MUST remain visible with a localized **Not reported** value; absence MUST NOT fail the connection, hide the existing DeviceInfo proof, or gate any action. MUST
823
823
-**AC-4 (existing proof retained)** — The chip, MicroPython version, free-memory value, and Disconnect action MUST remain present and retain their current semantics. MUST
824
824
-**AC-5 (connected-shell reachability)** — On `ready` and `running`, the always-visible status pill MUST append the same Board ID and PyBLE firmware values after its full localized state word. Tight layouts MAY ellipsize only the appended summary, never the state word; the semantics label MUST expose the complete state, **Board ID**, and **PyBLE firmware** values with context. While `DeviceInfo` is still loading the pill MAY show the state alone. MUST
825
+
-**AC-6 (connection-session consistency)** — A `DeviceInfo` result MUST apply only to the local connection session that requested it. After disconnect/reconnect or replacement of the active board, a late result from the prior session MUST be discarded; the pill MUST remain state-only until the current session's `DeviceInfo` arrives and MUST never flash or retain the prior board's ID or firmware. MUST
825
826
826
827
### 4.15 About & Open-Source Information (`lib/app/`) — FR-ABOUT
0 commit comments