summaryrefslogtreecommitdiff
path: root/source/ui/Nav.mc
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-19 22:28:09 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-19 22:28:09 +0200
commit35042ff04ffc50e55ff59a385849442be4429d6b (patch)
tree3c142dd9bfb995b7aacdf39128e591dd3f9370de /source/ui/Nav.mc
parent871aba901501302586895d266fe4569665d9fe70 (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.mc66
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);
+ }
+ }
+}