diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog index e874c8c67..299b1ec69 100644 --- a/apps/clockcal/ChangeLog +++ b/apps/clockcal/ChangeLog @@ -1 +1,2 @@ 0.01: Initial upload +0.2: Added scrollable calendar and swipe gestures diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md index c19ee54a6..da6887177 100644 --- a/apps/clockcal/README.md +++ b/apps/clockcal/README.md @@ -3,10 +3,14 @@ This is my "Hello World". I first made this watchface almost 10 years ago for my original Pebble and Pebble Time and I missed this so much, that I had to write it for the BangleJS2. I know that it seems redundant because there already **is** a *time&cal*-app, but it didn't fit my style. -- locked screen with only one minimal update/minute -- ![locked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot.png) -- unlocked screen (twist?) with seconds -- ![unlocked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot2.png) +|Screenshot|description| +|:--:|:-| +|![locked screen](screenshot.png)|locked: triggers only one minimal update/min| +|![unlocked screen](screenshot2.png)|unlocked: smaller clock, but with seconds| +|![big calendar](screenshot3.png)|swipe up for big calendar, (up down to scroll, left/right to exit)| + + + ## Configurable Features - Number of calendar rows (weeks) @@ -15,6 +19,14 @@ I know that it seems redundant because there already **is** a *time&cal*-app, bu - First day of the week - Red Saturday - Red Sunday +- Swipes (to disable all gestures) +- Swipes: music (swipe down) +- Spipes: messages (swipe right) + +## Auto detects your message/music apps: +- swiping down will search your files for an app with the string "music" in its filename and launch it +- swiping right will search your files for an app with the string "message" in its filename and launch it. +- Configurable apps coming soon. ## Feedback The clock works for me in a 24h/MondayFirst/WeekendFree environment but is not well-tested with other settings. diff --git a/apps/clockcal/app.js b/apps/clockcal/app.js index fc299912f..86fa0815a 100644 --- a/apps/clockcal/app.js +++ b/apps/clockcal/app.js @@ -7,15 +7,116 @@ var s = Object.assign({ FIRSTDAYOFFSET: 6, //First day of the week: 0-6: Sun, Sat, Fri, Thu, Wed, Tue, Mon REDSUN: true, // Use red color for sunday? REDSAT: true, // Use red color for saturday? + DRAGENABLED: true, + DRAGMUSIC: true, + DRAGMESSAGES: true }, require('Storage').readJSON("clockcal.json", true) || {}); const h = g.getHeight(); const w = g.getWidth(); const CELL_W = w / 7; +const CELL2_W = w / 8;//full calendar const CELL_H = 15; const CAL_Y = h - s.CAL_ROWS * CELL_H; const DEBUG = false; +var state = "watch"; +var monthOffset = 0; +/* + * Calendar features + */ +function drawFullCalendar(monthOffset) { + addMonths = function (_d, _am) { + var ay = 0, m = _d.getMonth(), y = _d.getFullYear(); + while ((m + _am) > 11) { ay++; _am -= 12; } + while ((m + _am) < 0) { ay--; _am += 12; } + n = new Date(_d.getTime()); + n.setMonth(m + _am); + n.setFullYear(y + ay); + return n; + }; + monthOffset = (typeof monthOffset == "undefined") ? 0 : monthOffset; + state = "calendar"; + var start = Date().getTime(); + const months = ['Jan.', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec.']; + const monthclr = ['#0f0', '#f0f', '#00f', '#ff0', '#0ff', '#fff']; + if (typeof dayInterval !== "undefined") clearTimeout(dayInterval); + if (typeof secondInterval !== "undefined") clearTimeout(secondInterval); + if (typeof minuteInterval !== "undefined") clearTimeout(minuteInterval); + d = addMonths(Date(), monthOffset); + tdy = Date().getDate() + "." + Date().getMonth(); + newmonth=false; + c_y = 0; + g.reset(); + g.setBgColor(0); + g.clear(); + var prevmonth = addMonths(d, -1) + const today = prevmonth.getDate(); + var rD = new Date(prevmonth.getTime()); + rD.setDate(rD.getDate() - (today - 1)); + const dow = (s.FIRSTDAYOFFSET + rD.getDay()) % 7; + rD.setDate(rD.getDate() - dow); + var rDate = rD.getDate(); + bottomrightY = c_y - 3; + clrsun=s.REDSUN?'#f00':'#fff'; + clrsat=s.REDSUN?'#f00':'#fff'; + var fg=[clrsun,'#fff','#fff','#fff','#fff','#fff',clrsat]; + for (var y = 1; y <= 11; y++) { + bottomrightY += CELL_H; + bottomrightX = -2; + for (var x = 1; x <= 7; x++) { + bottomrightX += CELL2_W; + rMonth = rD.getMonth(); + rDate = rD.getDate(); + if (tdy == rDate + "." + rMonth) { + caldrawToday(rDate); + } else if (rDate == 1) { + caldrawFirst(rDate); + } else { + caldrawNormal(rDate,fg[rD.getDay()]); + } + if (newmonth && x == 7) { + caldrawMonth(rDate,monthclr[rMonth % 6],months[rMonth],rD); + } + rD.setDate(rDate + 1); + } + } + delete addMonths; + if (DEBUG) console.log("Calendar performance (ms):" + (Date().getTime() - start)); +} +function caldrawMonth(rDate,c,m,rD) { + g.setColor(c); + g.setFont("Vector", 18); + g.setFontAlign(-1, 1, 1); + drawyear = ((rMonth % 11) == 0) ? String(rD.getFullYear()).substr(-2) : ""; + g.drawString(m + drawyear, bottomrightX, bottomrightY - CELL_H, 1); + newmonth = false; +} +function caldrawToday(rDate) { + g.setFont("Vector", 16); + g.setFontAlign(1, 1); + g.setColor('#0f0'); + g.fillRect(bottomrightX - CELL2_W + 1, bottomrightY - CELL_H - 1, bottomrightX, bottomrightY - 2); + g.setColor('#000'); + g.drawString(rDate, bottomrightX, bottomrightY); +} +function caldrawFirst(rDate) { + g.flip(); + g.setFont("Vector", 16); + g.setFontAlign(1, 1); + bottomrightY += 3; + newmonth = true; + g.setColor('#0ff'); + g.fillRect(bottomrightX - CELL2_W + 1, bottomrightY - CELL_H - 1, bottomrightX, bottomrightY - 2); + g.setColor('#000'); + g.drawString(rDate, bottomrightX, bottomrightY); +} +function caldrawNormal(rDate,c) { + g.setFont("Vector", 16); + g.setFontAlign(1, 1); + g.setColor(c); + g.drawString(rDate, bottomrightX, bottomrightY);//100 +} function drawMinutes() { if (DEBUG) console.log("|-->minutes"); var d = new Date(); @@ -52,8 +153,10 @@ function drawSeconds() { if (!dimSeconds) secondInterval = setTimeout(drawSeconds, 1000); } -function drawCalendar() { +function drawWatch() { if (DEBUG) console.log("CALENDAR"); + monthOffset = 0; + state = "watch"; var d = new Date(); g.reset(); g.setBgColor(0); @@ -91,7 +194,7 @@ function drawCalendar() { var nextday = (3600 * 24) - (d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds() + 1); if (DEBUG) console.log("Next Day:" + (nextday / 3600)); if (typeof dayInterval !== "undefined") clearTimeout(dayInterval); - dayInterval = setTimeout(drawCalendar, nextday * 1000); + dayInterval = setTimeout(drawWatch, nextday * 1000); } function BTevent() { @@ -103,17 +206,87 @@ function BTevent() { } } +function input(dir) { + if (s.DRAGENABLED) { + Bangle.buzz(100,1); + console.log("swipe:"+dir); + switch (dir) { + case "r": + if (state == "calendar") { + drawWatch(); + } else { + if (s.DRAGMUSIC) { + l=require("Storage").list(RegExp("music.*app")); + if (l.length > 0) { + load(l[0]); + } else Bangle.buzz(3000,1);//not found + } + } + break; + case "l": + if (state == "calendar") { + drawWatch(); + } + break; + case "d": + if (state == "calendar") { + monthOffset--; + drawFullCalendar(monthOffset); + } else { + if (s.DRAGMESSAGES) { + l=require("Storage").list(RegExp("message.*app")); + if (l.length > 0) { + load(l[0]); + } else Bangle.buzz(3000,1);//not found + } + } + break; + case "u": + if (state == "watch") { + state = "calendar"; + drawFullCalendar(0); + } else if (state == "calendar") { + monthOffset++; + drawFullCalendar(monthOffset); + } + break; + default: + if (state == "calendar") { + drawWatch(); + } + break; + } + } +} + +let drag; +Bangle.on("drag", e => { + if (s.DRAGENABLED) { + if (!drag) { + drag = { x: e.x, y: e.y }; + } else if (!e.b) { + const dx = e.x - drag.x, dy = e.y - drag.y; + var dir = "t"; + if (Math.abs(dx) > Math.abs(dy) + 10) { + dir = (dx > 0) ? "r" : "l"; + } else if (Math.abs(dy) > Math.abs(dx) + 10) { + dir = (dy > 0) ? "d" : "u"; + } + drag = null; + input(dir); + } + } +}); + //register events Bangle.on('lock', locked => { if (typeof secondInterval !== "undefined") clearTimeout(secondInterval); dimSeconds = locked; //dim seconds if lock=on - drawCalendar(); + drawWatch(); }); NRF.on('connect', BTevent); NRF.on('disconnect', BTevent); - dimSeconds = Bangle.isLocked(); -drawCalendar(); - +drawWatch(); Bangle.setUI("clock"); diff --git a/apps/clockcal/metadata.json b/apps/clockcal/metadata.json index ccc84a980..a42e1ad2e 100644 --- a/apps/clockcal/metadata.json +++ b/apps/clockcal/metadata.json @@ -1,7 +1,7 @@ { "id": "clockcal", "name": "Clock & Calendar", - "version": "0.01", + "version": "0.2", "description": "Clock with Calendar", "readme":"README.md", "icon": "app.png", diff --git a/apps/clockcal/screenshot3.png b/apps/clockcal/screenshot3.png new file mode 100644 index 000000000..ab34f4306 Binary files /dev/null and b/apps/clockcal/screenshot3.png differ diff --git a/apps/clockcal/settings.js b/apps/clockcal/settings.js index cc2a78181..c4ec764c9 100644 --- a/apps/clockcal/settings.js +++ b/apps/clockcal/settings.js @@ -8,6 +8,9 @@ FIRSTDAY: 6, //First day of the week: mo, tu, we, th, fr, sa, su REDSUN: true, // Use red color for sunday? REDSAT: true, // Use red color for saturday? + DRAGENABLED: true, //Enable drag gestures (bigger calendar etc) + DRAGMUSIC: true, //Enable drag down for music (looks for "music*app") + DRAGMESSAGES: true //Enable drag right for messages (looks for "message*app") }, require('Storage').readJSON(FILE, true) || {}); @@ -67,6 +70,30 @@ writeSettings(); } }, + 'Swipes (big cal.)?': { + value: settings.DRAGENABLED, + format: v => v ? "On" : "Off", + onchange: v => { + settings.DRAGENABLED = v; + writeSettings(); + } + }, + 'Swipes (music)?': { + value: settings.DRAGMUSIC, + format: v => v ? "On" : "Off", + onchange: v => { + settings.DRAGMUSIC = v; + writeSettings(); + } + }, + 'Swipes (messg)?': { + value: settings.DRAGMESSAGES, + format: v => v ? "On" : "Off", + onchange: v => { + settings.DRAGMESSAGES = v; + writeSettings(); + } + }, 'Load deafauls?': { value: 0, min: 0, max: 1, @@ -80,13 +107,16 @@ FIRSTDAY: 6, //First day of the week: mo, tu, we, th, fr, sa, su REDSUN: true, // Use red color for sunday? REDSAT: true, // Use red color for saturday? + DRAGENABLED: true, + DRAGMUSIC: true, + DRAGMESSAGES: true }; writeSettings(); - load() + load(); } } }, - } + }; // Show the menu E.showMenu(menu); -}) +});