- Replace placeholder SVG icons with custom PNG icons (80x80 padded) - AffineTransform for pixel-perfect icon centering in menu ring - Colored circles behind icons with icon drawn at 60% size - GPS: always wait full timeout (30s), keep best quality fix - History: show address, PLZ+city, coordinates on separate lines - Geocoding: fall back to "name" field for street-level results, include PLZ+city in cached address data - Address distance threshold raised to 70m Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
70 lines
3.5 KiB
MonkeyC
70 lines
3.5 KiB
MonkeyC
import Toybox.Graphics;
|
||
import Toybox.Lang;
|
||
|
||
// Central configuration. All tunable values live here so they can be
|
||
// changed without touching feature code.
|
||
(:glance)
|
||
module Config {
|
||
|
||
// --- Retention ------------------------------------------------------
|
||
const RETENTION_SEC = 7 * 24 * 60 * 60;
|
||
|
||
// --- GPS ------------------------------------------------------------
|
||
const GPS_TIMEOUT_MS = 30000;
|
||
|
||
// --- Menu ring -----------------------------------------------------
|
||
// Angle (degrees) at which the selected icon sits relative to the
|
||
// screen center. 0° = 3 o'clock, negative = upper half. −30° ≈ 2
|
||
// o'clock which lines up with the START/STOP button on most 5-
|
||
// button round Garmins (Forerunner 265, Fenix 7, Epix 2, Venu 3 …).
|
||
const SELECTION_ANGLE_DEG = -30.0;
|
||
|
||
// --- Animation / UI timings ----------------------------------------
|
||
const SUCCESS_DISPLAY_MS = 2500;
|
||
const ERROR_DISPLAY_MS = 5000;
|
||
const DELETE_HOLD_MS = 2500;
|
||
|
||
// --- Address resolution --------------------------------------------
|
||
const ADDRESS_MAX_DISTANCE_M = 70;
|
||
const PHOTON_URL = "https://photon.komoot.io/reverse";
|
||
|
||
// --- Colors (AMOLED: black background, white fg) -------------------
|
||
const COLOR_BG = 0x000000;
|
||
const COLOR_FG = 0xFFFFFF;
|
||
const COLOR_SUCCESS = 0x00AA00;
|
||
const COLOR_ERROR = 0xFF2222;
|
||
const COLOR_DELETE = 0xFF2222;
|
||
const COLOR_ACCENT = 0xFFFFFF;
|
||
|
||
// --- Event type keys ------------------------------------------------
|
||
const EVENT_GENERAL = "general";
|
||
const EVENT_START = "start";
|
||
const EVENT_END = "end";
|
||
const EVENT_ARRIVAL = "arrival";
|
||
const EVENT_ARREST = "arrest";
|
||
const EVENT_FORCE = "force";
|
||
const EVENT_EVIDENCE = "evidence";
|
||
const EVENT_SIGHTING = "sighting";
|
||
|
||
// --- Special menu actions ------------------------------------------
|
||
const ACTION_HISTORY = "history";
|
||
const ACTION_DELETE = "delete";
|
||
|
||
// Menu item metadata. Order matches display order (index 0 is first
|
||
// selected). Long German compounds are split into two lines so the
|
||
// center label never overlaps the surrounding icons.
|
||
function menuItems() as Array<Dictionary> {
|
||
return [
|
||
{ :key => ACTION_HISTORY, :icon => Rez.Drawables.IconHistory, :lines => ["Verlauf"], :color => 0xFFFFFF },
|
||
{ :key => EVENT_GENERAL, :icon => Rez.Drawables.IconEvent, :lines => ["Ereignis"], :color => 0xFFAA00 },
|
||
{ :key => EVENT_START, :icon => Rez.Drawables.IconStart, :lines => ["Einsatz", "beginn"], :color => 0x00FF00 },
|
||
{ :key => EVENT_END, :icon => Rez.Drawables.IconEnd, :lines => ["Einsatz", "ende"], :color => 0x00AAFF },
|
||
{ :key => EVENT_ARRIVAL, :icon => Rez.Drawables.IconArrival, :lines => ["Eintreffen"], :color => 0xFFFF00 },
|
||
{ :key => EVENT_ARREST, :icon => Rez.Drawables.IconArrest, :lines => ["Festnahme"], :color => 0xFF0088 },
|
||
{ :key => EVENT_FORCE, :icon => Rez.Drawables.IconForce, :lines => ["Zwang"], :color => 0xAA00FF },
|
||
{ :key => EVENT_EVIDENCE, :icon => Rez.Drawables.IconEvidence, :lines => ["Beweis", "mittel"], :color => 0x00FFFF },
|
||
{ :key => EVENT_SIGHTING, :icon => Rez.Drawables.IconSighting, :lines => ["Sichtung"], :color => 0xFF8800 },
|
||
{ :key => ACTION_DELETE, :icon => Rez.Drawables.IconDelete, :lines => ["Letzten", "löschen"], :color => 0xFF2222 }
|
||
];
|
||
}
|
||
}
|