Merge branch 'master' of github.com:espruino/BangleApps

master
Gordon Williams 2021-11-23 11:42:26 +00:00
commit aaf06b113c
41 changed files with 18698 additions and 220 deletions

View File

@ -377,40 +377,37 @@ that handles configuring the app.
When the app settings are opened, this function is called with one When the app settings are opened, this function is called with one
argument, `back`: a callback to return to the settings menu. argument, `back`: a callback to return to the settings menu.
Usually it will save any information in `app.json` where `app` is the name Usually it will save any information in `myappid.json` where `myappid` is the name
of your app - so you should change the example accordingly. of your app - so you should change the example accordingly.
Example `settings.js` Example `settings.js`
```js ```js
// make sure to enclose the function in parentheses // make sure to enclose the function in parentheses
(function(back) { (function(back) {
let settings = require('Storage').readJSON('app.json',1)||{}; function get(key, def) { return require('Settings').get('myappid', key, def); }
function save(key, value) { function set(key, value) { require('Settings').set('myappid', key, value); }
settings[key] = value;
require('Storage').write('app.json',settings);
}
const appMenu = { const appMenu = {
'': {'title': 'App Settings'}, '': {'title': 'App Settings'},
'< Back': back, '< Back': back,
'Monkeys': { 'Monkeys': {
value: settings.monkeys||12, value: get('monkeys', 12),
onchange: (m) => {save('monkeys', m)} onchange: (m) => set('monkeys', m)
} }
}; };
E.showMenu(appMenu) E.showMenu(appMenu)
}) })
``` ```
In this example the app needs to add `app.settings.js` to `storage` in `apps.json`. In this example the app needs to add `myappid.settings.js` to `storage` in `apps.json`.
It should also add `app.json` to `data`, to make sure it is cleaned up when the app is uninstalled. It should also add `myappid.json` to `data`, to make sure it is cleaned up when the app is uninstalled.
```json ```json
{ "id": "app", { "id": "myappid",
... ...
"storage": [ "storage": [
... ...
{"name":"app.settings.js","url":"settings.js"}, {"name":"myappid.settings.js","url":"settings.js"}
], ],
"data": [ "data": [
{"name":"app.json"} {"name":"myappid.json"}
] ]
}, },
``` ```

View File

@ -3649,7 +3649,7 @@
"id": "gbmusic", "id": "gbmusic",
"name": "Gadgetbridge Music Controls", "name": "Gadgetbridge Music Controls",
"shortName": "Music Controls", "shortName": "Music Controls",
"version": "0.06", "version": "0.07",
"description": "Control the music on your Gadgetbridge-connected phone", "description": "Control the music on your Gadgetbridge-connected phone",
"icon": "icon.png", "icon": "icon.png",
"screenshots": [{"url":"screenshot_v1.png"},{"url":"screenshot_v2.png"}], "screenshots": [{"url":"screenshot_v1.png"},{"url":"screenshot_v2.png"}],
@ -4240,11 +4240,18 @@
"id": "emojuino", "id": "emojuino",
"name": "Emojuino", "name": "Emojuino",
"shortName": "Emojuino", "shortName": "Emojuino",
"version": "0.01", "version": "0.02",
"description": "Emojis & Espruino: broadcast Unicode emojis via Bluetooth Low Energy.", "description": "Emojis & Espruino: broadcast Unicode emojis via Bluetooth Low Energy.",
"icon": "emojuino.png", "icon": "emojuino.png",
"screenshots": [
{ "url": "screenshot-tx.png" },
{ "url": "screenshot-swipe.png" },
{ "url": "screenshot-welcome.png" }
],
"type": "app",
"tags": "emoji", "tags": "emoji",
"supports" : [ "BANGLEJS2" ], "supports" : [ "BANGLEJS2" ],
"allow_emulator": true,
"readme": "README.md", "readme": "README.md",
"storage": [ "storage": [
{ "name": "emojuino.app.js", "url": "emojuino.js" }, { "name": "emojuino.app.js", "url": "emojuino.js" },
@ -4255,8 +4262,8 @@
"id": "cliclockJS2Enhanced", "id": "cliclockJS2Enhanced",
"name": "Commandline-Clock JS2 Enhanced", "name": "Commandline-Clock JS2 Enhanced",
"shortName": "CLI-Clock JS2", "shortName": "CLI-Clock JS2",
"version": "0.1", "version": "0.2",
"description": "Simple CLI-Styled Clock with enhancements. Modes that are hard to use and unneded are removed (BPM, battery info, memory ect) credit to hughbarney for the original code and design", "description": "Simple CLI-Styled Clock with enhancements. Modes that are hard to use and unneded are removed (BPM, battery info, memory ect) credit to hughbarney for the original code and design. Also added HID media controlls, just swipe on the clock face to controll the media! Gadgetbride support coming soon(hopefully) Thanks to t0m1o1 for media controls!",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screengrab.png"}], "screenshots": [{"url":"screengrab.png"}],
"type": "clock", "type": "clock",
@ -4288,7 +4295,7 @@
"name": "LCARS Clock", "name": "LCARS Clock",
"shortName":"LCARS", "shortName":"LCARS",
"icon": "lcars.png", "icon": "lcars.png",
"version":"0.02", "version":"0.03",
"supports": ["BANGLEJS2"], "supports": ["BANGLEJS2"],
"description": "Library Computer Access Retrieval System (LCARS) clock.", "description": "Library Computer Access Retrieval System (LCARS) clock.",
"type": "clock", "type": "clock",
@ -4348,5 +4355,24 @@
{"name":"authentiwatch.img","url":"app-icon.js","evaluate":true} {"name":"authentiwatch.img","url":"app-icon.js","evaluate":true}
], ],
"data": [{"name":"authentiwatch.json"}] "data": [{"name":"authentiwatch.json"}]
},
{ "id": "schoolCalendar",
"name": "School Calendar",
"shortName":"SCalendar",
"icon": "CalenderLogo.png",
"version": "0.01",
"description": "A simple calendar that you can see your upcoming events that you create in the customizer. Keep in note that your events reapeat weekly.(Beta)",
"tags": "tool",
"readme":"README.md",
"custom":"custom.html",
"supports": ["BANGLEJS"],
"screenshots": [{"url":"screenshot_basic.png"},{"url":"screenshot_info.png"}],
"storage": [
{"name":"schoolCalendar.app.js"},
{"name":"schoolCalendar.img","url":"app-icon.js","evaluate":true}
],
"data": [
{"name":"app.json"}
]
} }
] ]

View File

@ -0,0 +1,2 @@
0.01: Submitted to App Loader
0.02: Removed unneded code, added HID controlls thanks to t0m1o1 for his code :p

View File

