diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-20 01:51:05 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-20 01:51:05 +0200 |
| commit | 40d9a1d5c3e85486aea964c1446402a3be6ec05a (patch) | |
| tree | 7af82c46a459afc99156e5a6022946b43e35a3de /source/import/ImportReport.mc | |
| parent | bc228753bfb4a2faea540cddb20fc39ebd265db5 (diff) | |
feat(import): parse otpauth URIs and unencrypted Aegis JSON in resumable steps
Streaming JSON tokenizer with depth and length limits and native skipping
of long strings; Aegis reader for database versions 1-3 with groups and
encrypted-export detection; otpauth parser with ';' separators and Steam;
import job with Replace mode, duplicate and replacement checks, a sealed
multi-part buffer and a report. Google Authenticator exports deferred.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'source/import/ImportReport.mc')
| -rw-r--r-- | source/import/ImportReport.mc | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/source/import/ImportReport.mc b/source/import/ImportReport.mc new file mode 100644 index 0000000..b2a986a --- /dev/null +++ b/source/import/ImportReport.mc @@ -0,0 +1,71 @@ +// Author: cirakg & claude ai +// Summary: The outcome of one import: counts, per-item errors and skips, notes, and the texts for the status field and results screen. + +import Toybox.Lang; + +class ImportReport { + + // At most this many detail lines are kept (the results screen scrolls). + static const MAX_DETAILS = 40; + + var imported as Number = 0; + var pendingLocked as Number = 0; + var duplicates as Number = 0; + var errors as Number = 0; + var skipped as Number = 0; + var removed as Number = 0; + // Set when the whole import failed (not JSON, encrypted, storage full + // before anything was stored...). + var failure as String? = null; + // Set while a multi-part import waits for its next part. + var waitingChars as Number = -1; + var details as Array<String> = [] as Array<String>; + + function initialize() { + } + + function addDetail(line as String) as Void { + if (details.size() < MAX_DETAILS) { + details.add(line); + } else if (details.size() == MAX_DETAILS) { + details.add("…"); + } + } + + // One line for the phone's Import status field, for example + // "Imported 12 · 2 duplicates skipped · 1 error · 1 skipped". + function summary() as String { + var f = failure; + if (f != null) { + return "Not imported: " + f; + } + if (waitingChars >= 0) { + return "Waiting for more: received " + waitingChars + + " characters. Paste the next part into the import fields and turn 'Import now' on again."; + } + var text = "Imported " + imported; + if (pendingLocked > 0) { + text += " (" + pendingLocked + " locked, waiting for your PIN)"; + } + if (removed > 0) { + text += " · " + removed + " old imported removed"; + } + if (duplicates > 0) { + text += " · " + duplicates + (duplicates == 1 ? " duplicate skipped" : " duplicates skipped"); + } + if (errors > 0) { + text += " · " + errors + (errors == 1 ? " error" : " errors"); + } + if (skipped > 0) { + text += " · " + skipped + " skipped"; + } + return text; + } + + // The summary followed by the details, for the results screen. + function lines() as Array<String> { + var out = [summary()] as Array<String>; + out.addAll(details); + return out; + } +} |
