feat(license): wafer license gate, runtime warning, and first-launch wizard

- Gate READ/ERASE/DEBUG behind wafer license check; log hint to load .bin
- waferRuntimeExceeded() warns when onboard runtime > 350s
- LicenseModel: remove-license (soft hide, .bin stays on disk) via
  removed_licenses.txt; re-loading un-hides
- FirstLaunchWizard: 2-step popup (license + save dir) shown on first run
- Per-tab file memory in HomePage (map/graph/data don't bleed state)
- Merge test_device_controller_license into test_device_controller
This commit is contained in:
jack
2026-07-12 20:02:25 -07:00
parent 6003bde84d
commit 67158ed7ab
15 changed files with 699 additions and 54 deletions
@@ -62,7 +62,22 @@ Rectangle {
TabBar {
id: modeBar
// Guards the programmatic sync below from re-triggering
// onCurrentIndexChanged's setMode()/startStream() side effects.
property bool _syncing: false
currentIndex: 0
Component.onCompleted: {
// WaferMapTab (and this panel) is destroyed/recreated by
// its Loader on every tab switch, so this TabBar always
// starts fresh at index 0 — but streamController.mode is
// backend state that outlives the switch (streaming now
// continues off-tab). Sync the visual index to the real
// mode on creation instead of defaulting to "Review" and
// silently disagreeing with a still-live stream.
_syncing = true
currentIndex = streamController.mode === "live" ? 1 : 0
_syncing = false
}
spacing: 2
padding: 2
Layout.fillWidth: true
@@ -152,6 +167,7 @@ Rectangle {
}
onCurrentIndexChanged: {
if (_syncing) return;
if (currentIndex === 1) {
if (deviceController.connectionStatus !== "Connected") {
currentIndex = 0;