Merge branch 'espruino:master' into master

master
nxdefiant 2023-06-28 11:09:11 +02:00 committed by GitHub
commit c67964bf61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 256 additions and 40 deletions

1
apps/alyxclock/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: first release

4
apps/alyxclock/README.md Normal file
View File

@ -0,0 +1,4 @@
# Half-Life Alyx Style clock
![](screenshot_alyxclock.png)

View File

@ -0,0 +1,174 @@
const icoH = [
[0,1,1,0,0,1,1,0],
[1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1],
[0,1,1,1,1,1,1,0],
[0,0,1,1,1,1,0,0],
[0,0,0,1,1,0,0,0],
[0,0,0,0,0,0,0,0],
]
const icoR = [
[0,0,0,0,1,1,1,1,0,0,0,0],
[0,0,1,1,0,0,0,0,1,1,0,0],
[0,1,1,1,1,0,0,1,1,0,1,0],
[0,1,1,0,0,0,0,0,0,0,1,0],
[1,1,1,1,1,1,1,1,0,0,0,1],
[1,1,0,0,1,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,0,1,1,0,1],
[1,1,1,1,1,1,0,0,0,0,1,1],
[0,1,1,1,1,1,1,1,1,1,1,0],
[0,1,1,1,1,1,1,1,1,1,1,0],
[0,0,1,1,1,1,1,1,1,1,0,0],
[0,0,0,0,1,1,1,1,0,0,0,0],
]
let idTimeout = null;
function icon (icon, x, y, size, gap) {
const color = g.getColor();
for (let r=0; r<icon.length; r++) {
for (let c=0; c<icon[r].length; c++) {
if (icon[r][c]===1){
g.setColor(color);
g.fillRect(c * size + x, r * size + y, (c+1) * size - gap + x, (r+1)*size - gap + y);
g.setColor('#fff');
g.drawLine(c * size + x + size/2 - 1, r * size + y + size/2 - 1, c * size + x + size/2 - 1, r * size + y + size/2 - 1, )
}
}
}
g.setColor(color);
}
function ohmA(x, y) {
g.setColor('#666');
g.fillRect(x, y, x+8, y+15);
g.setColor('#00f');
g.drawLine(x, y + 4, x + 8, y + 4);
g.setColor('#f00');
g.drawLine(x, y + 6, x + 8, y + 6);
g.setColor('#0f0');
g.drawLine(x, y + 8, x + 8, y + 8);
}
function ohmB(x, y) {
g.setColor('#666');
g.fillRect(x, y, x+15, y+8);
g.setColor('#00f');
g.drawLine(x + 4, y + 8, x + 4, y);
g.setColor('#f00');
g.drawLine(x + 6, y + 8, x + 6, y);
g.setColor('#0f0');
g.drawLine(x + 8, y + 8, x + 8, y);
}
function heart (x, y) {
g.setColor('#000');
g.fillRect(x-2, y-2, x + 32, y + 32)
g.setColor('#666');
g.drawRect(x-2, y-2, x + 32, y + 32)
g.setColor('#f00');
icon(icoH, x, y, 4, 2);
}
function resin() {
let d = Date();
let h = d.getHours();
let m = d.getMinutes();
const resinPosX = 25;
const resinPosY = 130;
g.setColor('#000');
g.fillRect(resinPosX - 3, resinPosY - 3, Bangle.appRect.w - resinPosX + 2, resinPosY + 40);
g.setColor('#666');
g.drawRect(resinPosX - 3, resinPosY - 3, Bangle.appRect.w - resinPosX + 2, resinPosY + 40);
g.setColor('#6ff');
icon(icoR, resinPosX, resinPosY, 3, 1);
g.setFont('6x8', 5);
g.setFontAlign(-1, -1);
g.drawString('_' + (m<10?'0':'')+m, resinPosX + 40, resinPosY - 5);
g.setFontAlign(1, -1);
g.setFont('6x8', 2);
g.drawString(h, resinPosX + 66, resinPosY);
}
function screw(x, y) {
g.setColor('#666').fillCircle(x, y, 4).setColor('#000').drawLine(x - 4, y, x + 4, y)
}
function led(x,y) {
g.setColor('#0f0').fillCircle(x, y, 8).setColor('#fff').fillCircle(x-3, y-3, 3);
}
function drawTime() {
const R = Bangle.appRect;
g.setBgColor('#000');
g.clear();
Bangle.drawWidgets();
g.reset();
// pcb
g.setColor('#030').fillRect(R.x, R.y, R.x2, R.y2);
screw(R.x + 8, R.y + 8)
screw(R.x2 - 8, R.y + 8)
screw(R.x + 8, R.y2 - 8)
screw(R.x2 - 8, R.y2 - 8)
for(let i=0; i<6; i++) {
g.setColor('#fff');
g.drawLine(24 + i * 9, 70, 24 + i * 9, 110);
g.drawLine(24 + i * 9, 110, 54 + i * 9, 140);
}
ohmA(29, 90);
ohmA(56, 90);
ohmB(80, 90);
screw(90, 110)
// led
led(50, R.y+10);
led(70, R.y+10);
ohmB(20, R.y + 10);
ohmB(90, R.y + 2);
ohmB(90, R.y + 14);
heart(10, 52);
heart(50, 52);
heart(90, 52);
g.setColor('#666');
for (let i=0; i<6; i++) {
g.fillCircle(110 + i*10, 80+10, 3);
g.fillCircle(110 + i*10, 110+10, 3);
}
g.setColor('#000');
g.fillRect(110, 80+10, 170, 110+10);
g.setColor('#666');
g.drawRect(110, 80+10, 170, 110+10);
g.setFont('6x8').setColor('#666').drawString('AH-118080\n0WT 18-001', 112, 85+10);
resin();
let d = Date();
let t = d.getSeconds()*1000 + d.getMilliseconds();
idTimeout = setTimeout(drawTime, 60000 - t); // time till next minute
}
// special function to handle display switch on
Bangle.on('lcdPower', function(on){
if (on) {
drawTime();
} else {
if(idTimeout) {
clearTimeout(idTimeout);
}
}
});
// Show launcher when button pressed
Bangle.setUI("clock");
Bangle.loadWidgets();
drawTime();

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwkAqoA/AHlUmYADC69FC601C600C60yC6x4SAANTPCgyFkowTSCgACkZ4TAAVDPCwvCPCaqEPCSnDPCZeDmc0Uyh4TqQXFPCBGEPCQWFPCClEPCSlDmjZDdiUlMYZ4NIwg0EPBpGEDoh4NIIYpCPCDqGMoUydh4oDPB5GGPCBGGG4h4CGQ6HDN4gIEqkjSY4+DBYreDSZINDHYpoDKYw9FTww5DC5BGJPAg8MQQw6DBpBGJWIsyCwtUkQABZhA7CkjYKfJIsGAB9UCqgA/ACQ"))

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

