diff --git a/apps/calendar/ChangeLog b/apps/calendar/ChangeLog index 27e1e2517..c7902e263 100644 --- a/apps/calendar/ChangeLog +++ b/apps/calendar/ChangeLog @@ -13,3 +13,4 @@ 0.12: Mark dated events on a day 0.13: Switch to swipe left/right for month and up/down for year selection Display events for current month on touch +0.14: Add support for holidays diff --git a/apps/calendar/README.md b/apps/calendar/README.md index ec1c0c55a..5f90d0d52 100644 --- a/apps/calendar/README.md +++ b/apps/calendar/README.md @@ -10,6 +10,7 @@ Basic calendar - Swipe down (Bangle.js 2 only) to go to the next year - Touch to display events for current month - Press the button (button 3 on Bangle.js 1) to exit +- Holidays have same color as weekends and can be edited with the 'Download'-interface, e.g. by uploading an iCalendar file. ## Settings diff --git a/apps/calendar/calendar.js b/apps/calendar/calendar.js index 6aab1aecd..d7c43eb1f 100644 --- a/apps/calendar/calendar.js +++ b/apps/calendar/calendar.js @@ -16,6 +16,7 @@ const white = "#ffffff"; const red = "#d41706"; const blue = "#0000ff"; const yellow = "#ffff00"; +const cyan = "#00ffff"; let bgColor = color4; let bgColorMonth = color1; let bgColorDow = color2; @@ -23,6 +24,7 @@ let bgColorWeekend = color3; let fgOtherMonth = gray1; let fgSameMonth = white; let bgEvent = blue; +let bgOtherEvent = "#ff8800"; const eventsPerDay=6; // how much different events per day we can display const date = new Date(); @@ -36,9 +38,17 @@ const events = (require("Storage").readJSON("sched.json",1) || []).filter(a => a date.setHours(time.h); date.setMinutes(time.m); date.setSeconds(time.s); - return {date: date, msg: a.msg}; + return {date: date, msg: a.msg, type: "e"}; +}); +// add holidays & other events +(require("Storage").readJSON("calendar.days.json",1) || []).forEach(d => { + const date = new Date(d.date); + const o = {date: date, msg: d.name, type: d.type}; + if (d.repeat) { + o.repeat = d.repeat; + } + events.push(o); }); -events.sort((a,b) => a.date - b.date); if (settings.ndColors === undefined) { settings.ndColors = !g.theme.dark; @@ -52,68 +62,16 @@ if (settings.ndColors === true) { fgOtherMonth = blue; fgSameMonth = black; bgEvent = color2; + bgOtherEvent = cyan; } function getDowLbls(locale) { - let dowLbls; - //TODO: Find some clever way to generate this programmatically from locale lib - switch (locale) { - case "de_AT": - case "de_CH": - case "de_DE": - if (startOnSun) { - dowLbls = ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"]; - } else { - dowLbls = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]; - } - break; - case "nl_NL": - if (startOnSun) { - dowLbls = ["zo", "ma", "di", "wo", "do", "vr", "za"]; - } else { - dowLbls = ["ma", "di", "wo", "do", "vr", "za", "zo"]; - } - break; - case "fr_BE": - case "fr_CH": - case "fr_FR": - if (startOnSun) { - dowLbls = ["Di", "Lu", "Ma", "Me", "Je", "Ve", "Sa"]; - } else { - dowLbls = ["Lu", "Ma", "Me", "Je", "Ve", "Sa", "Di"]; - } - break; - case "sv_SE": - if (startOnSun) { - dowLbls = ["Di", "Lu", "Ma", "Me", "Je", "Ve", "Sa"]; - } else { - dowLbls = ["Lu", "Ma", "Me", "Je", "Ve", "Sa", "Di"]; - } - break; - case "it_CH": - case "it_IT": - if (startOnSun) { - dowLbls = ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa"]; - } else { - dowLbls = ["Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"]; - } - break; - case "oc_FR": - if (startOnSun) { - dowLbls = ["dg", "dl", "dm", "dc", "dj", "dv", "ds"]; - } else { - dowLbls = ["dl", "dm", "dc", "dj", "dv", "ds", "dg"]; - } - break; - default: - if (startOnSun) { - dowLbls = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]; - } else { - dowLbls = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"]; - } - break; - } - return dowLbls; + let days = startOnSun ? [0, 1, 2, 3, 4, 5, 6] : [1, 2, 3, 4, 5, 6, 0]; + const d = new Date(); + return days.map(i => { + d.setDate(d.getDate() + (i + 7 - d.getDay()) % 7); + return require("locale").dow(d, 1); + }); } function sameDay(d1, d2) { @@ -206,8 +164,13 @@ function drawCalendar(date) { weekBeforeMonth.setDate(weekBeforeMonth.getDate() - 7); const week2AfterMonth = new Date(date.getFullYear(), date.getMonth()+1, 0); week2AfterMonth.setDate(week2AfterMonth.getDate() + 14); + events.forEach(ev => { + if (ev.repeat === "y") { + ev.date.setFullYear(ev.date.getMonth() < 6 ? week2AfterMonth.getFullYear() : weekBeforeMonth.getFullYear()); + } + }); const eventsThisMonth = events.filter(ev => ev.date > weekBeforeMonth && ev.date < week2AfterMonth); - + eventsThisMonth.sort((a,b) => a.date - b.date); let i = 0; for (y = 0; y < rowN - 1; y++) { for (x = 0; x < colN; x++) { @@ -220,6 +183,33 @@ function drawCalendar(date) { const y1 = y * rowH + headerH + rowH; const x2 = x * colW + colW; const y2 = y * rowH + headerH + rowH + rowH; + + if (eventsThisMonth.length > 0) { + // Display events for this day + eventsThisMonth.forEach((ev, idx) => { + if (sameDay(ev.date, curDay)) { + switch(ev.type) { + case "e": // alarm/event + const hour = ev.date.getHours() + ev.date.getMinutes()/60.0; + const slice = hour/24*(eventsPerDay-1); // slice 0 for 0:00 up to eventsPerDay for 23:59 + const height = (y2-2) - (y1+2); // height of a cell + const sliceHeight = height/eventsPerDay; + const ystart = (y1+2) + slice*sliceHeight; + g.setColor(bgEvent).fillRect(x1+1, ystart, x2-2, ystart+sliceHeight); + break; + case "h": // holiday + g.setColor(bgColorWeekend).fillRect(x1+1, y1+1, x2-1, y2-1); + break; + case "o": // other + g.setColor(bgOtherEvent).fillRect(x1+1, y1+1, x2-1, y2-1); + break; + } + + eventsThisMonth.splice(idx, 1); // this event is no longer needed + } + }); + } + if (isToday) { g.setColor(red); g.drawRect(x1, y1, x2, y2); @@ -231,23 +221,6 @@ function drawCalendar(date) { ); } - if (eventsThisMonth.length > 0) { - // Display events for this day - g.setColor(bgEvent); - eventsThisMonth.forEach((ev, idx) => { - if (sameDay(ev.date, curDay)) { - const hour = ev.date.getHours() + ev.date.getMinutes()/60.0; - const slice = hour/24*(eventsPerDay-1); // slice 0 for 0:00 up to eventsPerDay for 23:59 - const height = (y2-2) - (y1+2); // height of a cell - const sliceHeight = height/eventsPerDay; - const ystart = (y1+2) + slice*sliceHeight; - g.fillRect(x1+1, ystart, x2-2, ystart+sliceHeight); - - eventsThisMonth.splice(idx, 1); // this event is no longer needed - } - }); - } - require("Font8x12").add(Graphics); g.setFont("8x12", fontSize); g.setColor(day < 50 ? fgOtherMonth : fgSameMonth); @@ -286,10 +259,11 @@ function setUI() { }, btn: (n) => n === (process.env.HWVERSION === 2 ? 1 : 3) && load(), touch: (n,e) => { + events.sort((a,b) => a.date - b.date); const menu = events.filter(ev => ev.date.getFullYear() === date.getFullYear() && ev.date.getMonth() === date.getMonth()).map(e => { const dateStr = require("locale").date(e.date, 1); const timeStr = require("locale").time(e.date, 1); - return { title: `${dateStr} ${timeStr}` + (e.msg ? " " + e.msg : "") }; + return { title: `${dateStr} ${e.type === "e" ? timeStr : ""}` + (e.msg ? " " + e.msg : "") }; }); if (menu.length === 0) { menu.push({title: /*LANG*/"No events"}); diff --git a/apps/calendar/interface.html b/apps/calendar/interface.html new file mode 100644 index 000000000..280a96c0b --- /dev/null +++ b/apps/calendar/interface.html @@ -0,0 +1,234 @@ + +
+ + + + + + + +Date | +Holiday | +Type | +Repeat | ++ |
---|