aboutsummaryrefslogtreecommitdiff
path: root/source/ui
diff options
context:
space:
mode:
Diffstat (limited to 'source/ui')
-rw-r--r--source/ui/MainMenu.mc2
-rw-r--r--source/ui/PinView.mc62
-rw-r--r--source/ui/QueueMenu.mc78
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);