1
0
Fork 0

Merge pull request #1773 from alessandrococco/alarms-dow

[Alarms & Timers] Support for Monday as first day of week
master
Gordon Williams 2022-05-04 08:29:38 +01:00 committed by GitHub
commit 3080255337
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 192 additions and 119 deletions

View File

@ -25,3 +25,4 @@
0.24: Automatically save the alarm/timer when the user returns to the main menu using the back arrow 0.24: Automatically save the alarm/timer when the user returns to the main menu using the back arrow
Add "Enable All", "Disable All" and "Remove All" actions Add "Enable All", "Disable All" and "Remove All" actions
0.25: Fix redrawing selected Alarm/Timer entry inside edit submenu 0.25: Fix redrawing selected Alarm/Timer entry inside edit submenu
0.26: Add support for Monday as first day of the week (#1780)

View File

@ -2,10 +2,14 @@ Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
// An array of alarm objects (see sched/README.md) // An array of alarm objects (see sched/README.md)
let alarms = require("sched").getAlarms(); var alarms = require("sched").getAlarms();
// 0 = Sunday
// 1 = Monday
var firstDayOfWeek = (require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0;
function getCurrentTime() { function getCurrentTime() {
let time = new Date(); var time = new Date();
return ( return (
time.getHours() * 3600000 + time.getHours() * 3600000 +
time.getMinutes() * 60000 + time.getMinutes() * 60000 +
@ -14,6 +18,9 @@ function getCurrentTime() {
} }
function saveAndReload() { function saveAndReload() {
// Before saving revert the dow to the standard format
alarms.forEach(a => a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek));
require("sched").setAlarms(alarms); require("sched").setAlarms(alarms);
require("sched").reload(); require("sched").reload();
} }
@ -28,6 +35,8 @@ function showMainMenu() {
/*LANG*/'New Timer': () => editTimer(-1) /*LANG*/'New Timer': () => editTimer(-1)
}; };
alarms.forEach((alarm, idx) => { alarms.forEach((alarm, idx) => {
alarm.dow = handleFirstDayOfWeek(alarm.dow, firstDayOfWeek);
var type, txt; // a leading space is currently required (JS error in Espruino 2v12) var type, txt; // a leading space is currently required (JS error in Espruino 2v12)
if (alarm.timer) { if (alarm.timer) {
type = /*LANG*/"Timer"; type = /*LANG*/"Timer";
@ -71,23 +80,25 @@ function editDOW(dow, onchange) {
'': { 'title': /*LANG*/'Days of Week' }, '': { 'title': /*LANG*/'Days of Week' },
/*LANG*/'< Back': () => onchange(dow) /*LANG*/'< Back': () => onchange(dow)
}; };
for (let i = 0; i < 7; i++) (i => { var dows = require("date_utils").dows(firstDayOfWeek);
let dayOfWeek = require("locale").dow({ getDay: () => i }); for (var i = 0; i < 7; i++) (i => {
menu[dayOfWeek] = { menu[dows[i]] = {
value: !!(dow&(1<<i)), value: !!(dow & (1 << (i + firstDayOfWeek))),
format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
onchange: v => v ? dow |= 1<<i : dow &= ~(1<<i), onchange: v => v ? (dow |= 1 << (i + firstDayOfWeek)) : (dow &= ~(1 << (i + firstDayOfWeek)))
}; };
})(i); })(i);
E.showMenu(menu); E.showMenu(menu);
} }
function editAlarm(alarmIndex, alarm) { function editAlarm(alarmIndex, alarm) {
let newAlarm = alarmIndex < 0; var newAlarm = alarmIndex < 0;
let a = require("sched").newDefaultAlarm(); var a = require("sched").newDefaultAlarm();
a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek);
if (!newAlarm) Object.assign(a, alarms[alarmIndex]); if (!newAlarm) Object.assign(a, alarms[alarmIndex]);
if (alarm) Object.assign(a, alarm); if (alarm) Object.assign(a, alarm);
let t = require("sched").decodeTime(a.t); var t = require("sched").decodeTime(a.t);
const menu = { const menu = {
'': { 'title': /*LANG*/'Alarm' }, '': { 'title': /*LANG*/'Alarm' },
@ -114,7 +125,7 @@ function editAlarm(alarmIndex, alarm) {
onchange: v => a.rp = v onchange: v => a.rp = v
}, },
/*LANG*/'Days': { /*LANG*/'Days': {
value: "SMTWTFS".split("").map((d,n)=>a.dow&(1<<n)?d:".").join(""), value: decodeDOW(a.dow),
onchange: () => setTimeout(editDOW, 100, a.dow, d => { onchange: () => setTimeout(editDOW, 100, a.dow, d => {
a.dow = d; a.dow = d;
a.t = require("sched").encodeTime(t); a.t = require("sched").encodeTime(t);
@ -156,11 +167,11 @@ function saveAlarm(newAlarm, alarmIndex, a, t) {
} }
function editTimer(alarmIndex, alarm) { function editTimer(alarmIndex, alarm) {
let newAlarm = alarmIndex < 0; var newAlarm = alarmIndex < 0;
let a = require("sched").newDefaultTimer(); var a = require("sched").newDefaultTimer();
if (!newAlarm) Object.assign(a, alarms[alarmIndex]); if (!newAlarm) Object.assign(a, alarms[alarmIndex]);
if (alarm) Object.assign(a, alarm); if (alarm) Object.assign(a, alarm);
let t = require("sched").decodeTime(a.timer); var t = require("sched").decodeTime(a.timer);
const menu = { const menu = {
'': { 'title': /*LANG*/'Timer' }, '': { 'title': /*LANG*/'Timer' },
@ -210,6 +221,26 @@ function saveTimer(newAlarm, alarmIndex, a, t) {
saveAndReload(); saveAndReload();
} }
function handleFirstDayOfWeek(dow, firstDayOfWeek) {
if (firstDayOfWeek == 1) {
if ((dow & 1) == 1) {
// By default 1 = Sunday.
// Here the week starts on Monday and Sunday is ON so move Sunday to 128.
dow += 127;
} else if ((dow & 128) == 128) {
dow -= 127;
}
}
return dow;
}
function decodeDOW(dow) {
return require("date_utils")
.dows(firstDayOfWeek, 2)
.map((day, index) => dow & (1 << (index + firstDayOfWeek)) ? day : "_")
.join("");
}
function enableAll(on) { function enableAll(on) {
E.showPrompt(/*LANG*/"Are you sure?", { E.showPrompt(/*LANG*/"Are you sure?", {
title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All" title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All"

View File

@ -2,7 +2,7 @@
"id": "alarm", "id": "alarm",
"name": "Alarms & Timers", "name": "Alarms & Timers",
"shortName": "Alarms", "shortName": "Alarms",
"version": "0.25", "version": "0.26",
"description": "Set alarms and timers on your Bangle", "description": "Set alarms and timers on your Bangle",
"icon": "app.png", "icon": "app.png",
"tags": "tool,alarm,widget", "tags": "tool,alarm,widget",

View File

@ -46,3 +46,5 @@
0.41: Stop users disabling all wake-up methods and locking themselves out (fix #1272) 0.41: Stop users disabling all wake-up methods and locking themselves out (fix #1272)
0.42: Fix theme customizer on new Bangle 2 firmware 0.42: Fix theme customizer on new Bangle 2 firmware
0.43: Add some Bangle 1 colours to theme customizer 0.43: Add some Bangle 1 colours to theme customizer
0.44: Add "Start Week On X" option (#1780)
UI improvements to Locale and Date & Time menu

View File

@ -7,7 +7,7 @@ This is Bangle.js's settings menu
* **Beep** most Bangle.js do not have a speaker inside, but they can use the vibration motor to beep in different pitches. You can change the behaviour here to use a Piezo speaker if one is connected * **Beep** most Bangle.js do not have a speaker inside, but they can use the vibration motor to beep in different pitches. You can change the behaviour here to use a Piezo speaker if one is connected
* **Vibration** enable/disable the vibration motor * **Vibration** enable/disable the vibration motor
* **Quiet Mode** prevent notifications/alarms from vibrating/beeping/turning the screen on - see below * **Quiet Mode** prevent notifications/alarms from vibrating/beeping/turning the screen on - see below
* **Locale** set time zone/whether the clock is 12/24 hour (for supported clocks) * **Locale** set time zone, the time format (12/24h, for supported clocks) and the first day of the week
* **Select Clock** if you have more than one clock face, select the default one * **Select Clock** if you have more than one clock face, select the default one
* **Set Time** Configure the current time - Note that this can be done much more easily by choosing 'Set Time' from the App Loader * **Set Time** Configure the current time - Note that this can be done much more easily by choosing 'Set Time' from the App Loader
* **LCD** Configure settings about the screen. How long it stays on, how bright it is, and when it turns on - see below. * **LCD** Configure settings about the screen. How long it stays on, how bright it is, and when it turns on - see below.

View File

@ -1,7 +1,7 @@
{ {
"id": "setting", "id": "setting",
"name": "Settings", "name": "Settings",
"version": "0.43", "version": "0.44",
"description": "A menu for setting up Bangle.js", "description": "A menu for setting up Bangle.js",
"icon": "settings.png", "icon": "settings.png",
"tags": "tool,system", "tags": "tool,system",

View File

@ -48,6 +48,7 @@ function resetSettings() {
HID: false, // BLE HID mode, off by default HID: false, // BLE HID mode, off by default
clock: null, // a string for the default clock's name clock: null, // a string for the default clock's name
"12hour" : false, // 12 or 24 hour clock? "12hour" : false, // 12 or 24 hour clock?
firstDayOfWeek: 0, // 0 -> Sunday (default), 1 -> Monday
brightness: 1, // LCD brightness from 0 to 1 brightness: 1, // LCD brightness from 0 to 1
// welcomed : undefined/true (whether welcome app should show) // welcomed : undefined/true (whether welcome app should show)
options: { options: {
@ -94,7 +95,7 @@ function showSystemMenu() {
/*LANG*/'LCD': ()=>showLCDMenu(), /*LANG*/'LCD': ()=>showLCDMenu(),
/*LANG*/'Locale': ()=>showLocaleMenu(), /*LANG*/'Locale': ()=>showLocaleMenu(),
/*LANG*/'Select Clock': ()=>showClockMenu(), /*LANG*/'Select Clock': ()=>showClockMenu(),
/*LANG*/'Set Time': ()=>showSetTimeMenu() /*LANG*/'Date & Time': ()=>showSetTimeMenu()
}; };
return E.showMenu(mainmenu); return E.showMenu(mainmenu);
@ -478,6 +479,7 @@ function showLocaleMenu() {
'< Back': ()=>showSystemMenu(), '< Back': ()=>showSystemMenu(),
/*LANG*/'Time Zone': { /*LANG*/'Time Zone': {
value: settings.timezone, value: settings.timezone,
format: v => (v > 0 ? "+" : "") + v,
min: -11, min: -11,
max: 13, max: 13,
step: 0.5, step: 0.5,
@ -486,13 +488,23 @@ function showLocaleMenu() {
updateSettings(); updateSettings();
} }
}, },
/*LANG*/'Clock Style': { /*LANG*/'Time Format': {
value: !!settings["12hour"], value: !!settings["12hour"],
format: v => v ? "12hr" : "24hr", format: v => v ? "12h" : "24h",
onchange: v => { onchange: v => {
settings["12hour"] = v; settings["12hour"] = v;
updateSettings(); updateSettings();
} }
},
/*LANG*/'Start Week On': {
value: settings["firstDayOfWeek"] || 0,
min: 0, // Sunday
max: 1, // Monday
format: v => require("date_utils").dow(v, 1),
onchange: v => {
settings["firstDayOfWeek"] = v;
updateSettings();
},
} }
}; };
return E.showMenu(localemenu); return E.showMenu(localemenu);
@ -606,11 +618,34 @@ function showClockMenu() {
function showSetTimeMenu() { function showSetTimeMenu() {
d = new Date(); d = new Date();
const timemenu = { const timemenu = {
'': { 'title': /*LANG*/'Set Time' }, '': { 'title': /*LANG*/'Date & Time' },
'< Back': function () { '< Back': function () {
setTime(d.getTime() / 1000); setTime(d.getTime() / 1000);
showSystemMenu(); showSystemMenu();
}, },
/*LANG*/'Day': {
value: d.getDate(),
onchange: function (v) {
this.value = ((v+30)%31)+1;
d.setDate(this.value);
}
},
/*LANG*/'Month': {
value: d.getMonth() + 1,
format: v => require("date_utils").month(v),
onchange: function (v) {
this.value = ((v+11)%12)+1;
d.setMonth(this.value - 1);
}
},
/*LANG*/'Year': {
value: d.getFullYear(),
min: 2019,
max: 2100,
onchange: function (v) {
d.setFullYear(v);
}
},
/*LANG*/'Hour': { /*LANG*/'Hour': {
value: d.getHours(), value: d.getHours(),
onchange: function (v) { onchange: function (v) {
@ -631,28 +666,6 @@ function showSetTimeMenu() {
this.value = (v+60)%60; this.value = (v+60)%60;
d.setSeconds(this.value); d.setSeconds(this.value);
} }
},
/*LANG*/'Date': {
value: d.getDate(),
onchange: function (v) {
this.value = ((v+30)%31)+1;
d.setDate(this.value);
}
},
/*LANG*/'Month': {
value: d.getMonth() + 1,
onchange: function (v) {
this.value = ((v+11)%12)+1;
d.setMonth(this.value - 1);
}
},
/*LANG*/'Year': {
value: d.getFullYear(),
min: 2019,
max: 2100,
onchange: function (v) {
d.setFullYear(v);
}
} }
}; };
return E.showMenu(timemenu); return E.showMenu(timemenu);

View File

@ -1,39 +1,65 @@
/* Utility functions that use the 'locale' module so can produce text // module "date_utils"
in the currently selected language. */ //
// Utility functions that use the "locale" module so can produce
// date-related text in the currently selected language.
//
// Some functions have a "firstDayOfWeek" parameter.
// Most used values are:
// - 0/undefined --> Sunday
// - 1 --> Monday
// but you can start the week from any day if you need it.
//
// Some functions have an "abbreviated" parameter.
// It supports the following 3 values:
// - 0/undefined --> get the full value, without abbreviation (eg.: "Monday", "January", etc.)
// - 1 --> get the short value (eg.: "Mon", "Jan", etc.)
// - 2 --> get only the first char (eg.: "M", "J", etc.)
//
/** Return the day of the week (0=Sunday) /**
short==0/undefined -> "Sunday" * @param {int} i The index of the day of the week (0 = Sunday)
short==1 -> "Sun" * @param {int} abbreviated
* @returns The localized name of the i-th day of the week
*/ */
exports.getDOW = (dow, short) => require("locale").dow({getDay:()=>dow},short); exports.dow = (i, abbreviated) => {
var dow = require("locale").dow(new Date(((i || 0) + 3.5) * 86400000), abbreviated).slice(0, (abbreviated == 2) ? 1 : 100);
/** Return the month (1=January) return abbreviated == 2 ? dow.toUpperCase() : dow;
short==0/undefined -> "January"
short==1 -> "Jan"
*/
exports.getMonth = (month, short) => require("locale").month({getMonth:()=>month-1},short);
/** Return all 7 days of the week as an array ["Sunday","Monday",...].
short==0/undefined -> ["Sunday",...
short==1 -> ["Sun",...
short==2 -> ["S",...
*/
exports.getDOWs = (short) => {
var locale = require("locale");
var days = [];
for (var i=0;i<7;i++)
days.push(locale.dow({getDay:()=>i},short).slice(0,(short==2)?1:100));
return days;
} }
/** Return all 12 months as an array ["January","February",...] /**
short==0/undefined -> ["January",... * @param {int} firstDayOfWeek 0/undefined -> Sunday,
short==1 -> ["Jan",... * 1 -> Monday
* @param {int} abbreviated
* @returns All 7 days of the week (localized) as an array
*/ */
exports.getMonths = (short) => { exports.dows = (firstDayOfWeek, abbreviated) => {
var dows = [];
var locale = require("locale"); var locale = require("locale");
for (var i = 0; i < 7; i++) {
dows.push(exports.dow(i + (firstDayOfWeek || 0), abbreviated))
}
return abbreviated == 2 ? dows.map(dow => dow.toUpperCase()) : dows;
};
/**
* @param {int} i The index of the month (1 = January)
* @param {int} abbreviated
* @returns The localized name of the i-th month
*/
exports.month = (i, abbreviated) => {
var month = require("locale").month(new Date((i - 0.5) * 2628000000), abbreviated).slice(0, (abbreviated == 2) ? 1 : 100);
return abbreviated == 2 ? month.toUpperCase() : month;
}
/**
* @param {int} abbreviated
* @returns All 12 months (localized) as an array
*/
exports.months = (abbreviated) => {
var months = []; var months = [];
for (var i=0;i<12;i++) var locale = require("locale");
months.push(locale.month({getMonth:()=>i},short)); for (var i = 1; i <= 12; i++) {
return months; months.push(locale.month(new Date((i - 0.5) * 2628000000), abbreviated).slice(0, (abbreviated == 2) ? 1 : 100));
} }
return abbreviated == 2 ? months.map(month => month.toUpperCase()) : months;
};