Phase 1: foundation modules

Central Config with all tunables (retention, GPS timeout, colors,
event type keys, menu item metadata). Event / EventStore handle
persistence via Application.Storage with 7-day pruning. Logger
mirrors the same retention. LayoutMetrics and Haversine provide
resolution-independent geometry helpers. German UI strings and
placeholder menu icons landed alongside so the build stays green.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
EiSiMo 2026-04-11 19:36:15 +02:00
parent 6f56c337f7
commit 43f970d764
19 changed files with 409 additions and 2 deletions

49
source/Logger.mc Normal file
View file

@ -0,0 +1,49 @@
import Toybox.Application;
import Toybox.Lang;
import Toybox.Time;
// Lightweight crash / diagnostic logger. Entries live in
// Application.Storage and are pruned with the same retention window
// as events so the watch storage never fills up.
module Logger {
const KEY = "logs";
const MAX_ENTRIES = 50;
function log(msg as String) as Void {
var raw = Application.Storage.getValue(KEY);
var arr = (raw instanceof Array) ? raw : [];
arr.add({
"ts" => Time.now().value(),
"msg" => msg
});
if (arr.size() > MAX_ENTRIES) {
arr = arr.slice(arr.size() - MAX_ENTRIES, arr.size());
}
Application.Storage.setValue(KEY, arr);
}
function getAll() as Array<Dictionary> {
var raw = Application.Storage.getValue(KEY);
return (raw instanceof Array) ? raw : [];
}
function pruneOld() as Void {
var raw = Application.Storage.getValue(KEY);
if (!(raw instanceof Array) || raw.size() == 0) {
return;
}
var cutoff = Time.now().value() - Config.RETENTION_SEC;
var kept = [];
for (var i = 0; i < raw.size(); i++) {
var d = raw[i] as Dictionary;
var ts = d["ts"];
if (ts != null && (ts as Number) >= cutoff) {
kept.add(d);
}
}
if (kept.size() != raw.size()) {
Application.Storage.setValue(KEY, kept);
}
}
}