Initial commit: Fenix 8 V3 data watch face
- Restore watchface-kit design (500x500, scaled per device) - 7 themes auto-generated from tokens via gen_themes.py -> Themes.mc - Four-segment gradient progress ring (22+21 ticks, 4 anchor dots) - Center time, date band w/ Bluetooth icon, top battery + dual complications, bottom distance/steps - 17 devices compiled clean (SDK 9.1.0) - Includes browser/JS preview (preview.html) + 7-theme SVG sheet
This commit is contained in:
28
source/Fenix8V3App.mc
Normal file
28
source/Fenix8V3App.mc
Normal file
@@ -0,0 +1,28 @@
|
||||
import Toybox.Application;
|
||||
import Toybox.Lang;
|
||||
import Toybox.WatchUi;
|
||||
|
||||
class Fenix8V3App extends Application.AppBase {
|
||||
|
||||
function initialize() {
|
||||
AppBase.initialize();
|
||||
}
|
||||
|
||||
function onStart(state as Dictionary?) as Void {
|
||||
}
|
||||
|
||||
function onStop(state as Dictionary?) as Void {
|
||||
}
|
||||
|
||||
function getInitialView() as [Views] or [Views, InputDelegates] {
|
||||
return [new Fenix8V3View()];
|
||||
}
|
||||
|
||||
function onSettingsChanged() as Void {
|
||||
WatchUi.requestUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
function getApp() as Fenix8V3App {
|
||||
return Application.getApp() as Fenix8V3App;
|
||||
}
|
||||
387
source/Fenix8V3View.mc
Normal file
387
source/Fenix8V3View.mc
Normal file
@@ -0,0 +1,387 @@
|
||||
import Toybox.Application;
|
||||
import Toybox.Graphics;
|
||||
import Toybox.Lang;
|
||||
import Toybox.Math;
|
||||
import Toybox.ActivityMonitor;
|
||||
import Toybox.Weather;
|
||||
import Toybox.System;
|
||||
import Toybox.Time;
|
||||
import Toybox.Time.Gregorian;
|
||||
import Toybox.WatchUi;
|
||||
import Themes;
|
||||
|
||||
class Fenix8V3View extends WatchUi.WatchFace {
|
||||
|
||||
// ----------------------------------------------------------------- utils
|
||||
function getSetting(name as String, def as Number) as Number {
|
||||
var v = Application.Properties.getValue(name);
|
||||
if (v == null) { return def; }
|
||||
return v as Number;
|
||||
}
|
||||
|
||||
function getBool(name as String, def as Boolean) as Boolean {
|
||||
var v = Application.Properties.getValue(name);
|
||||
if (v == null) { return def; }
|
||||
return v as Boolean;
|
||||
}
|
||||
|
||||
function currentTheme() as Dictionary {
|
||||
var idx = getSetting("Theme", 1); // 1..7
|
||||
var i = idx - 1;
|
||||
if (i < 0) { i = 0; }
|
||||
if (i > 6) { i = 0; }
|
||||
var id = Themes.ORDER[i];
|
||||
return Themes.THEMES[id] as Dictionary;
|
||||
}
|
||||
|
||||
function lerpColor(c1 as Number, c2 as Number, f as Float) as Number {
|
||||
var r1 = (c1 & 0xFF0000) >> 16;
|
||||
var g1 = (c1 & 0x00FF00) >> 8;
|
||||
var b1 = (c1 & 0x0000FF);
|
||||
var r2 = (c2 & 0xFF0000) >> 16;
|
||||
var g2 = (c2 & 0x00FF00) >> 8;
|
||||
var b2 = (c2 & 0x0000FF);
|
||||
var r = (r1 + ((r2 - r1) * f).toNumber()).toNumber();
|
||||
var g = (g1 + ((g2 - g1) * f).toNumber()).toNumber();
|
||||
var b = (b1 + ((b2 - b1) * f).toNumber()).toNumber();
|
||||
return (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
// interpolate a gradient stop array [[angle,color],...] (angles ascending)
|
||||
function lerpStops(stops as Array<Array<Number>>, t as Number) as Number {
|
||||
var n = stops.size();
|
||||
if (n == 0) { return 0x888888; }
|
||||
var first = stops[0];
|
||||
var last = stops[n - 1];
|
||||
if (t <= first[0]) { return first[1]; }
|
||||
if (t >= last[0]) { return last[1]; }
|
||||
for (var i = 0; i < n - 1; i++) {
|
||||
var a = stops[i];
|
||||
var b = stops[i + 1];
|
||||
if (t >= a[0] && t <= b[0]) {
|
||||
var f = ((t - a[0]) / (b[0] - a[0])).toFloat();
|
||||
return lerpColor(a[1], b[1], f);
|
||||
}
|
||||
}
|
||||
return last[1];
|
||||
}
|
||||
|
||||
// progress 0..1 for a metric index
|
||||
function metricProgress(idx as Number, info as ActivityMonitor.Info) as Float {
|
||||
if (info == null) { return 0.0f; }
|
||||
var p = 0.0f;
|
||||
if (idx == 0) { // Steps
|
||||
if (info.stepGoal != null && info.stepGoal > 0 && info.steps != null) {
|
||||
p = info.steps.toFloat() / info.stepGoal.toFloat();
|
||||
}
|
||||
} else if (idx == 1) { // Calories
|
||||
if (info.calories != null) { p = info.calories.toFloat() / 2000.0f; }
|
||||
} else if (idx == 2) { // Distance (cm -> 10 km cap)
|
||||
if (info.distance != null) { p = info.distance.toFloat() / 1000000.0f; }
|
||||
} else if (idx == 3) { // Floors
|
||||
if (info.floorsClimbed != null) {
|
||||
var goal = (info.floorsClimbedGoal != null && info.floorsClimbedGoal > 0)
|
||||
? info.floorsClimbedGoal.toFloat() : 10.0f;
|
||||
p = info.floorsClimbed.toFloat() / goal;
|
||||
}
|
||||
} else if (idx == 4) { // Move Bar
|
||||
if (info.moveBarLevel != null) { p = info.moveBarLevel.toFloat(); }
|
||||
}
|
||||
if (p > 1.0f) { p = 1.0f; }
|
||||
if (p < 0.0f) { p = 0.0f; }
|
||||
return p;
|
||||
}
|
||||
|
||||
// value string for a top complication type
|
||||
function complicationValue(typeIdx as Number, info as ActivityMonitor.Info,
|
||||
weather as Weather.CurrentConditions, stats as System.Stats) as String {
|
||||
if (typeIdx == 0) { // Weather temp
|
||||
if (weather != null && weather.temperature != null) {
|
||||
return weather.temperature.format("%d") + "\u00B0";
|
||||
}
|
||||
return "--";
|
||||
} else if (typeIdx == 1) { // Calories
|
||||
return info != null && info.calories != null ? info.calories.format("%d") : "0";
|
||||
} else if (typeIdx == 2) { // Steps
|
||||
return info != null && info.steps != null ? info.steps.format("%d") : "0";
|
||||
} else if (typeIdx == 3) { // Distance km
|
||||
if (info != null && info.distance != null) {
|
||||
return (info.distance.toFloat() / 100000.0).format("%.1f");
|
||||
}
|
||||
return "0.0";
|
||||
} else if (typeIdx == 4) { // Floors
|
||||
return info != null && info.floorsClimbed != null ? info.floorsClimbed.format("%d") : "0";
|
||||
} else { // Battery
|
||||
var pct = 0;
|
||||
if (stats != null && stats.battery != null) { pct = (stats.battery * 100.0).toNumber(); }
|
||||
return pct.format("%d") + "%";
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------- ring
|
||||
function drawTick(dc as Dc, cx as Number, cy as Number, rIn as Number, rOut as Number,
|
||||
w as Number, ang as Number, col as Number, mirror as Boolean) as Void {
|
||||
var eff = mirror ? -ang : ang;
|
||||
var rad = Math.toRadians(eff);
|
||||
var sin = Math.sin(rad);
|
||||
var cos = Math.cos(rad);
|
||||
var ix = (cx + sin * rIn).toNumber();
|
||||
var iy = (cy - cos * rIn).toNumber();
|
||||
var ox = (cx + sin * rOut).toNumber();
|
||||
var oy = (cy - cos * rOut).toNumber();
|
||||
dc.setPenWidth(w);
|
||||
dc.setColor(col, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawLine(ix, iy, ox, oy);
|
||||
}
|
||||
|
||||
function drawArcTop(dc as Dc, cx as Number, cy as Number, rIn as Number, rOut as Number,
|
||||
w as Number, angles as Array<Number>, stops as Array<Array<Number>>,
|
||||
off as Number, mirror as Boolean, lit as Number, anchorOuter as Boolean) as Void {
|
||||
var n = angles.size();
|
||||
for (var i = 0; i < n; i++) {
|
||||
var a = angles[i];
|
||||
var on = anchorOuter ? (i >= n - lit) : (i < lit);
|
||||
var col = on ? lerpStops(stops, a) : off;
|
||||
drawTick(dc, cx, cy, rIn, rOut, w, a, col, mirror);
|
||||
}
|
||||
}
|
||||
|
||||
function drawArcBottom(dc as Dc, cx as Number, cy as Number, rIn as Number, rOut as Number,
|
||||
w as Number, botAngles as Array<Number>, stops as Array<Array<Number>>,
|
||||
off as Number, mirror as Boolean, lit as Number) as Void {
|
||||
var n = botAngles.size();
|
||||
for (var i = 0; i < n; i++) {
|
||||
var a = botAngles[i];
|
||||
var on = (i < lit);
|
||||
var ang = (180.0 - a).toNumber();
|
||||
var col = on ? lerpStops(stops, a) : off;
|
||||
drawTick(dc, cx, cy, rIn, rOut, w, ang, col, mirror);
|
||||
}
|
||||
}
|
||||
|
||||
function drawRing(dc as Dc, cx as Number, cy as Number, s as Float, theme as Dictionary,
|
||||
pTR as Float, pTL as Float, pBR as Float, pBL as Float) as Void {
|
||||
var rOut = (249.5 * s).toNumber();
|
||||
var rIn = (231.5 * s).toNumber();
|
||||
var tickOff = theme["tickOff"] as Number;
|
||||
var topStops = theme["ringTop"] as Array<Array<Number>>;
|
||||
var botStops = theme["ringBottom"] as Array<Array<Number>>;
|
||||
var topW = (13.0 * s).toNumber();
|
||||
var botW = (9.0 * s).toNumber();
|
||||
|
||||
var TOP = [2,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,66,70,74,78,82,86];
|
||||
var BOT = [6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66];
|
||||
|
||||
var litTR = (pTR * 22.0).toNumber();
|
||||
var litTL = (pTL * 22.0).toNumber();
|
||||
var litBR = (pBR * 21.0).toNumber();
|
||||
var litBL = (pBL * 21.0).toNumber();
|
||||
|
||||
drawArcTop(dc, cx, cy, rIn, rOut, topW, TOP, topStops, tickOff, false, litTR, true);
|
||||
drawArcTop(dc, cx, cy, rIn, rOut, topW, TOP, topStops, tickOff, true, litTL, true);
|
||||
drawArcBottom(dc, cx, cy, rIn, rOut, botW, BOT, botStops, tickOff, true, litBL);
|
||||
drawArcBottom(dc, cx, cy, rIn, rOut, botW, BOT, botStops, tickOff, false, litBR);
|
||||
|
||||
// anchor dots
|
||||
var dotR = (9.5 * s).toNumber();
|
||||
var dotRad = (240.5 * s).toNumber();
|
||||
var dotCol = theme["anchorDot"] as Number;
|
||||
var dotAngles = [0.0, 93.3, 180.0, 266.7];
|
||||
dc.setColor(dotCol, Graphics.COLOR_TRANSPARENT);
|
||||
for (var i = 0; i < dotAngles.size(); i++) {
|
||||
var rad = Math.toRadians(dotAngles[i]);
|
||||
var dx = (cx + Math.sin(rad) * dotRad).toNumber();
|
||||
var dy = (cy - Math.cos(rad) * dotRad).toNumber();
|
||||
dc.fillCircle(dx, dy, dotR);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------- complications
|
||||
function drawBattery(dc as Dc, cx as Number, cy as Number, s as Float, theme as Dictionary,
|
||||
stats as System.Stats) as Void {
|
||||
var y = (53.5 * s).toNumber();
|
||||
var pct = 0;
|
||||
if (stats != null && stats.battery != null) { pct = (stats.battery * 100.0).toNumber(); }
|
||||
var txt = pct.format("%d") + "%";
|
||||
var gw = (30.0 * s).toNumber();
|
||||
var gh = (16.0 * s).toNumber();
|
||||
var gx = (cx - 52.0 * s).toNumber();
|
||||
var gy = (y - gh / 2).toNumber();
|
||||
dc.setPenWidth(2);
|
||||
dc.setColor(theme["accent"] as Number, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawRectangle(gx, gy, gw, gh);
|
||||
dc.fillRectangle((gx + gw).toNumber(), (gy + gh * 0.28).toNumber(),
|
||||
(3.0 * s).toNumber(), (gh * 0.44).toNumber());
|
||||
var fillW = ((gw - 4) * (pct.toFloat() / 100.0)).toNumber();
|
||||
dc.fillRectangle((gx + 2).toNumber(), (gy + 2).toNumber(), fillW, (gh - 4).toNumber());
|
||||
dc.setColor(theme["textPrimary"] as Number, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText((cx + 16.0 * s).toNumber(), y, Graphics.FONT_SMALL, txt,
|
||||
Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
}
|
||||
|
||||
function drawComplicationIcon(dc as Dc, x as Number, y as Number, r as Number, col as Number,
|
||||
typeIdx as Number) as Void {
|
||||
dc.setPenWidth(2);
|
||||
dc.setColor(col, Graphics.COLOR_TRANSPARENT);
|
||||
if (typeIdx == 0) { // sun
|
||||
dc.fillCircle(x, y, (r * 0.45).toNumber());
|
||||
for (var i = 0; i < 8; i++) {
|
||||
var rad = Math.toRadians(i * 45.0);
|
||||
var x1 = (x + Math.sin(rad) * r * 0.6).toNumber();
|
||||
var y1 = (y - Math.cos(rad) * r * 0.6).toNumber();
|
||||
var x2 = (x + Math.sin(rad) * r).toNumber();
|
||||
var y2 = (y - Math.cos(rad) * r).toNumber();
|
||||
dc.drawLine(x1, y1, x2, y2);
|
||||
}
|
||||
} else if (typeIdx == 1) { // flame
|
||||
dc.fillPolygon([[x, (y - r).toNumber()],
|
||||
[(x + r * 0.8).toNumber(), (y + r * 0.6).toNumber()],
|
||||
[(x - r * 0.8).toNumber(), (y + r * 0.6).toNumber()]]);
|
||||
} else if (typeIdx == 2) { // steps
|
||||
dc.drawLine((x - r * 0.5).toNumber(), (y - r * 0.3).toNumber(),
|
||||
(x + r * 0.5).toNumber(), (y - r * 0.3).toNumber());
|
||||
dc.drawLine((x - r * 0.3).toNumber(), y, (x + r * 0.6).toNumber(), y);
|
||||
} else if (typeIdx == 3) { // distance dot
|
||||
dc.fillCircle(x, y, (r * 0.5).toNumber());
|
||||
} else if (typeIdx == 4) { // floors chevron
|
||||
dc.fillPolygon([[x, (y - r).toNumber()],
|
||||
[(x + r * 0.7).toNumber(), (y + r * 0.2).toNumber()],
|
||||
[(x - r * 0.7).toNumber(), (y + r * 0.2).toNumber()]]);
|
||||
} else { // battery
|
||||
dc.drawRectangle((x - r * 0.6).toNumber(), (y - r * 0.4).toNumber(),
|
||||
(r * 1.2).toNumber(), (r * 0.8).toNumber());
|
||||
}
|
||||
}
|
||||
|
||||
function drawTopComplication(dc as Dc, cx as Number, cy as Number, s as Float, theme as Dictionary,
|
||||
typeIdx as Number, isLeft as Boolean, info as ActivityMonitor.Info,
|
||||
weather as Weather.CurrentConditions, stats as System.Stats) as Void {
|
||||
var sideX = isLeft ? (156.0 * s).toNumber() : (343.0 * s).toNumber();
|
||||
var iconY = (90.0 * s).toNumber();
|
||||
var valY = (130.5 * s).toNumber();
|
||||
var valStr = complicationValue(typeIdx, info, weather, stats);
|
||||
dc.setColor(theme["textPrimary"] as Number, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText(sideX, valY, Graphics.FONT_MEDIUM, valStr,
|
||||
Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
drawComplicationIcon(dc, sideX, iconY, (13.0 * s).toNumber(), theme["accent"] as Number, typeIdx);
|
||||
}
|
||||
|
||||
function drawBluetooth(dc as Dc, cx as Number, cy as Number, r as Number, col as Number) as Void {
|
||||
dc.setPenWidth(3);
|
||||
dc.setColor(col, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawLine(cx, (cy - r).toNumber(), cx, (cy + r).toNumber());
|
||||
dc.drawLine(cx, (cy - r).toNumber(), (cx + r * 0.7).toNumber(), (cy - r * 0.3).toNumber());
|
||||
dc.drawLine((cx + r * 0.7).toNumber(), (cy - r * 0.3).toNumber(), cx, cy);
|
||||
dc.drawLine(cx, cy, (cx + r * 0.7).toNumber(), (cy + r * 0.3).toNumber());
|
||||
dc.drawLine((cx + r * 0.7).toNumber(), (cy + r * 0.3).toNumber(), cx, (cy + r).toNumber());
|
||||
}
|
||||
|
||||
function drawDateBand(dc as Dc, w as Number, cx as Number, s as Float, theme as Dictionary,
|
||||
ds as System.DeviceSettings) as Void {
|
||||
var by = (286.5 * s).toNumber();
|
||||
var bh = (44.0 * s).toNumber();
|
||||
dc.setColor(theme["bandFill"] as Number, theme["bandFill"] as Number);
|
||||
dc.fillRectangle(0, by, w, bh);
|
||||
var txtCol = theme["bandText"] as Number;
|
||||
var yc = (308.5 * s).toNumber();
|
||||
drawBluetooth(dc, (36.5 * s).toNumber(), yc, (10.0 * s).toNumber(), txtCol);
|
||||
var gi = Gregorian.info(Time.now(), Time.FORMAT_MEDIUM);
|
||||
var DOW = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
|
||||
var MON = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
|
||||
var dow = DOW[gi.day_of_week - 1];
|
||||
var md = MON[gi.month - 1] + " " + gi.day.format("%d");
|
||||
dc.setColor(txtCol, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText((177.5 * s).toNumber(), yc, Graphics.FONT_SMALL, dow,
|
||||
Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
dc.drawText((297.5 * s).toNumber(), yc, Graphics.FONT_SMALL, md,
|
||||
Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
var ampm = gi.hour >= 12 ? "PM" : "AM";
|
||||
dc.drawText((465.0 * s).toNumber(), yc, Graphics.FONT_SMALL, ampm,
|
||||
Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
}
|
||||
|
||||
function drawTime(dc as Dc, cx as Number, cy as Number, s as Float, theme as Dictionary) as Void {
|
||||
var gi = Gregorian.info(Time.now(), Time.FORMAT_MEDIUM);
|
||||
var hh = gi.hour;
|
||||
if (hh == 0) { hh = 12; } else if (hh > 12) { hh = hh - 12; }
|
||||
var hStr = hh.format("%d");
|
||||
var mStr = gi.min.format("%02d");
|
||||
var ty = (220.0 * s).toNumber();
|
||||
dc.setColor(theme["hours"] as Number, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText((211.0 * s).toNumber(), ty, Graphics.FONT_NUMBER_HOT, hStr,
|
||||
Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
dc.setColor(theme["minutes"] as Number, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText((272.0 * s).toNumber(), ty, Graphics.FONT_NUMBER_HOT, mStr,
|
||||
Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
// colon: two blocks centred on x=250
|
||||
dc.setColor(theme["colon"] as Number, Graphics.COLOR_TRANSPARENT);
|
||||
var cw = (24.0 * s).toNumber();
|
||||
var ch = (20.0 * s).toNumber();
|
||||
var cxc = (238.0 * s).toNumber();
|
||||
dc.fillRectangle(cxc, (184.0 * s).toNumber(), cw, ch);
|
||||
dc.fillRectangle(cxc, (235.0 * s).toNumber(), cw, ch);
|
||||
}
|
||||
|
||||
function drawBottom(dc as Dc, cx as Number, s as Float, theme as Dictionary,
|
||||
info as ActivityMonitor.Info) as Void {
|
||||
var valY = (366.0 * s).toNumber();
|
||||
var labY = (410.5 * s).toNumber();
|
||||
var leftX = (234.0 * s).toNumber();
|
||||
var rightX = (266.0 * s).toNumber();
|
||||
var dist = info != null && info.distance != null
|
||||
? (info.distance.toFloat() / 100000.0).format("%.1f") : "0.0";
|
||||
var steps = info != null && info.steps != null ? info.steps.format("%d") : "0";
|
||||
dc.setColor(theme["textPrimary"] as Number, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText(leftX, valY, Graphics.FONT_MEDIUM, dist,
|
||||
Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
dc.setColor(theme["accent"] as Number, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText(leftX, labY, Graphics.FONT_SMALL, "DST",
|
||||
Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
dc.setColor(theme["textPrimary"] as Number, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText(rightX, valY, Graphics.FONT_MEDIUM, steps,
|
||||
Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
dc.setColor(theme["accent"] as Number, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText(rightX, labY, Graphics.FONT_SMALL, "STEP",
|
||||
Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------- main
|
||||
function onUpdate(dc as Dc) as Void {
|
||||
var w = dc.getWidth();
|
||||
var h = dc.getHeight();
|
||||
var s = w / 500.0;
|
||||
var cx = w / 2;
|
||||
var cy = h / 2;
|
||||
|
||||
var theme = currentTheme();
|
||||
var info = ActivityMonitor.getInfo();
|
||||
var stats = System.getSystemStats();
|
||||
var ds = System.getDeviceSettings();
|
||||
var weather = Weather.getCurrentConditions();
|
||||
|
||||
dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
|
||||
dc.clear();
|
||||
|
||||
var pTR = metricProgress(getSetting("RingTR", 0), info);
|
||||
var pTL = metricProgress(getSetting("RingTL", 1), info);
|
||||
var pBR = metricProgress(getSetting("RingBR", 4), info);
|
||||
var pBL = metricProgress(getSetting("RingBL", 3), info);
|
||||
drawRing(dc, cx, cy, s, theme, pTR, pTL, pBR, pBL);
|
||||
|
||||
if (getBool("ShowTop", true)) {
|
||||
drawBattery(dc, cx, cy, s, theme, stats);
|
||||
drawTopComplication(dc, cx, cy, s, theme, getSetting("LeftTop", 1), true, info, weather, stats);
|
||||
drawTopComplication(dc, cx, cy, s, theme, getSetting("RightTop", 0), false, info, weather, stats);
|
||||
}
|
||||
|
||||
drawTime(dc, cx, cy, s, theme);
|
||||
|
||||
if (getBool("ShowBand", true)) {
|
||||
drawDateBand(dc, w, cx, s, theme, ds);
|
||||
}
|
||||
|
||||
if (getBool("ShowBottom", true)) {
|
||||
drawBottom(dc, cx, s, theme, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
110
source/Themes.mc
Normal file
110
source/Themes.mc
Normal file
@@ -0,0 +1,110 @@
|
||||
// AUTO-GENERATED from watchface-tokens.json — do not edit by hand.
|
||||
module Themes {
|
||||
// THEMES: id -> theme dictionary.
|
||||
// ringTop / ringBottom are gradient stop arrays: [angle, 0xRRGGBB] sorted ascending.
|
||||
var THEMES = {
|
||||
"01" => {
|
||||
"name" => "Ember",
|
||||
"ringTop" => [[8,0xFFF203],[15,0xFDDB0D],[25,0xFFC203],[35,0xFFA00A],[45,0xFF8705],[55,0xFF610C],[65,0xFF4904],[75,0xFF2602],[86,0xFF2604]],
|
||||
"ringBottom" => [[7,0xAE1706],[14,0xB32504],[21,0xC03B03],[28,0xCD6206],[35,0xD57805],[42,0xDE9208],[47,0xC98D00]],
|
||||
"tickOff" => 0x545655,
|
||||
"anchorDot" => 0x525551,
|
||||
"bandFill" => 0xFEAA00,
|
||||
"bandText" => 0x000002,
|
||||
"accent" => 0xFCA901,
|
||||
"textPrimary" => 0xFAFAFA,
|
||||
"colon" => 0x525551,
|
||||
"hours" => 0xFBFBFB,
|
||||
"minutes" => 0xFCA901,
|
||||
},
|
||||
"02" => {
|
||||
"name" => "Aurora",
|
||||
"ringTop" => [[8,0xA5FA11],[15,0x9EFA23],[25,0x97F84B],[35,0x8CF965],[45,0x89F87F],[55,0x74FB9F],[65,0x6DFCC6],[75,0x64FCDF],[86,0x57FDFF]],
|
||||
"ringBottom" => [[7,0x55FDFF],[14,0x64FCDF],[21,0x6FFCC6],[28,0x74FBAE],[35,0x7EFA85],[42,0x88F96D],[47,0x81E654]],
|
||||
"tickOff" => 0x545655,
|
||||
"anchorDot" => 0x0F3C82,
|
||||
"bandFill" => 0x525551,
|
||||
"bandText" => 0xFFFFFF,
|
||||
"accent" => 0xABA9AC,
|
||||
"textPrimary" => 0xFAFAFA,
|
||||
"colon" => 0x525551,
|
||||
"hours" => 0xFBFBFB,
|
||||
"minutes" => 0xAAF701,
|
||||
},
|
||||
"03" => {
|
||||
"name" => "Brass",
|
||||
"ringTop" => [[8,0xB4814F],[15,0xB88954],[25,0xC5975C],[35,0xC59E65],[45,0xCBA775],[55,0xD7AE7F],[65,0xDEBC84],[75,0xE7C48D],[86,0xF0D097]],
|
||||
"ringBottom" => [[7,0xB97E4A],[14,0xB68954],[21,0xBD925E],[28,0xC69B67],[35,0xCEA26C],[42,0xD9AB74],[47,0xC59E70]],
|
||||
"tickOff" => 0x3A2815,
|
||||
"anchorDot" => 0x62441E,
|
||||
"bandFill" => 0x392810,
|
||||
"bandText" => 0xFFFFFF,
|
||||
"accent" => 0xB37C4A,
|
||||
"textPrimary" => 0xEBCB93,
|
||||
"colon" => 0x525551,
|
||||
"hours" => 0xFBFBFB,
|
||||
"minutes" => 0xECCC93,
|
||||
},
|
||||
"04" => {
|
||||
"name" => "Voltage",
|
||||
"ringTop" => [[8,0x5CAFF0],[15,0x6EB6E0],[25,0x7FBEC5],[35,0x96CA9D],[45,0xAAD87F],[55,0xBFDF66],[65,0xD6EA40],[75,0xE8F227],[86,0xFFFB0A]],
|
||||
"ringBottom" => [[7,0xF7FA11],[14,0xE9F225],[21,0xD6EB3F],[28,0xC0DE65],[35,0xADD880],[42,0xA0CF98],[47,0x88B98E]],
|
||||
"tickOff" => 0x545655,
|
||||
"anchorDot" => 0x53AAFF,
|
||||
"bandFill" => 0x53AAFF,
|
||||
"bandText" => 0x000000,
|
||||
"accent" => 0xABA9AC,
|
||||
"textPrimary" => 0x51A7FA,
|
||||
"colon" => 0x525551,
|
||||
"hours" => 0xFBFBFB,
|
||||
"minutes" => 0x52A8FD,
|
||||
},
|
||||
"05" => {
|
||||
"name" => "Reef",
|
||||
"ringTop" => [[8,0xF87E0D],[15,0xE78E25],[25,0xCE9B4D],[35,0xBDAC65],[45,0xA5BE88],[55,0x95CA9E],[65,0x7EDEC7],[75,0x6DEBE1],[86,0x57FDFF]],
|
||||
"ringBottom" => [[7,0xFF7905],[14,0xE78B29],[21,0xD59C3E],[28,0xBEAC63],[35,0xADB77F],[42,0xA0C796],[47,0x88B98E]],
|
||||
"tickOff" => 0x545655,
|
||||
"anchorDot" => 0xFE7900,
|
||||
"bandFill" => 0x52FDFF,
|
||||
"bandText" => 0x000000,
|
||||
"accent" => 0xFCA901,
|
||||
"textPrimary" => 0xFAFAFA,
|
||||
"colon" => 0x525551,
|
||||
"hours" => 0xFBFBFB,
|
||||
"minutes" => 0xFC7801,
|
||||
},
|
||||
"06" => {
|
||||
"name" => "Acid",
|
||||
"ringTop" => [[8,0x9CCC14],[15,0xA9CE0C],[25,0xA4D610],[35,0xACDB08],[45,0xB4E107],[55,0xB5E603],[65,0xBFEE04],[75,0xBDF108],[86,0xC7F808]],
|
||||
"ringBottom" => [[7,0xC7FA02],[14,0xBEF20A],[21,0xC0ED04],[28,0xB4E905],[35,0xB4E107],[42,0xADDD0C],[47,0x9BC603]],
|
||||
"tickOff" => 0x545655,
|
||||
"anchorDot" => 0xF58909,
|
||||
"bandFill" => 0x525551,
|
||||
"bandText" => 0x000000,
|
||||
"accent" => 0xC4F801,
|
||||
"textPrimary" => 0xFAFAFA,
|
||||
"colon" => 0x525551,
|
||||
"hours" => 0xDBF731,
|
||||
"minutes" => 0xC4F900,
|
||||
},
|
||||
"07" => {
|
||||
"name" => "Kelp",
|
||||
"ringTop" => [[8,0xEF8917],[15,0xD8901C],[25,0xBD9A34],[35,0xAD9E3C],[45,0x96A54E],[55,0x7DAE5D],[65,0x61B474],[75,0x4EBB84],[86,0x36C294]],
|
||||
"ringBottom" => [[7,0xCE520F],[14,0xB1631D],[21,0xA26A2F],[28,0x9D763E],[35,0x85874B],[42,0x76915D],[47,0x5E8651]],
|
||||
"tickOff" => 0x545655,
|
||||
"anchorDot" => 0xF58909,
|
||||
"bandFill" => 0x525551,
|
||||
"bandText" => 0x000000,
|
||||
"accent" => 0x31C192,
|
||||
"textPrimary" => 0xFAFAFA,
|
||||
"colon" => 0x525551,
|
||||
"hours" => 0xF28708,
|
||||
"minutes" => 0xF4880A,
|
||||
}
|
||||
};
|
||||
|
||||
// theme id list for settings enum (1-based index -> id)
|
||||
var ORDER = [
|
||||
"01", "02", "03", "04", "05", "06", "07"
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user