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/Nav.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/Nav.mc')
| -rw-r--r-- | source/ui/Nav.mc | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/source/ui/Nav.mc b/source/ui/Nav.mc new file mode 100644 index 0000000..3e823e4 --- /dev/null +++ b/source/ui/Nav.mc @@ -0,0 +1,66 @@ +// Author: cirakg & claude ai +// Summary: Navigation between screens (README 13.2): opening entries, asking for the PIN first when needed, the menu. + +import Toybox.Lang; +import Toybox.WatchUi; + +module Nav { + + // Open an entry from the list: its detail screen, or the PIN screen first + // when it is locked and the session is locked. + function openEntry(id as String) as Void { + var vault = AppState.theVault(); + var header = vault.header(id); + if (header == null) { + showInfo("Damaged entry", ["Damaged entry " + id + ". Delete it and add it again."]); + return; + } + if (header.locked && !vault.session.isUnlocked()) { + var action = new OpenAfterPin(id); + WatchUi.pushView(new PinView(PinView.MODE_UNLOCK, action.method(:run)), new PinDelegate(), WatchUi.SLIDE_LEFT); + return; + } + WatchUi.pushView(detailView(header), detailDelegate(header), WatchUi.SLIDE_LEFT); + } + + function detailView(header as Entry) as WatchUi.View { + if (header.kind == Entry.KIND_OTP) { + return new OtpView(header); + } + return new InfoView(header.name, ["Barcode display comes in a later version.", "ID " + header.id], "code"); + } + + function detailDelegate(header as Entry) as WatchUi.InputDelegate { + if (header.kind == Entry.KIND_OTP) { + return new OtpDelegate(); + } + return new InfoDelegate(); + } + + // A simple text screen. + function showInfo(title as String, lines as Array<String>) as Void { + WatchUi.pushView(new InfoView(title, lines, "info"), new InfoDelegate(), WatchUi.SLIDE_LEFT); + } + + function openMenu() as Void { + WatchUi.pushView(MainMenu.build(), new MainMenuDelegate(), WatchUi.SLIDE_UP); + } + + // Opens an entry once the PIN screen succeeded (replacing the PIN screen). + class OpenAfterPin { + private var _id as String; + + function initialize(id as String) { + _id = id; + } + + function run() as Void { + var header = AppState.theVault().header(_id); + if (header == null) { + WatchUi.popView(WatchUi.SLIDE_RIGHT); + return; + } + WatchUi.switchToView(detailView(header), detailDelegate(header), WatchUi.SLIDE_LEFT); + } + } +} |
