Files
fenix8v3-watchface/source/Settings.mc
ericwyuan 4d96ab0912 Update watch face: modular refactor + OWM/Solar/background + codegen tools
- Split render into FieldTable/Fields/Icons/Layout/Settings modules
- Add Fenix8V3Background, Owm (weather), Solar modules
- Add tools/ generators (gen_fields/gen_icons/gen_themes/gen_preview_svg)
- Tune README/manifest/strings/settings
2026-09-10 07:10:55 +08:00

94 lines
4.6 KiB
MonkeyC
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Toybox.Lang;
import Toybox.Application;
// ============================================================================
// 设置读取
// ----------------------------------------------------------------------------
// 所有存储的偏好设置集中在这里,默认值就是设计稿的那套配置。
// 键名与 resources/settings/properties.xml 一一对应。
//
// 为什么要包一层而不是各处直接调 Properties.getValue
// Connect IQ 的 Properties.getValue 遇到「手表还没存过的键」时**不是返回 null
// 而是抛 Out of Bounds 异常**。每次版本更新新增设置项,在手表把新的
// properties.xml 合并进去之前都会撞上这个坑,轻则某个字段读不到,重则整个表盘
// 崩掉。所以全部读取都走本模块,异常一律降级成默认值。
// ============================================================================
module Settings {
// ---- 四个数据位的默认字段 ----
// 字段编号沿用 https://watchface.io/docs/datafields与 Fields.mc 中一致。
// 这四个默认值合起来就是设计稿上的样子。
const DEF_LEFT_TOP = 712; // 左上:日出
const DEF_RIGHT_TOP = 639; // 右上:预报最高/最低气温
const DEF_BOTTOM_LEFT = 3; // 左下:距离
const DEF_BOTTOM_RIGHT = 1; // 右下:步数
// ------------------------------------------------------------------------
// 底层读取:吞掉「键不存在」异常,返回 null 交给上层兜底。
// 注意 catch 在这里是有效的Properties 抛的是普通异常);而 Background
// 模块的 Out of Bounds 属于 VM 级错误catch 不住,那边只能用别的办法绕开,
// 详见 Fenix8V3App.scheduleWeather()。
// ------------------------------------------------------------------------
function raw(key as String) {
try {
return Application.Properties.getValue(key);
} catch (e) {
return null;
}
}
// 读数字型设置,取不到就用 def。
function number(key as String, def as Number) as Number {
var v = raw(key);
if (v == null) { return def; }
return v as Number;
}
// 读布尔型设置,取不到就用 def。
function bool(key as String, def as Boolean) as Boolean {
var v = raw(key);
if (v == null) { return def; }
return v as Boolean;
}
// 读字符串型设置,取不到返回空串(不是 null省得每个调用点再判一次
function text(key as String) as String {
var v = raw(key);
if (v == null) { return ""; }
return v.toString();
}
// ------------------------------------------------------------------------
// 主题序号0 基)。做范围钳制是为了防止这种情况:用户存的是「主题 7」
// 之后某个版本删掉了一套主题,存量值就会越界 —— 直接崩数组下标。
// ------------------------------------------------------------------------
function themeIndex(count as Number) as Number {
var i = number("Theme", 1) - 1;
if (i < 0 || i >= count) { return 0; }
return i;
}
// ---- 四个数据位选中的字段编号 ----
function leftTop() as Number { return number("LeftTop", DEF_LEFT_TOP); }
function rightTop() as Number { return number("RightTop", DEF_RIGHT_TOP); }
function bottomLeft() as Number { return number("BottomLeft", DEF_BOTTOM_LEFT); }
function bottomRight() as Number { return number("BottomRight", DEF_BOTTOM_RIGHT); }
// ---- 进度环四段各自绑定的指标 ----
// 注意这里的编号是进度环自己的一张短表0 步数 / 1 卡路里 / 2 距离 /
// 3 楼层 / 4 动动条 / 5 活动分钟 / 6 身体电量),与上面数据位的字段编号
// 是两套体系,不要混用。取值逻辑在 Fenix8V3View.ringProgress()。
function ringTR() as Number { return number("RingTR", 0); } // 右上:步数
function ringTL() as Number { return number("RingTL", 1); } // 左上:卡路里
function ringBR() as Number { return number("RingBR", 4); } // 右下:动动条
function ringBL() as Number { return number("RingBL", 3); } // 左下:楼层
// 温度单位0 跟随手表 / 1 强制摄氏 / 2 强制华氏。
function tempUnit() as Number { return number("TempUnit", 0); }
// ---- 三个显隐开关 ----
function showTop() as Boolean { return bool("ShowTop", true); }
function showBand() as Boolean { return bool("ShowBand", true); }
function showBottom() as Boolean { return bool("ShowBottom", true); }
}