Merge remote-tracking branch 'upstream/master'
|
@ -0,0 +1,9 @@
|
|||
Copyright 2019 Gordon Williams, Pur3 Ltd
|
||||
|
||||
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.
|
||||
|
||||
|
215
README.md
|
@ -3,16 +3,16 @@ Bangle.js App Loader (and Apps)
|
|||
|
||||
Try it live at [banglejs.com/apps](https://banglejs.com/apps)
|
||||
|
||||
### How does it work?
|
||||
## How does it work?
|
||||
|
||||
* A list of apps is in `apps.json`
|
||||
* Each element references an app in `apps/` which is uploaded
|
||||
* Each element references an app in `apps/<id>` which is uploaded
|
||||
* When it starts, BangleAppLoader checks the JSON and compares
|
||||
it with the files it sees in the watch's storage.
|
||||
* To upload an app, BangleAppLoader checks the files that are
|
||||
listed in `apps.json`, loads them, and sends them over Web Bluetooth.
|
||||
|
||||
### What filenames are used
|
||||
## What filenames are used
|
||||
|
||||
Filenames in storage are limited to 8 characters. To
|
||||
easily distinguish between file types, we use the following:
|
||||
|
@ -22,15 +22,21 @@ easily distinguish between file types, we use the following:
|
|||
* `-stuff` is JS code
|
||||
* `=stuff` is JS code for stuff that is run at boot time - eg. handling settings or creating widgets on the clock screen
|
||||
|
||||
### Developing your own app
|
||||
## Developing your own app
|
||||
|
||||
* Head over to [the Web IDE](https://www.espruino.com/ide/) and ensure `Save on Send` in settings set to the *default setting* of `To RAM`
|
||||
* We'd recommend that you start off using code from 'Example Applications' (below) to get started...
|
||||
* Load [`app.js`](apps/_example_app/app.js) or [`widget.js`](apps/_example_widget/widget.js) into the IDE and start developing.
|
||||
* The `Upload` button will load your app to Bangle.js temporarily
|
||||
|
||||
## Adding your app to the menu
|
||||
|
||||
* Start writing your code in the IDE, with `Save on Send` in settings set to
|
||||
the *default* of `To RAM`
|
||||
* When you have your app as you want it, add it as a file in `apps/`, lets assume `apps/my-great-app.js`
|
||||
* Come up with a unique 7 character name, we'll assume `7chname`
|
||||
* Create `apps/my-great-app.png` as a 48px icon
|
||||
* Use http://www.espruino.com/Image+Converter to create as 1 bit, 4 bit or 8 bit Web Palette "Image String" and save it as `apps/my-great-app-icon.js`
|
||||
* Create an entry in `apps/my-great-app.json` as follows:
|
||||
* Create a folder called `apps/<id>`, lets assume `apps/7chname`
|
||||
* We'd recommend that you copy files from 'Example Applications' (below) as a base, or...
|
||||
* `apps/7chname/app.png` should be a 48px icon
|
||||
* Use http://www.espruino.com/Image+Converter to create `apps/7chname/app-icon.js`, using a 1 bit, 4 bit or 8 bit Web Palette "Image String"
|
||||
* Create an entry in `apps/7chname/app.json` as follows:
|
||||
|
||||
```
|
||||
{
|
||||
|
@ -40,23 +46,117 @@ the *default* of `To RAM`
|
|||
}
|
||||
```
|
||||
|
||||
* Create an entry in `apps.json` as follows:
|
||||
* Create an entry in `apps.json` as follows:
|
||||
|
||||
```
|
||||
{ "id": "7chname",
|
||||
"name": "My app's human readable name",
|
||||
"icon": "my-great-app.png",
|
||||
"icon": "app.png",
|
||||
"description": "A detailed description of my great app",
|
||||
"tags": "",
|
||||
"storage": [
|
||||
{"name":"+7chname","url":"my-great-app.json"},
|
||||
{"name":"-7chname","url":"my-great-app.js"},
|
||||
{"name":"*7chname","url":"my-great-app.js","evaluate":true}
|
||||
{"name":"+7chname","url":"app.json"},
|
||||
{"name":"-7chname","url":"app.js"},
|
||||
{"name":"*7chname","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
},
|
||||
```
|
||||
|
||||
### `apps.json` format
|
||||
## Testing
|
||||
|
||||
### Online
|
||||
|
||||
This is the best way to test...
|
||||
|
||||
* Fork the https://github.com/espruino/BangleApps git repository
|
||||
* Add your files
|
||||
* Go to GitHub Settings and activate GitHub Pages
|
||||
* Run your personal `Bangle App Loader` at https://\<your-github-username\>.github.io/BangleApps/index.html to load apps onto your device
|
||||
* Your apps should be inside it - if there are problems, check your web browser's 'developer console' for errors
|
||||
|
||||
Be aware of the delay between commits and updates on github.io - it can take a few minutes (and a 'hard refresh' of your browser) for changes to take effect.
|
||||
|
||||
### Offline
|
||||
|
||||
You can add the following to the Espruino Web IDE:
|
||||
|
||||
```
|
||||
// replace with your 7chname app name
|
||||
var appname = "mygreat";
|
||||
|
||||
require("Storage").write('*'+appname,
|
||||
// place app-icon.js contents here
|
||||
);
|
||||
|
||||
//
|
||||
require("Storage").write("+"+appname,{
|
||||
"name":"My Great App","type":"",
|
||||
"icon":"*"+appname,
|
||||
"src":"-"+appname,
|
||||
});
|
||||
|
||||
require("Storage").write("-"+appname,`
|
||||
// place contents of app.js here
|
||||
// be aware of double-quoting templated strings
|
||||
`
|
||||
```
|
||||
|
||||
When you upload code this way, your app will be uploaded to Bangle.js's menu
|
||||
without you having to use the `Bangle App Loader`
|
||||
|
||||
## Example Applications
|
||||
|
||||
To make the process easier we've come up with some example applications that you can use as a base
|
||||
when creating your own. Just come up with a unique 7 character name, copy `apps/_example_app`
|
||||
or `apps/_example_widget` to `apps/7chname`, and add `apps/_example_X/add_to_apps.json` to
|
||||
`apps.json`.
|
||||
|
||||
### App Example
|
||||
|
||||
The app example is available in [`apps/_example_app`](apps/_example_app)
|
||||
|
||||
Apps are listed in the Bangle.js menu, accessible from a clock app via the middle button.
|
||||
|
||||
* `add_to_apps.json` - insert into `apps.json`, describes the widget to bootloader and loader
|
||||
* `app.png` - app icon - 48x48px
|
||||
* `app-icon.js` - JS version of the icon (made with http://www.espruino.com/Image+Converter) for use in Bangle.js's menu
|
||||
* `app.json` - short app name for Bangle.js menu and storage filenames
|
||||
* `app.js` - app code
|
||||
|
||||
#### `app-icon.js`
|
||||
|
||||
The icon image and short description is used in the menu entry as selection posibility.
|
||||
|
||||
Use the Espruino [image converter](https://www.espruino.com/Image+Converter) and upload your `app.png` file.
|
||||
|
||||
Follow this steps to create a readable icon as image string.
|
||||
|
||||
1. upload a png file
|
||||
2. set _X_ Use Compression
|
||||
3. set _X_ Transparency (optional)
|
||||
4. set Diffusion: _flat_
|
||||
5. set Colours: _1 bit_, _4 bit_ or _8 bit Web Palette_
|
||||
6. set Output as: _Image String_
|
||||
|
||||
Replace this line with the image converter output:
|
||||
|
||||
```
|
||||
require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="));
|
||||
```
|
||||
|
||||
Keep in mind to use this converter for creating images you like to draw with `g.drawImage()` with your app.
|
||||
|
||||
|
||||
### Widget Example
|
||||
|
||||
The widget example is available in [`apps/_example_widget`](apps/_example_widget)
|
||||
|
||||
* `add_to_apps.json` - insert into `apps.json`, describes the widget to bootloader and loader
|
||||
* `widget.json` - short widget name and storage names
|
||||
* `widget.js` - widget code
|
||||
|
||||
|
||||
## `apps.json` format
|
||||
|
||||
```
|
||||
{ "id": "appid", // 7 character app id
|
||||
|
@ -84,6 +184,87 @@ the *default* of `To RAM`
|
|||
}
|
||||
```
|
||||
|
||||
### Credits
|
||||
* name, icon and description present the app in the app loader.
|
||||
* tags is used for grouping apps in the library, separate multiple entries by comma. Known tags are `tool`, `system`, `clock`, `game`, `sound`, `gps`, `widget` or empty.
|
||||
* storage is used to identify the app files and how to handle them
|
||||
|
||||
## Coding hints
|
||||
|
||||
- use `g.setFont(.., size)` to multiply the font size, eg ("6x8",3) : "18x24"
|
||||
|
||||
- use `g.drawString(text,x,y,true)` to draw with background color to overwrite existing text
|
||||
|
||||
- use `g.clearRect()` to clear parts of the screen, instead of using `g.clear()`
|
||||
|
||||
- use `g.fillPoly()` or `g.drawImage()` for complex graphic elements
|
||||
|
||||
- using `g.clear()` can cause screen flicker
|
||||
|
||||
- using `g.setLCDBrightness()` can save you power during long periods with lcd on
|
||||
|
||||
- chaining graphics methodes, eg `g.setColor(0xFD20).setFontAlign(0,0).setfont("6x8",3)`
|
||||
|
||||
### Graphic areas
|
||||
|
||||
The screen is parted in a widget and app area for lcd mode `direct`(default).
|
||||
|
||||
| areas | as rectangle or point |
|
||||
| :-:| :-: |
|
||||
| Widget | (0,0,239,23) |
|
||||
| Apps | (0,24,239,239) |
|
||||
| BTN1 | (230, 55) |
|
||||
| BTN2 | (230, 140) |
|
||||
| BTN3 | (230, 210) |
|
||||
| BTN4 | (0,0,119, 239)|
|
||||
| BTN5 | (120,0,239,239) |
|
||||
|
||||
- Use `g.setFontAlign(0, 0, 3)` to draw rotated string to BTN1-BTN3 with `g.drawString()`.
|
||||
|
||||
- For BTN4-5 the touch area is named
|
||||
|
||||
## Available colors
|
||||
|
||||
Yuu can use `g.setColor(r,g,b)` OR `g.setColor(16bitnumber)` - some common 16 bit colors are below:
|
||||
|
||||
| color-name | color-value|
|
||||
| :-: | :-: |
|
||||
| Black | 0x0000 |
|
||||
| Navy | 0x000F |
|
||||
| DarkGreen | 0x03E0 |
|
||||
| DarkCyan | 0x03EF |
|
||||
| Maroon | 0x7800 |
|
||||
| Purple | 0x780F |
|
||||
| Olive | 0x7BE0
|
||||
| LightGray | 0xC618
|
||||
| DarkGrey | 0x7BEF
|
||||
| Blue | 0x001F
|
||||
| Green | 0x07E0 |
|
||||
| Cyan | 0x07FF |
|
||||
| RED | 0xF800 |
|
||||
| Magenta | 0xF81F |
|
||||
| Yellow | 0xFFE0 |
|
||||
| White | 0xFFFF |
|
||||
| Orange | 0xFD20 |
|
||||
| GreenYellow | 0xAFE5 |
|
||||
| Pink | 0xF81F |
|
||||
|
||||
## API Reference
|
||||
|
||||
[Reference](http://www.espruino.com/Reference#software)
|
||||
|
||||
[Bangle Class](https://banglejs.com/reference#Bangle)
|
||||
|
||||
[Graphics Class](https://banglejs.com/reference#Graphics)
|
||||
|
||||
|
||||
## 'Testing' folder
|
||||
|
||||
The [`testing`](testing) folder contains snippets of code that might be useful for your apps.
|
||||
|
||||
* `testing/colors.js` - 16 bit colors as name value pairs
|
||||
* `testing/gpstrack.js` - code to store a GPS track in Bagle.js storage and output it back to the console
|
||||
* `testing/map` - code for splitting an image into map tiles and then displaying them
|
||||
|
||||
## Credits
|
||||
|
||||
The majority of icons used for these apps are from [Icons8](https://icons8.com/) - we have a commercial license but icons are also free for Open Source projects.
|
||||
|
|
|
@ -10,7 +10,7 @@ var AppInfo = {
|
|||
if (storageFile.content)
|
||||
return Promise.resolve(storageFile);
|
||||
else if (storageFile.url)
|
||||
return fileGetter("apps/"+storageFile.url).then(content => {
|
||||
return fileGetter(`apps/${app.id}/${storageFile.url}`).then(content => {
|
||||
return {
|
||||
name : storageFile.name,
|
||||
content : content,
|
||||
|
|
25
apps.json
|
@ -502,5 +502,30 @@
|
|||
{"name": "-gpsinfo","url": "gps-info.js"},
|
||||
{"name": "*gpsinfo","url": "gps-info-icon.js","evaluate": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "promodo",
|
||||
"name":"Promodoro",
|
||||
"icon":"promodoro.png",
|
||||
"description": "A simple promodoro timer.",
|
||||
"tags": "promodoro,cooking,tools",
|
||||
"type": "app",
|
||||
"storage": [
|
||||
{"name": "+promodo","url": "promodoro.json"},
|
||||
{"name": "-promodo","url": "promodoro.js"},
|
||||
{"name": "*promodo","url": "promodoro-icon.js","evaluate": true}
|
||||
]
|
||||
},
|
||||
{ "id": "blobclk",
|
||||
"name": "Large Digit Clock",
|
||||
"icon": "clock-blob.png",
|
||||
"description": "A clock with big digits",
|
||||
"tags": "clock",
|
||||
"type":"clock",
|
||||
"storage": [
|
||||
{"name":"+blobclk","url":"clock-blob.json"},
|
||||
{"name":"-blobclk","url":"clock-blob.js"},
|
||||
{"name":"*blobclk","url":"clock-blob-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,12 @@
|
|||
// Create an entry in apps.json as follows:
|
||||
{ "id": "7chname",
|
||||
"name": "My app's human readable name",
|
||||
"icon": "app.png",
|
||||
"description": "A detailed description of my great app",
|
||||
"tags": "",
|
||||
"storage": [
|
||||
{"name":"+7chname","url":"app.json"},
|
||||
{"name":"-7chname","url":"app.js"},
|
||||
{"name":"*7chname","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="));
|
|
@ -0,0 +1,15 @@
|
|||
(() => {
|
||||
|
||||
// place your const, vars, functions or classes here
|
||||
|
||||
|
||||
// special function to handle display switch on
|
||||
Bangle.on('lcdPower', (on) => {
|
||||
if (on) {
|
||||
// call your app function here
|
||||
}});
|
||||
|
||||
g.clear();
|
||||
// call your app function here
|
||||
|
||||
})();
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name":"Short Name",
|
||||
"icon":"*7chname",
|
||||
"src":"-7chname"
|
||||
}
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,11 @@
|
|||
// Create an entry in apps.json as follows:
|
||||
{ "id": "7chname",
|
||||
"name": "My widget's human readable name",
|
||||
"icon": "widget.png",
|
||||
"description": "A detailed description of my great widget",
|
||||
"tags": "",
|
||||
"storage": [
|
||||
{"name":"+7chname","url":"widget.json"},
|
||||
{"name":"-7chname","url":"widget.js"},
|
||||
],
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
(() => {
|
||||
|
||||
// add the width
|
||||
var xpos = WIDGETPOS.tr-<the widget width>;
|
||||
WIDGETPOS.tr-=<the widget width plus some extra pixel to keep distance to others>;
|
||||
|
||||
// draw your widget at xpos
|
||||
function draw() {
|
||||
|
||||
// add your code
|
||||
|
||||
}
|
||||
|
||||
// add your widget
|
||||
WIDGETS["mywidget"]={draw:draw};
|
||||
|
||||
})()
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name":"widgetname", "type":"widget",
|
||||
"src":"-7chname"
|
||||
}
|
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 743 B After Width: | Height: | Size: 743 B |
|
@ -1,7 +1,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
|
||||
<link rel="stylesheet" href="../css/spectre.min.css">
|
||||
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||
</head>
|
||||
<style>
|
||||
body {
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwhC/AH4AUmYAOCw0DC58wFyowHC/4X/C9mIxAGKC5IPBCIoXWnAXOB4ODAQQXTGQQXCJoyPMC4ggDC6IVBC6JKFC6JZDC6SODCgQXQFwalCSAoXJXAgXSdo4XOCIi/CL54XvABwX/C/4XtgYWPmAXFGCAWGAH4A/ABgA="))
|
|
@ -0,0 +1,108 @@
|
|||
(function(){
|
||||
const buf = Graphics.createArrayBuffer(144,200,1,{msb:true});
|
||||
const NUMBERS = [
|
||||
[1,1,1,1,3,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1],//0
|
||||
[0,1,1,1,3,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1],//1
|
||||
[1,1,1,1,3,0,0,1,1,1,2,1,1,1,4,1,1,1,0,0,1,1,1,1,1],//2
|
||||
[1,1,1,1,3,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1],//3
|
||||
[1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,5,1,1,1,1,0,0,1,1,1],//4
|
||||
[1,1,1,1,1,1,1,1,0,0,5,1,1,1,3,0,0,1,1,1,1,1,1,1,1],//5
|
||||
[1,1,1,1,1,1,1,1,0,0,1,1,1,1,3,1,1,0,1,1,1,1,1,1,1],//6
|
||||
[1,1,1,1,3,0,0,1,1,1,0,2,1,1,1,0,1,1,1,0,0,1,1,1,0],//7
|
||||
[1,1,1,1,3,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1],//8
|
||||
[1,1,1,1,3,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1] //9
|
||||
];
|
||||
let intervalRef = null;
|
||||
let digits = [-1,-1,-1,-1,-1,-1];
|
||||
function flip() {
|
||||
g.setColor(1,1,1);
|
||||
g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},55,26);
|
||||
try { if (drawWidgets) { drawWidgets();} } catch(err) {}
|
||||
}
|
||||
function drawPixel(ox,oy,x,y,r,p) {
|
||||
let x1 = ox+x*(r*2+1);
|
||||
let y1 = oy+y*(r*2+1);
|
||||
let xmid = x1+r;
|
||||
let ymid = y1+r;
|
||||
let x2 = xmid+r;
|
||||
let y2 = ymid+r;
|
||||
if (p > 0) {
|
||||
if (p > 1) {
|
||||
buf.setColor(0,0,0);
|
||||
buf.fillRect(x1,y1,x2,y2);
|
||||
}
|
||||
buf.setColor(1,1,1);
|
||||
} else {
|
||||
buf.setColor(0,0,0);
|
||||
}
|
||||
if (p < 2) {
|
||||
buf.fillRect(x1,y1,x2,y2);
|
||||
} else if (p === 2) {
|
||||
buf.fillPoly([xmid,y1,x2,y1,x2,y2,x1,y2,x1,ymid]);
|
||||
} else if (p === 3) {
|
||||
buf.fillPoly([x1,y1,xmid,y1,x2,ymid,x2,y2,x1,y2]);
|
||||
} else if (p === 4) {
|
||||
buf.fillPoly([x1,y1,x2,y1,x2,ymid,xmid,y2,x1,y2]);
|
||||
} else if (p === 5) {
|
||||
buf.fillPoly([x1,y1,x2,y1,x2,y2,xmid,y2,x1,ymid]);
|
||||
}
|
||||
}
|
||||
function redraw() {
|
||||
let time = new Date();
|
||||
let hours = time.getHours();
|
||||
let mins = time.getMinutes();
|
||||
let secs = time.getSeconds();
|
||||
|
||||
let newDigits = [Math.floor(hours/10),hours%10,Math.floor(mins/10),mins%10,Math.floor(secs/10),secs%10];
|
||||
|
||||
for (var p = 0;p<25;p++) {
|
||||
var px = p%5;
|
||||
var py = Math.floor(p/5);
|
||||
if (digits[0] === -1 || NUMBERS[newDigits[0]][p] !== NUMBERS[digits[0]][p] ) {
|
||||
drawPixel(0,20,px,py,6,NUMBERS[newDigits[0]][p]);
|
||||
}
|
||||
if (digits[1] === -1 || NUMBERS[newDigits[1]][p] !== NUMBERS[digits[1]][p] ) {
|
||||
drawPixel(78,20,px,py,6,NUMBERS[newDigits[1]][p]);
|
||||
}
|
||||
if (digits[2] === -1 || NUMBERS[newDigits[2]][p] !== NUMBERS[digits[2]][p] ) {
|
||||
drawPixel(0,92,px,py,6,NUMBERS[newDigits[2]][p]);
|
||||
}
|
||||
if (digits[3] === -1 || NUMBERS[newDigits[3]][p] !== NUMBERS[digits[3]][p] ) {
|
||||
drawPixel(78,92,px,py,6,NUMBERS[newDigits[3]][p]);
|
||||
}
|
||||
if (digits[4] === -1 || NUMBERS[newDigits[4]][p] !== NUMBERS[digits[4]][p] ) {
|
||||
drawPixel(69,164,px,py,3,NUMBERS[newDigits[4]][p]);
|
||||
}
|
||||
if (digits[5] === -1 || NUMBERS[newDigits[5]][p] !== NUMBERS[digits[5]][p] ) {
|
||||
drawPixel(108,164,px,py,3,NUMBERS[newDigits[5]][p]);
|
||||
}
|
||||
}
|
||||
digits = newDigits;
|
||||
flip();
|
||||
}
|
||||
function clearTimers() {
|
||||
if(intervalRef) {clearInterval(intervalRef);}
|
||||
}
|
||||
function startTimers() {
|
||||
g.clear();
|
||||
digits = [-1,-1,-1,-1,-1,-1];
|
||||
intervalRef = setInterval(redraw,1000);
|
||||
redraw();
|
||||
}
|
||||
startTimers();
|
||||
Bangle.on('lcdPower',function(on) {
|
||||
if (on) {
|
||||
g.clear();
|
||||
startTimers();
|
||||
try { if (drawWidgets) { drawWidgets();} } catch(err) {}
|
||||
} else {
|
||||
clearTimers();
|
||||
}
|
||||
});
|
||||
Bangle.on('faceUp',function(up){
|
||||
if (up && !Bangle.isLCDOn()) {
|
||||
clearTimers();
|
||||
Bangle.setLCDPower(true);
|
||||
}
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name":"Large Clock",
|
||||
"type":"clock",
|
||||
"icon":"*blobclk",
|
||||
"src":"-blobclk",
|
||||
"sortorder":-10
|
||||
}
|
After Width: | Height: | Size: 817 B |
|
@ -101,12 +101,28 @@ if (startapp) {
|
|||
function drawWidgets() {
|
||||
for (var w of WIDGETS) w.draw();
|
||||
}
|
||||
var clockApps = require("Storage").list().filter(a=>a[0]=='+').map(app=>{
|
||||
try { return require("Storage").readJSON(app); }
|
||||
catch (e) {}
|
||||
}).filter(app=>app.type=="clock").sort((a, b) => a.sortorder - b.sortorder);
|
||||
if (clockApps && clockApps.length > 0) eval(require("Storage").read(clockApps[0].src));
|
||||
var settings;
|
||||
try {
|
||||
settings = require("Storage").readJSON('@setting');
|
||||
} catch (e) {
|
||||
settings = {}
|
||||
}
|
||||
var clockApp = settings.clock;
|
||||
if (clockApp) {
|
||||
clockApp = require("Storage").read(clockApp)
|
||||
}
|
||||
if (!clockApp) {
|
||||
var clockApps = require("Storage").list().filter(a=>a[0]=='+').map(app=>{
|
||||
try { return require("Storage").readJSON(app); }
|
||||
catch (e) {}
|
||||
}).filter(app=>app.type=="clock").sort((a, b) => a.sortorder - b.sortorder);
|
||||
if (clockApps && clockApps.length > 0) {
|
||||
clockApp = require("Storage").read(clockApps[0].src);
|
||||
}
|
||||
}
|
||||
if (clockApp) eval(clockApp);
|
||||
else E.showMessage("No Clock Found");
|
||||
|
||||
delete clockApps;
|
||||
require("Storage").list().filter(a=>a[0]=='=').forEach(widget=>eval(require("Storage").read(widget)));
|
||||
setTimeout(drawWidgets,100);
|
Before Width: | Height: | Size: 741 B After Width: | Height: | Size: 741 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 303 B After Width: | Height: | Size: 303 B |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 617 B After Width: | Height: | Size: 617 B |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 506 B After Width: | Height: | Size: 506 B |
Before Width: | Height: | Size: 506 B After Width: | Height: | Size: 506 B |
Before Width: | Height: | Size: 632 B After Width: | Height: | Size: 632 B |