2023-10-15 08:17:03 +00:00
|
|
|
{
|
2021-06-24 13:28:46 +00:00
|
|
|
const maxX = g.getWidth();
|
|
|
|
const maxY = g.getHeight();
|
2021-12-17 12:51:18 +00:00
|
|
|
const fontSize = g.getWidth() > 200 ? 2 : 1;
|
2020-04-28 22:12:06 +00:00
|
|
|
const rowN = 7;
|
|
|
|
const colN = 7;
|
|
|
|
const headerH = maxY / 7;
|
|
|
|
const rowH = (maxY - headerH) / rowN;
|
|
|
|
const colW = maxX / colN;
|
|
|
|
const color1 = "#035AA6";
|
|
|
|
const color2 = "#4192D9";
|
|
|
|
const color3 = "#026873";
|
|
|
|
const color4 = "#038C8C";
|
2021-12-17 12:51:18 +00:00
|
|
|
const gray1 = "#bbbbbb";
|
2020-04-28 22:12:06 +00:00
|
|
|
const black = "#000000";
|
|
|
|
const white = "#ffffff";
|
|
|
|
const red = "#d41706";
|
2021-12-17 12:51:18 +00:00
|
|
|
const blue = "#0000ff";
|
|
|
|
const yellow = "#ffff00";
|
2023-05-04 19:27:20 +00:00
|
|
|
const cyan = "#00ffff";
|
2022-06-02 17:39:42 +00:00
|
|
|
let bgColor = color4;
|
|
|
|
let bgColorMonth = color1;
|
|
|
|
let bgColorDow = color2;
|
|
|
|
let bgColorWeekend = color3;
|
|
|
|
let fgOtherMonth = gray1;
|
|
|
|
let fgSameMonth = white;
|
2023-01-19 20:33:14 +00:00
|
|
|
let bgEvent = blue;
|
2023-05-04 19:27:20 +00:00
|
|
|
let bgOtherEvent = "#ff8800";
|
2023-01-19 20:33:14 +00:00
|
|
|
const eventsPerDay=6; // how much different events per day we can display
|
2023-02-10 16:10:37 +00:00
|
|
|
const date = new Date();
|
2020-04-28 22:12:06 +00:00
|
|
|
|
2023-01-19 20:33:14 +00:00
|
|
|
const timeutils = require("time_utils");
|
2021-12-07 18:32:49 +00:00
|
|
|
let settings = require('Storage').readJSON("calendar.json", true) || {};
|
2022-05-04 21:40:21 +00:00
|
|
|
let startOnSun = ((require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0) === 0;
|
2023-10-16 17:08:35 +00:00
|
|
|
let events;
|
2023-01-19 20:33:14 +00:00
|
|
|
|
2023-10-16 17:08:35 +00:00
|
|
|
const loadEvents = () => {
|
|
|
|
// all alarms that run on a specific date
|
|
|
|
events = (require("Storage").readJSON("sched.json",1) || []).filter(a => a.on && a.date).map(a => {
|
|
|
|
const date = new Date(a.date);
|
|
|
|
const time = timeutils.decodeTime(a.t);
|
|
|
|
date.setHours(time.h);
|
|
|
|
date.setMinutes(time.m);
|
|
|
|
date.setSeconds(time.s);
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
};
|
2021-12-17 12:51:18 +00:00
|
|
|
|
2023-10-19 18:00:54 +00:00
|
|
|
if (settings.ndColors === undefined) {
|
|
|
|
settings.ndColors = !g.theme.dark;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (settings.ndColors === true) {
|
2022-06-02 17:39:42 +00:00
|
|
|
bgColor = white;
|
|
|
|
bgColorMonth = blue;
|
|
|
|
bgColorDow = black;
|
|
|
|
bgColorWeekend = yellow;
|
|
|
|
fgOtherMonth = blue;
|
|
|
|
fgSameMonth = black;
|
2023-01-19 20:33:14 +00:00
|
|
|
bgEvent = color2;
|
2023-05-04 19:27:20 +00:00
|
|
|
bgOtherEvent = cyan;
|
2021-12-17 12:51:18 +00:00
|
|
|
}
|
|
|
|
|
2023-10-15 08:42:07 +00:00
|
|
|
const getDowLbls = function(locale) {
|
2023-05-02 17:33:29 +00:00
|
|
|
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);
|
|
|
|
});
|
2023-10-15 08:17:03 +00:00
|
|
|
};
|
2021-12-07 18:32:49 +00:00
|
|
|
|
2023-10-15 08:42:07 +00:00
|
|
|
const sameDay = function(d1, d2) {
|
2023-07-24 17:05:24 +00:00
|
|
|
"jit";
|
2023-01-19 20:33:14 +00:00
|
|
|
return d1.getFullYear() === d2.getFullYear() &&
|
|
|
|
d1.getMonth() === d2.getMonth() &&
|
|
|
|
d1.getDate() === d2.getDate();
|
2023-10-15 08:17:03 +00:00
|
|
|
};
|
2023-01-19 20:33:14 +00:00
|
|
|
|
2023-10-15 08:42:07 +00:00
|
|
|
const drawEvent = function(ev, curDay, x1, y1, x2, y2) {
|
2023-07-24 17:05:24 +00:00
|
|
|
"ram";
|
2023-07-24 16:24:14 +00:00
|
|
|
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;
|
|
|
|
}
|
2023-10-19 18:00:54 +00:00
|
|
|
};
|
2023-07-24 16:24:14 +00:00
|
|
|
|
2023-10-15 08:42:07 +00:00
|
|
|
const drawCalendar = function(date) {
|
2021-12-17 12:51:18 +00:00
|
|
|
g.setBgColor(bgColor);
|
2020-04-28 22:12:06 +00:00
|
|
|
g.clearRect(0, 0, maxX, maxY);
|
2021-12-17 12:51:18 +00:00
|
|
|
g.setBgColor(bgColorMonth);
|
2020-04-28 22:12:06 +00:00
|
|
|
g.clearRect(0, 0, maxX, headerH);
|
2022-05-04 21:40:21 +00:00
|
|
|
if (startOnSun){
|
2021-12-21 19:11:30 +00:00
|
|
|
g.setBgColor(bgColorWeekend);
|
|
|
|
g.clearRect(0, headerH + rowH, colW, maxY);
|
|
|
|
g.setBgColor(bgColorDow);
|
|
|
|
g.clearRect(0, headerH, maxX, headerH + rowH);
|
|
|
|
g.setBgColor(bgColorWeekend);
|
|
|
|
g.clearRect(colW * 6, headerH + rowH, maxX, maxY);
|
|
|
|
} else {
|
|
|
|
g.setBgColor(bgColorDow);
|
|
|
|
g.clearRect(0, headerH, maxX, headerH + rowH);
|
|
|
|
g.setBgColor(bgColorWeekend);
|
|
|
|
g.clearRect(colW * 5, headerH + rowH, maxX, maxY);
|
|
|
|
}
|
2020-04-28 22:12:06 +00:00
|
|
|
for (let y = headerH; y < maxY; y += rowH) {
|
|
|
|
g.drawLine(0, y, maxX, y);
|
|
|
|
}
|
|
|
|
for (let x = 0; x < maxX; x += colW) {
|
|
|
|
g.drawLine(x, headerH, x, maxY);
|
|
|
|
}
|
|
|
|
|
|
|
|
const month = date.getMonth();
|
|
|
|
const year = date.getFullYear();
|
2021-12-17 12:51:18 +00:00
|
|
|
const localeMonth = require('locale').month(date);
|
2020-04-28 22:12:06 +00:00
|
|
|
g.setFontAlign(0, 0);
|
2021-06-24 13:28:46 +00:00
|
|
|
g.setFont("6x8", fontSize);
|
2020-04-28 22:12:06 +00:00
|
|
|
g.setColor(white);
|
2021-12-17 12:51:18 +00:00
|
|
|
g.drawString(`${localeMonth} ${year}`, maxX / 2, headerH / 2);
|
2020-04-28 22:12:06 +00:00
|
|
|
g.drawPoly([10, headerH / 2, 20, 10, 20, headerH - 10], true);
|
|
|
|
g.drawPoly(
|
|
|
|
[maxX - 10, headerH / 2, maxX - 20, 10, maxX - 20, headerH - 10],
|
|
|
|
true
|
|
|
|
);
|
|
|
|
|
2021-12-17 12:51:18 +00:00
|
|
|
let dowLbls = getDowLbls(require('locale').name);
|
2020-04-28 22:12:06 +00:00
|
|
|
dowLbls.forEach((lbl, i) => {
|
|
|
|
g.drawString(lbl, i * colW + colW / 2, headerH + rowH / 2);
|
|
|
|
});
|
|
|
|
|
|
|
|
date.setDate(1);
|
2022-05-04 21:40:21 +00:00
|
|
|
const dow = date.getDay() + (startOnSun ? 1 : 0);
|
2020-04-28 22:12:06 +00:00
|
|
|
const dowNorm = dow === 0 ? 7 : dow;
|
|
|
|
|
|
|
|
const monthMaxDayMap = {
|
|
|
|
0: 31,
|
|
|
|
1: (2020 - year) % 4 === 0 ? 29 : 28,
|
|
|
|
2: 31,
|
|
|
|
3: 30,
|
|
|
|
4: 31,
|
|
|
|
5: 30,
|
|
|
|
6: 31,
|
|
|
|
7: 31,
|
|
|
|
8: 30,
|
|
|
|
9: 31,
|
|
|
|
10: 30,
|
|
|
|
11: 31
|
|
|
|
};
|
|
|
|
|
|
|
|
let days = [];
|
|
|
|
let nextMonthDay = 1;
|
|
|
|
let thisMonthDay = 51;
|
2022-03-25 18:01:34 +00:00
|
|
|
let prevMonthDay = monthMaxDayMap[month > 0 ? month - 1 : 11] - dowNorm + 1;
|
2020-04-28 22:12:06 +00:00
|
|
|
for (let i = 0; i < colN * (rowN - 1) + 1; i++) {
|
|
|
|
if (i < dowNorm) {
|
|
|
|
days.push(prevMonthDay);
|
|
|
|
prevMonthDay++;
|
|
|
|
} else if (thisMonthDay <= monthMaxDayMap[month] + 50) {
|
|
|
|
days.push(thisMonthDay);
|
|
|
|
thisMonthDay++;
|
|
|
|
} else {
|
|
|
|
days.push(nextMonthDay);
|
|
|
|
nextMonthDay++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-10 16:10:37 +00:00
|
|
|
const weekBeforeMonth = new Date(date.getTime());
|
|
|
|
weekBeforeMonth.setDate(weekBeforeMonth.getDate() - 7);
|
2023-02-10 16:25:35 +00:00
|
|
|
const week2AfterMonth = new Date(date.getFullYear(), date.getMonth()+1, 0);
|
|
|
|
week2AfterMonth.setDate(week2AfterMonth.getDate() + 14);
|
2023-05-03 20:09:14 +00:00
|
|
|
events.forEach(ev => {
|
|
|
|
if (ev.repeat === "y") {
|
2023-05-04 19:27:20 +00:00
|
|
|
ev.date.setFullYear(ev.date.getMonth() < 6 ? week2AfterMonth.getFullYear() : weekBeforeMonth.getFullYear());
|
2023-05-03 20:09:14 +00:00
|
|
|
}
|
|
|
|
});
|
2023-02-10 16:25:35 +00:00
|
|
|
const eventsThisMonth = events.filter(ev => ev.date > weekBeforeMonth && ev.date < week2AfterMonth);
|
2023-05-04 19:27:20 +00:00
|
|
|
eventsThisMonth.sort((a,b) => a.date - b.date);
|
2020-04-28 22:12:06 +00:00
|
|
|
let i = 0;
|
2023-07-24 16:24:14 +00:00
|
|
|
g.setFont("8x12", fontSize);
|
2020-04-28 22:12:06 +00:00
|
|
|
for (y = 0; y < rowN - 1; y++) {
|
|
|
|
for (x = 0; x < colN; x++) {
|
|
|
|
i++;
|
|
|
|
const day = days[i];
|
2023-01-19 20:33:14 +00:00
|
|
|
const curMonth = day < 15 ? month+1 : day < 50 ? month-1 : month;
|
|
|
|
const curDay = new Date(year, curMonth, day > 50 ? day-50 : day);
|
|
|
|
const isToday = sameDay(curDay, new Date());
|
|
|
|
const x1 = x * colW;
|
|
|
|
const y1 = y * rowH + headerH + rowH;
|
|
|
|
const x2 = x * colW + colW;
|
|
|
|
const y2 = y * rowH + headerH + rowH + rowH;
|
|
|
|
|
2023-02-10 16:10:37 +00:00
|
|
|
if (eventsThisMonth.length > 0) {
|
|
|
|
// Display events for this day
|
2023-02-10 16:45:14 +00:00
|
|
|
eventsThisMonth.forEach((ev, idx) => {
|
2023-02-10 16:10:37 +00:00
|
|
|
if (sameDay(ev.date, curDay)) {
|
2023-07-24 16:24:14 +00:00
|
|
|
drawEvent(ev, curDay, x1, y1, x2, y2);
|
2023-02-10 16:45:14 +00:00
|
|
|
|
|
|
|
eventsThisMonth.splice(idx, 1); // this event is no longer needed
|
2023-02-10 16:10:37 +00:00
|
|
|
}
|
2023-01-19 20:33:14 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-05-02 18:03:58 +00:00
|
|
|
if (isToday) {
|
|
|
|
g.setColor(red);
|
|
|
|
g.drawRect(x1, y1, x2, y2);
|
|
|
|
g.drawRect(
|
|
|
|
x1 + 1,
|
|
|
|
y1 + 1,
|
|
|
|
x2 - 1,
|
|
|
|
y2 - 1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-12-17 12:51:18 +00:00
|
|
|
g.setColor(day < 50 ? fgOtherMonth : fgSameMonth);
|
2020-04-28 22:12:06 +00:00
|
|
|
g.drawString(
|
|
|
|
(day > 50 ? day - 50 : day).toString(),
|
|
|
|
x * colW + colW / 2,
|
|
|
|
headerH + rowH + y * rowH + rowH / 2
|
|
|
|
);
|
2023-07-24 16:24:14 +00:00
|
|
|
} // end for (x = 0; x < colN; x++)
|
|
|
|
} // end for (y = 0; y < rowN - 1; y++)
|
2023-10-15 08:23:47 +00:00
|
|
|
}; // end function drawCalendar
|
2020-04-28 22:12:06 +00:00
|
|
|
|
2023-10-15 08:42:07 +00:00
|
|
|
const showMenu = function() {
|
2023-10-15 08:17:03 +00:00
|
|
|
const menu = {
|
|
|
|
"" : {
|
|
|
|
title : "Calendar",
|
|
|
|
remove: () => {
|
|
|
|
require("widget_utils").show();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"< Back": () => {
|
|
|
|
require("widget_utils").hide();
|
|
|
|
E.showMenu();
|
|
|
|
setUI();
|
|
|
|
},
|
2023-10-16 17:08:35 +00:00
|
|
|
/*LANG*/"Exit": () => load(),
|
2023-10-15 08:17:03 +00:00
|
|
|
/*LANG*/"Settings": () => {
|
|
|
|
const appSettings = eval(require('Storage').read('calendar.settings.js'));
|
2023-10-16 17:08:35 +00:00
|
|
|
appSettings(() => {
|
|
|
|
loadEvents();
|
|
|
|
showMenu();
|
|
|
|
});
|
2023-10-15 08:17:03 +00:00
|
|
|
},
|
|
|
|
};
|
2023-10-16 17:08:35 +00:00
|
|
|
if (require("Storage").read("alarm.app.js")) {
|
|
|
|
menu[/*LANG*/"Launch Alarms"] = () => {
|
|
|
|
load("alarm.app.js");
|
|
|
|
};
|
2023-10-15 08:17:03 +00:00
|
|
|
}
|
|
|
|
require("widget_utils").show();
|
|
|
|
E.showMenu(menu);
|
|
|
|
};
|
|
|
|
|
2023-10-15 08:42:07 +00:00
|
|
|
const setUI = function() {
|
2023-10-16 17:08:35 +00:00
|
|
|
require("widget_utils").hide(); // No space for widgets!
|
|
|
|
drawCalendar(date);
|
|
|
|
|
2023-02-10 16:10:37 +00:00
|
|
|
Bangle.setUI({
|
|
|
|
mode : "custom",
|
|
|
|
swipe: (dirLR, dirUD) => {
|
|
|
|
if (dirLR<0) { // left
|
|
|
|
const month = date.getMonth();
|
|
|
|
let prevMonth = month > 0 ? month - 1 : 11;
|
|
|
|
if (prevMonth === 11) date.setFullYear(date.getFullYear() - 1);
|
|
|
|
date.setMonth(prevMonth);
|
|
|
|
drawCalendar(date);
|
|
|
|
} else if (dirLR>0) { // right
|
|
|
|
const month = date.getMonth();
|
|
|
|
let nextMonth = month < 11 ? month + 1 : 0;
|
|
|
|
if (nextMonth === 0) date.setFullYear(date.getFullYear() + 1);
|
|
|
|
date.setMonth(nextMonth);
|
|
|
|
drawCalendar(date);
|
|
|
|
} else if (dirUD<0) { // up
|
|
|
|
date.setFullYear(date.getFullYear() - 1);
|
|
|
|
drawCalendar(date);
|
|
|
|
} else if (dirUD>0) { // down
|
|
|
|
date.setFullYear(date.getFullYear() + 1);
|
|
|
|
drawCalendar(date);
|
|
|
|
}
|
|
|
|
},
|
2023-10-15 08:17:03 +00:00
|
|
|
btn: (n) => {
|
|
|
|
if (process.env.HWVERSION === 2 || n === 2) {
|
|
|
|
showMenu();
|
|
|
|
} else if (n === 3) {
|
|
|
|
// directly exit only on Bangle.js 1
|
|
|
|
load();
|
|
|
|
}
|
|
|
|
},
|
2023-02-10 16:10:37 +00:00
|
|
|
touch: (n,e) => {
|
2023-05-03 20:09:14 +00:00
|
|
|
events.sort((a,b) => a.date - b.date);
|
2023-02-10 16:10:37 +00:00
|
|
|
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);
|
2023-05-02 18:03:58 +00:00
|
|
|
return { title: `${dateStr} ${e.type === "e" ? timeStr : ""}` + (e.msg ? " " + e.msg : "") };
|
2023-02-10 16:10:37 +00:00
|
|
|
});
|
|
|
|
if (menu.length === 0) {
|
|
|
|
menu.push({title: /*LANG*/"No events"});
|
|
|
|
}
|
|
|
|
menu[""] = { title: require("locale").month(date) + " " + date.getFullYear() };
|
|
|
|
menu["< Back"] = () => {
|
2023-10-15 08:17:03 +00:00
|
|
|
require("widget_utils").hide();
|
2023-02-10 16:10:37 +00:00
|
|
|
E.showMenu();
|
|
|
|
setUI();
|
|
|
|
};
|
2023-10-15 08:17:03 +00:00
|
|
|
require("widget_utils").show();
|
2023-02-10 16:10:37 +00:00
|
|
|
E.showMenu(menu);
|
|
|
|
}
|
|
|
|
});
|
2023-10-15 08:17:03 +00:00
|
|
|
};
|
2021-06-24 13:28:46 +00:00
|
|
|
|
2023-10-16 17:08:35 +00:00
|
|
|
loadEvents();
|
|
|
|
Bangle.loadWidgets();
|
2023-07-24 16:24:14 +00:00
|
|
|
require("Font8x12").add(Graphics);
|
2023-02-10 16:10:37 +00:00
|
|
|
setUI();
|
2023-10-15 08:17:03 +00:00
|
|
|
}
|