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
This commit is contained in:
@@ -1,12 +1,25 @@
|
||||
import Toybox.Application;
|
||||
import Toybox.Background;
|
||||
import Toybox.Lang;
|
||||
import Toybox.System;
|
||||
import Toybox.Time;
|
||||
import Toybox.WatchUi;
|
||||
import Owm;
|
||||
|
||||
// Application shell. A watch face has no menus or input of its own, so this
|
||||
// only hands back the view and forces a repaint when the wearer changes
|
||||
// something in the Connect IQ settings.
|
||||
// ============================================================================
|
||||
// 应用入口
|
||||
// ----------------------------------------------------------------------------
|
||||
// 表盘没有菜单也拿不到输入,所以这个壳子只做三件事:
|
||||
// 1. 交出 view
|
||||
// 2. 设置变更时请求重绘
|
||||
// 3. 管理拉取 OpenWeatherMap 的后台服务
|
||||
// ============================================================================
|
||||
class Fenix8V3App extends Application.AppBase {
|
||||
|
||||
// OWM 免费档的调用额度很宽裕,但表盘每分钟才重绘一次、数据本身也是小时级的,
|
||||
// 拉太勤只是白白唤醒射频费电。半小时是个合适的折中。
|
||||
const OWM_PERIOD_MIN = 30;
|
||||
|
||||
function initialize() {
|
||||
AppBase.initialize();
|
||||
}
|
||||
@@ -17,15 +30,55 @@ class Fenix8V3App extends Application.AppBase {
|
||||
function onStop(state as Dictionary?) as Void {
|
||||
}
|
||||
|
||||
// ⚠️ 定时器的注册必须放在 getInitialView 里,不能放 onStart。
|
||||
// 因为 onStart **在后台服务进程里也会被调用一次**,而在后台进程里调
|
||||
// registerForTemporalEvent 会抛 Out of Bounds。
|
||||
// getInitialView 只在前台进程运行,是安全的位置。
|
||||
function getInitialView() as [Views] or [Views, InputDelegates] {
|
||||
scheduleWeather();
|
||||
return [new Fenix8V3View()];
|
||||
}
|
||||
|
||||
// Fires when the phone pushes new settings down. The view reads every
|
||||
// preference fresh on each draw, so a repaint is all that is needed.
|
||||
function getServiceDelegate() as [System.ServiceDelegate] {
|
||||
return [new Fenix8V3Background()];
|
||||
}
|
||||
|
||||
// 只有用户真的填了 API key 才注册定时器 —— 没填就没什么可拉的,
|
||||
// 注册了纯属浪费电。反过来,用户把 key 清空时也要及时注销。
|
||||
function scheduleWeather() as Void {
|
||||
if (!(Background has :registerForTemporalEvent)) { return; }
|
||||
// ⚠️ deleteTemporalEvent 在「本来就没注册」时会抛 Out of Bounds,
|
||||
// 而这个错误是 VM 级的,**try/catch 抓不住**。
|
||||
// 所以这里不去问系统当前状态,而是自己在 Storage 里记一个标志位。
|
||||
// 重复注册本身是无害的(只是重置周期),所以只在状态真的变化时动手。
|
||||
var want = Owm.enabled();
|
||||
var have = Application.Storage.getValue("bgOn");
|
||||
have = (have != null) && (have as Boolean);
|
||||
if (want == have) { return; }
|
||||
if (want) {
|
||||
Background.registerForTemporalEvent(
|
||||
new Time.Duration(OWM_PERIOD_MIN * 60));
|
||||
} else {
|
||||
Background.deleteTemporalEvent();
|
||||
}
|
||||
Application.Storage.setValue("bgOn", want);
|
||||
}
|
||||
|
||||
// 手机把新设置推下来时触发。
|
||||
// view 每次绘制都是现读设置,所以重绘一下就够了;
|
||||
// 但天气定时器要跟着新的 key 状态启停,所以先过一遍 scheduleWeather。
|
||||
function onSettingsChanged() as Void {
|
||||
scheduleWeather();
|
||||
WatchUi.requestUpdate();
|
||||
}
|
||||
|
||||
// 后台服务把结果通过这里交回前台。存进 Storage 供表盘读取,然后重绘。
|
||||
function onBackgroundData(data as Application.PersistableType) as Void {
|
||||
if (data != null) {
|
||||
Application.Storage.setValue(Owm.STORE, data);
|
||||
WatchUi.requestUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getApp() as Fenix8V3App {
|
||||
|
||||
Reference in New Issue
Block a user