calendar: Add type other+repeat

master
Erik Andresen 2023-05-03 22:09:14 +02:00
parent 5da64a5f83
commit 044fc173c5
4 changed files with 83 additions and 30 deletions

View File

@ -10,7 +10,7 @@ Basic calendar
- Swipe down (Bangle.js 2 only) to go to the next year - Swipe down (Bangle.js 2 only) to go to the next year
- Touch to display events for current month - Touch to display events for current month
- Press the button (button 3 on Bangle.js 1) to exit - 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 - Holidays have same color as weekends and can be edited with the 'Download'-interface, e.g. by uploading an iCalendar file.
## Settings ## Settings

View File

@ -38,12 +38,15 @@ const events = (require("Storage").readJSON("sched.json",1) || []).filter(a => a
date.setSeconds(time.s); date.setSeconds(time.s);
return {date: date, msg: a.msg, type: "e"}; return {date: date, msg: a.msg, type: "e"};
}); });
// add holidays // add holidays & other events
(require("Storage").readJSON("calendar.holiday.json",1) || []).forEach(h => { (require("Storage").readJSON("calendar.days.json",1) || []).forEach(d => {
const date = new Date(h.date); const date = new Date(d.date);
events.push({date: date, msg: h.name, type: "h"}); 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) { if (settings.ndColors === undefined) {
settings.ndColors = !g.theme.dark; settings.ndColors = !g.theme.dark;
@ -158,8 +161,12 @@ function drawCalendar(date) {
weekBeforeMonth.setDate(weekBeforeMonth.getDate() - 7); weekBeforeMonth.setDate(weekBeforeMonth.getDate() - 7);
const week2AfterMonth = new Date(date.getFullYear(), date.getMonth()+1, 0); const week2AfterMonth = new Date(date.getFullYear(), date.getMonth()+1, 0);
week2AfterMonth.setDate(week2AfterMonth.getDate() + 14); week2AfterMonth.setDate(week2AfterMonth.getDate() + 14);
events.forEach(ev => {
if (ev.repeat === "y") {
ev.date.setFullYear(date.getFullYear());
}
});
const eventsThisMonth = events.filter(ev => ev.date > weekBeforeMonth && ev.date < week2AfterMonth); const eventsThisMonth = events.filter(ev => ev.date > weekBeforeMonth && ev.date < week2AfterMonth);
let i = 0; let i = 0;
for (y = 0; y < rowN - 1; y++) { for (y = 0; y < rowN - 1; y++) {
for (x = 0; x < colN; x++) { for (x = 0; x < colN; x++) {
@ -177,15 +184,21 @@ function drawCalendar(date) {
// Display events for this day // Display events for this day
eventsThisMonth.forEach((ev, idx) => { eventsThisMonth.forEach((ev, idx) => {
if (sameDay(ev.date, curDay)) { if (sameDay(ev.date, curDay)) {
if (ev.type === "e") { // alarm/event switch(ev.type) {
const hour = ev.date.getHours() + ev.date.getMinutes()/60.0; case "e": // alarm/event
const slice = hour/24*(eventsPerDay-1); // slice 0 for 0:00 up to eventsPerDay for 23:59 const hour = ev.date.getHours() + ev.date.getMinutes()/60.0;
const height = (y2-2) - (y1+2); // height of a cell const slice = hour/24*(eventsPerDay-1); // slice 0 for 0:00 up to eventsPerDay for 23:59
const sliceHeight = height/eventsPerDay; const height = (y2-2) - (y1+2); // height of a cell
const ystart = (y1+2) + slice*sliceHeight; const sliceHeight = height/eventsPerDay;
g.setColor(bgEvent).fillRect(x1+1, ystart, x2-2, ystart+sliceHeight); const ystart = (y1+2) + slice*sliceHeight;
} else if (ev.type === "h") { // holiday g.setColor(bgEvent).fillRect(x1+1, ystart, x2-2, ystart+sliceHeight);
g.setColor(bgColorWeekend).fillRect(x1+1, y1+1, x2-1, y2-1); break;
case "h": // holiday
g.setColor(bgColorWeekend).fillRect(x1+1, y1+1, x2-1, y2-1);
break;
case "o": // other
g.setColor("#88ff00").fillRect(x1+1, y1+1, x2-1, y2-1);
break;
} }
eventsThisMonth.splice(idx, 1); // this event is no longer needed eventsThisMonth.splice(idx, 1); // this event is no longer needed
@ -242,6 +255,7 @@ function setUI() {
}, },
btn: (n) => n === (process.env.HWVERSION === 2 ? 1 : 3) && load(), btn: (n) => n === (process.env.HWVERSION === 2 ? 1 : 3) && load(),
touch: (n,e) => { 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 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 dateStr = require("locale").date(e.date, 1);
const timeStr = require("locale").time(e.date, 1); const timeStr = require("locale").time(e.date, 1);

View File

@ -53,6 +53,7 @@ function eventToHoliday(event) {
const holiday = { const holiday = {
date: formatDate(date), date: formatDate(date),
name: event.summary, name: event.summary,
type: 'h',
}; };
return holiday; return holiday;
} }
@ -63,7 +64,7 @@ function formatDate(d) {
function upload() { function upload() {
Util.showModal("Saving..."); Util.showModal("Saving...");
Util.writeStorage("calendar.holiday.json", JSON.stringify(holidays), () => { Util.writeStorage("calendar.days.json", JSON.stringify(holidays), () => {
location.reload(); // reload so we see current data location.reload(); // reload so we see current data
}); });
} }
@ -82,7 +83,7 @@ function renderHoliday(holiday) {
inputTime.value = formatDate(localDate) inputTime.value = formatDate(localDate)
inputTime.onchange = (e => { inputTime.onchange = (e => {
const date = new Date(inputTime.value); const date = new Date(inputTime.value);
holiday.date = formatDate(date.toISOString()) holiday.date = formatDate(date);
}); });
tdTime.appendChild(inputTime); tdTime.appendChild(inputTime);
@ -101,13 +102,50 @@ function renderHoliday(holiday) {
tdSummary.appendChild(inputSummary); tdSummary.appendChild(inputSummary);
inputSummary.onchange(); inputSummary.onchange();
const tdInfo = document.createElement('td'); const tdType = document.createElement('td');
tr.appendChild(tdInfo); tr.appendChild(tdType);
const selectType = document.createElement("select");
selectType.classList.add('form-select');
tdType.prepend(selectType);
const optionHoliday = document.createElement("option");
optionHoliday.text = "Holiday";
optionHoliday.value = "h";
optionHoliday.selected = holiday.type === "h";
selectType.add(optionHoliday);
const optionOther = document.createElement("option");
optionOther.text = "Other";
optionOther.value = "o";
optionOther.selected = holiday.type === "o";
selectType.add(optionOther);
selectType.onchange = (e => {
holiday.type = e.target.value;
});
const tdRepeat = document.createElement('td');
tr.appendChild(tdRepeat);
const selectRepeat = document.createElement("select");
selectRepeat.classList.add('form-select');
tdRepeat.prepend(selectRepeat);
const optionNever = document.createElement("option");
optionNever.text = "Never";
optionNever.selected = !holiday.repeat;
selectRepeat.add(optionNever);
const optionYearly = document.createElement("option");
optionYearly.text = "Yearly";
optionYearly.value = "y";
optionYearly.selected = holiday.repeat === "y";
selectRepeat.add(optionYearly);
selectRepeat.onchange = (e => {
holiday.repeat = e.target.value;
});
const tdAction = document.createElement('td');
tr.appendChild(tdAction);
const buttonDelete = document.createElement('button'); const buttonDelete = document.createElement('button');
buttonDelete.classList.add('btn'); buttonDelete.classList.add('btn');
buttonDelete.classList.add('btn-action'); buttonDelete.classList.add('btn-action');
tdInfo.prepend(buttonDelete); tdAction.prepend(buttonDelete);
const iconDelete = document.createElement('i'); const iconDelete = document.createElement('i');
iconDelete.classList.add('icon'); iconDelete.classList.add('icon');
iconDelete.classList.add('icon-delete'); iconDelete.classList.add('icon-delete');
@ -129,22 +167,21 @@ function addHoliday() {
} }
function getData() { function getData() {
Util.showModal("Loading...");
Puck.write(`\x10(function() { Puck.write(`\x10(function() {
Bluetooth.print(JSON.stringify(require("Storage").list("calendar.holiday.json").sort())); Bluetooth.print(JSON.stringify(require("Storage").list("calendar.days.json").sort()));
})()\n`, contents => { })()\n`, contents => {
const fileNames = JSON.parse(contents); const fileNames = JSON.parse(contents);
if (fileNames.length > 0) { if (fileNames.length > 0) {
Util.showModal("Loading..."); Util.readStorage('calendar.days.json',data=>{
Util.readStorage('calendar.holiday.json',data=>{
holidays = JSON.parse(data || "[]") || []; holidays = JSON.parse(data || "[]") || [];
Util.hideModal(); Util.hideModal();
holidays.forEach(holiday => { render();
renderHoliday(holiday);
});
}); });
} else { } else {
holidays = []; holidays = [];
Util.hideModal();
} }
}); });
} }
@ -156,7 +193,7 @@ function onInit() {
</script> </script>
</head> </head>
<body> <body>
<h4>Holidays</h4> <h4 class="float-left">Holidays</h4>
<div class="float-right"> <div class="float-right">
<button class="btn" onclick="addHoliday();"> <button class="btn" onclick="addHoliday();">
@ -164,11 +201,13 @@ function onInit() {
</button> </button>
</div> </div>
<table class="table"> <table class="table table-scroll" style="clear:both;">
<thead> <thead>
<tr> <tr>
<th>Date</th> <th>Date</th>
<th>Holiday</th> <th>Holiday</th>
<th>Type</th>
<th>Repeat</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>

View File

@ -15,5 +15,5 @@
{"name":"calendar.settings.js","url":"settings.js"}, {"name":"calendar.settings.js","url":"settings.js"},
{"name":"calendar.img","url":"calendar-icon.js","evaluate":true} {"name":"calendar.img","url":"calendar-icon.js","evaluate":true}
], ],
"data": [{"name":"calendar.json"}, {"name":"calendar.holiday.json"}] "data": [{"name":"calendar.json"}, {"name":"calendar.days.json"}]
} }