From 59cc57a75a66b08a633f8c410ba5ccd2cb2a9d39 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 26 Nov 2019 10:27:31 +0000 Subject: [PATCH] merge skeleton README into original README, and make example apps so you can just copy the folder --- README.md | 212 +++++++++++- .../_example_app/add_to_apps.json | 8 +- .../_example_app/app-icon.js | 0 .../_example_app/app.js | 0 .../_example_app/app.json | 0 apps/_example_app/app.png | Bin 0 -> 1620 bytes .../_example_widget/add_to_apps.json | 6 +- .../_example_widget/widget.js | 0 .../_example_widget/widget.json | 0 apps/_example_widget/widget.png | Bin 0 -> 1620 bytes skeleton/README.md | 302 ------------------ skeleton/wrap_my-great-app.js | 15 - {skeleton => testing}/colors.js | 0 13 files changed, 203 insertions(+), 340 deletions(-) rename skeleton/add_my-great-app_to_apps.json => apps/_example_app/add_to_apps.json (50%) rename skeleton/my-great-app-icon.js => apps/_example_app/app-icon.js (100%) rename skeleton/my-great-app.js => apps/_example_app/app.js (100%) rename skeleton/my-great-app.json => apps/_example_app/app.json (100%) create mode 100644 apps/_example_app/app.png rename skeleton/add_my-great-widget_to_apps.json => apps/_example_widget/add_to_apps.json (59%) rename skeleton/my-great-widget.js => apps/_example_widget/widget.js (100%) rename skeleton/my-great-widget.json => apps/_example_widget/widget.json (100%) create mode 100644 apps/_example_widget/widget.png delete mode 100644 skeleton/README.md delete mode 100644 skeleton/wrap_my-great-app.js rename {skeleton => testing}/colors.js (100%) diff --git a/README.md b/README.md index cdbc7b24d..ee1173ffe 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ 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 @@ -12,7 +12,7 @@ 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,16 +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` * Come up with a unique 7 character name, we'll assume `7chname` -* When you have your app as you want it, add it as a file in `apps/`, lets assume `apps/7chname/my-great-app.js` -* Create `apps/7chname/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/7chname/my-great-app-icon.js` -* Create an entry in `apps/7chname/my-great-app.json` as follows: +* Create a folder called `apps/`, 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: ``` { @@ -46,18 +51,112 @@ as `apps/7chname/my-great-app-icon.js` ``` { "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-icon.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://\.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 @@ -85,6 +184,87 @@ as `apps/7chname/my-great-app-icon.js` } ``` -### 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. diff --git a/skeleton/add_my-great-app_to_apps.json b/apps/_example_app/add_to_apps.json similarity index 50% rename from skeleton/add_my-great-app_to_apps.json rename to apps/_example_app/add_to_apps.json index dd49bca18..941880a65 100644 --- a/skeleton/add_my-great-app_to_apps.json +++ b/apps/_example_app/add_to_apps.json @@ -1,12 +1,12 @@ // 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-icon.js","evaluate":true} + {"name":"+7chname","url":"app.json"}, + {"name":"-7chname","url":"app.js"}, + {"name":"*7chname","url":"app-icon.js","evaluate":true} ], } diff --git a/skeleton/my-great-app-icon.js b/apps/_example_app/app-icon.js similarity index 100% rename from skeleton/my-great-app-icon.js rename to apps/_example_app/app-icon.js diff --git a/skeleton/my-great-app.js b/apps/_example_app/app.js similarity index 100% rename from skeleton/my-great-app.js rename to apps/_example_app/app.js diff --git a/skeleton/my-great-app.json b/apps/_example_app/app.json similarity index 100% rename from skeleton/my-great-app.json rename to apps/_example_app/app.json diff --git a/apps/_example_app/app.png b/apps/_example_app/app.png new file mode 100644 index 0000000000000000000000000000000000000000..582cb2e0853a5a2899a3afbd7eb19cde2ee7f6a0 GIT binary patch literal 1620 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 S(*#!l0000 { - - // section for const and vars if needed - - ... - - // section for functions, classes - - ... - - function < your main function > () { - - ... - - } - - // special function to handle display switch on - Bangle.on('lcdPower', (on) => { - if (on) { - (); - }}); - - // clear screen and launch - g.clear(); - (); - -})(); -``` - -If you like store and restore data with your app, than use the prefix _@_ and your _7chname_, eg _@mygreat_ as name. - -Make sure to read [Coding Hints](#coding-hints). - -### my-great-app.png - -The png file is displayed in the app loader next to the app name. - -Use your favorite icon creator and go for a 48x48 png file. - -Check avaiable colors to draw a fancy colored icon for your app. - -### my-great-app-icon.js - -The icon image and short description is used in the menue entry as selection posibility. - -Use the Espruino [image converter](https://www.espruino.com/Image+Converter) and upload your my-great-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 -4. set Defusion: _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. - -## Files for WIDGET's - -To write a widget you need a few files in folder apps and add a few lines of JSON to file apps.json - -Be aware of this: Widgets are not listed as menue entry. - -### add\_my-great-app\_to\_apps.json - -``` -{ "id": "7chname", - "name": "My widget's human readable name", - "icon": "my-great-widget.png", - "description": "A detailed description of my great widget", - "tags": "widget", - "storage": [ - {"name":"+7chname","url":"my-great-widget.json"}, - {"name":"-7chname","url":"my-great-widget.js"}, - ], -}, -``` -### my-great-widget.js - -Write your widget code as encapsulation using anonymous functions with private functional scope. - -``` -(() => { - - // add the width - var xpos = WIDGETPOS.tr-; - WIDGETPOS.tr-=; - - // draw your widget at xpos - function draw() { - - // add your code - - } - - // add your widget - WIDGETS["mywidget"]={draw:draw}; - -})() -``` - -### my-great-widget.png - -Same as my-great-app.png - -### my-great-widget-icon.js - -Same as my-great-app-icon.png - - -## App development and testing - -Use the wrapper technic from file `wrap_my-great-app.js`, copy paste your code and upload Espruino via Web IDE - -Todo: add a wrapper script for this - -``` -// replace with your 7chname app name -var appname = "mygreat"; - -require("Storage").write('*'+appname,` - // place out of image conterver here -`); - -// -require("Storage").write("+"+appname,{ - "name":"My Great App","type":"", - "icon":"*"+appname, - "src":"-"+appname, -}); - -require("Storage").write("-"+appname,` -// place content of my-great-app.json here -` -``` - -Or fork BANGLEJS, got Setting and activate GitHub Pages and you are good to run your personal `Bangle App Launcher` (https://\.github.io/BangleApps/index.html). - -Now you can use the `Bangle App Launcher` to upload and test you new app - -Be aware of the delay between commit and avaiable on github.io - -##### One way to develop and test your work - -1. Use WebIDE for the development -2. Wrap code and run tests on device -3. Run final test with personal `Bangle App Launcher` - -## Appendex - -### API Reference - -[Reference](http://www.espruino.com/Reference#software) - -[Bangle Class](https://banglejs.com/reference#Bangle) - -[Graphics Class](https://banglejs.com/reference#Graphics) - -### Coding hints - -- use `g.setFont(.., size)` to multiply the font size, eg ("6x8",3) : "18x24" - -- use `g.drawString(..,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 - -| 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 | - - - - diff --git a/skeleton/wrap_my-great-app.js b/skeleton/wrap_my-great-app.js deleted file mode 100644 index de910b3a7..000000000 --- a/skeleton/wrap_my-great-app.js +++ /dev/null @@ -1,15 +0,0 @@ -var appname = 'mygreat'; - -require("Storage").write('*'+appname,` - -`); - -require("Storage").write('+'+appname,{ - "name":"My Great App","type":"", - "icon":"*"+appname, - "src":"-"+appname, -}); - -require("Storage").write("-"+appname,` - -` diff --git a/skeleton/colors.js b/testing/colors.js similarity index 100% rename from skeleton/colors.js rename to testing/colors.js