forked from FOSS/BangleApps
Merge branch 'master' of https://github.com/peerdavid/BangleApps
commit
d99cea9ae0
12
apps.json
12
apps.json
|
@ -32,7 +32,7 @@
|
|||
{
|
||||
"id": "messages",
|
||||
"name": "Messages",
|
||||
"version": "0.05",
|
||||
"version": "0.07",
|
||||
"description": "App to display notifications from iOS and Gadgetbridge",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
@ -41,18 +41,19 @@
|
|||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"messages.app.js","url":"app.js"},
|
||||
{"name":"messages.settings.js","url":"settings.js"},
|
||||
{"name":"messages.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"messages.wid.js","url":"widget.js"},
|
||||
{"name":"messages","url":"lib.js"}
|
||||
],
|
||||
"data": [{"name":"messages.json"}],
|
||||
"data": [{"name":"messages.json"},{"name":"messages.settings.json"}],
|
||||
"sortorder": -9
|
||||
},
|
||||
{
|
||||
"id": "android",
|
||||
"name": "Android Integration",
|
||||
"shortName": "Android",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "(BETA) App to display notifications from Gadgetbridge on Android. This will eventually replace the Gadgetbridge widget.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,system,messages,notifications",
|
||||
|
@ -60,6 +61,7 @@
|
|||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"android.app.js","url":"app.js"},
|
||||
{"name":"android.settings.js","url":"settings.js"},
|
||||
{"name":"android.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"android.boot.js","url":"boot.js"}
|
||||
],
|
||||
|
@ -551,8 +553,8 @@
|
|||
{
|
||||
"id": "cubescramble",
|
||||
"name": "Cube Scramble",
|
||||
"version":"0.03",
|
||||
"description": "A random scramble generator for the 3x3 Rubik's cube",
|
||||
"version":"0.04",
|
||||
"description": "A random scramble generator for the 3x3 Rubik's cube with a basic timer",
|
||||
"icon": "cube-scramble.png",
|
||||
"tags": "",
|
||||
"supports" : ["BANGLEJS","BANGLEJS2"],
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Remove messages on disconnect
|
||||
Fix music control
|
||||
0.03: Handling of message actions (ok/clear)
|
||||
0.04: Android icon now goes to settings page with 'find phone'
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
// Config app not implemented yet
|
||||
setTimeout(()=>load("messages.app.js"),10);
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
eval(require("Storage").read("android.settings.js"))(()=>load());
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
(function(back) {
|
||||
function gb(j) {
|
||||
Bluetooth.println(JSON.stringify(j));
|
||||
}
|
||||
var mainmenu = {
|
||||
"" : { "title" : "Android" },
|
||||
"< Back" : back,
|
||||
"Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" },
|
||||
"Find Phone" : () => E.showMenu({
|
||||
"" : { "title" : "Find Phone" },
|
||||
"< Back" : ()=>E.showMenu(mainmenu),
|
||||
"On" : _=>gb({t:"findPhone",n:true}),
|
||||
"Off" : _=>gb({t:"findPhone",n:false}),
|
||||
}),
|
||||
"Messages" : ()=>load("messages.app.js")
|
||||
};
|
||||
E.showMenu(mainmenu);
|
||||
})
|
|
@ -1,3 +1,4 @@
|
|||
0.01: Initial Release
|
||||
0.02: Replace icon with one found on https://icons8.com
|
||||
0.03: Re-render icon fixing display in settings
|
||||
0.04: Improved UX and display solve time
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
# Cube Scramble
|
||||
|
||||
A random scramble generator for the 3x3 Rubik's cube
|
||||
A random scramble generator for the 3x3 Rubik's cube with a basic timer.
|
||||
|
||||
## Future features
|
||||
|
||||
I'm keen to complete this project with
|
||||
|
||||
* Add a timer
|
||||
* Add the ability for times to be stored and exported
|
||||
|
||||
## Requests
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.9 KiB |
|
@ -1,4 +1,3 @@
|
|||
|
||||
// Scramble code from: https://raw.githubusercontent.com/bjcarlson42/blog-post-sample-code/master/Rubik's%20Cube%20JavaScript%20Scrambler/part_two.js
|
||||
const makeScramble = () => {
|
||||
const options = ["F", "F2", "F'", "R", "R2", "R'", "U", "U2", "U'", "B", "B2", "B'", "L", "L2", "L'", "D", "D2", "D'"];
|
||||
|
@ -59,16 +58,36 @@ const getRandomInt = max => Math.floor(Math.random() * Math.floor(max)); // retu
|
|||
const getRandomIntBetween = (min, max) => Math.floor(Math.random() * (max - min) + min);
|
||||
|
||||
const presentScramble = () => {
|
||||
g.clear();
|
||||
E.showMessage(makeScramble().join(" "));
|
||||
showPrompt(makeScramble().join(" "), {
|
||||
buttons: {"solve": true, "reset": false}
|
||||
}).then((v) => {
|
||||
if (v) {
|
||||
const start = new Date();
|
||||
showPrompt(" ", {
|
||||
buttons: {"stop": true}
|
||||
}).then(() => {
|
||||
const time = parseFloat(((new Date()).getTime() - start.getTime()) / 1000);
|
||||
showPrompt(String(time.toFixed(3)), {
|
||||
buttons: {"next": true}
|
||||
}).then(() => {
|
||||
presentScramble();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
presentScramble();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const showPrompt = (text, options = {}) => {
|
||||
options.title = options.title || "cube scramble";
|
||||
return E.showPrompt(text, options);
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
Bangle.setLCDTimeout(0);
|
||||
Bangle.setLCDPower(1);
|
||||
presentScramble();
|
||||
|
||||
setWatch(() => {
|
||||
presentScramble();
|
||||
}, BTN1, {repeat:true});
|
||||
};
|
||||
|
||||
init();
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
}
|
||||
var mainmenu = {
|
||||
"" : { "title" : "Gadgetbridge" },
|
||||
"< Back" : back,
|
||||
"Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" },
|
||||
"Show Icon" : {
|
||||
value: settings().showIcon,
|
||||
|
@ -34,8 +35,7 @@
|
|||
value: !!settings().hrm,
|
||||
format: v => v?"Yes":"No",
|
||||
onchange: v => updateSetting('hrm', v)
|
||||
},
|
||||
"< Back" : back,
|
||||
}
|
||||
};
|
||||
|
||||
var findPhone = {
|
||||
|
|
|
@ -3,3 +3,8 @@
|
|||
0.03: Fixes for Bangle.js 1
|
||||
0.04: Add require("messages").clearAll()
|
||||
0.05: Handling of message actions (ok/clear)
|
||||
0.06: New messages now go at the start (fix #898)
|
||||
Answering true/false now exits the messages app if no new messages
|
||||
Back now marks a message as read
|
||||
Clicking top-left opens a menu which allows you to delete a message or mark unread
|
||||
0.07: Added settings menu with option to choose vibrate pattern and frequency (fix #909)
|
||||
|
|
|
@ -46,7 +46,10 @@ var MESSAGES = require("Storage").readJSON("messages.json",1)||[];
|
|||
if (!Array.isArray(MESSAGES)) MESSAGES=[];
|
||||
var onMessagesModified = function(msg) {
|
||||
// TODO: if new, show this new one
|
||||
if (msg.new) Bangle.buzz();
|
||||
if (msg.new) {
|
||||
if (WIDGETS["messages"]) WIDGETS["messages"].buzz();
|
||||
else Bangle.buzz();
|
||||
}
|
||||
showMessage(msg.id);
|
||||
};
|
||||
function saveMessages() {
|
||||
|
@ -111,7 +114,7 @@ function showMapMessage(msg) {
|
|||
msg.new = false;
|
||||
saveMessages();
|
||||
layout = undefined;
|
||||
checkMessages();
|
||||
checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -126,7 +129,7 @@ function showMusicMessage(msg) {
|
|||
msg.new = false;
|
||||
saveMessages();
|
||||
layout = undefined;
|
||||
checkMessages();
|
||||
checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1});
|
||||
}
|
||||
layout = new Layout({ type:"v", c: [
|
||||
{type:"h", fillx:1, bgCol:colBg, c: [
|
||||
|
@ -148,6 +151,22 @@ function showMusicMessage(msg) {
|
|||
layout.render();
|
||||
}
|
||||
|
||||
function showMessageSettings(msg) {
|
||||
E.showMenu({"":{"title":"Message"},
|
||||
"< Back" : () => showMessage(msg.id),
|
||||
"Delete" : () => {
|
||||
MESSAGES = MESSAGES.filter(m=>m.id!=msg.id);
|
||||
saveMessages();
|
||||
checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0});
|
||||
},
|
||||
"Mark Unread" : () => {
|
||||
msg.new = true;
|
||||
saveMessages();
|
||||
checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function showMessage(msgid) {
|
||||
var msg = MESSAGES.find(m=>m.id==msgid);
|
||||
if (!msg) return checkMessages(); // go home if no message found
|
||||
|
@ -163,30 +182,30 @@ function showMessage(msgid) {
|
|||
title = g.wrapString(title, w).join("\n");
|
||||
}
|
||||
var buttons = [
|
||||
{type:"btn", src:getBackImage(), cb:()=>checkMessages(true)}, // back
|
||||
msg.new?{type:"btn", src:atob("HRiBAD///8D///wj///Fj//8bj//x3z//Hvx/8/fx/j+/x+Ad/B4AL8Rh+HxwH+PHwf+cf5/+x/n/PH/P8cf+cx5/84HwAB4fgAD5/AAD/8AAD/wAAD/AAAD8A=="), cb:()=>{
|
||||
{type:"btn", src:getBackImage(), cb:()=>{
|
||||
msg.new = false; // read mail
|
||||
saveMessages();
|
||||
checkMessages();
|
||||
}}:{}
|
||||
checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:1});
|
||||
}} // back
|
||||
];
|
||||
if (msg.positive) {
|
||||
buttons.push({type:"btn", src:getPosImage(), cb:()=>{
|
||||
msg.new = false; saveMessages();
|
||||
Bangle.messageResponse(msg,true);
|
||||
checkMessages();
|
||||
checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1});
|
||||
}});
|
||||
}
|
||||
if (msg.negative) {
|
||||
buttons.push({type:"btn", src:getNegImage(), cb:()=>{
|
||||
console.log("Response");
|
||||
msg.new = false; saveMessages();
|
||||
Bangle.messageResponse(msg,true);
|
||||
checkMessages();
|
||||
Bangle.messageResponse(msg,false);
|
||||
checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1});
|
||||
}});
|
||||
}
|
||||
layout = new Layout({ type:"v", c: [
|
||||
{type:"h", fillx:1, bgCol:colBg, c: [
|
||||
{ type:"img", src:getMessageImage(msg), pad:2 },
|
||||
{ type:"btn", src:getMessageImage(msg), cb:()=>showMessageSettings(msg) },
|
||||
{ type:"v", fillx:1, c: [
|
||||
{type:"txt", font:fontMedium, label:msg.src||"Message", bgCol:colBg, fillx:1, pad:2 },
|
||||
title?{type:"txt", font:titleFont, label:title, bgCol:colBg, fillx:1, pad:2 }:{},
|
||||
|
@ -199,28 +218,37 @@ function showMessage(msgid) {
|
|||
layout.render();
|
||||
}
|
||||
|
||||
function checkMessages(forceShowMenu) {
|
||||
|
||||
/* options = {
|
||||
clockIfNoMsg : bool
|
||||
clockIfAllRead : bool
|
||||
showMsgIfUnread : bool
|
||||
}
|
||||
*/
|
||||
function checkMessages(options) {
|
||||
options=options||{};
|
||||
// If no messages, just show 'no messages' and return
|
||||
if (!MESSAGES.length) {
|
||||
if (forceShowMenu) return E.showPrompt("No Messages",{
|
||||
if (!options.clockIfNoMsg) return E.showPrompt("No Messages",{
|
||||
title:"Messages",
|
||||
img:require("heatshrink").decompress(atob("kkk4UBrkc/4AC/tEqtACQkBqtUDg0VqAIGgoZFDYQIIM1sD1QAD4AIBhnqA4WrmAIBhc6BAWs8AIBhXOBAWz0AIC2YIC5wID1gkB1c6BAYFBEQPqBAYXBEQOqBAnDAIQaEnkAngaEEAPDFgo+IKA5iIOhCGIAFb7RqAIGgtUBA0VqobFgNVA")),
|
||||
buttons : {"Ok":1}
|
||||
}).then(() => { load() });
|
||||
load();
|
||||
return;
|
||||
return load();
|
||||
}
|
||||
// we have >0 messages
|
||||
var newMessages = MESSAGES.filter(m=>m.new);
|
||||
// If we have a new message, show it
|
||||
if (!forceShowMenu) {
|
||||
var newMessages = MESSAGES.filter(m=>m.new);
|
||||
if (newMessages.length)
|
||||
return showMessage(newMessages[0].id);
|
||||
}
|
||||
if (options.showMsgIfUnread && newMessages.length)
|
||||
return showMessage(newMessages[0].id);
|
||||
// no new messages - go to clock?
|
||||
if (options.clockIfAllRead && newMessages.length==0)
|
||||
return load();
|
||||
|
||||
// Otherwise show a menu
|
||||
E.showScroller({
|
||||
h : 48,
|
||||
c : Math.min(MESSAGES.length+1,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11)
|
||||
c : Math.max(MESSAGES.length+1,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11)
|
||||
draw : function(idx, r) {"ram"
|
||||
var msg = MESSAGES[idx-1];
|
||||
if (msg && msg.new) g.setBgColor(colBg);
|
||||
|
@ -239,7 +267,7 @@ function checkMessages(forceShowMenu) {
|
|||
x += 50;
|
||||
}
|
||||
var m = msg.title+"\n"+msg.body;
|
||||
if (msg.src) g.setFontAlign(1,-1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+2);
|
||||
if (msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2);
|
||||
if (title) g.setFontAlign(-1,-1).setFont(fontBig).drawString(title, x,r.y+2);
|
||||
if (body) {
|
||||
g.setFontAlign(-1,-1).setFont("6x8");
|
||||
|
@ -261,4 +289,6 @@ function checkMessages(forceShowMenu) {
|
|||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
checkMessages(true); // force showing a menu
|
||||
setTimeout(() => {
|
||||
checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:1});
|
||||
},10); // if checkMessages wants to 'load', do that
|
||||
|
|
|
@ -17,7 +17,10 @@ exports.pushMessage = function(event) {
|
|||
mIdx=-1;
|
||||
} else { // add/modify
|
||||
if (event.t=="add") event.new=true; // new message
|
||||
if (mIdx<0) mIdx=messages.push(event)-1;
|
||||
if (mIdx<0) {
|
||||
mIdx=0;
|
||||
messages.unshift(event); // add new messages to the beginning
|
||||
}
|
||||
else Object.assign(messages[mIdx], event);
|
||||
}
|
||||
require("Storage").writeJSON("messages.json",messages);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
WIDGETS["messages"]={area:"tl",width:0,draw:function() {
|
||||
if (!this.width) return;
|
||||
var c = (Date.now()-this.t)/1000;
|
||||
|
@ -5,9 +6,11 @@ WIDGETS["messages"]={area:"tl",width:0,draw:function() {
|
|||
g.clearRect(this.x,this.y,this.x+this.width,this.y+23);
|
||||
g.setFont("6x8:1x2").setFontAlign(0,0).drawString("MESSAGES", this.x+this.width/2, this.y+12);
|
||||
//if (c<60) Bangle.setLCDPower(1); // keep LCD on for 1 minute
|
||||
if (c<120 && (Date.now()-this.l)>4000) {
|
||||
let settings = require('Storage').readJSON("messages.settings.json", true) || {};
|
||||
if (settings.repeat===undefined) settings.repeat = 4;
|
||||
if (c<120 && (Date.now()-this.l)>settings.repeat*1000) {
|
||||
this.l = Date.now();
|
||||
Bangle.buzz(); // buzz every 4 seconds
|
||||
WIDGETS["messages"].buzz(); // buzz every 4 seconds
|
||||
}
|
||||
setTimeout(()=>WIDGETS["messages"].draw(), 1000);
|
||||
},show:function() {
|
||||
|
@ -21,4 +24,13 @@ WIDGETS["messages"]={area:"tl",width:0,draw:function() {
|
|||
delete WIDGETS["messages"].l;
|
||||
WIDGETS["messages"].width=0;
|
||||
Bangle.drawWidgets();
|
||||
},buzz:function() {
|
||||
let v = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrate || ".";
|
||||
function b() {
|
||||
var c = v[0];
|
||||
v = v.substr(1);
|
||||
if (c==".") Bangle.buzz().then(()=>setTimeout(b,100));
|
||||
if (c=="-") Bangle.buzz(500).then(()=>setTimeout(b,100));
|
||||
}
|
||||
b();
|
||||
}};
|
||||
|
|
Loading…
Reference in New Issue