diff --git a/apps/calendar/ChangeLog b/apps/calendar/ChangeLog index 12776867f..6edb54f65 100644 --- a/apps/calendar/ChangeLog +++ b/apps/calendar/ChangeLog @@ -15,3 +15,5 @@ Display events for current month on touch 0.14: Add support for holidays 0.15: Edit holidays on device in settings +0.16: Add menu to fast open settings to edit holidays + Display Widgets in menus diff --git a/apps/calendar/README.md b/apps/calendar/README.md index 5f90d0d52..7fa7bea1c 100644 --- a/apps/calendar/README.md +++ b/apps/calendar/README.md @@ -1,6 +1,6 @@ # Calendar -Basic calendar +Monthly calendar, displays holidays uploaded from the web interface and scheduled events. ## Usage @@ -14,4 +14,4 @@ Basic calendar ## Settings -- B2 Colors: use non-dithering colors (default, recommended for Bangle 2) or the original color scheme. +B2 Colors: use non-dithering colors (default, recommended for Bangle 2) or the original color scheme. diff --git a/apps/calendar/calendar.js b/apps/calendar/calendar.js index 0ae852d83..7477775ca 100644 --- a/apps/calendar/calendar.js +++ b/apps/calendar/calendar.js @@ -1,3 +1,4 @@ +{ const maxX = g.getWidth(); const maxY = g.getHeight(); const fontSize = g.getWidth() > 200 ? 2 : 1; @@ -17,71 +18,85 @@ const red = "#d41706"; const blue = "#0000ff"; const yellow = "#ffff00"; const cyan = "#00ffff"; -let bgColor = color4; -let bgColorMonth = color1; -let bgColorDow = color2; -let bgColorWeekend = color3; -let fgOtherMonth = gray1; -let fgSameMonth = white; -let bgEvent = blue; -let bgOtherEvent = "#ff8800"; +let bgColor; +let bgColorMonth; +let bgColorDow; +let bgColorWeekend; +let fgOtherMonth; +let fgSameMonth; +let bgEvent; +let bgOtherEvent; const eventsPerDay=6; // how much different events per day we can display const date = new Date(); const timeutils = require("time_utils"); -let settings = require('Storage').readJSON("calendar.json", true) || {}; let startOnSun = ((require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0) === 0; - // all alarms that run on a specific date -const 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); -}); - -if (settings.ndColors === undefined) { - settings.ndColors = !g.theme.dark; -} - -if (settings.ndColors === true) { - bgColor = white; - bgColorMonth = blue; - bgColorDow = black; - bgColorWeekend = yellow; - fgOtherMonth = blue; - fgSameMonth = black; - bgEvent = color2; - bgOtherEvent = cyan; -} - -function getDowLbls(locale) { - let days = startOnSun ? [0, 1, 2, 3, 4, 5, 6] : [1, 2, 3, 4, 5, 6, 0]; +let events; +const dowLbls = function() { + const locale = require('locale').name; + const 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) { +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); + }); +}; + +const loadSettings = () => { + let settings = require('Storage').readJSON("calendar.json", true) || {}; + if (settings.ndColors === undefined) { + settings.ndColors = !g.theme.dark; + } + if (settings.ndColors === true) { + bgColor = white; + bgColorMonth = blue; + bgColorDow = black; + bgColorWeekend = yellow; + fgOtherMonth = blue; + fgSameMonth = black; + bgEvent = color2; + bgOtherEvent = cyan; + } else { + bgColor = color4; + bgColorMonth = color1; + bgColorDow = color2; + bgColorWeekend = color3; + fgOtherMonth = gray1; + fgSameMonth = white; + bgEvent = blue; + bgOtherEvent = "#ff8800"; + } +}; + +const sameDay = function(d1, d2) { "jit"; return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate(); -} +}; -function drawEvent(ev, curDay, x1, y1, x2, y2) { +const drawEvent = function(ev, curDay, x1, y1, x2, y2) { "ram"; switch(ev.type) { case "e": // alarm/event @@ -99,9 +114,33 @@ function drawEvent(ev, curDay, x1, y1, x2, y2) { g.setColor(bgOtherEvent).fillRect(x1+1, y1+1, x2-1, y2-1); break; } -} +}; -function drawCalendar(date) { +const calcDays = (month, monthMaxDayMap, dowNorm) => { + "jit"; + const maxDay = colN * (rowN - 1) + 1; + const days = []; + let nextMonthDay = 1; + let thisMonthDay = 51; + const month2 = month; + let prevMonthDay = monthMaxDayMap[month > 0 ? month - 1 : 11] - dowNorm + 1; + + for (let i = 0; i < maxDay; i++) { + if (i < dowNorm) { + days.push(prevMonthDay); + prevMonthDay++; + } else if (thisMonthDay <= monthMaxDayMap[month] + 50) { + days.push(thisMonthDay); + thisMonthDay++; + } else { + days.push(nextMonthDay); + nextMonthDay++; + } + } + return days; +}; + +const drawCalendar = function(date) { g.setBgColor(bgColor); g.clearRect(0, 0, maxX, maxY); g.setBgColor(bgColorMonth); @@ -139,7 +178,6 @@ function drawCalendar(date) { true ); - let dowLbls = getDowLbls(require('locale').name); dowLbls.forEach((lbl, i) => { g.drawString(lbl, i * colW + colW / 2, headerH + rowH / 2); }); @@ -163,23 +201,7 @@ function drawCalendar(date) { 11: 31 }; - let days = []; - let nextMonthDay = 1; - let thisMonthDay = 51; - let prevMonthDay = monthMaxDayMap[month > 0 ? month - 1 : 11] - dowNorm + 1; - 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++; - } - } - + const days = calcDays(month, monthMaxDayMap, dowNorm); const weekBeforeMonth = new Date(date.getTime()); weekBeforeMonth.setDate(weekBeforeMonth.getDate() - 7); const week2AfterMonth = new Date(date.getFullYear(), date.getMonth()+1, 0); @@ -189,8 +211,15 @@ function drawCalendar(date) { 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); + + const eventsThisMonthPerDay = events.filter(ev => ev.date > weekBeforeMonth && ev.date < week2AfterMonth).reduce((acc, ev) => { + const day = ev.date.getDate(); + if (!acc[day]) { + acc[day] = []; + } + acc[day].push(ev); + return acc; + }, []); let i = 0; g.setFont("8x12", fontSize); for (y = 0; y < rowN - 1; y++) { @@ -205,13 +234,13 @@ function drawCalendar(date) { const x2 = x * colW + colW; const y2 = y * rowH + headerH + rowH + rowH; - if (eventsThisMonth.length > 0) { + const eventsThisDay = eventsThisMonthPerDay[curDay.getDate()]; + if (eventsThisDay && eventsThisDay.length > 0) { // Display events for this day - eventsThisMonth.forEach((ev, idx) => { + eventsThisDay.forEach((ev, idx) => { if (sameDay(ev.date, curDay)) { drawEvent(ev, curDay, x1, y1, x2, y2); - - eventsThisMonth.splice(idx, 1); // this event is no longer needed + eventsThisDay.splice(idx, 1); // this event is no longer needed } }); } @@ -235,9 +264,44 @@ function drawCalendar(date) { ); } // end for (x = 0; x < colN; x++) } // end for (y = 0; y < rowN - 1; y++) -} // end function drawCalendar +}; // end function drawCalendar + +const showMenu = function() { + const menu = { + "" : { + title : "Calendar", + remove: () => { + require("widget_utils").show(); + } + }, + "< Back": () => { + require("widget_utils").hide(); + E.showMenu(); + setUI(); + }, + /*LANG*/"Exit": () => load(), + /*LANG*/"Settings": () => { + const appSettings = eval(require('Storage').read('calendar.settings.js')); + appSettings(() => { + loadSettings(); + loadEvents(); + showMenu(); + }); + }, + }; + if (require("Storage").read("alarm.app.js")) { + menu[/*LANG*/"Launch Alarms"] = () => { + load("alarm.app.js"); + }; + } + require("widget_utils").show(); + E.showMenu(menu); +}; + +const setUI = function() { + require("widget_utils").hide(); // No space for widgets! + drawCalendar(date); -function setUI() { Bangle.setUI({ mode : "custom", swipe: (dirLR, dirUD) => { @@ -261,7 +325,14 @@ function setUI() { drawCalendar(date); } }, - btn: (n) => n === (process.env.HWVERSION === 2 ? 1 : 3) && load(), + btn: (n) => { + if (process.env.HWVERSION === 2 || n === 2) { + showMenu(); + } else if (n === 3) { + // directly exit only on Bangle.js 1 + 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 => { @@ -274,16 +345,19 @@ function setUI() { } menu[""] = { title: require("locale").month(date) + " " + date.getFullYear() }; menu["< Back"] = () => { + require("widget_utils").hide(); E.showMenu(); - drawCalendar(date); setUI(); }; + require("widget_utils").show(); E.showMenu(menu); } }); -} +}; +loadSettings(); +loadEvents(); +Bangle.loadWidgets(); require("Font8x12").add(Graphics); -drawCalendar(date); setUI(); -// No space for widgets! +} diff --git a/apps/calendar/metadata.json b/apps/calendar/metadata.json index bd35c8879..e263efe35 100644 --- a/apps/calendar/metadata.json +++ b/apps/calendar/metadata.json @@ -1,8 +1,8 @@ { "id": "calendar", "name": "Calendar", - "version": "0.15", - "description": "Simple calendar", + "version": "0.16", + "description": "Monthly calendar, displays holidays uploaded from the web interface and scheduled events.", "icon": "calendar.png", "screenshots": [{"url":"screenshot_calendar.png"}], "tags": "calendar,tool", diff --git a/apps/calendar/settings.js b/apps/calendar/settings.js index de731c632..50beed8c0 100644 --- a/apps/calendar/settings.js +++ b/apps/calendar/settings.js @@ -1,13 +1,14 @@ (function (back) { - var FILE = "calendar.json"; + const FILE = "calendar.json"; const HOLIDAY_FILE = "calendar.days.json"; - var settings = require('Storage').readJSON(FILE, 1) || {}; - if (settings.ndColors === undefined) + const settings = require('Storage').readJSON(FILE, true) || {}; + if (settings.ndColors === undefined) { if (process.env.HWVERSION == 2) { settings.ndColors = true; } 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() {