From 1a932b0618b32865e625889de75e7bc1d4eb9b59 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Mon, 24 Jul 2023 18:24:14 +0200 Subject: [PATCH] Calendar: Edit holidays on device in settings app: Only refactoring, no changed functionality --- apps/calendar/ChangeLog | 1 + apps/calendar/calendar.js | 48 ++++++------ apps/calendar/metadata.json | 2 +- apps/calendar/settings.js | 151 +++++++++++++++++++++++++++++++++--- 4 files changed, 167 insertions(+), 35 deletions(-) diff --git a/apps/calendar/ChangeLog b/apps/calendar/ChangeLog index c7902e263..12776867f 100644 --- a/apps/calendar/ChangeLog +++ b/apps/calendar/ChangeLog @@ -14,3 +14,4 @@ 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 +0.15: Edit holidays on device in settings diff --git a/apps/calendar/calendar.js b/apps/calendar/calendar.js index d7c43eb1f..11baf6855 100644 --- a/apps/calendar/calendar.js +++ b/apps/calendar/calendar.js @@ -75,11 +75,31 @@ function getDowLbls(locale) { } function sameDay(d1, d2) { + "compiled"; return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate(); } +function drawEvent(ev, curDay, x1, y1, x2, y2) { + switch(ev.type) { + case "e": // alarm/event + const hour = 0|ev.date.getHours() + 0|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; + } +} + function drawCalendar(date) { g.setBgColor(bgColor); g.clearRect(0, 0, maxX, maxY); @@ -118,7 +138,6 @@ function drawCalendar(date) { true ); - g.setFont("6x8", fontSize); let dowLbls = getDowLbls(require('locale').name); dowLbls.forEach((lbl, i) => { g.drawString(lbl, i * colW + colW / 2, headerH + rowH / 2); @@ -172,6 +191,7 @@ function drawCalendar(date) { const eventsThisMonth = events.filter(ev => ev.date > weekBeforeMonth && ev.date < week2AfterMonth); eventsThisMonth.sort((a,b) => a.date - b.date); let i = 0; + g.setFont("8x12", fontSize); for (y = 0; y < rowN - 1; y++) { for (x = 0; x < colN; x++) { i++; @@ -188,22 +208,7 @@ function drawCalendar(date) { // 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; - } + drawEvent(ev, curDay, x1, y1, x2, y2); eventsThisMonth.splice(idx, 1); // this event is no longer needed } @@ -221,17 +226,15 @@ function drawCalendar(date) { ); } - require("Font8x12").add(Graphics); - g.setFont("8x12", fontSize); g.setColor(day < 50 ? fgOtherMonth : fgSameMonth); g.drawString( (day > 50 ? day - 50 : day).toString(), x * colW + colW / 2, headerH + rowH + y * rowH + rowH / 2 ); - } - } -} + } // end for (x = 0; x < colN; x++) + } // end for (y = 0; y < rowN - 1; y++) +} // end function drawCalendar function setUI() { Bangle.setUI({ @@ -279,6 +282,7 @@ function setUI() { }); } +require("Font8x12").add(Graphics); drawCalendar(date); setUI(); // No space for widgets! diff --git a/apps/calendar/metadata.json b/apps/calendar/metadata.json index 44a68d879..bd35c8879 100644 --- a/apps/calendar/metadata.json +++ b/apps/calendar/metadata.json @@ -1,7 +1,7 @@ { "id": "calendar", "name": "Calendar", - "version": "0.14", + "version": "0.15", "description": "Simple calendar", "icon": "calendar.png", "screenshots": [{"url":"screenshot_calendar.png"}], diff --git a/apps/calendar/settings.js b/apps/calendar/settings.js index 54ed50a64..40eca9f68 100644 --- a/apps/calendar/settings.js +++ b/apps/calendar/settings.js @@ -1,5 +1,6 @@ (function (back) { var FILE = "calendar.json"; + const HOLIDAY_FILE = "calendar.days.json"; var settings = require('Storage').readJSON(FILE, true) || {}; if (settings.ndColors === undefined) if (process.env.HWVERSION == 2) { @@ -7,21 +8,147 @@ } else { settings.ndColors = false; } + const holidays = require("Storage").readJSON(HOLIDAY_FILE,1).sort((a,b) => new Date(a.date) - new Date(b.date)) || []; function writeSettings() { require('Storage').writeJSON(FILE, settings); } - E.showMenu({ - "": { "title": "Calendar" }, - "< Back": () => back(), - 'B2 Colors': { - value: settings.ndColors, - onchange: v => { - settings.ndColors = v; - writeSettings(); - } - }, - }); -}) + function writeHolidays() { + holidays.sort((a,b) => new Date(a.date) - new Date(b.date)); + require('Storage').writeJSON(HOLIDAY_FILE, holidays); + } + function formatDate(d) { + return d.getFullYear() + "-" + (d.getMonth() + 1).toString().padStart(2, '0') + "-" + d.getDate().toString().padStart(2, '0'); + } + + const editdate = (i) => { + const holiday = holidays[i]; + const date = new Date(holiday.date); + const dateStr = require("locale").date(date, 1); + const menu = { + "": { "title" : holiday.name}, + "< Back": () => { + writeHolidays(); + editdates(); + }, + /*LANG*/"Day": { + value: date ? date.getDate() : null, + min: 1, + max: 31, + wrap: true, + onchange: v => { + date.setDate(v); + holiday.date = formatDate(date); + } + }, + /*LANG*/"Month": { + value: date ? date.getMonth() + 1 : null, + format: v => require("date_utils").month(v), + onchange: v => { + date.setMonth((v+11)%12); + holiday.date = formatDate(date); + } + }, + /*LANG*/"Year": { + value: date ? date.getFullYear() : null, + min: 1900, + max: 2100, + onchange: v => { + date.setFullYear(v); + holiday.date = formatDate(date); + } + }, + /*LANG*/"Name": () => { + require("textinput").input({text:holiday.name}).then(result => { + holiday.name = result; + editdate(i); + }); + }, + /*LANG*/"Type": { + value: function() { + switch(holiday.type) { + case 'h': return 0; + case 'o': return 1; + } + return 0; + }(), + min: 0, max: 1, + format: v => [/*LANG*/"Holiday", /*LANG*/"Other"][v], + onchange: v => { + holiday.type = function() { + switch(v) { + case 0: return 'h'; + case 1: return 'o'; + } + }(); + } + }, + /*LANG*/"Repeat": { + value: !!holiday.repeat, + format: v => v ? /*LANG*/"Yearly" : /*LANG*/"Never", + onchange: v => { + holiday.repeat = v ? 'y' : undefined; + } + }, + /*LANG*/"Delete": () => E.showPrompt(/*LANG*/"Delete" + " " + menu[""].title + "?").then(function(v) { + if (v) { + holidays.splice(i, 1); + writeHolidays(); + editdates(); + } else { + editday(i); + } + } + ), + }; + try { + require("textinput"); + } catch(e) { + // textinput not installed + delete menu[/*LANG*/"Name"]; + } + + E.showMenu(menu); + }; + + const editdates = () => { + const menu = holidays.map((holiday,i) => { + const date = new Date(holiday.date); + const dateStr = require("locale").date(date, 1); + return { + title: dateStr + ' ' + holiday.name, + onchange: v => setTimeout(() => editdate(i), 10), + }; + }); + + menu[''] = { 'title': 'Holidays' }; + menu['< Back'] = ()=>settingsmenu(); + E.showMenu(menu); + }; + + const settingsmenu = () => { + E.showMenu({ + "": { "title": "Calendar" }, + "< Back": () => back(), + 'B2 Colors': { + value: settings.ndColors, + onchange: v => { + settings.ndColors = v; + writeSettings(); + } + }, + /*LANG*/"Edit Holidays": () => editdates(), + /*LANG*/"Add Holiday": () => { + holidays.push({ + "date":formatDate(new Date()), + "name":/*LANG*/"New", + "type":'h', + }); + editdate(holidays.length-1); + }, + }); + }; + settingsmenu(); +})