Merge branch 'espruino:master' into master

pull/2211/head
jukioo 2022-11-02 12:38:46 +02:00 committed by GitHub
commit 1a33dff88a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 176 additions and 48 deletions

View File

@ -56,4 +56,6 @@
0.50: Allow setting of screen rotation
Remove support for 2v11 and earlier firmware
0.51: Remove patches for 2v10 firmware (BEEPSET and setUI)
Add patch to ensure that compass heading is corrected
Add patch to ensure that compass heading is corrected on pre-2v15.68 firmware
Ensure clock is only fast-loaded if it doesn't contain widgets
0.52: Ensure heading patch for pre-2v15.68 firmware applies to getCompass

View File

@ -1,5 +1,10 @@
// This runs after a 'fresh' boot
var s = require("Storage").readJSON("setting.json",1)||{};
/* If were being called from JS code in order to load the clock quickly (eg from a launcher)
and the clock in question doesn't have widgets, force a normal 'load' as this will then
reset everything and remove the widgets. */
if (global.__FILE__ && !s.clockHasWidgets) {load();throw "Clock has no widgets, can't fast load";}
// Otherwise continue to try and load the clock
var _clkApp = require("Storage").read(s.clock);
if (!_clkApp) {
_clkApp = require("Storage").list(/\.info$/)
@ -13,7 +18,8 @@ if (!_clkApp) {
.sort((a, b) => a.sortorder - b.sortorder)[0];
if (_clkApp){
s.clock = _clkApp.src;
_clkApp = require("Storage").read(_clkApp.src);
_clkApp = require("Storage").read(_clkApp.src);
s.clockHasWidgets = _clkApp.includes("Bangle.loadWidgets");
require("Storage").writeJSON("setting.json", s);
}
}

View File

@ -79,7 +79,8 @@ if (s.rotate) boot+=`g.setRotation(${s.rotate&3},${s.rotate>>2});\n` // screen r
// ================================================== FIXING OLDER FIRMWARES
// 2v15.68 and before had compass heading inverted.
if (process.version.replace("v","")<215.68)
boot += `Bangle.on('mag',e=>{if(!isNaN(e.heading)) e.heading=360-e.heading;});`;
boot += `Bangle.on('mag',e=>{if(!isNaN(e.heading))e.heading=360-e.heading;});
Bangle.getCompass=(c=>(()=>{e=c();if(!isNaN(e.heading))e.heading=360-e.heading;return e;}))(Bangle.getCompass);`;
// ================================================== BOOT.JS
// Append *.boot.js files

View File

@ -1,7 +1,7 @@
{
"id": "boot",
"name": "Bootloader",
"version": "0.51",
"version": "0.52",
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
"icon": "bootloader.png",
"type": "bootloader",

View File

@ -7,3 +7,4 @@
0.07: Read app icons on demand
Add swipe-to-exit
0.08: Only use fast loading for switching to clock to prevent problems in full screen apps
0.09: Remove fast load option since clocks containing Bangle.loadWidgets are now always normally loaded

View File

@ -10,7 +10,3 @@ This launcher shows 9 apps per screen, making it much faster to navigate versus
## Technical note
The app uses `E.showScroller`'s code in the app but not the function itself because `E.showScroller` doesn't report the position of a press to the select function.
### Fastload option
Fastload clears up the memory used by the launcher and directly evals the code of the clock to load.

View File

@ -1,6 +1,6 @@
{
const s = require("Storage");
const settings = s.readJSON("launch.json", true) || { showClocks: true, fullscreen: false,direct:false,swipeExit:false,oneClickExit:false,fastload:false };
const settings = s.readJSON("launch.json", true) || { showClocks: true, fullscreen: false,direct:false,swipeExit:false,oneClickExit:false};
if (!settings.fullscreen) {
Bangle.loadWidgets();
Bangle.drawWidgets();
@ -180,24 +180,20 @@
};
const returnToClock = function() {
if (settings.fastload == true){
Bangle.setUI();
delete launchCache;
delete launchHash;
delete drawItemAuto;
delete drawText;
delete selectItem;
delete onDrag;
delete drawItems;
delete drawItem;
delete returnToClock;
delete idxToY;
delete YtoIdx;
delete settings;
setTimeout(eval, 0, s.read(".bootcde"));
} else {
load();
}
Bangle.setUI();
delete launchCache;
delete launchHash;
delete drawItemAuto;
delete drawText;
delete selectItem;
delete onDrag;
delete drawItems;
delete drawItem;
delete returnToClock;
delete idxToY;
delete YtoIdx;
delete settings;
setTimeout(eval, 0, s.read(".bootcde"));
};

View File

@ -2,7 +2,7 @@
"id": "iconlaunch",
"name": "Icon Launcher",
"shortName" : "Icon launcher",
"version": "0.08",
"version": "0.09",
"icon": "app.png",
"description": "A launcher inspired by smartphones, with an icon-only scrollable menu.",
"tags": "tool,system,launcher",

View File

@ -5,8 +5,7 @@
fullscreen: false,
direct: false,
oneClickExit: false,
swipeExit: false,
fastload: false
swipeExit: false
}, require("Storage").readJSON("launch.json", true) || {});
let fonts = g.getFonts();
@ -36,10 +35,6 @@
/*LANG*/"Swipe exit": {
value: settings.swipeExit == true,
onchange: m => { save("swipeExit", m) }
},
/*LANG*/"Fastload": {
value: settings.fastload == true,
onchange: (m) => { save("fastload", m) }
}
};
E.showMenu(appMenu);