View File

@ -0,0 +1,17 @@
{
"id": "alyxclock",
"name": "Alyx Clock",
"version": "0.01",
"description": "A clock in the style of half-life alyx gravity gloves",
"icon": "alyxclock.png",
"screenshots": [{"url":"screenshot_alyxclock.png"}],
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS2"],
"readme": "README.md",
"allow_emulator": true,
"storage": [
{"name":"alyxclock.app.js","url":"alyxclock.app.js"},
{"name":"alyxclock.img","url":"alyxclock.icon.js","evaluate":true}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,3 +1,5 @@
0.01: New App!
0.02: New config options such as step, meridian, short/long formats, custom prefix/suffix
0.03: Allows showing the month in short or long format by setting `"shortMonth"` to true or false
0.04: Improves touchscreen drag handling for background apps such as Pattern Launcher
0.05: Fixes step count not resetting after a new day starts

View File

@ -4,6 +4,7 @@
* 1. Module dependencies and initial configurations
* ---------------------------------------------------------------
*/
let storage = require("Storage");
let locale = require("locale");
let widgets = require("widget_utils");
@ -30,6 +31,7 @@
* 2. Graphical and visual configurations
* ---------------------------------------------------------------
*/
let w = g.getWidth();
let h = g.getHeight();
let totalWidth, totalHeight;
@ -40,6 +42,7 @@
* 3. Touchscreen Handlers
* ---------------------------------------------------------------
*/
let touchHandler;
let dragHandler;
let movementDistance = 0;
@ -49,6 +52,7 @@
* 4. Font loading function
* ---------------------------------------------------------------
*/
let loadCustomFont = function() {
Graphics.prototype.setFontBrunoAce = function() {
// Actual height 23 (24 - 2)
@ -66,6 +70,7 @@
* 5. Initial settings of boxes and their positions
* ---------------------------------------------------------------
*/
for (let key in boxesConfig) {
if (key === 'bg' && boxesConfig[key].img) {
bgImage = storage.read(boxesConfig[key].img);
@ -167,6 +172,7 @@
* 7. String forming helper functions
* ---------------------------------------------------------------
*/
let isBool = function(val, defaultVal) {
return typeof val !== 'undefined' ? Boolean(val) : defaultVal;
};
@ -211,6 +217,7 @@
* 8. Main draw function
* ---------------------------------------------------------------
*/
let draw = (function() {
let updatePerMinute = true; // variable to track the state of time display
@ -242,7 +249,7 @@
boxes.batt.string = modString(boxes.batt, E.getBattery());
}
if (boxes.step) {
boxes.step.string = modString(boxes.step, Bangle.getStepCount());
boxes.step.string = modString(boxes.step, Bangle.getHealthStatus("day").steps);
}
boxKeys.forEach((boxKey) => {
let boxItem = boxes[boxKey];
@ -272,6 +279,7 @@
* 9. Helper function for touch event
* ---------------------------------------------------------------
*/
let touchInText = function(e, boxItem, boxKey) {
calcBoxSize(boxItem);
const pos = calcBoxPos(boxKey);
@ -296,6 +304,7 @@
* 10. Setup function to configure event handlers
* ---------------------------------------------------------------
*/
let setup = function() {
// ------------------------------------
// Define the touchHandler function
@ -343,6 +352,8 @@
// Define the dragHandler function
// ------------------------------------
dragHandler = function(e) {
// Check if any box is being dragged
if (!Object.values(isDragging).some(Boolean)) return;
// Calculate the movement distance
movementDistance += Math.abs(e.dx) + Math.abs(e.dy);
// Check if the movement distance exceeds a threshold
@ -396,6 +407,7 @@
* 11. Main execution part
* ---------------------------------------------------------------
*/
Bangle.loadWidgets();
widgets.swipeOn();
modSetColor();

View File

@ -1,7 +1,7 @@
{
"id": "boxclk",
"name": "Box Clock",
"version": "0.03",
"version": "0.05",
"description": "A customizable clock with configurable text boxes that can be positioned to show your favorite background",
"icon": "app.png",
"screenshots": [

View File

@ -5,6 +5,7 @@
"icon": "app.png",
"type": "clkinfo",
"tags": "clkinfo,sunrise",
"dependencies": {"mylocation":"app"},
"supports" : ["BANGLEJS2"],
"storage": [
{"name":"sunrise.clkinfo.js","url":"clkinfo.js"}

View File

@ -7,3 +7,4 @@ Addict.
0.06: Add compatibility with Fastload Utils.
0.07: Remove just the specific listeners to not interfere with Quick Launch
when fastloading.
0.08: Issue newline before GB commands (solves issue with console.log and ignored commands)

View File

@ -144,6 +144,7 @@ let simpleSearchTerm = function() { // input a simple search term without tags,
let searchPlayWOTags = function() { //make a search and play using entered terms
searchString = simpleSearch;
Bluetooth.println("");
Bluetooth.println(JSON.stringify({
t: "intent",
action: "android.media.action.MEDIA_PLAY_FROM_SEARCH",
@ -157,6 +158,7 @@ let searchPlayWOTags = function() { //make a search and play using entered terms
};
let gadgetbridgeWake = function() {
Bluetooth.println("");
Bluetooth.println(JSON.stringify({
t: "intent",
target: "activity",
@ -174,6 +176,7 @@ let actFn = function(actName, activOrServ) {
// Send the intent message to Gadgetbridge
let btMsg = function(activOrServ, cls, actName, xtra) {
Bluetooth.println("");
Bluetooth.println(JSON.stringify({
t: "intent",
action: actFn(actName, activOrServ),

View File

@ -2,7 +2,7 @@
"id": "podadrem",
"name": "Podcast Addict Remote",
"shortName": "PA Remote",
"version": "0.07",
"version": "0.08",
"description": "Control Podcast Addict on your android device.",
"readme": "README.md",
"type": "app",

View File

@ -2,4 +2,4 @@
0.02: Rebasing on latest changes to showScroller_Q3 (https://github.com/espruino/Espruino/commit/2d3c34ef7c2b9fe2118e816aacd2e096adb99596).
0.03: Rebasing on latest changes to showScroller_Q3 (https://github.com/espruino/Espruino/commit/b6f8105b6348bb6f7cd03ac11efc1f3585c6ad79). Ensure that changing a menu item when half-scrolled off screen doesn't overwrite widgets.
0.04: Rebasing on latest changes to showScroller_Q3 (https://github.com/espruino/Espruino/commit/a0e2d9231df709849f81abf572a742b0fceab85b). Fixes missing `isActive` function that caused an error.
0.05: Fix for the rebase in ver 0.04. Check boxes didn't behave but now they do.

View File

@ -1,4 +1,4 @@
E.showScroller = (function(options) {
E.showScroller = (function(options) {
/* options = {
h = height
c = # of items
@ -19,20 +19,20 @@ E.showScroller = (function(options) {
*/
if (!options) return Bangle.setUI(); // remove existing handlers
var touchHandler = (_,e)=>{
if (e.y<R.y-4) return;
var i = YtoIdx(e.y);
if ((menuScrollMin<0 || i>=0) && i<options.c){
let yAbs = (e.y + rScroll - R.y);
let yInElement = yAbs - i*options.h;
options.select(i, {x:e.x, y:yInElement});
}
var draw = () => {
g.reset().clearRect(R).setClipRect(R.x,R.y,R.x2,R.y2);
var a = YtoIdx(R.y);
var b = Math.min(YtoIdx(R.y2),options.c-1);
for (var i=a;i<=b;i++)
options.draw(i, {x:R.x,y:idxToY(i),w:R.w,h:options.h});
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
};
Bangle.setUI({
mode : "custom",
back : options.back,
remove : options.remove,
redraw : draw,
swipe : (_,UD)=>{
pixels = 120;
var dy = UD*pixels;
@ -45,13 +45,13 @@ Bangle.setUI({
rScroll = s.scroll &~1;
dy = oldScroll-rScroll;
if (!dy || options.c<=3) return; //options.c<=3 should maybe be dynamic, so 3 would be replaced by a variable dependent on R=Bangle.appRect. It's here so we don't try to scroll if all entries fit in the app rectangle.
g.reset().setClipRect(R.x,R.y,R.x2,R.y2);
g.scroll(0,dy);
g.reset().setClipRect(R.x,R.y,R.x2,R.y2).scroll(0,dy);
var d = UD*pixels;
if (d < 0) {
g.setClipRect(R.x,R.y2-(1-d),R.x2,R.y2);
let i = YtoIdx(R.y2-(1-d));
let y = idxToY(i);
let y = Math.max(R.y2-(1-d), R.y);
g.setClipRect(R.x,y,R.x2,R.y2);
let i = YtoIdx(y);
y = idxToY(i);
//print(i, options.c, options.c-i); //debugging info
while (y < R.y2 - (options.h*((options.c-i)<=0)) ) { //- (options.h*((options.c-i)<=0)) makes sure we don't go beyond the menu entries in the menu object "options". This has to do with "dy = s.scroll - menuScrollMax-8" above.
options.draw(i, {x:R.x,y:y,w:R.w,h:options.h});
@ -59,10 +59,10 @@ Bangle.setUI({
y += options.h;
}
} else { // d>0
g.setClipRect(R.x,R.y,R.x2,R.y+d);
let i = YtoIdx(R.y+d);
let y = idxToY(i);
//print(i, options.c, options.c-i); //debugging info
let y = Math.min(R.y+d, R.y2);
g.setClipRect(R.x,R.y,R.x2,y);
let i = YtoIdx(y);
y = idxToY(i);
while (y > R.y-options.h) {
options.draw(i, {x:R.x,y:y,w:R.w,h:options.h});
y -= options.h;
@ -70,7 +70,15 @@ Bangle.setUI({
}
}
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
}, touch : touchHandler
}, touch : (_,e)=>{
if (e.y<R.y-4) return;
var i = YtoIdx(e.y);
if ((menuScrollMin<0 || i>=0) && i<options.c){
let yAbs = (e.y + rScroll - R.y);
let yInElement = yAbs - i*options.h;
options.select(i, {x:e.x, y:yInElement});
}
}
});
var menuShowing = false;
@ -87,24 +95,16 @@ function idxToY(i) {
function YtoIdx(y) {
return Math.floor((y + rScroll - R.y)/options.h);
}
var s = {
scroll : E.clip(0|options.scroll,menuScrollMin,menuScrollMax),
draw : () => {
g.reset().clearRect(R.x,R.y,R.x2,R.y2);
g.setClipRect(R.x,R.y,R.x2,R.y2);
var a = YtoIdx(R.y);
var b = Math.min(YtoIdx(R.y2),options.c-1);
for (var i=a;i<=b;i++)
options.draw(i, {x:R.x,y:idxToY(i),w:R.w,h:options.h});
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
}, drawItem : i => {
var y = idxToY(i);
g.reset().setClipRect(R.x,Math.max(y,R.y),R.x2,Math.min(y+options.h,R.y2));
options.draw(i, {x:R.x,y:y,w:R.w,h:options.h});
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
}, isActive : () => Bangle.touchHandler == touchHandler
};
draw : draw, drawItem : i => {
var y = idxToY(i);
g.reset().setClipRect(R.x,Math.max(y,R.y),R.x2,Math.min(y+options.h,R.y2));
options.draw(i, {x:R.x,y:y,w:R.w,h:options.h});
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
}, isActive : () => Bangle.uiRedraw == draw
};
var rScroll = s.scroll&~1; // rendered menu scroll (we only shift by 2 because of dither)
s.draw(); // draw the full scroller
g.flip(); // force an update now to make this snappier

View File

@ -1,7 +1,7 @@
{
"id": "swscroll",
"name": "Swipe menus",
"version": "0.04",
"version": "0.05",
"description": "Replace built in E.showScroller to act on swipe instead of drag. Navigate menus in discrete steps instead of a continuous motion.",
"readme": "README.md",
"icon": "app.png",