Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ text to paste into the **Release notes** field when uploading the `.pbw` to the
the build, so the portal does not auto-fill it). The store **Description** lives
in [`PUBLISHING.md`](PUBLISHING.md).

## 0.0.3

- Fix settings being completely ignored on a real watch. 0.0.2 sent every
setting by name in the `pebblejs://close` payload; on a real watch that
payload is length-limited, so it was truncated, the JSON failed to parse, and
the save was silently dropped (it worked on the emulator, which uses a
different return path). Numeric settings now travel positionally (values only,
no key names), shrinking the payload ~3.6× so it always fits — while still
applying every shown value (WYSIWYG preserved).
- The loading splash now shows the real app version instead of a hard-coded
"3.0".

## 0.0.2

- Settings are now WYSIWYG: saving the config page applies **every** value it
Expand Down
11 changes: 8 additions & 3 deletions PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,15 @@ Rebble guides:
**Keywords / tags:** calendar, weather, complications, date, week number,
battery, moon phase, world time, minimal, localizable

## Release notes — v0.0.1
## Release notes — v0.0.3

> First public release.
>
> • Settings are now WYSIWYG and reliable: saving applies exactly what the
> configuration page shows (an earlier build could silently drop a save on a
> real watch).
> • Coloured weather icons on colour watches (basalt, emery) — sun amber,
> rain/snow blue, lightning amber, moon pale yellow — with a Default / Colour /
> Black & White choice under Weather → Icon style.
> • The loading splash shows the real app version.
> • Configurable complication rows (status bar, above the time, above the
> calendar) — one centred or two side by side per row.
> • One shared, alphabetical menu for every slot, incl. watch/phone battery,
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
calendar below, and fully configurable complication rows you arrange yourself.**

[![CI](https://github.com/eldios/TimelyNG/actions/workflows/ci.yml/badge.svg)](https://github.com/eldios/TimelyNG/actions/workflows/ci.yml)
![Version](https://img.shields.io/badge/version-0.0.1-blue)
![Version](https://img.shields.io/badge/version-0.0.3-blue)
![Platforms](https://img.shields.io/badge/Pebble-emery%20·%20flint%20·%20basalt%20·%20diorite-orange)
![Language](https://img.shields.io/badge/C-C99-555?logo=c)
![PebbleKit JS](https://img.shields.io/badge/config-PebbleKit%20JS-f5a623?logo=javascript&logoColor=white)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "TimelyNG",
"author": "Emanuele 'Lele' Calo",
"version": "0.0.2",
"version": "0.0.3",
"description": "A calendar watchface for Pebble: date, time and weather up top, a 3-week calendar below, and fully configurable complication rows. Appstore copy in PUBLISHING.md; release notes in CHANGELOG.md.",
"private": true,
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion src/Timely.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "suntimes.h"
#define DEBUGLOG 0
#define TRANSLOG 0
#define CONFIG_VERSION "2.6"
#define CONFIG_VERSION "3.0" // config-protocol version (own sequence); major bump: the save wire format changed
/*
* If you fork this code and release the resulting app, please be considerate and change all the appropriate values in appinfo.json
*
Expand Down
20 changes: 14 additions & 6 deletions src/js/app.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var CONFIG_SPEC = require('./config');
var buildConfigPage = require('./configpage');
var WIRE_KEYS = require('./wirekeys'); // decode the positional numeric settings (see webviewclosed)

// The bundled SunCalc library (below) used to attach itself to `window`; under
// the CommonJS bundler there is no global object, so it populates this
Expand Down Expand Up @@ -312,18 +313,25 @@ V = waning crescent 0.25 +
Pebble.addEventListener("webviewclosed", function (e) {
if (!e || !e.response) { return; } // user cancelled

// The page sends every non-translation setting plus any changed translation
// string. Merge them into the stored settings so the config page keeps the
// full picture (incl. translations) and doesn't show untouched settings as
// reset on the next open.
// The page sends the numeric settings positionally in `n` (WIRE_KEYS order),
// plus the string settings and any changed translations by name. Expand `n`
// back to keys to rebuild the full desired state. (A legacy flat payload with
// no `n` is still accepted: its keys pass through unchanged.)
var dict;
try { dict = JSON.parse(decodeURIComponent(e.response)); } catch (err) { return; }
var full = {};
if (dict.n && dict.n.length) {
for (var i = 0; i < WIRE_KEYS.length; i++) { full[WIRE_KEYS[i]] = dict.n[i]; }
delete dict.n;
}
for (var k in dict) { full[k] = dict[k]; } // strings, translations, or legacy flat keys

var stored = {};
try { stored = JSON.parse(localStorage.getItem("timely_settings") || "{}"); } catch (err) {}
for (var k in dict) { stored[k] = dict[k]; }
for (var sk in full) { stored[sk] = full[sk]; }
localStorage.setItem("timely_settings", JSON.stringify(stored));

Pebble.sendAppMessage(dict,
Pebble.sendAppMessage(full,
function (e) {
console.log("Delivered config with transactionId=" + e.data.transactionId);
},
Expand Down
22 changes: 14 additions & 8 deletions src/js/configpage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict';

var WIRE_KEYS = require('./wirekeys'); // numeric settings sent positionally (see below)

// Builds the offline settings page as a self-contained HTML string from the
// config spec. No external CSS/JS/host: app.js serves it via a data: URI, so it
// works with no network. On submit the page redirects to `return_to` (provided
Expand Down Expand Up @@ -197,6 +199,7 @@ function buildConfigPage(spec, current) {
'return m?decodeURIComponent(m[1]):d;}' +
'var RET=qp("return_to","pebblejs://close#");' +
'var BASELINE=' + JSON.stringify(baseline) + ';' +
'var WK=' + JSON.stringify(WIRE_KEYS) + ';' +
'var LANGS=' + JSON.stringify(LANGS) + ';' +
// Language selector: resolve the chosen code, fill the (hidden) translation
// fields from the table, and toggle the Custom editor.
Expand Down Expand Up @@ -239,14 +242,17 @@ function buildConfigPage(spec, current) {
'els=document.querySelectorAll("[data-key]");for(var i=0;i<els.length;i++){' +
'o[els[i].getAttribute("data-key")]=val(els[i]);}' +
'if(augment(o)===false)return;' +
// WYSIWYG: always send every non-translation setting so the watch matches the
// page exactly (a drifted phone-side baseline must never leave a shown value
// unapplied). Translation strings (trans_*) are bulk; keep them delta-only so
// the payload stays within the watch's 1280-byte inbox — the language picker
// already resends them whenever it changes them.
'var send={};for(var k in o){' +
'if(k.indexOf("trans_")===0){if(String(o[k])!==String(BASELINE[k]))send[k]=o[k];}' +
'else{send[k]=o[k];}}' +
// WYSIWYG: send every numeric setting positionally (in WK order) so the watch
// matches the page exactly — a drifted phone-side baseline must never leave a
// shown value unapplied. Encoding values-only keeps the pebblejs://close
// payload tiny so a real watch carries it without truncation (the old verbose
// per-key dump got dropped). The two short string settings ride along by name,
// and changed translation strings are appended (delta — they are bulk).
'var n=[];for(var wi=0;wi<WK.length;wi++){var wv=o[WK[wi]];n.push(wv==null?0:wv);}' +
'var send={n:n};' +
'if(o.strftime_format!=null)send.strftime_format=o.strftime_format;' +
'if(o.language!=null)send.language=o.language;' +
'for(var k in o){if(k.indexOf("trans_")===0&&String(o[k])!==String(BASELINE[k]))send[k]=o[k];}' +
'document.location=RET+encodeURIComponent(JSON.stringify(send));};';
return '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8">' +
'<meta name="viewport" content="width=device-width,initial-scale=1">' +
Expand Down
21 changes: 21 additions & 0 deletions src/js/wirekeys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use strict';

// Ordered list of the numeric (uint8 / int8) settings sent on EVERY save. They
// travel positionally — values only, no key names — so the whole desired state
// fits in the tiny pebblejs://close payload a real watch can carry (the verbose
// per-key JSON of the full state gets truncated by the phone and the save is
// silently lost). configpage.js encodes values in this order; app.js decodes
// them back to keys. This order IS the wire contract between the two: never
// reorder or remove an entry — only APPEND new numeric keys at the end.
//
// The two non-translation STRING settings (strftime_format, language) and any
// changed translation strings travel by name alongside the array; they are few
// and short, so they do not blow the payload.
module.exports = [
'theme', 'theme_mode', 'style_day_inv', 'style_grid', 'intl_fmt_date',
'slot_stat_l', 'slot_stat_r', 'slot_ctr_l', 'slot_ctr_r', 'style_week', 'style_am_pm',
'batt_style', 'intl_fmt_week', 'clock2_tz', 'intl_dowo', 'cal_week_pattern',
'weather_fmt', 'weather_update', 'weather_icons', 'show_stat_bar', 'show_stat_batt',
'vibe_pat_disconnect', 'vibe_pat_connect', 'debugging_on', 'debuglang_on',
'vibe_days', 'vibe_hour', 'vibe_start', 'vibe_stop', 'dnd_noaccel', 'dnd_start', 'dnd_stop'
];
5 changes: 4 additions & 1 deletion src/splash.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
#include "theme.h"
#include "layout.h"

// Version shown on the loading splash. Keep in sync with package.json "version".
#define APP_VERSION "0.0.3"

static Layer *s_splash_layer;

static void splash_render(Layer *me, GContext* ctx) {
(void)me;
int w = layout_get().slot_bot.w; // full width: center the splash on any screen
setColors(ctx);
graphics_draw_text(ctx, "TimelyNG", fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD), GRect(0,0,w,36), GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
graphics_draw_text(ctx, "3.0", fonts_get_system_font(FONT_KEY_GOTHIC_28), GRect(0,32,w,36), GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
graphics_draw_text(ctx, APP_VERSION, fonts_get_system_font(FONT_KEY_GOTHIC_28), GRect(0,32,w,36), GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
}

void splash_create(Layer *parent, GRect frame) {
Expand Down
Loading