View File

@ -66,7 +66,7 @@ E.showScroller({
});
g.flip(); // force a render before widgets have finished drawing
function returnToClock() {
let returnToClock = function() {
// unload everything manually
// ... or we could just call `load();` but it will be slower
Bangle.setUI(); // remove scroller's handling
@ -85,7 +85,7 @@ if (process.env.HWVERSION==2) {
// 10s of inactivity goes back to clock
Bangle.setLocked(false); // unlock initially
let lockTimeout;
function lockHandler(locked) {
let lockHandler = function(locked) {
if (lockTimeout) clearTimeout(lockTimeout);
lockTimeout = undefined;
if (locked)

View File

@ -57,4 +57,4 @@
0.50: Add Bangle.js 2 touchscreen calibration - for 2v16 or 2v15 cutting edge builds
0.51: Add setting for configuring a launcher
0.52: Add option for left-handed users
0.53: Ensure that when clock is set, clockHasWidgets is set correctly too

View File

@ -1,7 +1,7 @@
{
"id": "setting",
"name": "Settings",
"version": "0.52",
"version": "0.53",
"description": "A menu for setting up Bangle.js",
"icon": "settings.png",
"tags": "tool,system",

View File

@ -39,6 +39,7 @@ function resetSettings() {
timezone: 0, // Set the timezone for the device
HID: false, // BLE HID mode, off by default
clock: null, // a string for the default clock's name
// clockHasWidgets: false, // Does the clock in 'clock' contain the string 'Bangle.loadWidgets'
"12hour" : false, // 12 or 24 hour clock?
firstDayOfWeek: 0, // 0 -> Sunday (default), 1 -> Monday
brightness: 1, // LCD brightness from 0 to 1
@ -674,11 +675,10 @@ function showClockMenu() {
label = "* " + label;
}
clockMenu[label] = () => {
if (settings.clock !== app.src) {
settings.clock = app.src;
updateSettings();
showMainMenu();
}
settings.clock = app.src;
settings.clockHasWidgets = require("Storage").read(app.src).includes("Bangle.loadWidgets");
updateSettings();
showMainMenu();
};
});
if (clockApps.length === 0) {
@ -703,11 +703,9 @@ function showLauncherMenu() {
label = "* " + label;
}
launcherMenu[label] = () => {
if (settings.launcher !== app.src) {
settings.launcher = app.src;
updateSettings();
showMainMenu();
}
settings.launcher = app.src;
updateSettings();
showMainMenu();
};
});
if (launcherApps.length === 0) {

View File

@ -0,0 +1 @@
0.01: New App!

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEw4X/AAMfBIWSyhL/ACkD1cAlWq1WABYk6BYnABQcO1QLa3//FwgLEHIoABlQLO3WsBZHqHYwLGEooLF0ALHnW/BZMDDII8DmoLDAAILDmtVBZHV+oLEmEA1Ws6vAgNVh5EB+Eq/2lq4cCqqPBIYMqytVoALCioLD6tVBYMDqALEr4KBqotBqkAgsP/9VvkMhoLBhoLCKwQrCIoQLCBQITBM4QPB+ALBFYYLBhpHDBY0BIoILFuEPBYNcBY1XP4fAmgLENIYDBI4JGCNIlXqp3CCof/F4UPIIILEI4wtEIQVwAYIzCO4oLCSgIXFqpfCIwjTBCQXAEQgA/AAoA="))

117
apps/slopeclock/app.js Normal file
View File

@ -0,0 +1,117 @@
Graphics.prototype.setFontPaytoneOne = function(scale) {
// Actual height 81 (91 - 11)
this.setFontCustom(
E.toString(require('heatshrink').decompress(atob('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'))),
46,
atob("ITZOMzs7SDxHNUdGIQ=="),
113+(scale<<8)+(1<<16)
);
return this;
};
{ // must be inside our own scope here so that when we are unloaded everything disappears
// we also define functions using 'let fn = function() {..}' for the same reason. function decls are global
let drawTimeout;
let g2 = Graphics.createArrayBuffer(g.getWidth(),90,1,{msb:true});
let g2img = {
width:g2.getWidth(), height:g2.getHeight(), bpp:1,
buffer:g2.buffer, transparent:0
};
const slope = 20;
const offsy = 20; // offset of numbers from middle
const fontBorder = 4; // offset from left/right
const slopeBorder = 10, slopeBorderUpper = 4; // fudge-factor to move minutes down from slope
let R,x,y; // middle of the clock face
let dateStr = "";
let bgColors = g.theme.dark ? ["#ff0","#0ff","#f0f"] : ["#f00","#0f0","#00f"];
let bgColor = bgColors[(Math.random()*bgColors.length)|0];
// Draw the hour, and the minute into an offscreen buffer
let draw = function() {
R = Bangle.appRect;
x = R.w / 2;
y = R.y + R.h / 2 - 12; // 12 = room for date
var date = new Date();
var hourStr = date.getHours();
var minStr = date.getMinutes().toString().padStart(2,0);
dateStr = require("locale").dow(date, 1).toUpperCase()+ " "+
require("locale").date(date, 0).toUpperCase();
// Draw hour
g.reset().clearRect(R); // clear whole background (w/o widgets)
g.setFontAlign(-1, 0).setFont("PaytoneOne");
g.drawString(hourStr, fontBorder, y-offsy);
// add slope in background color
g.setColor(g.theme.bg).fillPoly([0,y+slope-slopeBorderUpper, R.w,y-slope-slopeBorderUpper,
R.w,y-slope, 0,y+slope]);
// Draw minute to offscreen buffer
g2.setColor(0).fillRect(0,0,g2.getWidth(),g2.getHeight()).setFontAlign(1, 0).setFont("PaytoneOne");
g2.setColor(1).drawString(minStr, g2.getWidth()-fontBorder, g2.getHeight()/2);
g2.setColor(0).fillPoly([0,0, g2.getWidth(),0, 0,slope*2]);
// start the animation *in*
animate(true);
// queue next draw
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
animate(false, function() {
draw();
});
}, 60000 - (Date.now() % 60000));
};
let isAnimIn = true;
let animInterval;
// Draw *just* the minute image
let drawMinute = function() {
var yo = slopeBorder + offsy + y - 2*slope*minuteX/R.w;
// draw over the slanty bit
g.setColor(bgColor).fillPoly([0,y+slope, R.w,y-slope, R.w,R.h+R.y, 0,R.h+R.y]);
// draw the minutes
g.setColor(g.theme.bg).drawImage(g2img, x+minuteX-(g2.getWidth()/2), yo-(g2.getHeight()/2));
};
let animate = function(isIn, callback) {
if (animInterval) clearInterval(animInterval);
isAnimIn = isIn;
minuteX = isAnimIn ? -g2.getWidth() : 0;
drawMinute();
animInterval = setInterval(function() {
minuteX += 8;
let stop = false;
if (isAnimIn && minuteX>=0) {
minuteX=0;
stop = true;
} else if (!isAnimIn && minuteX>=R.w)
stop = true;
drawMinute();
if (stop) {
clearInterval(animInterval);
animInterval=undefined;
if (callback) callback();
if (isAnimIn) {
// draw the date
g.setColor(g.theme.bg).setFontAlign(0, 0).setFont("6x15").drawString(dateStr, R.x + R.w/2, R.y+R.h-9);}
}
}, 20);
};
// Show launcher when middle button pressed
Bangle.setUI({
mode : "clock",
remove : function() {
// Called to unload all of the clock app
if (animInterval) clearInterval(animInterval);
animInterval = undefined;
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
delete Graphics.prototype.setFontPaytoneOne;
}});
// Load widgets
Bangle.loadWidgets();
draw();
setTimeout(Bangle.drawWidgets,0);
}

BIN
apps/slopeclock/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,14 @@
{ "id": "slopeclock",
"name": "Slope Clock",
"version":"0.01",
"description": "A clock where hours and minutes are divided by a sloping line. When the minute changes, the numbers slide off the screen",
"icon": "app.png",
"screenshots": [{"url":"screenshot.png"}],
"type": "clock",
"tags": "clock",
"supports" : ["BANGLEJS2"],
"storage": [
{"name":"slopeclock.app.js","url":"app.js"},
{"name":"slopeclock.img","url":"app-icon.js","evaluate":true}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB