diff options
Diffstat (limited to 'source/ui')
| -rw-r--r-- | source/ui/MainMenu.mc | 2 | ||||
| -rw-r--r-- | source/ui/PinView.mc | 62 | ||||
| -rw-r--r-- | source/ui/QueueMenu.mc | 78 |
3 files changed, 111 insertions, 31 deletions
diff --git a/source/ui/MainMenu.mc b/source/ui/MainMenu.mc index 21f427c..a4a57da 100644 --- a/source/ui/MainMenu.mc +++ b/source/ui/MainMenu.mc @@ -133,7 +133,7 @@ class MainMenuDelegate extends WatchUi.Menu2InputDelegate { WatchUi.SLIDE_LEFT); Results.markSeen(); } else if (id == :queue) { - WatchUi.switchToView(QueueMenu.build(), new QueueMenuDelegate(), WatchUi.SLIDE_LEFT); + QueueMenu.open(); } else if (id == :ids) { var screen = new EntryIdsScreen(); MainMenu.idsScreen = screen; diff --git a/source/ui/PinView.mc b/source/ui/PinView.mc index af18e2b..da032ad 100644 --- a/source/ui/PinView.mc +++ b/source/ui/PinView.mc @@ -16,7 +16,9 @@ // * Entered digits show as dots. A wrong PIN vibrates and shows any wait. // * Creating or changing the PIN asks twice. // * Key derivation (about 1 s) runs as a job on a timer, so the screen -// shows "Checking..." and the watchdog never trips. +// shows "Checking..." and the watchdog never trips. So does the work +// after a correct or new PIN (LockJob: pending entries are promoted, +// waiting "Require PIN" changes applied); its lines go to the results. // The typed digits are a ByteArray that is wiped after every attempt. import Toybox.Attention; @@ -58,6 +60,10 @@ class PinView extends WatchUi.View { private var _jobPin as ByteArray? = null; // The running derivation's timer driver (kept so it isn't collected). var runner as Jobs.JobRunner? = null; + private var _lockJob as LockJob? = null; + // A LockJob ran for this screen's PIN (a legacy PIN's new PIN runs a + // second one, which adds to the first one's lines). + private var _lockJobRan as Boolean = false; private var _ticker as Timer.Timer? = null; private var _keys as Array<Array<Number>> = [] as Array<Array<Number>>; // [x, y, w, h, key] private var _shownLogged as Boolean = false; @@ -79,6 +85,11 @@ class PinView extends WatchUi.View { } function onHide() as Void { + if (_lockJobRan && _lockJob == null) { + // Closed (or replaced): a "Confirm all" that follows has taken + // the lock lines already; else they are in the results. + ChangeQueue.takeLockLines(); + } var ticker = _ticker; if (ticker != null) { ticker.stop(); @@ -234,24 +245,16 @@ class PinView extends WatchUi.View { } function onUnlockDone() as Void { - busy = false; - _shownLogged = false; Bytes.wipe(_jobPin); _jobPin = null; var vault = AppState.theVault(); if (vault.finishUnlock(_job as PinJob)) { _job = null; - vault.promotePending(); - ChangeQueue.applyLocks(vault); - // Unlocked: "Encrypt names" can now reach locked entries. - AppState.processSettings(); - if (legacy) { - askForNewPin(); - return; - } - succeed(); + startLockJob(); return; } + busy = false; + _shownLogged = false; _job = null; buzz(); if (!vault.hasPin()) { @@ -264,14 +267,39 @@ class PinView extends WatchUi.View { } function onSetDone() as Void { - busy = false; Bytes.wipe(_jobPin); _jobPin = null; - var vault = AppState.theVault(); - vault.finishSetPin(_job as PinJob); + AppState.theVault().finishSetPin(_job as PinJob); _job = null; - vault.promotePending(); - ChangeQueue.applyLocks(vault); + startLockJob(); + } + + // Unlocked: promote the pending entries and apply waiting "Require + // PIN" changes in steps, still showing the busy state (BACK waits). + private function startLockJob() as Void { + var job = new LockJob(AppState.theVault(), !_lockJobRan); + _lockJobRan = true; + _lockJob = job; + var r = new Jobs.JobRunner(job, 1, method(:onLockJobDone)); + r.start(); + runner = r; + } + + function onLockJobDone() as Void { + busy = false; + _shownLogged = false; + var job = _lockJob as LockJob; + _lockJob = null; + if (job.lines.size() > 0) { + Results.add(job.lines); // the list says "Results ready (menu)" + } + // "Encrypt names" can now reach locked entries, and a lock just + // applied changes what the glance may show. + AppState.processSettings(); + if (legacy) { + askForNewPin(); + return; + } succeed(); } diff --git a/source/ui/QueueMenu.mc b/source/ui/QueueMenu.mc index 3f9161d..0ec9daf 100644 --- a/source/ui/QueueMenu.mc +++ b/source/ui/QueueMenu.mc @@ -5,20 +5,32 @@ // the point is that a person at the watch agrees, not that a key is // available. (Before any PIN exists only "Require PIN" can wait here, and // confirming creates the PIN. "Require PIN" items are applied by the PIN -// screen itself, ChangeQueue.applyLocks, and listed in the results.) The changes are then applied by a -// ChangeQueueJob on a timer and the results screen shows what happened. +// screen itself, LockJob, and listed in the results.) The changes are then +// applied by a ChangeQueueJob on a timer and the results screen shows what +// happened. The menu is built from DescribeJob's lines, read behind a short +// "Reading…" screen (opening 16 items in one event trips the watchdog). import Toybox.Lang; import Toybox.WatchUi; module QueueMenu { - function build() as WatchUi.Menu2 { + // The "Reading…" screen while it runs (kept so the runner isn't collected). + var screen as QueueMenuScreen? = null; + + // Open the menu (replacing the current view). + function open() as Void { + var s = new QueueMenuScreen(); + screen = s; + s.start(); + } + + // The menu for these descriptions (DescribeJob.lines). + function build(items as Array<String>) as WatchUi.Menu2 { var vault = AppState.theVault(); var menu = new WatchUi.Menu2({:title => "Phone changes"}); menu.addItem(new WatchUi.MenuItem("Confirm all", vault.hasPin() ? "Asks for your PIN" : "Sets a PIN first", :confirm, null)); menu.addItem(new WatchUi.MenuItem("Reject all", null, :reject, null)); - var items = ChangeQueue.descriptions(vault); for (var i = 0; i < items.size(); i++) { menu.addItem(new WatchUi.MenuItem(items[i], null, i, null)); } @@ -26,10 +38,44 @@ module QueueMenu { } } -class QueueMenuDelegate extends WatchUi.Menu2InputDelegate { +// Shows "Reading…", runs DescribeJob, then replaces that screen with the +// menu, unless the user left it meanwhile. +class QueueMenuScreen { + + var runner as Jobs.JobRunner? = null; + private var _job as DescribeJob = new DescribeJob(AppState.theVault()); + private var _reading as InfoView = new InfoView("Phone changes", ["Reading…"] as Array<String>, "queue_reading"); function initialize() { + } + + function start() as Void { + WatchUi.switchToView(_reading, new InfoDelegate(), WatchUi.SLIDE_LEFT); + var r = new Jobs.JobRunner(_job, 1, method(:done)); + runner = r; + r.start(); + } + + function done() as Void { + runner = null; + QueueMenu.screen = null; + if (WatchUi.getCurrentView()[0] == _reading) { + WatchUi.switchToView(QueueMenu.build(_job.lines), new QueueMenuDelegate(_job.lines, _job.keys), WatchUi.SLIDE_IMMEDIATE); + } + } +} + +class QueueMenuDelegate extends WatchUi.Menu2InputDelegate { + + // The descriptions the menu shows, and the keys of the items read + // (DescribeJob): confirming or rejecting acts on exactly those. + private var _items as Array<String>; + private var _keys as Array<String>; + + function initialize(items as Array<String>, keys as Array<String>) { Menu2InputDelegate.initialize(); + _items = items; + _keys = keys; } function onSelect(item as WatchUi.MenuItem) as Void { @@ -37,22 +83,25 @@ class QueueMenuDelegate extends WatchUi.Menu2InputDelegate { var id = item.getId(); var vault = AppState.theVault(); if (id == :confirm) { - var then = new ApplyQueueAfterPin(); + var then = new ApplyQueueAfterPin(_keys); var mode = vault.hasPin() ? PinView.MODE_UNLOCK : PinView.MODE_CREATE; WatchUi.switchToView(new PinView(mode, then.method(:run)), new PinDelegate(), WatchUi.SLIDE_LEFT); } else if (id == :reject) { var lines = ["Rejected these changes from the phone:"] as Array<String>; - lines.addAll(ChangeQueue.descriptions(vault)); - ChangeQueue.clear(vault); + lines.addAll(_items); + var late = ChangeQueue.remove(vault, _keys); + if (late > 0) { + lines.add(late + (late == 1 ? " change" : " changes") + " arrived meanwhile and still " + + (late == 1 ? "waits" : "wait") + " (menu, Phone changes)"); + } Results.save(lines); WatchUi.switchToView(new InfoView("Results", lines, "results"), new InfoDelegate(), WatchUi.SLIDE_LEFT); Results.markSeen(); AppState.processSettings(); // the About fields mention waiting changes } else if (id instanceof Number) { // The full text of one change (menu labels are cut short). - var items = ChangeQueue.descriptions(vault); - if (id < items.size()) { - WatchUi.pushView(new InfoView("Change", [items[id]] as Array<String>, "change"), new InfoDelegate(), + if (id < _items.size()) { + WatchUi.pushView(new InfoView("Change", [_items[id]] as Array<String>, "change"), new InfoDelegate(), WatchUi.SLIDE_LEFT); } } @@ -65,12 +114,15 @@ class ApplyQueueAfterPin { // The job's timer driver (kept so it isn't collected while it runs). var runner as Jobs.JobRunner? = null; private var _job as ChangeQueueJob? = null; + private var _keys as Array<String>; - function initialize() { + // keys: the items the menu showed (DescribeJob.keys). + function initialize(keys as Array<String>) { + _keys = keys; } function run() as Void { - var job = new ChangeQueueJob(AppState.theVault()); + var job = new ChangeQueueJob(AppState.theVault(), _keys); _job = job; WatchUi.switchToView(new InfoView("Results", ["Applying the changes…"] as Array<String>, "applying"), new InfoDelegate(), WatchUi.SLIDE_LEFT); |