@ -4,24 +4,96 @@ var fontsizeTime = g.getWidth()>200 ? 4 : 4;
var fontheight = 10*fontsize; var fontheight = 10*fontsize;
var fontheightTime = 10*fontsizeTime; var fontheightTime = 10*fontsizeTime;
var locale = require("locale"); var locale = require("locale");
var marginTop = 40; var marginTop = 25;
var flag = false; var flag = false;
var hrtOn = false; var storage = require('Storage');
var hrtStr = "Hrt: ??? bpm";
const NONE_MODE = "none"; const settings = storage.readJSON('setting.json',1) || { HID: false };
const ID_MODE = "id";
const VER_MODE = "ver"; var sendHid, next, prev, toggle, up, down, profile;
const BATT_MODE = "batt"; var lasty = 0;
const MEM_MODE = "mem"; var lastx = 0;
const STEPS_MODE = "step";
const HRT_MODE = "hrt"; if (settings.HID=="kbmedia") {
const NONE_FN_MODE = "no_fn"; profile = 'Music';
const HRT_FN_MODE = "fn_hrt"; sendHid = function (code, cb) {
try {
NRF.sendHIDReport([1,code], () => {
NRF.sendHIDReport([1,0], () => {
if (cb) cb();
});
});
} catch(e) {
print(e);
}
};
next = function (cb) { sendHid(0x01, cb); };
prev = function (cb) { sendHid(0x02, cb); };
toggle = function (cb) { sendHid(0x10, cb); };
up = function (cb) {sendHid(0x40, cb); };
down = function (cb) { sendHid(0x80, cb); };
} else {
E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) {
if (enable) {
settings.HID = "kbmedia";
require("Storage").write('setting.json', settings);
setTimeout(load, 1000, "hidmsicswipe.app.js");
} else setTimeout(load, 1000);
});
}
if (next) {
setWatch(function(e) {
var len = e.time - e.lastTime;
E.showMessage('lock');
setTimeout(drawApp, 1000);
Bangle.setLocked(true);
}, BTN1, { edge:"falling",repeat:true,debounce:50});
Bangle.on('drag', function(e) {
if(!e.b){
console.log(lasty);
console.log(lastx);
if(lasty > 40){
writeLine('Down', 3);
// setTimeout(drawApp, 1000);
// Bluetooth.println(JSON.stringify({t:"music", n:"volumedown"}));
down(() => {});
}
else if(lasty < -40){
writeLine('Up', 3);
// setTimeout(drawApp, 1000);
//Bluetooth.println(JSON.stringify({t:"music", n:"volumeup"}));
up(() => {});
} else if(lastx < -40){
writeLine('Prev', 3);
// setTimeout(drawApp, 1000);
// Bluetooth.println(JSON.stringify({t:"music", n:"previous"}));
prev(() => {});
} else if(lastx > 40){
writeLine('Next', 3);
// setTimeout(drawApp, 1000);
// Bluetooth.println(JSON.stringify({t:"music", n:"next"}));
next(() => {});
} else if(lastx==0 && lasty==0){
writeLine('play/pause', 3);
//setTimeout(drawApp, 1000);
// Bluetooth.println(JSON.stringify({t:"music", n:"play"}));
toggle(() => {});
}
lastx = 0;
lasty = 0;
}
else{
lastx = lastx + e.dx;
lasty = lasty + e.dy;
}
});
}
let infoMode = NONE_MODE;
let functionMode = NONE_FN_MODE;
let textCol = g.theme.dark ? "#0f0" : "#080"; let textCol = g.theme.dark ? "#0f0" : "#080";
@ -33,13 +105,12 @@ function drawAll(){
function updateRest(now){ function updateRest(now){
writeLine(locale.dow(now),1); writeLine(locale.dow(now),1);
writeLine(locale.date(now,1),2); writeLine(locale.date(now,1),2);
drawInfo(5);
} }
function updateTime(){ function updateTime(){
if (!Bangle.isLCDOn()) return; if (!Bangle.isLCDOn()) return;
let now = new Date(); let now = new Date();
writeLine(locale.time(now,1),0); writeLine(locale.time(now,1),0);
writeLine(flag?" ":"_",3); writeLine(flag?" ":"_ ",3);
flag = !flag; flag = !flag;
if(now.getMinutes() == 0) if(now.getMinutes() == 0)
updateRest(now); updateRest(now);
@ -65,142 +136,13 @@ function writeLine(str,line){
var y = marginTop+(line-1)*fontheight+fontheightTime; var y = marginTop+(line-1)*fontheight+fontheightTime;
g.setFont("6x8",fontsize); g.setFont("6x8",fontsize);
g.setColor(textCol).setFontAlign(-1,-1); g.setColor(textCol).setFontAlign(-1,-1);
g.clearRect(0,y,((str.length+1)*20),y+fontheight-1); g.clearRect(0,y,((str.length+10)*40),y+fontheightTime-1);
writeLineStart(line); writeLineStart(line);
g.drawString(str,25,y); g.drawString(str,25,y);
} }
} }
function drawInfo(line) {
let val;
let str = "";
let col = textCol; // green
//console.log("drawInfo(), infoMode=" + infoMode + " funcMode=" + functionMode);
switch(functionMode) {
case NONE_FN_MODE:
break;
case HRT_FN_MODE:
col = g.theme.dark ? "#0ff": "#088"; // cyan
str = "HRM: " + (hrtOn ? "ON" : "OFF");
drawModeLine(line,str,col);
return;
}
switch(infoMode) {
case NONE_MODE:
col = g.theme.bg;
str = "";
break;
case HRT_MODE:
str = hrtStr;
break;
case STEPS_MODE:
str = "Steps: " + stepsWidget().getSteps();
break;
case ID_MODE:
val = NRF.getAddress().split(":");
str = "Id: " + val[4] + val[5];
break;
case VER_MODE:
str = "Fw: " + process.env.VERSION;
break;
case MEM_MODE:
val = process.memory();
str = "Memory: " + Math.round(val.usage*100/val.total) + "%";
break;
case BATT_MODE:
default:
str = "Battery: " + E.getBattery() + "%";
}
drawModeLine(line,str,col);
}
function drawModeLine(line, str, col) {
g.setColor(col);
var y = marginTop+line*fontheight;
g.fillRect(0, y, 239, y+fontheight-1);
g.setColor(g.theme.bg).setFontAlign(0, 0);
g.drawString(str, g.getWidth()/2, y+fontheight/2);
}
function changeInfoMode() {
switch(functionMode) {
case NONE_FN_MODE:
break;
case HRT_FN_MODE:
hrtOn = !hrtOn;
Bangle.buzz();
Bangle.setHRMPower(hrtOn ? 1 : 0);
if (hrtOn) infoMode = HRT_MODE;
return;
}
switch(infoMode) {
case NONE_MODE:
if (stepsWidget() !== undefined)
infoMode = hrtOn ? HRT_MODE : STEPS_MODE;
else
infoMode = VER_MODE;
break;
case HRT_MODE:
if (stepsWidget() !== undefined)
infoMode = STEPS_MODE;
else
infoMode = VER_MODE;
break;
case STEPS_MODE:
infoMode = ID_MODE;
break;
case ID_MODE:
infoMode = VER_MODE;
break;
case VER_MODE:
infoMode = BATT_MODE;
break;
case BATT_MODE:
infoMode = MEM_MODE;
break;
case MEM_MODE:
default:
infoMode = NONE_MODE;
}
}
function changeFunctionMode() {
//console.log("changeFunctionMode()");
switch(functionMode) {
case NONE_FN_MODE:
functionMode = HRT_FN_MODE;
break;
case HRT_FN_MODE:
default:
functionMode = NONE_FN_MODE;
}
//console.log(functionMode);
}
function stepsWidget() {
if (WIDGETS.activepedom !== undefined) {
return WIDGETS.activepedom;
} else if (WIDGETS.wpedom !== undefined) {
return WIDGETS.wpedom;
}
return undefined;
}
Bangle.on('HRM', function(hrm) {
if(hrm.confidence > 90){
hrtStr = "Hrt: " + hrm.bpm + " bpm";
} else {
hrtStr = "Hrt: ??? bpm";
}
});
g.clear(); g.clear();
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
@ -211,6 +153,5 @@ Bangle.on('lcdPower',function(on) {
var click = setInterval(updateTime, 1000); var click = setInterval(updateTime, 1000);
// Show launcher when button pressed // Show launcher when button pressed
Bangle.setUI("clockupdown", btn=>{ Bangle.setUI("clockupdown", btn=>{
if (btn<0) changeInfoMode();
drawAll(); drawAll();
}); });

View File

@ -1 +1,2 @@
0.01: New App! 0.01: New App!
0.02: Upgraded text to images, added welcome screen and subtitles.

View File

@ -4,29 +4,48 @@
*/ */
// Emojis are integer pairs with the form [ image, Unicode code point ] // Emoji images are 96px x 96px, 4bpp (https://www.espruino.com/Image+Converter)
// and adapted from Font Awesome 5
const GRIN = "sFgwkBiIATDwoaUFi4ynQZ4uuGDzlTF1wwaFyowYFy4wWiAvZgIutGCgubSKRecMCQudMCBeeMCAufMBxegMBwuhMBheiMBgujMBRekMBQvvF0qQIL0xgIF94unSA4vuR1CQGF94upSAovuR1SQEF94urSAY/PCBivQF5z/DEBQ+DEB5ePCJYOEMBgNNF8MBHpogNHwqBNF/4vsEAovOX7TviBhYgFD5Q/EEJoANEAY/OLxgAQPx5edAH4A/AH4A/AH4A/AEUQF1sBF/4v/F/4vviILJBRQANEZYLJHQIMKFpYABQhIiKC4QaMIhBHLF6AAVEhRQIF8ZuCF5B6GACYjMF9ZrOF8jAiKRgvvSEJROBo5gYEBw+IMCwfPB5BgWDxBPHCCBeVJxBgdJqIvJMCQcTCRAwRFxJ8KChQwODKwVJGBouKbZgXLDBQVLPBoZLDYxDMLxocQACLXOMBwARFxxgfLx5gfFyBgdLyIwcFyaRbFygwZFywwXFzAwVFzQwTFzgwRFzwxOFsIyKDSg";
const MEH = "sFgwkBiIATDwoaUFi4ynQZ4uuGDzlTF1wwaFyowYFy4wWiAvZgIutGCgubSKRecMCQudMCBeeMCAufMBxegMBwuhMBheiMBgujMBRekMBQvvF0qQIL0xgIF94unSA4vuR1CQGF94upSAovuR1SQEF94urSAY/PCBivQF5z/DEBQ+DEB5ePCJYOEMBgNNF8MBHpogNHwqBNF/4vsEAovOX7TviBhYgFD5Q/EEJoANEAY/OLxgAQPx5edAH4A/AH4A/AH4A/AEUQF1sBF/4v/F/4vviIvtiIv/F9qeBACDgNB5ouSECAOLFyaBMKAYvrByQvgSBS/fD4jAfXxwQMADxAQF8iQLADjeGF96QoFwxgnLw4vwSEwuIMEpeJMEouKMEZeLMEYuMMEJeNMEIuOMD5ePMD4uQMDpeRGDguTSLYuUGDIuWGC4uYGCouaGCYucGCIueGJwthGRQaUA";
const FROWN = "sFgwkBiIATDwoaUFi4ynQZ4uuGDzlTF1wwaFyowYFy4wWiAvZgIutGCgubSKRecMCQudMCBeeMCAufMBxegMBwuhMBheiMBgujMBRekMBQvvF0qQIL0xgIF94unSA4vuR1CQGF94upSAovuR1SQEF94urSAY/PCBivQF5z/DEBQ+DEB5ePCJYOEMBgNNF8MBHpogNHwqBNF/4vsEAovOX7TviBhYgFD5Q/EEJoANEAY/OLxgAQPx5edAH4A/AH4A/AH4A/AEUQF1sBF/4v/F/4vUgMRAAQZWFqwxWCgIuZGCYvSFxIcUFzYdTOZyNKSKQdCCJwuNMB5NDLzZOPIKAviCJguPJxpNEF94RLRyBONIKAvHNRQvRCKAMUJpIvOZxx9WAEbSTADReHF+CQmFxBglLxJglFxRgjLxZgjFxhghLxpghFxxgfLx5gfFyBgdLyIwcFyaRbFygwZFywwXFzAwVFzQwTFzgwRFzwxOFsIyKDSg";
const THUMBS_UP = "sFgwkBiIAaiAiBDzYAQKYZQcLyAwsF4qSpcoxgoF4xgnRwwvxSEwvvFw4vwYEwv/F/4AOiAv/R1Av/F/6+PgIv/RzwvjLxQvkFxTujLxYvjFxaOiLxgvvR1wviR3gviR3YviFxg6iF7AwVRxowhFzUAgIvuMCSObF6YucSCJedF6IudSARQIHQheeAAIgKGAYufF+CbMF/4v/WYQv/F/6yPF/6OeF9wgNL/4v/F/4vhEQIv/R/4v/F/7ueF/4v/Xx4v/F/4v/F/4v/F/4v/F7ogOF/6OSEAgHCiAvrAwQHHRz4v/F/4v/F58QF8cBE4wPDGLYvHB5aTaKwQvUMS4vYGCx8QF5AwULwgvWYiZJQIAowXDowvYGJyqRFx4bKDRQA==";
const THUMBS_DOWN = "sFgwkBiIAbiAoGEroAHLZgttMcK9RXEZgmFyZgHDZA/JFyogFDZQwHFqovXLiyQHB5wtaF6gubF/4v/F/4vwgIv/F7wgPF/6QTF/4v/F/4v/F/4v/F/4AdF/4v/YCIv/F/4v9EQIv/R/4v/F/7ueL+gFBiMQF8oiBE4wHHF/6QQF/4v/YigvugInBiAvrM5QvvM4gvqMFgvDMD0BF55gegJPKgIvEMDoeLF4pgdJ5QuGF7gjHABaQbFyRgbFygvZFyqQOEixgYF8RgMgIv/SH5gPYH6QfF8aQvMBgvjMBaQjMBYvkMBQv/SEAv/F/7APF/6QfF/4v/F/0BF8sQF/4vnF0rAJF9yOmSBAunF4xeoSAouqMAYTQA==";
const HEART = "sFgwkBiIA/AH4A/AH4AogAADC1EQC4gaQCo8BIqYwRCyxdJDJoVLMJYuMGBIVNGBQYNDI5FOO5IXODI4WWI6BgGCywYTDIYVVO6gvXSAoYTDIQVTMAgYTDIJFUMAgYUACyOXAC7XWF7YurSAYvuR1iQCF/4v/F54utAH4A/AH4A/AH4A/AGMQF1sBF/4v/F58RF9sRF/4vgYFi+BMFouCF+CQqRwYvwSFQuEMFJeFMFIuGME5eHME4uIMEpeJMEouKMEZeLMEYuMMEJeNMEIuOMD5ePMD4uQMDpeRMDouSMDZeTMDYuUMDJeVMDIuWMC5eXMC4uYMCpeZMCouaMCZebMCYucMCJedF+CQQFzxgPFz5gPF8JgMXr5gPF0RgLL0ZgLF0hgJL0pgJF0xgHL05gHF1BgFL1JgFF1QwDF1gA/AH4A/AH4AJA=";
const TX = "k8XwkBiIAYEYogLHBAUIiBNKGxooKEggvJCYYHDKxAMFAoRrOCRAsHCYqbNHQibLKAauOLBCJHQw6JMQBIJBRJDWJThK5JJJi5KbpaJKFBaKEE5ybGHRhcOACEQA";
// Emojis are pairs with the form [ Image String, Unicode code point ]
// For code points see https://unicode.org/emoji/charts/emoji-list.html // For code points see https://unicode.org/emoji/charts/emoji-list.html
const EMOJIS = [ const EMOJIS = [
[ ':)', 0x1f642 ], // Slightly smiling [ GRIN, 0x1f642 ], // Slightly smiling
[ ':|', 0x1f610 ], // Neutral [ MEH, 0x1f610 ], // Neutral
[ ':(', 0x1f641 ], // Slightly frowning [ FROWN, 0x1f641 ], // Slightly frowning
[ '+1', 0x1f44d ], // Thumbs up [ THUMBS_UP, 0x1f44d ], // Thumbs up
[ '-1', 0x1f44e ], // Thumbs down [ THUMBS_DOWN, 0x1f44e ], // Thumbs down
[ '<3', 0x02764 ], // Heart [ HEART, 0x02764 ], // Heart
]; ];
const EMOJI_TRANSMISSION_MILLISECONDS = 5000; const EMOJI_TRANSMISSION_MILLISECONDS = 5000;
const BLINK_PERIOD_MILLISECONDS = 500; const BLINK_PERIOD_MILLISECONDS = 500;
const TRANSMIT_BUZZ_MILLISECONDS = 200; const TRANSMIT_BUZZ_MILLISECONDS = 200;
const CYCLE_BUZZ_MILLISECONDS = 50; const CYCLE_BUZZ_MILLISECONDS = 50;
const WELCOME_MESSAGE = 'Emojuino:\r\n\r\n< Swipe >\r\nto select\r\n\r\nTap\r\nto transmit';
// Non-user-configurable constants // Non-user-configurable constants
const IMAGE_INDEX = 0; const IMAGE_INDEX = 0;
const CODE_POINT_INDEX = 1; const CODE_POINT_INDEX = 1;
const EMOJI_PX = 96;
const EMOJI_X = (g.getWidth() - EMOJI_PX) / 2;
const EMOJI_Y = (g.getHeight() - EMOJI_PX) / 2;
const TX_X = 68;
const TX_Y = 12;
const FONT_SIZE = 24;
const BTN_WATCH_OPTIONS = { repeat: true, debounce: 20, edge: "falling" }; const BTN_WATCH_OPTIONS = { repeat: true, debounce: 20, edge: "falling" };
const UNICODE_CODE_POINT_ELIDED_UUID = [ 0x49, 0x6f, 0x49, 0x44, 0x55, const UNICODE_CODE_POINT_ELIDED_UUID = [ 0x49, 0x6f, 0x49, 0x44, 0x55,
0x54, 0x46, 0x2d, 0x33, 0x32 ]; 0x54, 0x46, 0x2d, 0x33, 0x32 ];
// Global variables // Global variables
let emojiIndex = 0; let emojiIndex = 0;
let isToggleOn = false; let isToggleOn = false;
@ -72,6 +91,7 @@ function transmitEmoji(image, codePoint, duration) {
require('ble_eddystone_uid').advertise(UNICODE_CODE_POINT_ELIDED_UUID, require('ble_eddystone_uid').advertise(UNICODE_CODE_POINT_ELIDED_UUID,
instance); instance);
isTransmitting = true; isTransmitting = true;
drawImage(EMOJIS[emojiIndex][IMAGE_INDEX], true);
let displayIntervalId = setInterval(toggleImage, BLINK_PERIOD_MILLISECONDS, let displayIntervalId = setInterval(toggleImage, BLINK_PERIOD_MILLISECONDS,
image); image);
@ -85,14 +105,14 @@ function terminateEmoji(displayIntervalId) {
NRF.setAdvertising({ }); NRF.setAdvertising({ });
isTransmitting = false; isTransmitting = false;
clearInterval(displayIntervalId); clearInterval(displayIntervalId);
drawImage(EMOJIS[emojiIndex][IMAGE_INDEX]); drawImage(EMOJIS[emojiIndex][IMAGE_INDEX], false);
} }
// Toggle the display between image/off // Toggle the display between image/off
function toggleImage(image) { function toggleImage(image) {
if(isToggleOn) { if(isToggleOn) {
drawImage(EMOJIS[emojiIndex][IMAGE_INDEX]); drawImage(EMOJIS[emojiIndex][IMAGE_INDEX], true);
} }
else { else {
g.clear(); g.clear();
@ -102,9 +122,15 @@ function toggleImage(image) {
// Draw the given emoji // Draw the given emoji
function drawImage(image) { function drawImage(image, isTx) {
g.clear(); g.clear();
g.drawString(image, g.getWidth() / 2, g.getHeight() / 2); g.drawImage(require("heatshrink").decompress(atob(image)), EMOJI_X, EMOJI_Y);
if(isTx) {
g.drawImage(require("heatshrink").decompress(atob(TX)), TX_X, TX_Y);
}
else {
g.drawString("< Swipe >", g.getWidth() / 2, g.getHeight() - FONT_SIZE);
}
g.flip(); g.flip();
} }
@ -131,15 +157,15 @@ function handleDrag(event) {
// Special function to handle display switch on // Special function to handle display switch on
Bangle.on('lcdPower', (on) => { Bangle.on('lcdPower', (on) => {
if(on) { if(on) {
drawImage(EMOJIS[emojiIndex][IMAGE_INDEX]); drawImage(EMOJIS[emojiIndex][IMAGE_INDEX], false);
} }
}); });
// On start: display the first emoji and handle drag and touch events // On start: display the first emoji and handle drag and touch events
g.clear(); g.clear();
g.setFont('Vector', 80); g.setFont('Vector', FONT_SIZE);
g.setFontAlign(0, 0); g.setFontAlign(0, 0);
drawImage(EMOJIS[emojiIndex][IMAGE_INDEX]); g.drawString(WELCOME_MESSAGE, g.getWidth() / 2, g.getHeight() / 2);
Bangle.on('touch', handleTouch); Bangle.on('touch', handleTouch);
Bangle.on('drag', handleDrag); Bangle.on('drag', handleDrag);

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -4,3 +4,4 @@
0.04: Setting to disable touch controls, minor bugfix 0.04: Setting to disable touch controls, minor bugfix
0.05: Setting to disable double/triple press control, remove touch controls setting, reduce fadeout flicker 0.05: Setting to disable double/triple press control, remove touch controls setting, reduce fadeout flicker
0.06: Bangle.js 2 support 0.06: Bangle.js 2 support
0.07: Fix "previous" button image

View File

@ -303,7 +303,7 @@ function drawControls() {
l.up.col = cc("volumeup" in tCommand); l.up.col = cc("volumeup" in tCommand);
l.down.col = cc("volumedown" in tCommand); l.down.col = cc("volumedown" in tCommand);
} }
l.prev.icon = (stat==="play") ? "pause" : "prev"; l.prev.icon = (stat==="play") ? "pause" : "previous";
l.prev.col = cc("prev" in tCommand || "pause" in tCommand); l.prev.col = cc("prev" in tCommand || "pause" in tCommand);
l.next.icon = (stat==="play") ? "next" : "play"; l.next.icon = (stat==="play") ? "next" : "play";
l.next.col = cc("next" in tCommand || "play" in tCommand); l.next.col = cc("next" in tCommand || "play" in tCommand);

View File

@ -1,2 +1,3 @@
0.01: Launch app 0.01: Launch app
0.02: Swipe left/right to set an alarm. 0.02: Swipe left/right to set an alarm.
0.03: New design with different icons if gps, hrm or compass is on.

View File

@ -11,6 +11,9 @@ the [Pedometer widget](https://banglejs.com/apps/#pedometer%20widget).
* Shows the number of daily steps * Shows the number of daily steps
* Swipe left/right to activate an alarm * Swipe left/right to activate an alarm
## Icons
<div>Icons made by <a href="https://www.flaticon.com/authors/smashicons" title="Smashicons">Smashicons</a>, <a href="https://www.freepik.com" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a></div>
## Creator ## Creator
Made by [David Peer](https://github.com/peerdavid) Made by [David Peer](https://github.com/peerdavid)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

BIN
apps/lcars/bg_large.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
apps/lcars/bg_small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
apps/lcars/icon_alarm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
apps/lcars/icon_compass.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
apps/lcars/icon_gps.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
apps/lcars/icon_hrm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
apps/lcars/icon_planet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -3,11 +3,42 @@
*/ */
const locale = require('locale'); const locale = require('locale');
var alarm = -1; var alarm = -1;
var hrmStr = "-"
var img = { var backgroundImage = {
width : 176, height : 151, bpp : 3, width : 176, height : 151, bpp : 3,
transparent : 0, transparent : 2,
buffer : require("heatshrink").decompress(atob("gF58+eAR14IN1fvv374CN7yD/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/AH4A/AH4A/AB1z588+YCN+RBuj158+eARyD/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf4AUhyD/gEDQaHz4BCuQaNAIN0PQaHIIN0BQaF5IN0AQaHPkBBug6DQ8iEvQaE8yBBuhyDPAQNAINsBQaACBkhCuQaACpVo0cQaACo4CFGjyD/AAMPQf4ACQf4ADgiD+AH4A/AH8J02atICIwEAgPnz15AR3gEgM27dt2wCTF4IABgYROgN9+/fAR14ILsaQBKDakwjKF5oABKZ6DwgxTPQeEmQf5cPQeMBLhyDxgJTRQd0JKaKDuhKD/gENQf6D/F4VNQf8AKaKDvKBYnBAGZQKzBB1QZOwIGqDJsBA2QZJA3QZGYIPCDH4CD/0xA4QY+wIPKDGwCD/tpB6Qf6DHthA5QY1oIPSD/QY9gQf/bIPaD/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/AF8JQYgCdsEHnnz54CJgIdLwEAhqDEATtggPnz15ARHkgIdLIIKAgQcCAgQcAA/gAA==")) buffer : require("heatshrink").decompress(atob("AEcEiFBASFADpETps06YCcEYXnz15ASBBJzVp0wCdEYU8+fPASHAIJCAdQf6DpoUIkGCATCDWIBCDDzANJAGaDC6BB9QYWAQf804CD/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/QbhA9Qf6D2oMEiFAQfoyB6ZBKQeYyBzVgQf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6Dnz1586D+AGaDNAGaD/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qc8Bg8euPv337ASHwDQNz588+YCC5AlCjR6CARCDN+/fvoCV6AbBj158+eAQV4EwUTPQQCIQZcB859SQdkPQCyDpvaAWQbmYIBUDQC6DQAC8eQC6DQAC8XQf6D/AASAYQdCAYQf6DHAESDeAESD/Qf6D/Qf6DK+2LtmXQfu8FEiDb8BB9QYRA9QYZB+Qf6D/AAccuPHIPwA/AH4A/AH4AHyVJkhB+zVp0yD/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6D/Qf6DlwCD/02QQf8kyVIkGChACeFAMo0WKAQOIC56/CQYQCi0kAgMv33794CUQYYChQYU9+/fvoCTviD/Qf6D/Qf6D/Qf6DLjSD/94="))
}
var iconPlanet = {
width : 50, height : 50, bpp : 3,
transparent : 5,
buffer : require("heatshrink").decompress(atob("23btoCD6PHjlx9oLGAQuGiVJkmSpIRK2lxEYQCDCJOGjEhEYNBwUI5drEw/xEYwCB8oRGDoMhwmSsAFBkGM237NZICGj15OgnaDoOGI4cgwUa5dv332EwdHEZACB8+evYRCtAdBEAQpDscs3379+9HAW8EZPHz158+WSQQjFwUYsMs2QjBEwPrSRZuCJQN5TAJuCEYkhwUS5cvJQRxCNxZKDOIXgJQkh0mYtMk2XLJQXv1u0EZSVDOIWsJQsSpMkyVJljgB9gmB7YjLOgtq4BKEsIjCAQNLlgCBt+9EZwCCj8sJQpxB00aJoYCB5cBEZ4CB+RKFJoeGjAjCoOGzBKaAQeGJQQFBwJKSsAjIcweSBwRKRjojKOgYFCxZKRtAaBjHrlm4FJUN3hKQi3ShAjB2XLAQQmI7dHJR97tsh9gjEAQLpHlu2+PnExvF23an3794mF2BKFm3btsevImMjwRB23v3wmB3xNF5BuDCIPb8+eEwOeExIRCtojCJo5uEEwRxBEwRuJHAdI+YmCTYlgJQIREtrjCEwLdHCIiYBhF7OgnJSQgmFjhxCOgiSDAQvSX4QmB90IkQRIX4gmCEZICDvwmCBY3QA"))
}
var iconGps = {
width : 50, height : 50, bpp : 3,
transparent : 2,
buffer : require("heatshrink").decompress(atob("pMkyQCFpH0BAwCJv/6CJ8l589CJ0kyf//wIDpVEChM8+/fBAdZ8QRIp++///0gIBlMkxI4IuZKB+/SKAPHzpKJ/YkB//pKAP2BYeXhIFDx88+fPvqYBnibEkmUAofv34lC/RQBBYdcmPCXIYjBEwPfvnzJoILBQoUlHAUuJQYmCDodw48cuBKGTA0WEYIEBJQ6YEQwMMuImBJQyYEkmZFAVkyVSJQ6YCyUcmPDjgmBTAJKETAlJiS4ETANPJQpxCJQtxTALgBEwnfvohBI4NZkmWpNlcAgAD/wzBEYaYCy8cJQiYEyIjCTAWS3wlGTAVIEwkerJKFTAkmOIclToK8GAAIPBIgImCufHyxxG59pEIS8DvfypMr968HEwOHEwfx8+cEYkpCIeSoiYByVf/uSkmTEQP7ZIiYDnl5AQNwBYgCGyOn38k2+2pIRKyVeuPPj1x4ccCJVKSgP/5cJA4NSExMps+cSoMMKAIVCCg7SBpd7TANZkmUHBMevPnjlwcwXCCJFEzYDBA4WWKIIRHpEw4+eNwUxEwKYIkVJk1IyIKFHA+DR4VcJQYCBJRBoCkxHBAgNkyyYKkmXEYaYMAQMSEYKYNAQOHEwnSfBYjBAgVaCJdJJSMkTAK8KYQyVKAQ4jBNxiYEcBCYJXIkgA="))
}
var iconHrm = {
width : 50, height : 50, bpp : 3,
transparent : 1,
buffer : require("heatshrink").decompress(atob("kmSpIC/AX4CT+PHjlxARfBkmGjFhAR2REZwCC7AjPAQIjQ48dw0//4ANsOB49/CJv8JQNjEh32JQN3BY/5AwpKLkhKQ8+eBIhKK/jZBJR/+vPnJR/JkmTJR3xJQN5JRPypMkz5uByfJk5KI/zXCFQMev/nC4JKIkhrBn4pB/+Sp5KJfwnnOIqVHSQS5CFgaVIDQPHj4FBOIJNCSo/9EAI/CFIJNCSo/njiSC/KYDcBH6IgQAFcBHx44RGcBYAHcBIAHJRAAJJRAAJJSrdEARfYsOGjACOngjP48EyQdHx04BAtkyTnCAQYsCDoILGAQ2OnfvCJ2TIgNwCJuSpHj335CJnxNYvBChU48ZKC3378gRJp6SGiQ4JkaSBJQP7EwIOEyA"))
}
var iconCompass = {
width : 50, height : 50, bpp : 3,
transparent : 2,
buffer : require("heatshrink").decompress(atob("pMkyQCDl//AAPSBYwCFv4RCAAOkCJNLCAgACCJm2rNn34FB+g1Jvny5cs2XPn///QRI9uWEYP2rNly5NHNYN82YjB/4mC5YmBOgkl//9y1bsuW/4CB/Nlz//9I4D3/8I4M8EAICB55NCL4g/BIgRKBAQtnL4lf+QdCI4YCD2Y4DSQPZtojHsuerI4Dv/flnzEZB3CHAJuB8ojIAQY4CNwJHI2XHTAY4B/4gJrGBAoSqBpf2EZMQmRxEv/5Nw9YyVCAoO+rf/0v/Nw/PjFB4ZxCn/+y7dBJQyNBkAIDz/6/7dBJQsYsMEhgsE//+7IjFsTYBwAIE/4ABEYs8uPEiFyF4gRBXIImEBAPSpAjDtuX//9+YmERgMcuODBAU9+xKCr68Ev4lBNwm//IJCnhxDDQPx4xuFJQhBDDQXwTwpKBSos8//HjlwYQyVG34aB2zCG//1Nw6SFAQTgD/JuD+wjFrbgCr/yMQI+B/lxEY08UgPpl4jCNwP+I4wCBUgOk3/8DoXxI44CBn/0yREDzx0EAQlndANJv4gJAQf3/VJkq8CJoZuGXIPpkg4BOIZuI5/9CII4BEZAmDNwIRBHAJxDNxH+CII4CSQW+NALgBtomBt5uCHAbjB2ZoCAQPyJQP/NwIRCkm//4gBIgP/SQn/CImSYALjDviSDQAYUDL4ImEEYYRGL4X/76PCI4P/SQYCFl4MBAAgRJEwYRPOgZrHpMgA"))
}
var iconAlarm = {
width : 50, height : 50, bpp : 3,
transparent : 1,
buffer : require("heatshrink").decompress(atob("kmSpICEp//BAwCJn/+CJ8k//5CKAABCJs8uPH//x48EI5YjCAARNKEYUcv//jgFBExEnEYoAC+QmHIgIgC/gpCuPBCI2fIgU4AQXjA4P8CIuTEYZKBAolwHApXBEAWP//jxwpBAALaFDoYCIiQmDDIP4EAT+CEwnJEwYjLAQLaFEYomDKALmDNwoCIOIZuD8AkFgCYDHAQjMAQTdDNwOAEg0Dx0/cYeREZtxQYOTHgJuHOIvkXJy8DNwIACJQ8Ah4NDAAfxEZARHOIIkHg4jQAQb1CQ4KVJgEOnDIBSoIjNAQPBcAaVJcAKVBcDGOcD7OBMQM48BuH8f//JKCnhKNggRBkmfTQJxBEwhuD/gRCyVHJRlyCIVJXgYmB8ZQBAoIKBXIQmCOIt/NxAUCOIImCIgIpCBAJuDAQZEE/huIAQWTDgImBTYQGC8gRFcYpKFCI8kDwQAFCJBfBEAX/+IjBiQRIEw4jJAQc8v//NYwCIOgJrIJpA1OcwbaFAQWQA="))
} }
Graphics.prototype.setFontAntonioMedium = function(scale) { Graphics.prototype.setFontAntonioMedium = function(scale) {
@ -38,14 +69,32 @@ function draw(queue){
g.clearRect(0, 24, g.getWidth(), g.getHeight()); g.clearRect(0, 24, g.getWidth(), g.getHeight());
// Draw background image // Draw background image
g.drawImage(img, 0, 24); g.drawImage(backgroundImage, 0, 24);
// Draw raster
for(var x=0; x<6; x++){
g.drawLine(115+x*10, 100, 115+x*10, 160);
}
for(var y=0; y<6; y++){
g.drawLine(110, 105+y*10, 170, 105+y*10);
}
// Draw symbol
var iconImg =
alarm >= 0 ? iconAlarm :
Bangle.isGPSOn() ? iconGps :
Bangle.isHRMOn() ? iconHrm :
Bangle.isCompassOn() ? iconCompass :
iconPlanet;
g.drawImage(iconImg, 115, 105);
// Write time // Write time
var currentDate = new Date(); var currentDate = new Date();
var timeStr = locale.time(currentDate,1); var timeStr = locale.time(currentDate,1);
g.setFontAlign(0,0,0); g.setFontAlign(0,0,0);
g.setFontAntonioLarge(); g.setFontAntonioLarge();
g.drawString(timeStr, 100, 50); g.drawString(timeStr, 57, 57);
// Write date // Write date
g.setFontAlign(1,-1, 0); g.setFontAlign(1,-1, 0);
@ -53,41 +102,32 @@ function draw(queue){
var dayName = locale.dow(currentDate, true).toUpperCase(); var dayName = locale.dow(currentDate, true).toUpperCase();
var day = currentDate.getDate(); var day = currentDate.getDate();
g.drawString(day, 170, 30); g.drawString(day, 133, 37);
g.drawString(dayName, 170, 50); g.drawString(dayName, 133, 57);
// Alarm // Alarm within symbol
if(alarm > 0){
g.setFontAlign(0,0,0);
g.drawString(alarm, 115+25, 105+25);
g.setFontAlign(-1,-1,0);
}
// HRM
g.setFontAlign(-1,-1,0); g.setFontAlign(-1,-1,0);
g.drawString("TMR:", 30, 107); g.drawString("HRM:", 20, 104);
var alrmText = alarm >= 0 ? "T-"+alarm : "OFF"; g.drawString(hrmStr, 60, 104);
g.drawString(alrmText, 65, 107);
// Draw steps
var steps = getSteps();
g.drawString("STEP:", 20, 124);
g.drawString(steps, 60, 124);
// Draw battery // Draw battery
var bat = E.getBattery(); var bat = E.getBattery();
var charging = Bangle.isCharging() ? "*" : ""; var charging = Bangle.isCharging() ? "*" : "";
g.drawString("BAT:", 30, 127); g.drawString("BAT:", 20, 144);
g.drawString(charging + bat+ "%", 65, 127); g.drawString(charging + bat+ "%", 60, 144);
// Draw steps
var steps = getSteps();
g.drawString("STEP:", 30, 147);
g.drawString(steps, 65, 147);
// GPS
var gpsText = Bangle.isGPSOn() ? "ON" : "OFF";
g.drawString("GPS:", 115, 107);
g.drawString(gpsText, 149, 107);
// HRM
var gpsText = Bangle.isHRMOn() ? "ON" : "OFF";
g.drawString("HRM:", 115, 127);
g.drawString(gpsText, 149, 127);
// CMP
var compassText = Bangle.isCompassOn() ? "ON" : "OFF";
g.drawString("CMP:", 115, 147);
g.drawString(compassText, 149, 147);
// Queue draw in one minute // Queue draw in one minute
if(queue){ if(queue){
@ -174,6 +214,14 @@ Bangle.on('swipe',function(dir) {
}); });
/*
* Measure heart rate
*/
Bangle.on('HRM', function(hrm) {
hrmStr = hrm.bpm;
});
/* /*
* Stop updates when LCD is off, restart when on * Stop updates when LCD is off, restart when on
*/ */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -34,14 +34,12 @@ function getApp() {
var ir = require("heatshrink").decompress(atob("jk0ggGDhvdAAXQCYwMEBxAMFAAIaH6c/+c9DgwMC/8zDg4aC/4YCHIwNB7/zHAwNCAgM/DQwqDAYIaHBonT/oNMFBAND74NNBhApEBrQAKBrrrGWpANZHBT7FBpYqIFAYcJBgkA5oMF7gNFFQwoFDgwMHHIoMIAAPM5gMKBrk0oANLmcwBu0zBrMDBv4AFN5gA/ADYA=")); var ir = require("heatshrink").decompress(atob("jk0ggGDhvdAAXQCYwMEBxAMFAAIaH6c/+c9DgwMC/8zDg4aC/4YCHIwNB7/zHAwNCAgM/DQwqDAYIaHBonT/oNMFBAND74NNBhApEBrQAKBrrrGWpANZHBT7FBpYqIFAYcJBgkA5oMF7gNFFQwoFDgwMHHIoMIAAPM5gMKBrk0oANLmcwBu0zBrMDBv4AFN5gA/ADYA="));
var ig = require("heatshrink").decompress(atob("jk0ggGDg93AAVwCYwMEBxAMFAAIaHuc/+c3DgwMC/8yDg4aC/4YCHIwNBv/zHAwNCAgM/DQwqDAYIaHBolz+4NMFBANDv8nBpgMIFIgNaABQNddYy1IBrI4KfYoNLFRAoDDhIMEgHnBgt+BooqGFAoqGBg4OFBhAODBhQNcmUgBpczmAN2mYNZgYN/AApvMAH4Ab")); var ig = require("heatshrink").decompress(atob("jk0ggGDg93AAVwCYwMEBxAMFAAIaHuc/+c3DgwMC/8yDg4aC/4YCHIwNBv/zHAwNCAgM/DQwqDAYIaHBolz+4NMFBANDv8nBpgMIFIgNaABQNddYy1IBrI4KfYoNLFRAoDDhIMEgHnBgt+BooqGFAoqGBg4OFBhAODBhQNcmUgBpczmAN2mYNZgYN/AApvMAH4Ab"));
var igift = require("heatshrink").decompress(atob("q1QxH+ADOi0QbZ5nMHDQAbKgIACKa4ACKnJWVKghW0KgxWTKgxWyKhBWRKhBWwKhRWPKhRWuKhhWNKhhWtKpxWKKhys8KxBU8Ky5U+KypU/KyhU/KyhU/KynGKn5WTKn5WUKmHCADpJJE7uYABZUfKuuYKv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/AAv+Kv5VT/wADyIAaKpIlbABZSEKv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/ADNtKv6rdKzZVwKhAABy5V/Khw")); var igift = require("heatshrink").decompress(atob("q1QxH+ADOi0QbZ5nMHDQAbKgIACKa4ACKnJWVKghW0KgxWTKgxWyKhBWRKhBWwKhRWPKhRWuKhhWNKhhWtKpxWKKhys8KxBU8Ky5U+KypU/KyhU/KyhU/KynGKn5WTKn5WUKmHCADpJJE7uYABZUfKuuYKv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/AAv+Kv5VT/wADyIAaKpIlbABZSEKv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/Kv5V/ADNtKv6rdKzZVwKhAABy5V/Khw"));
var W=240,H=240; var W=240,H=240;
var blns = []; var blns = [];
function updateFlake(f) { function updateFlake(f) {
f.im = [ir,ig,ib][Math.round(Math.random()*100)%3]; f.im = [ir,ig,ib][Math.round(Math.random()*100)%3];
f.s = 0.4+Math.random()*0.5; f.s = 0.4+Math.random()*0.5;
} }
for (var i=0;i<6;i++) { for (var i=0;i<6;i++) {
var f = { var f = {
y:Math.random()*H,x:(0.5+(i<3?i:i+5))*W/11, y:Math.random()*H,x:(0.5+(i<3?i:i+5))*W/11,
@ -51,7 +49,6 @@ var ig = require("heatshrink").decompress(atob("jk0ggGDg93AAVwCYwMEBxAMFAAIaHuc/
updateFlake(f); updateFlake(f);
blns.push(f); blns.push(f);
} }
function draw() { function draw() {
blns.forEach(f=>{ blns.forEach(f=>{
f.y-=f.v;f.r+=f.t; f.y-=f.v;f.r+=f.t;
@ -71,7 +68,6 @@ var ig = require("heatshrink").decompress(atob("jk0ggGDg93AAVwCYwMEBxAMFAAIaHuc/
g.drawString(${JSON.stringify(line4)},x,y+=10); g.drawString(${JSON.stringify(line4)},x,y+=10);
g.flip(); g.flip();
} }
g.clear(); g.clear();
setInterval(draw,50); setInterval(draw,50);
})()`; })()`;
@ -79,7 +75,6 @@ var ig = require("heatshrink").decompress(atob("jk0ggGDg93AAVwCYwMEBxAMFAAIaHuc/
return `(function() { return `(function() {
var isnow = require("heatshrink").decompress(atob("jEagQWTgfAAocf+gFDh4FDiARBggVB3AFBl3Agf8jfkn/AgX/v/9/+Agfv/2//YrBgfwh4wCgfghYFJCIYdFFIw1EIIpNFL44FFOIoAP")); var isnow = require("heatshrink").decompress(atob("jEagQWTgfAAocf+gFDh4FDiARBggVB3AFBl3Agf8jfkn/AgX/v/9/+Agfv/2//YrBgfwh4wCgfghYFJCIYdFFIw1EIIpNFL44FFOIoAP"));
var itree = require("heatshrink").decompress(atob("mtWxH+ADHHDTI0aGuXH5vNGmhqvTYIzBGtoxF6fTG4g4oGgQyBAAZssGoI0Ga1g1FGdo01ZgIAEGmHHNoLSuAAN/rdb0YFBGlgCBGYIABA4YArGYY1CGn4znAAM6GeVd5PQ5Iyurc/vQ0oGZFAn+d4XC3d5GddiGYIEBy+7zoEBGlFhoEcsQ9GT08+oFk1mkGdaVBMgNArnJ6/KzswGs/J6GlrlbqtbvPC5PCy8wGohniMIPJvIpCqmX3e7vI0BqhqlMIY0DqhtBqoEBa0xgBMIIoEqoABGQwzfsIhBv4qHABM50vQGjg1CGaN66DoBGt1ioGd5LoBGjo1PGYNhvLoCa7wnBqgvGA4YzCAgN5GUAsCqoDBmAHCAYU/wPQ0oSDGcBiDqkwAYcxoFd5PX6GdGjrIIqtUAAc3jk5vPC4fCy5pef5I2BTQMcnAHBy+7y95T0oADnFk1ekBpI2aGRUin7NGAA9hsIzVsIgHTAKZBZoPJ5LNDGhBpXGolcwOsrtcA4TNB3bNDGb/+sVin9AoGe6HX5InEvN/TkP+5XQwM/sRsBzqWB4QuKGjvC6HQ4QdDvKWBZYMwmAuHmFUCYNbqibX3fD5O7qolEZQQ0FBwgKDqgJBGiphEDwNUEgJbBFIQqCAgYOCB4IzCnE6GyhYFGoQnDABYzGAAQ1UAAo2NBoQSBnOB0t/Gjo2EABIPCoGe6HX4QzTGRIAEqtVF4QEBBQc4oE4y/J5PCvIxeABk/oADBvO73eXTyAyZMwM/Awd5vIOFGslAr2Av4PLNcU/jmA6HX5I1KasFcn8dTIOd5PJ4SZGGiNhAAIyNn0ckU+ZYe7AAJpJEYJnNGZk+n9kw9cBAcwGoN5aZg1JJJQABm8/oEjoDKC5ALCrUwqh/NrvQ6HDGp04n9doEdoE/sQJBZQZhCqgABGZk6zw0K/1dnVAoNAFwOlCYL1FubJBy4GCGh1AnOX4XC3YzHFYOeCgdV5PQ5OdD4rKBqqYNGYlbv+X3edGY3CGgKMDAAO7JAJgDAClcr2BEYgADaIZ0DL4uXGbDuB6HX5I1GsP+sNhOgWXIhBmWd4Od5PK4TwFGIJoBAYI2BAD0/jlcQoO7AAJaEGQQADGr0/sjNEvOdAoZmDGgw2ZsVAkeAZpQACGZI2VsU/kVGn1bZoPJZogpGGhA4GfRYwBoGC1mlBQbNFFoo0JNxAGCEod/wM6oFAn9iv/J6/Kzo1Ey9/MZQAKCg4GCFgTDEvPCSwI0BC5I0RN4ocEYYPQ5OdHgeXSwTFKGaJyKFYPC3f+MIdbpzFLAD4zB/1OqtbqtOGgYArGAIADGl9UAAI0wGQN5GoQ0vvIABGoI0uGYQABqo0zNOg0uaQY0/GllOGn40//w=")); var itree = require("heatshrink").decompress(atob("mtWxH+ADHHDTI0aGuXH5vNGmhqvTYIzBGtoxF6fTG4g4oGgQyBAAZssGoI0Ga1g1FGdo01ZgIAEGmHHNoLSuAAN/rdb0YFBGlgCBGYIABA4YArGYY1CGn4znAAM6GeVd5PQ5Iyurc/vQ0oGZFAn+d4XC3d5GddiGYIEBy+7zoEBGlFhoEcsQ9GT08+oFk1mkGdaVBMgNArnJ6/KzswGs/J6GlrlbqtbvPC5PCy8wGohniMIPJvIpCqmX3e7vI0BqhqlMIY0DqhtBqoEBa0xgBMIIoEqoABGQwzfsIhBv4qHABM50vQGjg1CGaN66DoBGt1ioGd5LoBGjo1PGYNhvLoCa7wnBqgvGA4YzCAgN5GUAsCqoDBmAHCAYU/wPQ0oSDGcBiDqkwAYcxoFd5PX6GdGjrIIqtUAAc3jk5vPC4fCy5pef5I2BTQMcnAHBy+7y95T0oADnFk1ekBpI2aGRUin7NGAA9hsIzVsIgHTAKZBZoPJ5LNDGhBpXGolcwOsrtcA4TNB3bNDGb/+sVin9AoGe6HX5InEvN/TkP+5XQwM/sRsBzqWB4QuKGjvC6HQ4QdDvKWBZYMwmAuHmFUCYNbqibX3fD5O7qolEZQQ0FBwgKDqgJBGiphEDwNUEgJbBFIQqCAgYOCB4IzCnE6GyhYFGoQnDABYzGAAQ1UAAo2NBoQSBnOB0t/Gjo2EABIPCoGe6HX4QzTGRIAEqtVF4QEBBQc4oE4y/J5PCvIxeABk/oADBvO73eXTyAyZMwM/Awd5vIOFGslAr2Av4PLNcU/jmA6HX5I1KasFcn8dTIOd5PJ4SZGGiNhAAIyNn0ckU+ZYe7AAJpJEYJnNGZk+n9kw9cBAcwGoN5aZg1JJJQABm8/oEjoDKC5ALCrUwqh/NrvQ6HDGp04n9doEdoE/sQJBZQZhCqgABGZk6zw0K/1dnVAoNAFwOlCYL1FubJBy4GCGh1AnOX4XC3YzHFYOeCgdV5PQ5OdD4rKBqqYNGYlbv+X3edGY3CGgKMDAAO7JAJgDAClcr2BEYgADaIZ0DL4uXGbDuB6HX5I1GsP+sNhOgWXIhBmWd4Od5PK4TwFGIJoBAYI2BAD0/jlcQoO7AAJaEGQQADGr0/sjNEvOdAoZmDGgw2ZsVAkeAZpQACGZI2VsU/kVGn1bZoPJZogpGGhA4GfRYwBoGC1mlBQbNFFoo0JNxAGCEod/wM6oFAn9iv/J6/Kzo1Ey9/MZQAKCg4GCFgTDEvPCSwI0BC5I0RN4ocEYYPQ5OdHgeXSwTFKGaJyKFYPC3f+MIdbpzFLAD4zB/1OqtbqtOGgYArGAIADGl9UAAI0wGQN5GoQ0vvIABGoI0uGYQABqo0zNOg0uaQY0/GllOGn40//w="));
var W=g.getWidth(),H=g.getHeight(); var W=g.getWidth(),H=g.getHeight();
var flakes = []; var flakes = [];
for (var i=0;i<10;i++) { for (var i=0;i<10;i++) {
@ -94,7 +89,6 @@ var ig = require("heatshrink").decompress(atob("jk0ggGDg93AAVwCYwMEBxAMFAAIaHuc/
f.v = f.s * (1+Math.random()); f.v = f.s * (1+Math.random());
flakes.push(f); flakes.push(f);
} }
function draw() { function draw() {
flakes.forEach(f=>{ flakes.forEach(f=>{
f.y+=f.v;f.r+=f.t; f.y+=f.v;f.r+=f.t;
@ -111,7 +105,6 @@ var ig = require("heatshrink").decompress(atob("jk0ggGDg93AAVwCYwMEBxAMFAAIaHuc/
g.drawString(${JSON.stringify(line4)},x,y+=10); g.drawString(${JSON.stringify(line4)},x,y+=10);
g.flip(); g.flip();
} }
g.clear(); g.clear();
setInterval(draw,50); setInterval(draw,50);
})(); })();

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
0.01: App is created with gradient background.

View File

@ -0,0 +1,27 @@
# School Calendar
School Calendar is a calendar that you can see your upcoming classes or schedule.
## Usage:
Enter your calendar events on the customizer then upload. (all day events are not supported yet)
Once uploaded on the watch when in the table mode you can use BTN1 and BTN3 to scroll up and down on the list. (The red rectangle indicates your current position on the table and your yellow rectangle indicates your current schedule item or your next schedule item.)
If you press BTN2 it will go into detail mode, and you can see additional information about your schedule item. Also, in this mode you can scroll up and down with BTN1 and BTN3 to move around in the table. To exit detail mode press BTN2 again.
## Screenshots:
![screenshot (5)](https://user-images.githubusercontent.com/89286474/142801592-485aa0b0-c417-44c8-8097-befa81d2599c.png)
![screenshot (6)](https://user-images.githubusercontent.com/89286474/142801595-47f73c63-501a-4221-baba-84dd97b65bf9.png)
## Updates Coming Soon:
- [ ] Notifications
- [ ] All Day Events
- [ ] Improved Rendering Screen
- [ ] Better Graphics
- [ ] Scrolling Table
- [ ] Bangle.js V2 Compatibility
- [ ] Full Calendar (Calendar that does not have repeating weekly events.)
## Creator
Ronin0000

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwyBC/AH4A/AH4A/AH4A/AH4A/AH4A80s0AIIh/L/5f/EP4ATscsAIo9DBY4BVEJZf/L/5fRznzAIJfdEJZfpymyAJmSBpwPLBZRfqIYYBwL9OMuIBzL9VRAMRTDCJhfymBpkL+GEmABzL9UQAJelinOrPWzQDBymSCpe96+c6YnNL9N794tBAYoFD5152u21t1AoP332MuIPDVIJxB88c///AoODD4gFBLoYJBL9YBT888M4IHDNYPvvoDDznzD5pfq54BT737L4QHCVYQFCL4XTD5pfpueuAKOtqpRBxlRB5JfDEJpfqxwBIG4OOwkw/4AC+++xlxC5ZfBymyDoYlHAIJf0AImEiBbB0s0MIOtuoTJL4glML9NrtoBTLoJTBBpJfCyQfNL9VNAKZfB88cBpJfED5hfslgzEAoT3BxlxBYd795RB2uWC4tjAoQNBC4olFCIZfpFoIBJe4JJB+++AYe964XLL4YPLAIJfqhgBNueuAIJnBCp4BPL9Na9YBBsQBCAoY3BA4YBRC4INPL9oBS5YXWDoxfqJIIByL9NS1QBzL9WKAIgzBAooHFAMBfpMJABqLtYA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4ALA"))

View File

@ -0,0 +1,6 @@
// check for alarms
(function() {
var alarms = require('Storage').readJSON('schoolCalendarAlarms.json',1)||[];
var time = new Date();
E.showPrompt(School Calendar Alarm Test)
})();

View File

@ -0,0 +1,420 @@
<html>
<head>
<style>
body {
padding: 0;
margin: 0;
}
html, body, #map {
height: 100%;
width: 100%;
}
#controls {
padding: 10px;
margin: 10px;
border: 1px solid black;
position:absolute;
right:0px;bottom:0px;
background-color: rgb(255, 255, 255);
z-index: 100;
}
</style>
<link href='fullcalendar/main.css' rel='stylesheet' />
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<div>
<p>Create your events on the week shown. Keep in note that your events repeat weekly.</p>
<p>One you have created your events, Click <button id="upload" class="btn btn-primary">Upload</button>.</p>
<p>All day events are not supported. A feature that lets you get the calendar from your watch will be added in a future update.</p>
</div>
<script src='fullcalendar/main.js'></script>
<script src="../../core/lib/customize.js"></script>
<script>
var calendar;
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'timeGridWeek',
headerToolbar: {
left: '',
center: 'title',
right: 'timeGridWeek,listWeek'
},
navLinks: true, // can click day/week names to navigate views
editable: true,
selectable: true,
selectMirror: true,
nowIndicator: true,
editable: true,
height: 600,
initialDate: '2018-06-03', // will be parsed as local
select: function(arg) {
var title = prompt('Event Title:');
if (title) {
calendar.addEvent({
title: title,
start: arg.start,
end: arg.end,
allDay: arg.allDay
})
}
calendar.unselect()
},
eventClick: function(arg) {
if (confirm('Are you sure you want to delete this event?')) {
arg.event.remove()
}
},
});
calendar.render();
});
// When the 'upload' button is clicked...
document.getElementById("upload").addEventListener("click", function () {
//Cacultate data:
var calendarEvents = calendar.getEvents();
let schedule = []
//--------------------
for(i=0;i<calendarEvents.length;i++){
var calendarEntry = {}
calendarEntry['cn'] = calendarEvents[i].title;
calendarEntry['dow'] = calendarEvents[i].start.getDate()-3;
calendarEntry['sh'] = calendarEvents[i].start.getHours();
calendarEntry['sm'] = calendarEvents[i].start.getMinutes();
calendarEntry['eh'] = calendarEvents[i].end.getHours();
calendarEntry['em'] = calendarEvents[i].end.getMinutes();
schedule.push(calendarEntry)
}
// build the app's text using a templated String
var app = `
require("Font8x12").add(Graphics);
require("Font7x11Numeric7Seg", 2).add(Graphics);
var file = require("Storage").open("calendarItems.csv","w");
let nIntervId;
function redrawScreen() {
layout.render(layout.background);
layout.render(layout.buttons);
draw();
}
function updateDay(ffunction,day){
if(ffunction == 1){
switch (day) {
case 0:
return "Sunday";
case 1:
day = "Monday";
break;
case 2:
day = "Tuesday";
break;
case 3:
day = "Wednesday";
break;
case 4:
day = "Thursday";
break;
case 5:
day = "Friday";
break;
case 6:
day = "Saturday";
}
return day;
}else if(ffunction == 2){
switch (day) {
case 0:
return "Sun";
case 1:
day = "Mon";
break;
case 2:
day = "Tue";
break;
case 3:
day = "Wed";
break;
case 4:
day = "Thu";
break;
case 5:
day = "Fri";
break;
case 6:
day = "Sat";
}
return day;
}else if(ffunction == 3){
switch (day) {
case 0:
return "S";
case 1:
day = "M";
break;
case 2:
day = "T";
break;
case 3:
day = "W";
break;
case 4:
day = "R";
break;
case 5:
day = "F";
break;
case 6:
day = "S";
}
return day;
}
}
function getScheduleTable() {
let schedule = [//Monday:
{cn: "Biblical Theology", dow:1, sh: 8, sm: 10, eh:9, em: 5, r:"207", t:"Mr. Besaw"},
{cn: "English", dow:1, sh: 9, sm: 5, eh:10, em: 0, t:"Dr. Wong"},
{cn: "Break", dow:1, sh: 10, sm: 0, eh:10, em: 10, t:""},
{cn: "MS Robotics", dow:1, sh: 10, sm: 10, eh:11, em: 0, r:"211", t:"Mr. Broyles"}];//${JSON.stringify(schedule)};
logDebug(JSON.stringify(schedule));
return schedule;
}
function findNextScheduleIndex() {
var schedule = getScheduleTable();
var currentDate = new Date();
var minuteOfWeek = (currentDate.getDay()*3600)+(currentDate.getHours()*60)+currentDate.getMinutes();
//var minuteOfWeek = (4*3600)+(16*60)+0;
var currentPosition;
for(currentPosition = 0;currentPosition < schedule.length; currentPosition++){
var scheduleItemStartMinuteOfWeek = schedule[currentPosition].dow*3600 + schedule[currentPosition].eh*60+schedule[currentPosition].em;
if(scheduleItemStartMinuteOfWeek > minuteOfWeek) {
return currentPosition;
}
}
return 0;
}
function getUpArrow() {return require("heatshrink").decompress(atob("hkOyANKmv9AIIjRCoYZRlvdAI8U3YVK3oBJC4Mc7YVRC4sc7gVCzoBNC4oZDGowXGR58lvoBFC9FcAIoXongBFC58dngBFC6EcAIoPHA"));}
function getDownArrow() {return require("heatshrink").decompress(atob("hkOyALImv9AIojPmvdAIoXPlvdAIoXQ3oBFC9GdAIoXnkt9AIoPPAI8U3cc7cc7gBBDIVcAJYXFGYwXOLpU8AI4XBO5sdjgBFR54ZFBpIA=="));}
function getMenuIcon() {return require("heatshrink").decompress(atob("iEQyBC/AEU+rwBEn02js17st3stvklrkljkc/cc3cUzYBBD5AdUD4oA/P/4A/P/4A/ADoA=="));}
function getDotIcon() {return require("heatshrink").decompress(atob("iEQyBC/AA0t3oBBA4ndAIIPGA4gAFkt9lt9AYIHEzoBBBIwRED41cks8AYIJGA44RGP8xtGP44RJBYh1CAIIHHBJJ/KroBBPoqBFB4YRDAA8dngHHBJKdq3oBDBI4RNP4l9AIYHHBJJBJks8AIIHTAH4ABA="));}
var currentPositionTable = 0;
var numberOfItemsShown = 8;
//Table Positions:
var rectStart = 45;
var rectEnd = 65;
var rectStartX = 10;
var rectEndX = 210;
//Scences:
LIST = 1;
INFORMATION = 2;
currentStage = LIST;
function splitter(str, l){
var strs = [];
while(str.length > l){
var pos = str.substring(0, l).lastIndexOf(' ');
pos = pos <= 0 ? l : pos;
strs.push(str.substring(0, pos));
var i = str.indexOf(' ', pos)+1;
if(i < pos || i > pos+l)
i = pos;
str = str.substring(i);
}
strs.push(str);
return strs;
}
function updateMinutesToCurrentTime(currentMinuteFunction) {
if (currentMinuteFunction<10){
currentMinuteUpdatedFunction = "0"+currentMinuteFunction;
}else{
currentMinuteUpdatedFunction = currentMinuteFunction;
}
return currentMinuteUpdatedFunction;
}
function renderBackground(l) {
g.clearRect(0,0,240,20);
g.drawImage(getBackgroundImage(),110,130,{scale:9,rotate:0});
}
function renderTable(l) {
var foundNumber = findNextScheduleIndex();
var yellowIndex = 3;
if (foundNumber < 3) { yellowIndex = foundNumber; }
for(var x = 0;x<=numberOfItemsShown;x++){
g.setColor(255,255,255);
g.drawRect(rectStartX,rectStart+(x*20),rectEndX,rectEnd+(20*x));
}
g.setColor(255,205,0);
g.drawRect(rectStartX,rectStart+(yellowIndex*20),rectEndX,rectEnd+(20*yellowIndex));
g.setColor(255,0,0);
g.drawRect(rectStartX,rectStart+(currentPositionTable*20),rectEndX,rectEnd+(20*currentPositionTable));
}
function renderTableText(l) {
var foundSchedule = getScheduleTable();
var foundNumber = findNextScheduleIndex();
var startNumber = foundNumber - 2;
if (startNumber < 0) { startNumber = 0; }
var endNumber = startNumber + 8 - (foundNumber - startNumber);
if (endNumber > foundSchedule.length-1) { endNumber = foundSchedule.length-1; }
var scheduleHourUpdated;
var scheduleMinuteUpdated;
for(var currentNumber = startNumber; currentNumber<=endNumber; currentNumber++){
scheduleMinuteUpdatedStart = updateMinutesToCurrentTime(foundSchedule[currentNumber].sm);
scheduleHourUpdatedStart = foundSchedule[currentNumber].sh;
scheduleMinuteUpdatedEnd = updateMinutesToCurrentTime(foundSchedule[currentNumber].em);
scheduleHourUpdatedEnd = foundSchedule[currentNumber].eh;
scheduleDecriptionUpdated = foundSchedule[currentNumber].cn.substring(0, 20);
if(foundSchedule[currentNumber].cn.length >= 15){
scheduleDecriptionUpdated = foundSchedule[currentNumber].cn.substring(0, 20)+"...";
}
schduleDay = updateDay(3,foundSchedule[currentNumber].dow);
g.setFont("8x12");
g.drawString(scheduleHourUpdatedStart+":"+scheduleMinuteUpdatedStart+"-"+scheduleHourUpdatedEnd+":"+scheduleMinuteUpdatedEnd+" "+schduleDay+" "+scheduleDecriptionUpdated,13,50+(currentNumber*20));
}
}
function buttonsF(l){
if(currentStage == LIST){
g.drawImage(getDotIcon(),223.5,115);
}else{
g.drawImage(getMenuIcon(),223.5,115);
}
g.drawImage(getUpArrow(),225,30);
g.drawImage(getDownArrow(),225,215);
}
function draw() {
var currentDate = new Date();
var currentDayOfWeek = currentDate.getDay();
var currentHour = currentDate.getHours();
var currentMinute = currentDate.getMinutes();
var currentMinuteUpdated = updateMinutesToCurrentTime(currentMinute);
if (layout) {
if(currentStage == LIST){
layout.time.label = currentHour+":"+currentMinuteUpdated;
layout.time.x = 147;
layout.time.y = 10;
layout.render(layout.table);
layout.render(layout.tableText);
logDebug("Rendered"+currentPositionTable);
}else{
layout.time.label = currentHour+":"+currentMinuteUpdated;
layout.time.x = 147;
layout.time.y = 10;
layout.render(layout.info);
logDebug("Rendered"+currentPositionTable);
}
g.clearRect(150,0,220,35);
layout.render(layout.time);
}
}
function RedRectDown() {
if(currentPositionTable > 0){
currentPositionTable -= 1;
if(currentStage == INFORMATION){
redrawScreen();
}else{
draw();
}
}
}
function RedRectUp() {
if(currentPositionTable < numberOfItemsShown){
currentPositionTable += 1;
if(currentStage == INFORMATION){
redrawScreen();
}else{
draw();
}
}
}
function renderMiniBackground(l){
for(var i = 233;i<=240;i++){
g.drawImage(getBackgroundImage(),i,123,{scale:10,rotate:0});
}
}
function renderLoading(l){
g.setFont("8x12");
g.drawString("Loading...",240/2-20,240/2-20);
}
function renderInformation(l){
var foundNumber = findNextScheduleIndex();
var foundSchedule = getScheduleTable();
var startNumber = foundNumber - 2;
if (startNumber < 0) { startNumber = 0; }
if ((startNumber+currentPositionTable) <= foundSchedule.length-1) {
scheduleMinuteUpdatedStart = updateMinutesToCurrentTime(foundSchedule[foundNumber].sm);
scheduleHourUpdatedStart = foundSchedule[foundNumber].sh;
scheduleMinuteUpdatedEnd = updateMinutesToCurrentTime(foundSchedule[foundNumber].em);
scheduleHourUpdatedEnd = foundSchedule[foundNumber].eh;
scheduleDay = updateDay(1,foundSchedule[(startNumber+currentPositionTable)].dow);
g.setColor(255,255,255);
g.setFont("8x12",2);
var splitClassNames = splitter(foundSchedule[(startNumber+currentPositionTable)].cn, 15);
var currentY = 5;
for (var j=0; j < splitClassNames.length; j++) {
g.drawString(splitClassNames[j],13,currentY+50);
currentY = currentY + 25;
}
g.setFont("8x12");
g.drawString(schduleDay,13,currentY+50);
g.drawString(scheduleHourUpdatedStart+":"+scheduleMinuteUpdatedStart+"-"+scheduleHourUpdatedEnd+":"+scheduleMinuteUpdatedEnd,13,currentY+15+50);
}
}
var Layout = require("Layout");
var layout = new Layout(
{type:"h", c: [
{type:"custom", render:renderTableText, id:"tableText"},
{type:"custom", render:buttonsF, id:"buttons"},
{type:"custom", render:renderBackground, id:"background"},
{type:"custom", render:renderTable, id:"table"},
{type:"custom", render:renderMiniBackground, id:"miniBackground"},
{type:"custom", render:renderLoading, id:"loading"},
{type:"custom", render:renderInformation, id:"info"},
{type:"txt", font:"7x11Numeric7Seg:2", label:"00:00", id:"time"},
]},
{type:"v", c:[
]},
{btns:[
{label:"", cb: RedRectUp()},
{label:"", cb: l=>print("Two")},
{label:"", cb: RedRectDown()}
]});
function getBackgroundImage() {return require("heatshrink").decompress(atob("j0ZyEKIf4A4gIB6gQB6gYB6ggB6goB6gwB6g4B6hAABAYIBHBZIVLAK8IhIBXgAThhQB6hYB6hgB6hoB6hwB6h4B6iAB6iIB6iQBHiAJOB54XSiYB6igB6ioB6iwB6i4B5A="));}
function logDebug(message) {console.log(message);}
function changeScene(){
layout.render(layout.buttons);
if(currentStage == INFORMATION){
currentStage = LIST;
nIntervId = setInterval(redrawScreen, 100000);
}else if(currentStage == LIST){
currentStage = INFORMATION;
clearInterval();
}
layout.render(layout.background);
layout.render(layout.buttons);
draw();
}
// timeout used to update every minute
var drawTimeout;
setInterval(draw, 15000);
setWatch(RedRectUp, BTN3, { repeat:true, edge:'rising', debounce : 50 });
setWatch(RedRectDown, BTN1, { repeat:true, edge:'rising', debounce : 50 });
setWatch(changeScene, BTN2, { repeat:true, edge:'rising', debounce : 50 });
layout.update();
layout.render(layout.loading);
layout.render(layout.background);
layout.render(layout.buttons);
draw();
file.write(JSON.stringify(schedule));
`;
// send finished app (in addition to contents of app.json)
sendCustomizedApp({
storage: [
{ name: "schoolCalendar.app.js", url: "app.js", content: app },
]
});
});
</script>
<div id='calendar'></div>
</body>
</html>

View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2021 Adam Shaw
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,8 @@
# FullCalendar Interaction Plugin
Provides functionality for event drag-n-drop, resizing, dateClick, and selectable actions
[View the docs &raquo;](https://fullcalendar.io/docs/editable)
This package was created from the [FullCalendar monorepo &raquo;](https://github.com/fullcalendar/fullcalendar)

View File

@ -0,0 +1,32 @@
{
"name": "@fullcalendar/interaction",
"version": "5.9.0",
"title": "FullCalendar Interaction Plugin",
"description": "Provides functionality for event drag-n-drop, resizing, dateClick, and selectable actions",
"docs": "https://fullcalendar.io/docs/editable",
"dependencies": {
"@fullcalendar/common": "workspace:~5.9.0",
"tslib": "^2.1.0"
},
"main": "main.cjs.js",
"module": "main.js",
"types": "main.d.ts",
"jsdelivr": "main.global.min.js",
"browserGlobal": "FullCalendarInteraction",
"homepage": "https://fullcalendar.io/",
"bugs": "https://fullcalendar.io/reporting-bugs",
"repository": {
"type": "git",
"url": "https://github.com/fullcalendar/fullcalendar.git",
"homepage": "https://github.com/fullcalendar/fullcalendar"
},
"license": "MIT",
"author": {
"name": "Adam Shaw",
"email": "arshaw@arshaw.com",
"url": "http://arshaw.com/"
},
"devDependencies": {
"@fullcalendar/core-preact": "workspace:*"
}
}

View File

@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base",
"compilerOptions": {
"rootDir": "src",
"outDir": "tsc"
},
"include": [
"src/**/*"
],
"references": [
{ "path": "../common" }
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -209,6 +209,8 @@ apps.forEach((app,appIdx) => {
// prefer "appid.json" over "appid.settings.json" (TODO: change to ERROR once all apps comply?) // prefer "appid.json" over "appid.settings.json" (TODO: change to ERROR once all apps comply?)
if (dataNames.includes(app.id+".settings.json") && !dataNames.includes(app.id+".json")) if (dataNames.includes(app.id+".settings.json") && !dataNames.includes(app.id+".json"))
WARN(`App ${app.id} uses data file ${app.id+'.settings.json'} instead of ${app.id+'.json'}`) WARN(`App ${app.id} uses data file ${app.id+'.settings.json'} instead of ${app.id+'.json'}`)
else if (dataNames.includes(app.id+".settings.json"))
WARN(`App ${app.id} uses data file ${app.id+'.settings.json'}`)
// settings files should be listed under data, not storage (TODO: change to ERROR once all apps comply?) // settings files should be listed under data, not storage (TODO: change to ERROR once all apps comply?)
if (fileNames.includes(app.id+".settings.json")) if (fileNames.includes(app.id+".settings.json"))
WARN(`App ${app.id} uses storage file ${app.id+'.settings.json'} instead of data file`) WARN(`App ${app.id} uses storage file ${app.id+'.settings.json'} instead of data file`)

101
modules/Settings.js Normal file
View File

@ -0,0 +1,101 @@
/*
- Read/write app settings, stored in <appid>.json
- Read/write global settings (stored in setting.json)
Usage:
```
// read a single app setting
value = require('Settings').get(appid, key, default);
// omit key to read all app settings
value = require('Settings').get();
// write a single app setting
require('Settings').set(appid, key, value)
// omit key and pass an object as values to overwrite all settings
require('Settings').set(appid, values)
// read Bangle settings by passing the Bangle object instead of an app name
value = require('Settings').get(Bangle, key, default);
// read all global settings
values = require('Settings').get(Bangle);
// write a global setting
require('Settings').set(Bangle, key, value)
```
For example:
```
require('Settings').set('test', 'foo', 123); // writes to 'test.json'
require('Settings').set('test', 'bar', 456); // updates 'test.json'
// 'test.json' now contains {baz:123,bam:456}
baz = require('Settings').get('test', 'foo'); // baz = 123
def = require('Settings').get('test', 'jkl', 789); // def = 789
all = require('Settings').get('test'); // all = {foo: 123, bar: 456}
baz = require('Settings').get('test', 'baz'); // baz = undefined
// read global setting
vibrate = require('Settings').get(Bangle, 'vibrate', true);
// Hint: if your app reads multiple settings, you can create a helper function:
function s(key, def) { return require('Settings').get('myapp', key, def); }
var foo = s('foo setting', 'default value'), bar = s('bar setting');
```
*/
/**
* Read setting value from file
*
* @param {string} file Settings file
* @param {string} key Setting to get, omit to get all settings as object
* @param {*} def Default value
* @return {*} Setting value (or default if not found)
*/
function get(file, key, def) {
var s = require("Storage").readJSON(file);
if (def===undefined && ["object", "undefined"].includes(typeof key)) {
// get(file) or get(file, def): get all settings
return (s!==undefined) ? s : key;
}
return ((typeof s==="object") && (key in s)) ? s[key] : def;
}
/**
* Write setting value to file
*
* @param {string} file Settings file
* @param {string} key Setting to change, omit to replace all settings
* @param {*} value Value to store
*/
function set(file, key, value) {
if (value===undefined && typeof key==="object") {
// set(file, value): overwrite settings completely
require("Storage").writeJSON(file, key);
return;
}
var s = require("Storage").readJSON(file, 1);
if (typeof s!=="object") s = {};
s[key] = value;
require("Storage").write(file, s);
}
/**
* Read setting value
*
* @param {string|object} app App name or Bangle
* @param {string} key Setting to get, omit to get all settings as object
* @param {*} def Default value
* @return {*} Setting value (or default if not found)
*/
exports.get = function(app, key, def) {
return get((app===Bangle) ? 'setting.json' : app+".json", key, def);
};
/**
* Write setting value
*
* @param {string|object} app App name or Bangle
* @param {string} key Setting to change, omit to replace all settings
* @param {*} val Value to store
*/
exports.set = function(app, key, val) {
set((app===Bangle) ? 'setting.json' : app+".json", key, val);
};