diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-19 22:28:09 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-19 22:28:09 +0200 |
| commit | 35042ff04ffc50e55ff59a385849442be4429d6b (patch) | |
| tree | 3c142dd9bfb995b7aacdf39128e591dd3f9370de /source/ui/DebugMenu.mc | |
| parent | 871aba901501302586895d266fe4569665d9fe70 (diff) | |
feat(ui): add the list, OTP detail, PIN entry, menu, info screens and glance
List with live codes and countdowns, adaptive rows and lazy headers; OTP
detail with ring or bar, next code and HOTP next; PIN keypad or button
selector with create, unlock, change, lockout display and pending
promotion; native menu; glance with the entry count; self-test after the
first frame; option properties with defaults. Codes are computed one per
timer event, apart from drawing, for the watchdog. A UI-test build
(uitest.jungle) starts with fake entries, PIN 123456 and a frozen clock.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'source/ui/DebugMenu.mc')
| -rw-r--r-- | source/ui/DebugMenu.mc | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/source/ui/DebugMenu.mc b/source/ui/DebugMenu.mc new file mode 100644 index 0000000..f1ab407 --- /dev/null +++ b/source/ui/DebugMenu.mc @@ -0,0 +1,110 @@ +// Author: cirakg & claude ai +// Summary: Debug-only menu items: load demo entries, the performance overlay and the on-watch benchmark. +// +// Release builds compile the empty (:release) module instead, so none of this +// reaches the Store build. The benchmark is how the watch's real speed gets +// measured (docs/PERFORMANCE.md): sideload a debug build and run it. + +import Toybox.Lang; +import Toybox.System; +import Toybox.Timer; +import Toybox.WatchUi; + +(:debug) +module DebugMenu { + + function addItems(menu as WatchUi.Menu2) as Void { + menu.addItem(new WatchUi.MenuItem("Debug: demo entries", "Adds fake entries", :debugDemo, null)); + menu.addItem(new WatchUi.MenuItem("Debug: overlay", Diag.overlayOn ? "On" : "Off", :debugOverlay, null)); + menu.addItem(new WatchUi.MenuItem("Debug: benchmark", "Takes a few seconds", :debugBench, null)); + } + + function handle(id as Object?) as Void { + if (id == :debugDemo) { + try { + Fixtures.load(AppState.theVault()); + } catch (e instanceof VaultError) { + // Entry cap or full store: load what fits. + } + AppState.theCodes().clear(); + WatchUi.popView(WatchUi.SLIDE_DOWN); + } else if (id == :debugOverlay) { + Diag.overlayOn = !Diag.overlayOn; + WatchUi.popView(WatchUi.SLIDE_DOWN); + } else if (id == :debugBench) { + var runner = new BenchRunner(); + bench = runner; + WatchUi.switchToView(new InfoView("Benchmark", ["Measuring…"], "bench_running"), new InfoDelegate(), + WatchUi.SLIDE_LEFT); + runner.start(); + } + } + + // The running benchmark (kept so its timer isn't collected). + var bench as BenchRunner? = null; + + // Times the operations the budgets depend on, one per timer event, so no + // event comes near the watchdog limit (it is enforced on the watch and in + // normal simulator runs). + class BenchRunner { + + private var _lines as Array<String> = [] as Array<String>; + private var _step as Number = 0; + private var _timer as Timer.Timer? = null; + + function initialize() { + } + + function start() as Void { + var t = new Timer.Timer(); + t.start(method(:tick), 200, true); + _timer = t; + } + + function tick() as Void { + var t = System.getTimer(); + if (_step == 0) { + for (var i = 0; i < 5; i++) { + Otp.totp(Hashes.SHA1, new [20]b, 1800000000l, 30, 6); + } + _lines.add("TOTP SHA-1: " + (System.getTimer() - t) / 5 + " ms"); + } else if (_step == 1) { + Otp.totp(Hashes.SHA512, new [64]b, 1800000000l, 30, 6); + _lines.add("TOTP SHA-512: " + (System.getTimer() - t) + " ms"); + } else if (_step == 2) { + _lines.add("PIN derivation: " + Kdf.calibrate(1000, Kdf.ITERATIONS_PER_STEP) + " iterations per second"); + } else if (_step == 3) { + var vault = AppState.theVault(); + var ids = vault.ids(); + for (var i = 0; i < ids.size(); i++) { + vault.header(ids[i]); + } + _lines.add("Headers: " + ids.size() + " in " + (System.getTimer() - t) + " ms"); + } else if (_step == 4) { + SelfTest.run(); + _lines.add("Self-test: " + (System.getTimer() - t) + " ms"); + } else { + var stats = System.getSystemStats(); + _lines.add("Memory: " + stats.usedMemory / 1024 + " of " + stats.totalMemory / 1024 + " KB"); + var timer = _timer; + if (timer != null) { + timer.stop(); + } + bench = null; + WatchUi.switchToView(new InfoView("Benchmark", _lines, "bench"), new InfoDelegate(), WatchUi.SLIDE_IMMEDIATE); + return; + } + _step++; + } + } +} + +(:release) +module DebugMenu { + + function addItems(menu as WatchUi.Menu2) as Void { + } + + function handle(id as Object?) as Void { + } +} |
