Merge pull request #7 from espruino/master

Update nujw repo before making changes
master
nujw 2025-03-18 16:11:47 +13:00 committed by GitHub
commit 4572081fa6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4280 changed files with 214849 additions and 19521 deletions

View File

@ -1,6 +1,8 @@
apps/animclk/V29.LBM.js
apps/banglerun/rollup.config.js # Needs to be ignored because it uses ESM export/import
apps/schoolCalendar/fullcalendar/main.js apps/gipy/pkg/gps.js
apps/authentiwatch/qr_packed.js apps/gipy/pkg/gps.d.ts
apps/qrcode/qr-scanner.umd.min.js apps/gipy/pkg/gps_bg.wasm.d.ts
*.test.js
# Needs to be ignored because it includes broken JS
apps/health/chart.min.js

250
.eslintrc.js Normal file
View File

@ -0,0 +1,250 @@
const lintExemptions = require("./apps/lint_exemptions.js");
const fs = require("fs");
const path = require("path");
function findGeneratedJS(roots) {
function* listFiles(dir, allow) {
for (const f of fs.readdirSync(dir)) {
const filepath = path.join(dir, f);
const stat = fs.statSync(filepath);
if (stat.isDirectory()) {
yield* listFiles(filepath, allow);
} else if(allow(filepath)) {
yield filepath;
}
}
}
return roots.flatMap(root =>
[...listFiles(root, f => f.endsWith(".ts"))]
.map(f => f.replace(/\.ts$/, ".js"))
);
}
module.exports = {
"env": {
// TODO: "espruino": false
// TODO: "banglejs": false
// For a prototype of the above, see https://github.com/espruino/BangleApps/pull/3237
},
"extends": "eslint:recommended",
"globals": {
// Methods and Fields at https://banglejs.com/reference
"Array": "readonly",
"ArrayBuffer": "readonly",
"ArrayBufferView": "readonly",
"Bangle": "readonly",
"BluetoothDevice": "readonly",
"BluetoothRemoteGATTCharacteristic": "readonly",
"BluetoothRemoteGATTServer": "readonly",
"BluetoothRemoteGATTService": "readonly",
"Boolean": "readonly",
"console": "readonly",
"DataView": "readonly",
"Date": "readonly",
"E": "readonly",
"Error": "readonly",
"Flash": "readonly",
"Float32Array": "readonly",
"Float64Array": "readonly",
"Function": "readonly",
"Graphics": "readonly",
"I2C": "readonly",
"Int16Array": "readonly",
"Int32Array": "readonly",
"Int8Array": "readonly",
"InternalError": "readonly",
"JSON": "readonly",
"Math": "readonly",
"Modules": "readonly",
"NRF": "readonly",
"Number": "readonly",
"Object": "readonly",
"OneWire": "readonly",
"Pin": "readonly",
"process": "readonly",
"Promise": "readonly",
"ReferenceError": "readonly",
"RegExp": "readonly",
"Serial": "readonly",
"SPI": "readonly",
"StorageFile": "readonly",
"String": "readonly",
"SyntaxError": "readonly",
"TFMicroInterpreter": "readonly",
"TypeError": "readonly",
"Uint16Array": "readonly",
"Uint24Array": "readonly",
"Uint32Array": "readonly",
"Uint8Array": "readonly",
"Uint8ClampedArray": "readonly",
"Unistroke": "readonly",
"Waveform": "readonly",
// Methods and Fields at https://banglejs.com/reference
"__FILE__": "readonly",
"analogRead": "readonly",
"analogWrite": "readonly",
"arguments": "readonly",
"atob": "readonly",
"Bluetooth": "readonly",
"BTN": "readonly",
"BTN1": "readonly",
"BTN2": "readonly",
"BTN3": "readonly",
"BTN4": "readonly",
"BTN5": "readonly",
"btoa": "readonly",
"changeInterval": "readonly",
"clearInterval": "readonly",
"clearTimeout": "readonly",
"clearWatch": "readonly",
"decodeURIComponent": "readonly",
"digitalPulse": "readonly",
"digitalRead": "readonly",
"digitalWrite": "readonly",
"dump": "readonly",
"echo": "readonly",
"edit": "readonly",
"encodeURIComponent": "readonly",
"eval": "readonly",
"getPinMode": "readonly",
"getSerial": "readonly",
"getTime": "readonly",
"global": "readonly",
"globalThis": "readonly",
"HIGH": "readonly",
"I2C1": "readonly",
"Infinity": "readonly",
"isFinite": "readonly",
"isNaN": "readonly",
"LED": "readonly",
"LED1": "readonly",
"LED2": "readonly",
"load": "readonly",
"LoopbackA": "readonly",
"LoopbackB": "readonly",
"LOW": "readonly",
"NaN": "readonly",
"parseFloat": "readonly",
"parseInt": "readonly",
"peek16": "readonly",
"peek32": "readonly",
"peek8": "readonly",
"pinMode": "readonly",
"poke16": "readonly",
"poke32": "readonly",
"poke8": "readonly",
"print": "readonly",
"require": "readonly",
"reset": "readonly",
"save": "readonly",
"Serial1": "readonly",
"setBusyIndicator": "readonly",
"setInterval": "readonly",
"setSleepIndicator": "readonly",
"setTime": "readonly",
"setTimeout": "readonly",
"setWatch": "readonly",
"shiftOut": "readonly",
"SPI1": "readonly",
"Terminal": "readonly",
"trace": "readonly",
"VIBRATE": "readonly",
// Aliases and not defined at https://banglejs.com/reference
"g": "readonly",
"WIDGETS": "readonly",
"module": "readonly",
"exports": "writable",
"D0": "readonly",
"D1": "readonly",
"D2": "readonly",
"D3": "readonly",
"D4": "readonly",
"D5": "readonly",
"D6": "readonly",
"D7": "readonly",
"D8": "readonly",
"D9": "readonly",
"D10": "readonly",
"D11": "readonly",
"D12": "readonly",
"D13": "readonly",
"D14": "readonly",
"D15": "readonly",
"D16": "readonly",
"D17": "readonly",
"D18": "readonly",
"D19": "readonly",
"D20": "readonly",
"D21": "readonly",
"D22": "readonly",
"D23": "readonly",
"D24": "readonly",
"D25": "readonly",
"D26": "readonly",
"D27": "readonly",
"D28": "readonly",
"D29": "readonly",
"D30": "readonly",
"D31": "readonly",
"bleServiceOptions": "writable", // available in boot.js code that's called ad part of bootupdate
},
"parserOptions": {
"ecmaVersion": 11
},
"rules": {
"indent": [
"off",
2,
{
"SwitchCase": 1
}
],
"no-constant-condition": "off",
"no-delete-var": "off",
"no-empty": ["warn", { "allowEmptyCatch": true }],
"no-global-assign": "off",
"no-inner-declarations": "off",
"no-prototype-builtins": "off",
"no-redeclare": "off",
"no-unreachable": "warn",
"no-cond-assign": "warn",
"no-useless-catch": "warn",
"no-undef": "warn",
"no-unused-vars": ["warn", { "args": "none" } ],
"no-useless-escape": "off",
"no-control-regex" : "off"
},
overrides: [
{
files: ["*.ts"],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
rules: {
"no-delete-var": "off",
"no-empty": ["error", { "allowEmptyCatch": true }],
"no-prototype-builtins": "off",
"prefer-const": "off",
"prefer-rest-params": "off",
"no-control-regex" : "off",
"@typescript-eslint/no-delete-var": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-this-alias": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-var-requires": "off",
}
},
...Object.entries(lintExemptions).map(([filePath, {rules}]) => ({
files: [filePath],
rules: Object.fromEntries(rules.map(rule => [rule, "off"])),
})),
],
ignorePatterns: findGeneratedJS(["apps/", "modules/"]),
reportUnusedDisableDirectives: true,
}

12
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: espruino
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['http://www.espruino.com/Donate']# Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@ -58,3 +58,7 @@ body:
validations: validations:
required: true required: true
- type: textarea
id: apps
attributes:
label: Installed apps

9
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: "gitsubmodule"
directory: "/"
schedule:
interval: "daily"
reviewers:
- "gfwilliams"

View File

@ -1,4 +1,4 @@
name: Node CI name: build
on: [push, pull_request] on: [push, pull_request]
@ -6,29 +6,22 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
steps: steps:
- name: Checkout repository and submodules - name: Checkout repository and submodules
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js 18.x
uses: actions/setup-node@v1 uses: actions/setup-node@v3
with: with:
node-version: ${{ matrix.node-version }} node-version: 18.x
- name: install testing dependencies - name: Install testing dependencies
run: npm i run: npm ci
- name: test all apps and widgets - name: Test all apps and widgets
run: npm run test run: npm test
- name: install typescript dependencies - name: Install typescript dependencies
working-directory: ./typescript working-directory: ./typescript
run: npm ci run: npm ci
- name: build types - name: Build all TS apps and widgets
working-directory: ./typescript
run: npm run build:types
- name: build all TS apps and widgets
working-directory: ./typescript working-directory: ./typescript
run: npm run build run: npm run build

5
.gitignore vendored
View File

@ -1,6 +1,5 @@
.htaccess .htaccess
node_modules node_modules
package-lock.json
.DS_Store .DS_Store
*.js.bak *.js.bak
appdates.csv appdates.csv
@ -12,3 +11,7 @@ tests/Layout/testresult.bmp
apps.local.json apps.local.json
_site _site
.jekyll-cache .jekyll-cache
.owncloudsync.log
Desktop.ini
.sync_*.db*
*.swp

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "EspruinoAppLoaderCore"] [submodule "EspruinoAppLoaderCore"]
path = core path = core
url = https://github.com/espruino/EspruinoAppLoaderCore.git url = https://github.com/espruino/EspruinoAppLoaderCore.git
[submodule "webtools"]
path = webtools
url = https://github.com/espruino/EspruinoWebTools.git

9
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,9 @@
Contributing to BangleApps
==========================
https://github.com/espruino/BangleApps?tab=readme-ov-file#getting-started
has some links to tutorials on developing for Bangle.js.
Please check out the Wiki to get an idea what sort of things
we'd like to see for contributed apps: https://github.com/espruino/BangleApps/wiki/App-Contribution

View File

@ -1,11 +1,13 @@
Bangle.js App Loader (and Apps) Bangle.js App Loader (and Apps)
================================ ================================
[![Build Status](https://app.travis-ci.com/espruino/BangleApps.svg?branch=master)](https://app.travis-ci.com/github/espruino/BangleApps) [![Build Status](https://github.com/espruino/BangleApps/actions/workflows/nodejs.yml/badge.svg)](https://github.com/espruino/BangleApps/actions/workflows/nodejs.yml)
* Try the **release version** at [banglejs.com/apps](https://banglejs.com/apps) * Try the **release version** at [banglejs.com/apps](https://banglejs.com/apps)
* Try the **development version** at [espruino.github.io](https://espruino.github.io/BangleApps/) * Try the **development version** at [espruino.github.io](https://espruino.github.io/BangleApps/)
The release version is manually refreshed with regular intervals while the development version is continuously updated as new code is committed to this repository.
**All software (including apps) in this repository is MIT Licensed - see [LICENSE](LICENSE)** By **All software (including apps) in this repository is MIT Licensed - see [LICENSE](LICENSE)** By
submitting code to this repository you confirm that you are happy with it being MIT licensed, submitting code to this repository you confirm that you are happy with it being MIT licensed,
and that it is not licensed in another way that would make this impossible. and that it is not licensed in another way that would make this impossible.
@ -98,7 +100,7 @@ This is the best way to test...
**Note:** It's a great idea to get a local copy of the repository on your PC, **Note:** It's a great idea to get a local copy of the repository on your PC,
then run `bin/sanitycheck.js` - it'll run through a bunch of common issues then run `bin/sanitycheck.js` - it'll run through a bunch of common issues
that there might be. that there might be. To get the project running locally, you have to initialize and update the git submodules first: `git submodule update --init`.
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. 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.
@ -191,7 +193,7 @@ widget bar at the top of the screen they can add themselves to the global
``` ```
WIDGETS["mywidget"]={ WIDGETS["mywidget"]={
area:"tl", // tl (top left), tr (top right) area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right)
sortorder:0, // (Optional) determines order of widgets in the same corner sortorder:0, // (Optional) determines order of widgets in the same corner
width: 24, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout width: 24, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout
draw:draw // called to draw the widget draw:draw // called to draw the widget
@ -255,8 +257,11 @@ and which gives information about the app for the Launcher.
// 'app' - an application // 'app' - an application
// 'clock' - a clock - required for clocks to automatically start // 'clock' - a clock - required for clocks to automatically start
// 'widget' - a widget // 'widget' - a widget
// 'module' - this provides a module that can be used with 'require'.
// 'provides_modules' should be used if type:module is specified
// 'bootloader' - an app that at startup (app.boot.js) but doesn't have a launcher entry for 'app.js' // 'bootloader' - an app that at startup (app.boot.js) but doesn't have a launcher entry for 'app.js'
// 'settings' - apps that appear in Settings->Apps (with appname.settings.js) but that have no 'app.js' // 'settings' - apps that appear in Settings->Apps (with appname.settings.js) but that have no 'app.js'
// 'clkinfo' - Provides a 'myapp.clkinfo.js' file that can be used to display info in clocks - see modules/clock_info.js
// 'RAM' - code that runs and doesn't upload anything to storage // 'RAM' - code that runs and doesn't upload anything to storage
// 'launch' - replacement 'Launcher' // 'launch' - replacement 'Launcher'
// 'textinput' - provides a 'textinput' library that allows text to be input on the Bangle // 'textinput' - provides a 'textinput' library that allows text to be input on the Bangle
@ -265,11 +270,28 @@ and which gives information about the app for the Launcher.
// 'notify' - provides 'notify' library for showing notifications // 'notify' - provides 'notify' library for showing notifications
// 'locale' - provides 'locale' library for language-specific date/distance/etc // 'locale' - provides 'locale' library for language-specific date/distance/etc
// (a version of 'locale' is included in the firmware) // (a version of 'locale' is included in the firmware)
"tags": "", // comma separated tag list for searching // 'defaultconfig' - a set of apps that will can be installed and will wipe out all previously installed apps
"tags": "", // comma separated tag list for searching (don't include uppercase or spaces)
// common types are:
// 'clock' - it's a clock
// 'widget' - it is (or provides) a widget
// 'outdoors' - useful for outdoor activities
// 'tool' - a useful utility (timer, calculator, etc)
// 'game' - a game
// 'bluetooth' - uses Bluetooth LE
// 'system' - used by the system
// 'clkinfo' - provides or uses clock_info module for data on your clock face or clocks that support it (see apps/clock_info/README.md)
// 'health' - e.g. heart rate monitors or step counting
"supports": ["BANGLEJS2"], // List of device IDs supported, either BANGLEJS or BANGLEJS2 "supports": ["BANGLEJS2"], // List of device IDs supported, either BANGLEJS or BANGLEJS2
"dependencies" : { "notify":"type" } // optional, app 'types' we depend on (see "type" above) "dependencies" : { "notify":"type" } // optional, app 'types' we depend on (see "type" above)
"dependencies" : { "messages":"app" } // optional, depend on a specific app ID "dependencies" : { "messages":"app" } // optional, depend on a specific app ID
// for instance this will use notify/notifyfs is they exist, or will pull in 'notify' // for instance this will use notify/notifyfs is they exist, or will pull in 'notify'
"dependencies" : { "messageicons":"module" } // optional, depend on a specific library to be used with 'require' - see provides_modules
"dependencies" : { "message":"widget" } // optional, depend on a specific type of widget - see provides_widgets
"provides_modules" : ["messageicons"] // optional, this app provides a module that can be used with 'require'
"provides_widgets" : ["battery"] // optional, this app provides a type of widget - 'alarm/battery/bluetooth/pedometer/message'
"provides_features" : ["welcome"] // optional, this app provides some feature, used to ensure two aren't installed at once. Currently just 'welcome'
"default" : true, // set if an app is the default implementer of something (a widget/module/etc)
"readme": "README.md", // if supplied, a link to a markdown-style text file "readme": "README.md", // if supplied, a link to a markdown-style text file
// that contains more information about this app (usage, etc) // that contains more information about this app (usage, etc)
// A 'Read more...' link will be added under the app // A 'Read more...' link will be added under the app
@ -324,7 +346,7 @@ and which gives information about the app for the Launcher.
``` ```
* name, icon and description present the app in the app loader. * 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`, `launcher` or empty. * tags is used for grouping apps in the library, separate multiple entries by comma. Known tags are `tool`, `system`, `clock`, `game`, `sound`, `gps`, `widget`, `launcher`, `bluetooth` or empty.
* storage is used to identify the app files and how to handle them * storage is used to identify the app files and how to handle them
* data is used to clean up files when the app is uninstalled * data is used to clean up files when the app is uninstalled
@ -385,7 +407,7 @@ in an iframe.
<link rel="stylesheet" href="../../css/spectre.min.css"> <link rel="stylesheet" href="../../css/spectre.min.css">
</head> </head>
<body> <body>
<script src="../../lib/interface.js"></script> <script src="../../core/lib/interface.js"></script>
<div id="t">Loading...</div> <div id="t">Loading...</div>
<script> <script>
function onInit() { function onInit() {
@ -454,7 +476,10 @@ It should also add `myappid.json` to `data`, to make sure it is cleaned up when
## Modules ## Modules
You can include any of [Espruino's modules](https://www.espruino.com/Modules) as You can include any of [Espruino's modules](https://www.espruino.com/Modules) as
normal with `require("modulename")`. If you want to develop your own module for your normal with `require("modulename")`. To include [Bangle's modules](modules) for use in the Web
IDE, [upload the modules to internal storage](modules#upload-the-module-to-the-bangles-internal-storage)
or [change the IDE's search path](modules#change-the-web-ide-search-path-to-include-banglejs-modules).
If you want to develop your own module for your
app(s) then you can do that too. Just add the module into the `modules` folder app(s) then you can do that too. Just add the module into the `modules` folder
then you can use it from your app as normal. then you can use it from your app as normal.
@ -533,6 +558,30 @@ You can use `g.setColor(r,g,b)` OR `g.setColor(16bitnumber)` - some common 16 bi
| GreenYellow | 0xAFE5 | | GreenYellow | 0xAFE5 |
| Pink | 0xF81F | | Pink | 0xF81F |
## Fonts
A recent addition to Bangle.js is the ability to use extra fonts with support for more characters.
For example [all regions](https://banglejs.com/apps/?id=fontall) or [extended](https://banglejs.com/apps/?id=fontext) fonts.
Once installed, these apps cause a new font, `Intl` to be added to `Graphics`, which can be used with just `g.setFont("Intl")`.
There is also a `font` library - this is not implemented yet, but more information about the planned implementation
is available at https://github.com/espruino/BangleApps/issues/3109
For now, to make your app work with the international font, you can check if `Graphics.prototype.setFontIntl` exists,
and if so you can change the font you plan on using:
```JS
myFont = "6x8:2";
if (Graphics.prototype.setFontIntl)
myFont = "Intl";
```
Any new Font library must contain the metadata `"icon": "app.png", "tags": "font", "type": "module", "provides_modules" : ["fonts"],`
and should provide a `font` library, as well as a `boot.js` that adds `Graphics.prototype.setFontIntl`. If you plan on
making a new library it's best to just copy one of the existing ones for now.
## API Reference ## API Reference
[Reference](http://www.espruino.com/Reference#software) [Reference](http://www.espruino.com/Reference#software)

View File

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.8,maximum-scale=0.8, minimum-scale=0.8, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=0.8">
<link rel="stylesheet" href="css/spectre.min.css"> <link rel="stylesheet" href="css/spectre.min.css">
<link rel="stylesheet" href="css/spectre-exp.min.css"> <link rel="stylesheet" href="css/spectre-exp.min.css">
<link rel="stylesheet" href="css/spectre-icons.min.css"> <link rel="stylesheet" href="css/spectre-icons.min.css">
@ -20,12 +20,9 @@
<title>Bangle.js App Loader</title> <title>Bangle.js App Loader</title>
</head> </head>
<body> <body>
<!--<button id="test">Test</button>
<div id="status"></div>-->
<header class="navbar-primary navbar"> <header class="navbar-primary navbar">
<section class="navbar-section" > <section class="navbar-section" >
<a href="https://banglejs.com" target="_blank" class="navbar-brand mr-2" ><img src="img/banglejs-logo-sml.png" alt="Bangle.js"> <a href="https://banglejs.com" target="_blank" class="navbar-brand mr-2"><img src="img/banglejs-logo-small.svg" alt="Bangle.js">
<div>App Loader</div></a> <div>App Loader</div></a>
<!-- <a href="#" class="btn btn-link">...</a> --> <!-- <a href="#" class="btn btn-link">...</a> -->
</section> </section>
@ -76,20 +73,27 @@
</ul> </ul>
</div> </div>
<div class="filter-nav"> <div class="filter-nav">
<label class="chip active" filterid="">Default</label> <label class="chip active" filterid="" data-tooltip="Show all apps">All</label>
<label class="chip" filterid="clock">Clocks</label> <label class="chip tooltip" filterid="clock" data-tooltip="To tell the time!">Clocks</label>
<label class="chip" filterid="game">Games</label> <label class="chip tooltip" filterid="launch" data-tooltip="Choose which apps to launch">Launchers</label>
<label class="chip" filterid="tool">Tools</label> <label class="chip tooltip" filterid="game" data-tooltip="Have fun!">Games</label>
<label class="chip" filterid="widget">Widgets</label> <label class="chip tooltip" filterid="tool" data-tooltip="Useful applications">Tools</label>
<label class="chip" filterid="bluetooth">Bluetooth</label> <label class="chip tooltip" filterid="textinput" data-tooltip="To allow you to enter text">Keyboards</label>
<label class="chip" filterid="outdoors">Outdoors</label> <label class="chip tooltip" filterid="widget" data-tooltip="Appear in the top bar of Bangle.js apps">Widgets</label>
<label class="chip" filterid="favourites">Favourites</label> <label class="chip tooltip" filterid="bluetooth" data-tooltip="Using Bluetooth Functionality">Bluetooth</label>
<label class="chip tooltip" filterid="outdoors" data-tooltip="For outdoor use">Outdoors</label>
<label class="chip tooltip" filterid="ram" data-tooltip="Apps that don't save anything to flash memory">Online</label>
<label class="chip tooltip" filterid="clkinfo" data-tooltip="Info displayed on clocks, or clocks with info">Clock Info</label>
<label class="chip tooltip" filterid="health" data-tooltip="Apps for your health">Health</label>
<label class="chip tooltip" filterid="favourites" data-tooltip="Apps that you've liked ❤️">Favourites</label>
</div> </div>
<div class="sort-nav hidden"> <div class="sort-nav hidden">
<span>Sort by:</span> <span>Sort by:</span>
<label class="chip active" sortid="">None</label> <label class="chip active" sortid="">None</label>
<label class="chip" sortid="created">New</label> <label class="chip hidden tooltip" sortid="created" data-tooltip="Most recent apps">New</label>
<label class="chip" sortid="modified">Updated</label> <label class="chip hidden tooltip" sortid="modified" data-tooltip="Most recently changed">Updated</label>
<label class="chip hidden tooltip" sortid="installs" data-tooltip="Most installed by users">Installed</label>
<label class="chip hidden tooltip" sortid="favourites" data-tooltip="Most liked by users">Favourited</label>
</div> </div>
</div> </div>
@ -130,13 +134,21 @@
<p>Using <a href="https://espruino.com/" target="_blank">Espruino</a>, Icons from <a href="https://icons8.com/" target="_blank">icons8.com</a></p> <p>Using <a href="https://espruino.com/" target="_blank">Espruino</a>, Icons from <a href="https://icons8.com/" target="_blank">icons8.com</a></p>
<h3>Utilities</h3> <h3>Utilities</h3>
<p><button class="btn" id="settime">Set Bangle.js Time</button> <p>
<button class="btn" id="removeall" data-tooltip="Delete everything from your Bangle, leaving it blank">Remove all Apps</button> <button class="btn tooltip" id="settime" data-tooltip="Set the Bangle's time to your Browser's time">Set Bangle.js Time</button>
<button class="btn" id="reinstallall" data-tooltip="Remove and re-install every app, leaving all other data intact">Reinstall apps</button> <button class="btn tooltip" id="screenshot" data-tooltip="Create screenshot">Screenshot</button>
<button class="btn" id="installdefault">Install default apps</button> <button class="btn tooltip" id="downloadallapps" data-tooltip="Download all Bangle.js files to a ZIP file">Backup</button>
<button class="btn" id="installfavourite" data-tooltip="Delete everything, install apps you've marked as favourites">Install favourite apps</button></p> <button class="btn tooltip" id="uploadallapps" data-tooltip="Restore Bangle.js from a ZIP file">Restore</button>
<p><button class="btn tooltip tooltip-right" id="downloadallapps" data-tooltip="Download all Bangle.js files to a ZIP file">Backup</button> </p><p>
<button class="btn tooltip tooltip-right" id="uploadallapps" data-tooltip="Restore Bangle.js from a ZIP file">Restore</button></p> <button class="btn tooltip" id="removeall" data-tooltip="Delete everything, leave it blank">Remove all Apps</button>
<button class="btn tooltip" id="reinstallall" data-tooltip="Re-install every app, leave all data">Reinstall apps</button>
<button class="btn tooltip" id="installdefault" data-tooltip="Delete everything, install default apps">Install default apps</button>
<button class="btn tooltip" id="installfavourite" data-tooltip="Delete everything, install your favourites">Install favourite apps</button>
<button class="btn tooltip" id="defaultbanglesettings" data-tooltip="Reset your Bangle's settings to the defaults">Reset Settings</button>
</p><p>
<button class="btn tooltip" id="newGithubIssue" data-tooltip="Create a new issue on GitHub">New issue on GitHub</button>
<button class="btn tooltip" id="webideremote" data-tooltip="Enable the Web IDE remote server">Web IDE Remote</button>
</p>
<h3>Settings</h3> <h3>Settings</h3>
<div class="form-group"> <div class="form-group">
<label class="form-switch"> <label class="form-switch">
@ -147,22 +159,46 @@
<input type="checkbox" id="settings-settime"> <input type="checkbox" id="settings-settime">
<i class="form-icon"></i> Always update time when we connect <i class="form-icon"></i> Always update time when we connect
</label> </label>
<label class="form-switch">
<input type="checkbox" id="settings-usage-stats">
<i class="form-icon"></i> Send app analytics to banglejs.com (apps installed, favourites, firmware version).<br/>
<small>Used for 'Sort by Installed/Favourited' functionality. See the <a href="http://www.espruino.com/Privacy">privacy policy</a></small>.
</label>
<div class="form-group"> <div class="form-group">
<select class="form-select form-inline" id="settings-lang" style="width: 10em"> <select class="form-select form-inline" id="settings-lang" style="width: 10em">
<option value="">None (English)</option> <option value="">None (English)</option>
</select>&nbsp;&nbsp;<span>Translations (<a href="https://github.com/espruino/BangleApps/issues/1311" target="_blank">BETA - more info</a>). Any apps that are uploaded to Bangle.js after changing this will have any text automatically translated.</span> </select>&nbsp;&nbsp;<span>Translations (<a href="https://github.com/espruino/BangleApps/issues/1311" target="_blank">BETA - more info</a>). Any apps that are uploaded to Bangle.js after changing this will have any text automatically translated.</span>
</div> </div>
<button class="btn" id="defaultsettings">Default settings</button> <details>
<summary>Advanced Options</summary>
<label class="form-switch">
<input type="checkbox" id="settings-minify">
<i class="form-icon"></i> Minify apps before upload (⚠DANGER⚠: Not recommended. Uploads smaller, faster apps but this <b>will</b> break many apps)
</label>
<label class="form-switch">
<input type="checkbox" id="settings-alwaysAllowUpdate">
<i class="form-icon"></i> Always show "reinstall app" button <i class="icon icon-refresh"></i> regardless of the version
</label>
<label class="form-switch">
<input type="checkbox" id="settings-autoReload">
<i class="form-icon"></i> Automatically reload watch after app App Loader actions (removes "Hold button" prompt)
</label>
<button class="btn" id="defaultsettings">Reset App Loader settings to defaults</button>
</details>
</div> </div>
<div id="more-deviceinfo" style="display:none"> <div id="more-deviceinfo" style="display:none">
<h3>Device info</h3> <h3>Device info</h3>
<div id="more-deviceinfo-content"></div> <div id="more-deviceinfo-content"></div>
<div class="editor--terminal">
<div class="editor__canvas" style="position:relative;height:20rem;display:none;"></div>
<button class="btn" id="terminalEnable">Enable Terminal</button>
</div>
</div> </div>
</div> </div>
</div> </div>
<footer class="floating hidden"> <footer class="floating hidden">
<!-- Install button, hidden by default --> <!-- PWA Install button, hidden by default -->
<div id="installContainer" class="hidden"> <div id="installContainer" class="hidden">
<button id="butInstall" type="button"> <button id="butInstall" type="button">
Install Install
@ -170,10 +206,10 @@
</div> </div>
</footer> </footer>
<script src="https://www.puck-js.com/puck.js"></script> <script src="webtools/puck.js"></script>
<script src="webtools/heatshrink.js"></script>
<script src="core/lib/marked.min.js"></script> <script src="core/lib/marked.min.js"></script>
<script src="core/lib/espruinotools.js"></script> <script src="core/lib/espruinotools.js"></script>
<script src="core/lib/heatshrink.js"></script>
<script src="core/js/utils.js"></script> <script src="core/js/utils.js"></script>
<script src="loader.js"></script> <script src="loader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script> <!-- for backup.js --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script> <!-- for backup.js -->
@ -183,6 +219,9 @@
<script src="core/js/appinfo.js"></script> <script src="core/js/appinfo.js"></script>
<script src="core/js/index.js"></script> <script src="core/js/index.js"></script>
<script src="core/js/pwa.js" defer></script> <script src="core/js/pwa.js" defer></script>
<!-- FIXME - use espruino.com/ide, github -->
<script src="https://espruino.github.io/EspruinoWebIDE/js/libs/peerjs.min.js"></script>
<script src="https://espruino.github.io/EspruinoWebIDE/EspruinoTools/libs/webrtc-connection.js"></script>
<script> <script>
/*Android = { /*Android = {
bangleTx : function(data) { bangleTx : function(data) {
@ -208,15 +247,22 @@ if (typeof Android!=="undefined") {
if (writecb) setTimeout(writecb,10); if (writecb) setTimeout(writecb,10);
}, },
close : function() {}, close : function() {},
on : function(evt,cb) { connection.handlers[evt] = cb; },
received : "", received : "",
hadData : false hadData : false,
handlers : []
} }
connection.on("data", function(d) {
connection.received += d;
connection.hadData = true;
if (connection.cb) connection.cb(d);
});
function bangleRx(data) { function bangleRx(data) {
// document.getElementById("status").innerText = "RX:"+data; // document.getElementById("status").innerText = "RX:"+data;
connection.received += data; // call data event
connection.hadData = true; if (connection.handlers["data"])
if (connection.cb) connection.cb(data); connection.handlers["data"](data);
} }
function log(level, s) { function log(level, s) {
@ -301,6 +347,7 @@ if (typeof Android!=="undefined") {
// ---------------------------------------------------------- // ----------------------------------------------------------
Puck = { Puck = {
/// Are we writing debug information? 0 is no, 1 is some, 2 is more, 3 is all. /// Are we writing debug information? 0 is no, 1 is some, 2 is more, 3 is all.
debug : Puck.debug, debug : Puck.debug,
@ -311,7 +358,8 @@ if (typeof Android!=="undefined") {
/// Called with the current send progress or undefined when done - you can replace this with your own function /// Called with the current send progress or undefined when done - you can replace this with your own function
writeProgress : Puck.writeProgress, writeProgress : Puck.writeProgress,
connect : function(callback) { connect : function(callback) {
setTimeout(callback, 10); setTimeout(callback, 10, connection);
return connection;
}, },
write : write, write : write,
eval : function(expr, cb) { eval : function(expr, cb) {
@ -346,7 +394,57 @@ if (typeof Android!=="undefined") {
if ("object"==typeof err) console.log(err.stack); if ("object"==typeof err) console.log(err.stack);
}); });
}, 500); }, 500);
} else {
showToast("You're running the App Loader version for Gadgetbridge, but you don't seem to be in Gadgetbridge!","error");
} }
function showWebRTCID(id) {
showToast("Bridge's Peer ID: "+id);
showPrompt("Web IDE Remote Access",`
Remote access enabled. Peer ID:
<br/><br/>
<b>${id}</b>
<br/><br/>
Go to <b>espruino.com/ide</b> on your
desktop and enter this code under
<b>Remote Connection Bridge Peer ID</b> in Settings.
Then connect to the <b>Android</b> device.
`,{ok:1},false/*shouldEscapeHtml*/).then(() => {
}, function() { /* cancelled */ });
}
// Button to Enable Remote Web IDE
var el = document.getElementById("webideremote");
var webrtc;
if (el) el.addEventListener("click", event=>{
if (webrtc) showWebRTCID(webrtc.peerId);
else {
webrtc = webrtcInit({
bridge:true,
onStatus : function(s) {
showToast(s);
},
onPeerID : function(id) {
showWebRTCID(id);
},
onGetPorts : function(cb) {
cb([{path:"Android",description:"Remote Device Connection",type:"socket"}]);
},
onPortConnect : function(serialPort, cb) {
cb(); // we're already connected...
},
onPortDisconnect : function(serialPort) {
},
onPortWrite : function(data, cb) {
Puck.write(data, cb);
}
});
connection.on("data", function(d) {
webrtc.onPortReceived(d);
});
}
});
</script> </script>
</body> </body>
</html> </html>

View File

@ -1 +1,2 @@
0.01: New Widget! 0.01: New Widget!
0.02: Minor code improvements

View File

@ -1,7 +1,7 @@
{ {
"id": "1button", "id": "1button",
"name": "One-Button-Tracker", "name": "One-Button-Tracker",
"version": "0.01", "version": "0.02",
"description": "A widget that turns BTN1 into a tracker, records time of button press/release.", "description": "A widget that turns BTN1 into a tracker, records time of button press/release.",
"icon": "widget.png", "icon": "widget.png",
"type": "widget", "type": "widget",

View File

@ -22,7 +22,7 @@
console.log("Button let go"); console.log("Button let go");
digitalWrite(LED2,0); digitalWrite(LED2,0);
var unpress_time = new Date(); var unpress_time = new Date();
recFile = require("Storage").open("one_button_presses.csv","a"); const recFile = require("Storage").open("one_button_presses.csv","a");
recFile.write([press_time.getTime(),unpress_time.getTime()].join(",")+"\n"); recFile.write([press_time.getTime(),unpress_time.getTime()].join(",")+"\n");
}, BTN1, { repeat: true, edge: 'falling', debounce: 50 }); }, BTN1, { repeat: true, edge: 'falling', debounce: 50 });

View File

@ -1,3 +1,4 @@
{ // wrap app in scope to prevent minifier from removing the class definition completely
class TwoK { class TwoK {
constructor() { constructor() {
this.b = Array(4).fill().map(() => Array(4).fill(0)); this.b = Array(4).fill().map(() => Array(4).fill(0));
@ -121,13 +122,13 @@ function dragHandler(e) {
} }
} }
function swipeHandler() { /*function swipeHandler() {
} }*/
function buttonHandler() { /*function buttonHandler() {
} }*/
var twok = new TwoK(); var twok = new TwoK();
twok.addDigit(); twok.addDigit(); twok.addDigit(); twok.addDigit();
@ -138,3 +139,4 @@ if (process.env.HWVERSION==1) {
setWatch(() => { res = twok.shift(2); if (res) twok.addDigit(); twok.render(); }, BTN1, {repeat: true}); setWatch(() => { res = twok.shift(2); if (res) twok.addDigit(); twok.render(); }, BTN1, {repeat: true});
setWatch(() => { res = twok.shift(-2); if (res) twok.addDigit(); twok.render(); }, BTN3, {repeat: true}); setWatch(() => { res = twok.shift(-2); if (res) twok.addDigit(); twok.render(); }, BTN3, {repeat: true});
} }
}

View File

@ -1,2 +1,4 @@
0.01: New app! 0.01: New app!
0.02: Better support for watch themes 0.02: Better support for watch themes
0.03: Workaround minifier bug
0.04: Minor code improvements

View File

@ -2,7 +2,7 @@
"name": "2047pp", "name": "2047pp",
"shortName":"2047pp", "shortName":"2047pp",
"icon": "app.png", "icon": "app.png",
"version":"0.02", "version": "0.04",
"description": "Bangle version of a tile shifting game", "description": "Bangle version of a tile shifting game",
"supports" : ["BANGLEJS","BANGLEJS2"], "supports" : ["BANGLEJS","BANGLEJS2"],
"allow_emulator": true, "allow_emulator": true,

View File

@ -0,0 +1,2 @@
0.01: New App!
0.02: Minor code improvements

11
apps/2ofthemclk/README.md Normal file
View File

@ -0,0 +1,11 @@
# two of them clock
You can now wear teh memez on your wrist.
![](screenshot.png)
Also serves as an example of displaying seconds only when unlocked or charging and only refreshing on the minute otherwise.
Widgets not supported
## Creator
- [Kilrah](https://github.com/kilrah)

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwgZC/AH4ADkAPOgVJkgEBAQQAJiQRByEJgmQCJWSpMEAQMkyQJCpASHhAOBpAmBJJgjBCIUJCRg4CCIJxFMQ2SoARCkmACI0EBAJHCCIMLj4RFiUBskAgIXBEAU5A4P34CtCiEJsEJ/AHBCgOBAoQAEi0H////HciQsBwywICIXWzkG4A+BEY0gif46dt6/cgnIgkWnHfLIP/MoUWwHbpvC/kAjEEj0HNYQCCkEfGgP/64RB2EAifHLwMAjg1CCIMD/0H/0B8EAh+HgeAkARCE4IjC/4jBYIMPLIcIAYUPB4OBCIQABhu/AoShCHYIRBx6QBDgUw2//8OHPwcJ39//ILBCIU9LgMBSQgsBJAYRBkE/CIIABgRHD3wRFkk/2zBDAYU//3b/oRB8ARBj6ABgEE7YREEYf+oMkSwINCyClCn//z//+4RBgMkgU3EgUcwFJgEeboOXCIP2EYJCDAAVJkkGWoIuBgf2EYQPDkECCIOGd4ffyEJkgFBAAcSoEkwQCBhw+BwQaByVAkGAKwIFBBANLkEQgAyBCIVIkBpBgmSBYOQoApBgcgiQRCAQIyCCgsSjIFBCIcgRgJNCCgQyBpAgDAQT2BCgIOBBAQUCCIpfBCIwCKP4QRNpCSDCLyJBCIbjBTwYRLboJ0BCI4QD"))

90
apps/2ofthemclk/app.js Normal file

File diff suppressed because one or more lines are too long

BIN
apps/2ofthemclk/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
apps/2ofthemclk/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -0,0 +1,17 @@
{
"id": "2ofthemclk",
"name": "two of them clock",
"version": "0.02",
"description": "You can now wear teh memez on your wrist.",
"readme": "README.md",
"icon": "app.png",
"screenshots": [{"url":"screenshot.png"}],
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS2"],
"allow_emulator": true,
"storage": [
{"name":"2ofthemclk.app.js","url":"app.js"},
{"name":"2ofthemclk.img","url":"app-icon.js","evaluate":true}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

6
apps/3dclock/README.md Normal file
View File

@ -0,0 +1,6 @@
A simple clock with perspective scaling.
Battery drainer, performance tester, show-off piece work-in-progress.
Demo.

1
apps/3dclock/app-icon.js Normal file
View File

@ -0,0 +1 @@
atob("MDAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJmZCZmZAAAAAAAAAAAAAAAAAAAAAAAAAACZAAkJkJAAAAAAAAAAAAAAAAAAAAAACQkJmZmQCZkAAAAAAAAAAAAAAAAAAAAACQAAAAAJmQmZAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAJCZkACQAAAAAAAAAAAAAAAJAAAAAAAAAACZAACZAAAAAAAAAAAAAAAAAAAAAAAAAAmZAJmZkAAAAAAAAAAAAAAAAAAAAACQmQkAmQAJmQAAAAAAAAAAAAAAAAAAAAmZAJkAAAkJmQAAAAAAAAAAAAAAAAkAAAAA///wAAAJmf///wAAAAmQAAAAAAAJAAD/////8AAJD/////AAAAAAAAAJAAAJCQD//////wCZ//////AAAJAAAAAJAAD//w//8AAP/wCf//kAD/AAAAkAAAAAAAD5CQ8J8AAP/wCZkJkAAPAAAJCQAAAAAJn//w//mQAP/wAAmQCQAPAAAAAAAA//CQ///w8J+ZAP/wAACQCQD/AAAACQAP//CQDw/58P/////wAACQAA//AAAJCQAAD/AAAP+QDwn///8AAAAAAP//AACQAAAAD/AAAP8JCZn////wAAmZ///wAAAACZAJD/AACfCQmZkJmf/wAAAP//8AAAAJkAkAD/AACfAJCQmZCf/wkJD//wAAAAAAAJAP//8ADwCQCZmZmf/wAA//8AAAAAAACQkAAJAJAACQ//mZmf/wAA//CQAAAAAAkAmQAACQAACQn//////5mf//////AAAAkACQAACQAACQn/////8AkP//////AAAAAJkACQAJAJkJAJ////AJmf//////AAAAmQAAAAmZCZmZmZkJmZkJAJCZAAAAAAAAAAAACZCZmZmZmQCZmQmQAJAAAAAAAAAACQkAAJmZmZmZmZmZmZkJmZkAAAAAAAAAAJkJCZkJmZmZmZmQkJCZmQAAAAAAAAAAAAAJAACZmZmZmZmQmZkJmZAAAAAAAAAAAACQkJmZmZmZmZmZmZCZkAAAAAAAAAAAAAAAAAkJmZmZmZkJmQkJkAAAAAAAAAAAAAAJmQmZCZmQCZmZmZAAAAAAAAAAAAAAAAAACQmZmZmZAJkJkJAAAAAAAAAAAAAAAAAAAJmQmZkJkACQkAAAAAAAAAAAAAAAAAAAAAAACZmZmQmZkAAAAAAAAAAAAAAAAAAAAAAAAJkAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")

70
apps/3dclock/app.js Normal file

File diff suppressed because one or more lines are too long

BIN
apps/3dclock/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

View File

@ -0,0 +1,16 @@
{ "id": "3dclock",
"name": "3D Clock",
"shortName":"3DClock",
"icon": "app.png",
"version":"0.01",
"description": "This is a simple 3D scaling demo based on Anton Clock",
"screenshots" : [ { "url":"screenshot.png" }],
"type":"clock",
"tags": "clock",
"readme": "README.md",
"supports": ["BANGLEJS2"],
"storage": [
{"name":"3dclock.app.js","url":"app.js"},
{"name":"3dclock.img","url":"app-icon.js","evaluate":true}
]
}

BIN
apps/3dclock/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -269,7 +269,7 @@ function actions(v){
} }
// Get Messages status // Get Messages status
var messages = require("Storage").readJSON("messages.json",1)||[]; var messages_installed = require("Storage").read("messages") !== undefined;
//var BTconnected = NRF.getSecurityStatus().connected; //var BTconnected = NRF.getSecurityStatus().connected;
//NRF.on('connect',BTconnected = NRF.getSecurityStatus().connected); //NRF.on('connect',BTconnected = NRF.getSecurityStatus().connected);
@ -282,7 +282,7 @@ function drawWidgeds() {
//print(BluetoothDevice.connected); //print(BluetoothDevice.connected);
var x1Bt = 160; var x1Bt = 160;
var y1Bt = 0; var y1Bt = 0;
var x2Bt = x1Bt + 30; //var x2Bt = x1Bt + 30;
var y2Bt = y2Bt; var y2Bt = y2Bt;
if (NRF.getSecurityStatus().connected) if (NRF.getSecurityStatus().connected)
@ -318,7 +318,7 @@ function drawWidgeds() {
var x2M = x1M + 25; var x2M = x1M + 25;
var y2M = y2B; var y2M = y2B;
if (messages.some(m=>m.new)) { if (messages_installed && require("messages").status() == "new") {
g.setColor(g.theme.fg); g.setColor(g.theme.fg);
g.fillRect(x1M,y1M,x2M,y2M); g.fillRect(x1M,y1M,x2M,y2M);
g.setColor(g.theme.bg); g.setColor(g.theme.bg);
@ -391,4 +391,4 @@ Bangle.on('lock', function(on) {
SetFull(Bangle.isLocked()); SetFull(Bangle.isLocked());
var secondInterval = setInterval(draw, 1000); /*var secondInterval =*/ setInterval(draw, 1000);

View File

@ -1,2 +1,4 @@
0.01: Initial version for upload 0.01: Initial version for upload
0.02: better theme support, configurable colors, small improvements 0.02: Better theme support, configurable colors, small improvements
0.03: Use `messages` library to check for new messages
0.04: Minor code improvements

View File

@ -1,7 +1,7 @@
{ "id": "7x7dotsclock", { "id": "7x7dotsclock",
"name": "7x7 Dots Clock", "name": "7x7 Dots Clock",
"shortName":"7x7 Dots Clock", "shortName":"7x7 Dots Clock",
"version":"0.02", "version": "0.04",
"description": "A clock with a big 7x7 dots Font", "description": "A clock with a big 7x7 dots Font",
"icon": "dotsfontclock.png", "icon": "dotsfontclock.png",
"tags": "clock", "tags": "clock",

BIN
apps/8ball/8ball.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

1
apps/8ball/ChangeLog Normal file
View File

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

1
apps/8ball/app-icon.js Normal file
View File

@ -0,0 +1 @@
atob("MDCBAAAAAAAAAAAAAAAAAAAAH/AAAAAAf/4AAAAB4AeAAAAHgAHgAAAOAABwAAAcAAA4AAA4AMAcAABwAMAOAABgA/AGAADAAeADAAHAAMADgAGAAAABgAGAAAABgAMAAAAAwAMBAAAAwAMDAAAAwAMHwAAAwAMHwAAAwAMDAACAwAMBAADAwAMAAAPgwAMAAAPgwAMAAADAwAGAAACBgAGAAAABgAHAAAADgADAAAADAADgAAAHAAB////+AAB////+AABgAAAGAABgAAAGAABgAAAGAADAAAADAADAAAADAADAAAADAAGAAAABgAGAAAABgAH/////gAP/////wAYAAAAAYAYAAAAAYAf/////4AP/////wAAAAAAAAAAAAAAAAA==")

92
apps/8ball/app.js Normal file
View File

@ -0,0 +1,92 @@
var keyboard = "textinput";
var Name = "";
Bangle.setLCDTimeout(0);
var menuOpen = 1;
var answers = new Array("no", "yes","WHAT????","What do you think", "That was a bad question", "YES!!!", "NOOOOO!!", "nope","100%","yup","why should I answer that?","think for yourself","ask again later, I'm busy", "what Was that horrible question","how dare you?","you wanted to hear yes? okay, yes", "Don't get angry when I say no","you are 100% wrong","totally, for sure","hmmm... I'll ponder it and get back to you later","wow, you really have a lot of questions", "NOPE","is the sky blue, hmmm...","I don't have time to answer","How many more questions before you change my name?","theres this thing called wikipedia","hmm... I don't seem to be able to reach the internet right now","if you phrase it like that, yes","Huh, never thought so hard in my life","The winds of time say no");
var consonants = new Array("b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z");
var vowels = new Array("a","e","i","o","u");
try {keyboard = require(keyboard);} catch(e) {keyboard = null;}
function generateName()
{
Name = "";
var nameLength = Math.round(Math.random()*5);
for(var i = 0; i < nameLength; i++){
var cosonant = consonants[Math.round(Math.random()*consonants.length/2)];
var vowel = vowels[Math.round(Math.random()*vowels.length/2)];
Name = Name + cosonant + vowel;
if(Name == "")
{
generateName();
}
}
}
generateName();
function menu()
{
g.clear();
E.showMenu();
menuOpen = 1;
E.showMenu({
"" : { title : Name },
"< Back" : () => menu(),
"Start" : () => {
E.showMenu();
g.clear();
menuOpen = 0;
Drawtext("ask " + Name + " a yes or no question");
},
"regenerate name" : () => {
menu();
generateName();
},
"show answers" : () => {
var menu = new Array([]);
for(var i = 0; i < answers.length; i++){
menu.push({title : answers[i]});
}
E.showMenu(menu);
},
"Add answer" : () => {
E.showMenu();
keyboard.input({}).then(result => {if(result != ""){answers.push(result);} menu();});
},
"Edit name" : () => {
E.showMenu();
keyboard.input({}).then(result => {if(result != ""){Name = result;} menu();});
},
"Exit" : () => load(),
});
}
menu();
var answer;
function Drawtext(text)
{
g.clear();
g.setFont("Vector", 20);
g.drawString(g.wrapString(text, g.getWidth(), -20).join("\n"));
}
function WriteAnswer()
{
if (menuOpen == 0)
{
var randomnumber = Math.round(Math.random()*answers.length);
answer = answers[randomnumber];
Drawtext(answer);
setTimeout(function() {
Drawtext("ask " + Name + " a yes or no question");
}, 3000);
}
}
setWatch(function() {
menu();
}, (process.env.HWVERSION==2) ? BTN1 : BTN2, {repeat:true, edge:"falling"});
Bangle.on('touch', function(button, xy) { WriteAnswer(); });

19
apps/8ball/metadata.json Normal file
View File

@ -0,0 +1,19 @@
{ "id": "8ball",
"name": "Magic 8 ball",
"shortName":"8ball",
"icon": "8ball.png",
"version":"0.01",
"screenshots": [
{"url":"screenshot.png"},
{"url":"screenshot-1.png"},
{"url":"screenshot-2.png"}
],
"allow_emulator": true,
"description": "A very sarcastic magic 8ball",
"tags": "game",
"supports": ["BANGLEJS2"],
"storage": [
{"name":"8ball.app.js","url":"app.js"},
{"name":"8ball.img","url":"app-icon.js","evaluate":true}
]
}

BIN
apps/8ball/screenshot-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
apps/8ball/screenshot-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
apps/8ball/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -1,2 +1,4 @@
0.01: New App! 0.01: New App!
0.02: Fullscreen settings. 0.02: Fullscreen settings.
0.03: Tell clock widgets to hide.
0.04: Use widget_utils.

View File

@ -1,6 +1,7 @@
const SETTINGS_FILE = "90sclk.setting.json"; const SETTINGS_FILE = "90sclk.setting.json";
const locale = require('locale'); const locale = require('locale');
const storage = require('Storage'); const storage = require('Storage');
const widget_utils = require('widget_utils');
/* /*
@ -109,12 +110,15 @@ function draw() {
// Draw widgets if not fullscreen // Draw widgets if not fullscreen
if(settings.fullscreen){ if(settings.fullscreen){
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} widget_utils.hide();
} else { } else {
Bangle.drawWidgets(); Bangle.drawWidgets();
} }
} }
// Show launcher when middle button pressed
Bangle.setUI("clock");
Bangle.loadWidgets(); Bangle.loadWidgets();
// Clear the screen once, at startup // Clear the screen once, at startup
@ -140,5 +144,3 @@ Bangle.on('lock', function(isLocked) {
}); });
// Show launcher when middle button pressed
Bangle.setUI("clock");

View File

@ -1,7 +1,7 @@
{ {
"id": "90sclk", "id": "90sclk",
"name": "90s Clock", "name": "90s Clock",
"version": "0.02", "version": "0.04",
"description": "A 90s style watch-face", "description": "A 90s style watch-face",
"readme": "README.md", "readme": "README.md",
"icon": "app.png", "icon": "app.png",
@ -14,5 +14,6 @@
{"name":"90sclk.app.js","url":"app.js"}, {"name":"90sclk.app.js","url":"app.js"},
{"name":"90sclk.img","url":"app-icon.js","evaluate":true}, {"name":"90sclk.img","url":"app-icon.js","evaluate":true},
{"name":"90sclk.settings.js","url":"settings.js"} {"name":"90sclk.settings.js","url":"settings.js"}
] ],
"data": [{"name":"90sclk.setting.json"}]
} }

View File

@ -21,7 +21,6 @@
'< Back': back, '< Back': back,
'Full Screen': { 'Full Screen': {
value: settings.fullscreen, value: settings.fullscreen,
format: () => (settings.fullscreen ? 'Yes' : 'No'),
onchange: () => { onchange: () => {
settings.fullscreen = !settings.fullscreen; settings.fullscreen = !settings.fullscreen;
save(); save();

View File

@ -4,3 +4,4 @@
0.04: Set 00:00 to 12:00 for 12 hour time 0.04: Set 00:00 to 12:00 for 12 hour time
0.05: Display time, even on Thursday 0.05: Display time, even on Thursday
0.06: Fix light theme issue, where widgets would end up on a light strip 0.06: Fix light theme issue, where widgets would end up on a light strip
0.07: Minor code improvements

View File

@ -8,7 +8,7 @@ var imgBg = require("heatshrink").decompress(atob("2GwgJC/AH4A/AH4A/AH4A/AH4A/AC
// reg number first char 48 28 by 41 // reg number first char 48 28 by 41
var fontNum = atob("AAAAAAAAAAAAAA//8D//g//8P/+I//8//44//w//j4//A/+P4/8A/4/4AAAAD/4AAAAP/wAAAAf/gAAAA//AAAAB/+AAAAD/8AAAAH/4AAAAP/wAAAAf/gAAAA//AAAAB/+AAAAD/8AAAAH/wAAAAH/H/gH/H8f/gf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wB/4AP/4H/4A//4f/4D//5//4P//h//4//+B//4AAAAAAAAAAAAAAAAAf/+AAAB//4gAAD//jgAAD/+PgABj/4/gAHj/j/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8f88AAfx/8wAAfH/8AAAcf/8AAAR//4AAAH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAA4AAAAAD4AAYAAP4AD8AA/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAHgAH/H/GH/H8f/gf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAP//AAAAP//AAAAP//AAAAP/8AAAAP/2AAAAP/eAAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAB/7x/4AH/7H/4Af/4f/4B//5//4H//h//4f/+B//4AAAAAAAAAAAAAD//wAAAD//wAAAj//gAADj/+AAAPj/5gAA/j/ngAD/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8AA8f8fwAAx/8fAAAH/8cAAAf/8QAAA//8AAAA//8AAAAAAAAAAAAAA//8D//g//8P/+I//8//44//0//j4//Y/+P4/94/4/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAPwAH/AAPH/H8AAMf/HwAAB//HAAAH//EAAAH//AAAAH//AAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAGAAAAAAOAAAAAAeAAAAAA+AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB8AAAAADx/4B/4HH/4H/4Mf/4f/4R//5//4H//h//4f/+B//4AAAAAAAAAAAAAD//wP/+D//w//4j//z//jj//T/+Pj/9j/4/j/3j/j/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8f+8f8fx/+x/8fH/+H/8cf/+f/8R//4f/8H//gf/8AAAAAAAAAAAAAA//8AAAA//8AAAI//8AAA4//0AAD4//YAAP4/94AA/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAPwAH/H/vH/H8f/sf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); var fontNum = atob("AAAAAAAAAAAAAA//8D//g//8P/+I//8//44//w//j4//A/+P4/8A/4/4AAAAD/4AAAAP/wAAAAf/gAAAA//AAAAB/+AAAAD/8AAAAH/4AAAAP/wAAAAf/gAAAA//AAAAB/+AAAAD/8AAAAH/wAAAAH/H/gH/H8f/gf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wB/4AP/4H/4A//4f/4D//5//4P//h//4//+B//4AAAAAAAAAAAAAAAAAf/+AAAB//4gAAD//jgAAD/+PgABj/4/gAHj/j/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8f88AAfx/8wAAfH/8AAAcf/8AAAR//4AAAH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAA4AAAAAD4AAYAAP4AD8AA/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAHgAH/H/GH/H8f/gf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAP//AAAAP//AAAAP//AAAAP/8AAAAP/2AAAAP/eAAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAB/7x/4AH/7H/4Af/4f/4B//5//4H//h//4f/+B//4AAAAAAAAAAAAAD//wAAAD//wAAAj//gAADj/+AAAPj/5gAA/j/ngAD/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8AA8f8fwAAx/8fAAAH/8cAAAf/8QAAA//8AAAA//8AAAAAAAAAAAAAA//8D//g//8P/+I//8//44//0//j4//Y/+P4/94/4/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAPwAH/AAPH/H8AAMf/HwAAB//HAAAH//EAAAH//AAAAH//AAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAGAAAAAAOAAAAAAeAAAAAA+AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB8AAAAADx/4B/4HH/4H/4Mf/4f/4R//5//4H//h//4f/+B//4AAAAAAAAAAAAAD//wP/+D//w//4j//z//jj//T/+Pj/9j/4/j/3j/j/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8f+8f8fx/+x/8fH/+H/8cf/+f/8R//4f/8H//gf/8AAAAAAAAAAAAAA//8AAAA//8AAAI//8AAA4//0AAD4//YAAP4/94AA/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAPwAH/H/vH/H8f/sf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
// tiny font for percentage first char 48 6 by 8 // tiny font for percentage first char 48 6 by 8
var fontTiny = atob("AH6BgYF+ACFB/wEBAGGDhYlxAEKBkZFuAAx0hP8EAPqRkZGOAH6RkZFOAICHmKDAAG6RkZFuAHKJiYl+AAAAAAAAAAAAAAAA"); //var fontTiny = atob("AH6BgYF+ACFB/wEBAGGDhYlxAEKBkZFuAAx0hP8EAPqRkZGOAH6RkZFOAICHmKDAAG6RkZFuAHKJiYl+AAAAAAAAAAAAAAAA");
// date font first char 48 12 by 15 // date font first char 48 12 by 15
var fontDate = atob("AAAAAfv149wAeADwAeADwAeADvHr9+AAAAAAAAAAAAAAAAAAAAAAAAAPHn9/AAAAAAP0A9wweGDwweGDwweGDvAL8AAAAAAAAAAAgwOGDwweGDwweGDvHp98AAAAA/gB6AAwAGAAwAGAAwAGAPHj9/AAAAAfgF6BwweGDwweGDwweGDgHoB+AAAAAfv169wweGDwweGDwweGDgHoB+AAAAAAAAAAgAGAAwAGAAwAGAAvHh9/AAAAAfv169wweGDwweGDwweGDvHr9+AAAAAfgF6BwweGDwweGDwweGDvHr9+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); var fontDate = atob("AAAAAfv149wAeADwAeADwAeADvHr9+AAAAAAAAAAAAAAAAAAAAAAAAAPHn9/AAAAAAP0A9wweGDwweGDwweGDvAL8AAAAAAAAAAAgwOGDwweGDwweGDvHp98AAAAA/gB6AAwAGAAwAGAAwAGAPHj9/AAAAAfgF6BwweGDwweGDwweGDgHoB+AAAAAfv169wweGDwweGDwweGDgHoB+AAAAAAAAAAgAGAAwAGAAwAGAAvHh9/AAAAAfv169wweGDwweGDwweGDvHr9+AAAAAfgF6BwweGDwweGDwweGDvHr9+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
@ -25,7 +25,7 @@ var imgSun = E.toArrayBuffer(atob("Ig8BwHf7D7Ac/MHD/z8wMP/PzMQ/8/M/D/z8z8QPf7f6A
// define icons // define icons
var imgSep = E.toArrayBuffer(atob("BhsBAAAAAA///////////////AAAAAAA")); var imgSep = E.toArrayBuffer(atob("BhsBAAAAAA///////////////AAAAAAA"));
var imgPercent = E.toArrayBuffer(atob("BwcBuq7ffbqugA==")); //var imgPercent = E.toArrayBuffer(atob("BwcBuq7ffbqugA=="));
var img24hr = E.toArrayBuffer(atob("EwgBj7vO53na73tcDtu9uDev7vA93g==")); var img24hr = E.toArrayBuffer(atob("EwgBj7vO53na73tcDtu9uDev7vA93g=="));
var imgPM = E.toArrayBuffer(atob("EwgB+HOfdnPu1X3ar4dV9+q+/bfftg==")); var imgPM = E.toArrayBuffer(atob("EwgB+HOfdnPu1X3ar4dV9+q+/bfftg=="));

View File

@ -3,7 +3,7 @@
"shortName":"93 Dub", "shortName":"93 Dub",
"icon": "93dub.png", "icon": "93dub.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"}],
"version":"0.06", "version": "0.07",
"description": "Fan recreation of orviwan's 91 Dub app for the Pebble smartwatch. Uses assets from his 91-Dub-v2.0 repo", "description": "Fan recreation of orviwan's 91 Dub app for the Pebble smartwatch. Uses assets from his 91-Dub-v2.0 repo",
"tags": "clock", "tags": "clock",
"type": "clock", "type": "clock",

View File

@ -1 +1,2 @@
0.01: New App! 0.01: New App!
0.02: Minor code improvements

View File

@ -25,7 +25,7 @@ declare global variables for the toggle button
statuses; if you add an additional toggle button statuses; if you add an additional toggle button
you should declare it and initiase it here */ you should declare it and initiase it here */
var status_spk = {value: true}; //var status_spk = {value: true};
var status_face = {value: true}; var status_face = {value: true};
var status_iris_light = {value: false}; var status_iris_light = {value: false};
var status_iris = {value: false}; var status_iris = {value: false};

View File

@ -2,7 +2,7 @@
"id": "BLEcontroller", "id": "BLEcontroller",
"name": "BLE Customisable Controller with Joystick", "name": "BLE Customisable Controller with Joystick",
"shortName": "BLE Controller", "shortName": "BLE Controller",
"version": "0.01", "version": "0.02",
"description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.", "description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.",
"icon": "BLEcontroller.png", "icon": "BLEcontroller.png",
"tags": "tool,bluetooth", "tags": "tool,bluetooth",

1
apps/Tyreid/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: Change log created

18
apps/Tyreid/README.md Normal file
View File

@ -0,0 +1,18 @@
Tyreid
Tyreid is a Bluetooth war-driving app for the Bangle.js 2.
Menu options:
- Start: This turns on the Bluetooth and starts logging Bluetooth packets with time, latitude, and longitude information to a CSV file.
- Pause/Continue: These functions pause the capture and then allow it to resume.
- Devices: When paused this menu option will display the MAC addresses of discovered Bluetooth devices. Selecting a device will then display the MAC, Manufacturer code, the time it was first seen, and the RSSI of the first sighting.
- Marker: This command adds a 'marker' to the CSV log, which consists of the time and location information, but the Bluetooth packet information is replaced with the word MARKER. Markers can also be added by pressing the watch's button.
- Exit: This exits the app.
The current number of discovered devices is displayed in the top left corner.
This value is displayed in green when the GPS has a fix, or red otherwise.
To retrieve the CSV file, connect to the watch through the Espruino web IDE (https://www.espruino.com/ide/). From there the files stored on the watch can be downloaded by clicking the storage icon in the IDE's central column.

1
apps/Tyreid/app-icon.js Normal file
View File

@ -0,0 +1 @@
E.toArrayBuffer(atob("MDACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAtAAAAAAAAAAAAAAB/QAAAAAAAAAAAAAD/0AAAAAAAAAAAAAH+9AAAAAAAAAAAAAPtfQAAAAAAAAAAAAudH0AAAAAAAAAAAB8tB9AAAAAAAAAAAD0tAfQAAAAAAAAAAHgtAH0AAAAAAAAAAPAtAB9AAAAAAAAAAtAtAAfQAAAAAAAAB8AtAAH0AAAAAAAAD0AtAAB9AAAAAAAALgAtAAAfQAAAAAAAfAAtAAAH0AAAAAAA9AAtAAAB9AAAAAAC4AAtAAAAfQAAAAADwAAtAAAALwAAAAAAQAAtAAAAvgAAAAAAAAAsAAAC9AAAAAAAAAAsAAAP0AAAAAAAAAAsAAB/AAAAAAAAAAAsAAH4AAAAAAAAAAAsAAvQAAAAAAAAAAAsAD9AAAAAAAAAAAAsAD0AAAAAAAAAAAAsAB8AAAAAAAAAAAAsAAtAAAAAAAAAAAAsAAPQAAAAAAAAAAAsAAHwAAAAAAAAAAAsAAC4AAAAAAAAAAAsAAA9AAAAAAAAAAAsAAAPAAAAAAAAAAAsAAAHgAAAAAAAAAA8AAAC0AAAAAAAAAA8AAAA8AAAAAAAAAA8AAAAEAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))

272
apps/Tyreid/app.js Normal file

File diff suppressed because one or more lines are too long

14
apps/Tyreid/metadata.json Normal file
View File

@ -0,0 +1,14 @@
{ "id": "Tyreid",
"name": "Tyreid",
"shortName":"Tyreid",
"version":"0.01",
"description": "Bluetooth war-driving app for Bangle.js 2",
"icon": "small_logo.png",
"tags": "",
"supports" : ["BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"Tyreid.app.js","url":"app.js"},
{"name":"Tyreid.img","url":"app-icon.js","evaluate":true}
]
}

BIN
apps/Tyreid/small_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -1 +1,2 @@
0.01: 1st ver, defining a common UI/UX 0.01: 1st ver, defining a common UI/UX
0.02: Minor code improvements

View File

@ -5,7 +5,7 @@ identify device and dimensions
max printable position max_x-1 i.e 239 max printable position max_x-1 i.e 239
*/ */
var colbackg='#111111';//black //var colbackg='#111111';//black
var colorange='#e56e06'; //RGB format rrggbb var colorange='#e56e06'; //RGB format rrggbb
var v_color_lines=0xFFFF; //White hex format var v_color_lines=0xFFFF; //White hex format
var v_color_b_area='#111111'; var v_color_b_area='#111111';
@ -13,13 +13,13 @@ max printable position max_x-1 i.e 239
var v_font1size=10; //out of quotes var v_font1size=10; //out of quotes
var v_font2size=12; var v_font2size=12;
var v_font_banner_size=30; var v_font_banner_size=30;
var v_clicks=0; //var v_clicks=0;
//pend identify widget area dinamically //pend identify widget area dinamically
var v_model=process.env.BOARD; var v_model=process.env.BOARD;
console.log("device="+v_model); console.log("device="+v_model);
var x_max_screen=g.getWidth();//240; var x_max_screen=g.getWidth();//240;
var y_max_screen=g.getHeight(); //240; //var y_max_screen=g.getHeight(); //240;
var y_wg_bottom=g.getHeight()-25; var y_wg_bottom=g.getHeight()-25;
var y_wg_top=25; var y_wg_top=25;
if (v_model=='BANGLEJS') { if (v_model=='BANGLEJS') {

View File

@ -2,10 +2,10 @@
"id": "UI4swatch", "id": "UI4swatch",
"name": "UI 4 swatch", "name": "UI 4 swatch",
"shortName": "UI 4 swatch", "shortName": "UI 4 swatch",
"version": "0.01", "version": "0.02",
"description": "A UI/UX for espruino smartwatches, displays dinamically calc. x,y coordinates.", "description": "A UI/UX for espruino smartwatches, displays dinamically calc. x,y coordinates.",
"icon": "app.png", "icon": "app.png",
"tags": "Color,input,buttons,touch,UI", "tags": "color,input,buttons,touch,ui",
"supports": ["BANGLEJS"], "supports": ["BANGLEJS"],
"readme": "README.md", "readme": "README.md",
"screenshots": [{"url":"UI4swatch_icon.png"},{"url":"UI4swatch_s1.png"}], "screenshots": [{"url":"UI4swatch_icon.png"},{"url":"UI4swatch_s1.png"}],

4
apps/Uke/ChangeLog Normal file
View File

@ -0,0 +1,4 @@
0.01: New App!
0.02: Increased Legibility, GUI rework
0.03: 13 new chords
0.04: Minor code improvements

12
apps/Uke/README.md Normal file
View File

@ -0,0 +1,12 @@
# Uke Chords
An app that simply describes finger placements on a Ukulele to form common chords.
## Usage
Select a chord to view.
Use the button to return to the chord selection menu.
## Creator
NovaDawn999

1
apps/Uke/app-icon.js Normal file
View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwgtqiAXWiMRDKsBolBCqcQilEoQwTiMUoMkkJGUiQwUFwVCGCcUoVEkJ5SgJ2CAQMROyIsBoVDoIXQgMSiJ2EPB4uBdwMieCMBCoIZCDoJdQAAMSUYUBLqIXBIhxCBCAJdDIZwPBTgIAEFxrOCAAIuTCwVELoQuToIuRgIuDCoUiFxjNCFwq7BC5YWBFoZdDAQIXLCwpdEogXKLYgWBXYZ9BC5SKDCwQYCkIHBC5IuFFQIYBiQhCC5JdFCoIYBBIYXJIwlEFwUUBIYXOLgIYDA4ReJC4i4BI4RODOxj/CAQIyBFwSOMoIYCagQ4BCxQXEigrBiS7CLpRHGAIMiMwYXMQoYwCSogXKU4gwCC6gwCC6ApEUoIFDRxR4Fd4QXReAgcEC5hIFLyAwJFxwwIiIWODATbDCyIYCAAQWSACY"))

259
apps/Uke/app.js Normal file
View File

@ -0,0 +1,259 @@
const stringInterval = 30;
const stringLength = 131;
const fretHeight = 35;
const fingerOffset = 17;
const x = 44;
const y = 32;
//chords
const cc = [
"C",
"x",
"x",
"x",
"33"
];
const dd = [
"D",
"22",
"23",
"24",
"x"
];
var ee = [
"E",
"33",
"32",
"34",
"11"
];
const ff = [
"F",
"22",
"x",
"11",
"x"
];
const gg = [
"G",
"x",
"21",
"33",
"22",
];
const aa = [
"A",
"22",
"11",
"x",
"x"
];
const bb = [
"B",
"42",
"43",
"44",
"21"
];
const cm = [
"Cm",
"11",
"x",
"12",
"34"
];
const dm = [
"Dm",
"x",
"22",
"33",
"11"
];
const em = [
"Em",
"x",
"43",
"32",
"21"
];
const fm = [
"Fm",
"33",
"11",
"11",
"11"
];
const gm = [
"Gm",
"x",
"22",
"33",
"11"
];
const am = [
"Am",
"22",
"23",
"11",
"x"
];
const bm = [
"Bm",
"x",
"43",
"32",
"21"
];
const c7 = [
"C7",
"22",
"33",
"11",
"x"
];
const d7 = [
"D7",
"x",
"22",
"11",
"23"
];
const e7 = [
"E7",
"x",
"11",
"x",
"x"
];
const f7 = [
"F7",
"11",
"22",
"11",
"11"
];
const g7 = [
"G7",
"x",
"x",
"x",
"11"
];
const a7 = [
"A7",
"21",
"21",
"21",
"32"
];
const b7 = [
"B7",
"11",
"22",
"x",
"23"
];
var menu = {
"" : { "title" : "Uke Chords" },
"C" : function() { draw(cc); },
"D" : function() { draw(dd); },
"E" : function() { draw(ee); },
"F" : function() { draw(ff); },
"G" : function() { draw(gg); },
"A" : function() { draw(aa); },
"B" : function() { draw(bb); },
"C7" : function() { draw(c7); },
"D7" : function() { draw(d7); },
"E7" : function() { draw(e7); },
"F7" : function() { draw(f7); },
"G7" : function() { draw(g7); },
"A7" : function() { draw(a7); },
"B7" : function() { draw(b7); },
"Cm" : function() { draw(cm); },
"Dm" : function() { draw(dm); },
"Em" : function() { draw(em); },
"Fm" : function() { draw(fm); },
"Gm" : function() { draw(gm); },
"Am" : function() { draw(am); },
"Bm" : function() { draw(bm); },
"About" : function() {
E.showMessage(
"Created By:\nNovaDawn999", {
title:"About"
}
);
}
};
function drawBase() {
for (let i = 0; i < 4; i++) {
g.drawLine(x + i * stringInterval, y, x + i * stringInterval, y + stringLength);
g.fillRect(x- 1, y + i * fretHeight - 1, x + stringInterval * 3 + 1, y + i * fretHeight + 1);
}
}
function drawChord(chord) {
g.drawString(chord[0], g.getWidth() * 0.5 - (chord[0].length * 5), 16);
for (let i = 0; i < chord.length; i++) {
if (i === 0 || chord[i][0] === "x") {
continue;
}
if (chord[i][0] === "0") {
g.drawString(chord[i][1], x + (i - 1) * stringInterval - 5, y + fretHeight * chord[i][0] + 2, true);
g.drawCircle(x + (i - 1) * stringInterval -1, y + fretHeight * chord[i][0], 10);
}
else {
g.drawString(chord[i][1], x + (i - 1) * stringInterval -5, y -fingerOffset + fretHeight * chord[i][0] + 2, true);
g.drawCircle(x + (i - 1) * stringInterval -1, y -fingerOffset + fretHeight * chord[i][0], 10);
}
}
}
function buttonPress() {
setWatch(() => {
buttonPress();
}, BTN);
E.showMenu(menu);
}
function draw(chord) {
g.clear();
drawBase();
drawChord(chord);
}
function main() {
E.showMenu(menu);
setWatch(() => {
buttonPress();
}, BTN);
}
main();

BIN
apps/Uke/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

14
apps/Uke/metadata.json Normal file
View File

@ -0,0 +1,14 @@
{ "id": "Uke",
"name": "Uke Chords",
"shortName":"Uke",
"version": "0.04",
"description": "Wrist mounted ukulele chords",
"icon": "app.png",
"tags": "uke,chords",
"supports" : ["BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"Uke.app.js","url":"app.js"},
{"name":"Uke.img","url":"app-icon.js","evaluate":true}
]
}

View File

@ -1,5 +1,10 @@
# App Name # App Name
More information on making apps:
* http://www.espruino.com/Bangle.js+First+App
* http://www.espruino.com/Bangle.js+App+Loader
Describe the app... Describe the app...
Add screen shots (if possible) to the app folder and link then into this file with ![](<name>.png) Add screen shots (if possible) to the app folder and link then into this file with ![](<name>.png)

View File

@ -0,0 +1 @@
0.01: New Clock Info!

View File

@ -0,0 +1,27 @@
# Clock Info Name
More info on making Clock Infos and what they are: http://www.espruino.com/Bangle.js+Clock+Info
Describe the clock info...
Add screen shots (if possible) to the app folder and link then into this file with ![](<name>.png)
## Usage
Describe how to use it
## Features
Name the function
## Controls
Name the buttons and what they are used for
## Requests
Name who should be contacted for support/update requests
## Creator
Your name

View File

@ -0,0 +1,16 @@
(function() {
return {
name: "Bangle",
// img: 24x24px image for this list of items. The default "Bangle" list has its own image so this is not needed
items: [
{ name : "Item1",
get : function() { return { text : "TextOfItem1",
// v : 10, min : 0, max : 100, - optional
img : atob("GBiBAAAAAAAAAAAYAAD/AAOBwAYAYAwAMAgAEBgAGBAACBCBCDHDjDCBDBAACBAACBhCGAh+EAwYMAYAYAOBwAD/AAAYAAAAAAAAAA==") }},
show : function() {},
hide : function() {},
// run : function() {} optional (called when tapped)
}
]
};
}) // must not have a semi-colon!

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,14 @@
{ "id": "7chname",
"name": "My clock info's human readable name",
"shortName":"Short Name",
"version":"0.01",
"description": "A detailed description of my clock info",
"icon": "icon.png",
"type": "clkinfo",
"tags": "clkinfo",
"supports" : ["BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"7chname.clkinfo.js","url":"clkinfo.js"}
]
}

View File

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

View File

@ -0,0 +1,25 @@
# Clock Name
More info on making Clock Faces: https://www.espruino.com/Bangle.js+Clock
Describe the Clock...
## Usage
Describe how to use it
## Features
Name the function
## Controls
Name the buttons and what they are used for
## Requests
Name who should be contacted for support/update requests
## Creator
Your name

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="))

View File

@ -0,0 +1,50 @@
{
// timeout used to update every minute
let drawTimeout;
// schedule a draw for the next minute
let queueDraw = function() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw();
}, 60000 - (Date.now() % 60000));
};
let draw = function() {
// queue next draw in one minute
queueDraw();
// Work out where to draw...
var x = g.getWidth()/2;
var y = g.getHeight()/2;
g.reset();
// work out locale-friendly date/time
var date = new Date();
var timeStr = require("locale").time(date,1);
var dateStr = require("locale").date(date);
// draw time
g.setFontAlign(0,0).setFont("Vector",48);
g.clearRect(0,y-20,g.getWidth(),y+25); // clear the background
g.drawString(timeStr,x,y);
// draw date
y += 30;
g.setFontAlign(0,0).setFont("6x8");
g.clearRect(0,y-4,g.getWidth(),y+4); // clear the background
g.drawString(dateStr,x,y);
};
// Clear the screen once, at startup
g.clear();
// draw immediately at first, queue update
draw();
// Show launcher when middle button pressed
Bangle.setUI({mode:"clock", remove:function() {
// free any memory we allocated to allow fast loading
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
}});
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,16 @@
{ "id": "7chname",
"name": "My clock human readable name",
"shortName":"Short Name",
"version":"0.01",
"description": "A detailed description of my clock",
"icon": "icon.png",
"screenshots": [{"url":"screenshot.png"}],
"type": "clock",
"tags": "clock",
"supports" : ["BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"7chname.app.js","url":"app.js"},
{"name":"7chname.img","url":"app-icon.js","evaluate":true}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,5 +1,7 @@
# Widget Name # Widget Name
More info on making Widgets and what they are: http://www.espruino.com/Bangle.js+Widgets
Describe the app... Describe the app...
Add screen shots (if possible) to the app folder and link then into this file with ![](<name>.png) Add screen shots (if possible) to the app folder and link then into this file with ![](<name>.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -3,7 +3,7 @@
"shortName":"Short Name", "shortName":"Short Name",
"version":"0.01", "version":"0.01",
"description": "A detailed description of my great widget", "description": "A detailed description of my great widget",
"icon": "widget.png", "icon": "icon.png",
"type": "widget", "type": "widget",
"tags": "widget", "tags": "widget",
"supports" : ["BANGLEJS2"], "supports" : ["BANGLEJS2"],

View File

@ -1,16 +1,14 @@
/* run widgets in their own function scope so they don't interfere with /* run widgets in their own function scope if they need to define local
currently-running apps */ variables so they don't interfere with currently-running apps */
(() => { (() => {
function draw() { // add your widget
WIDGETS["mywidget"]={
area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right), be aware that not all apps support widgets at the bottom of the screen
width: 28, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout
draw:function() {
g.reset(); // reset the graphics context to defaults (color/font/etc) g.reset(); // reset the graphics context to defaults (color/font/etc)
// add your code // add your code
g.drawString("X", this.x, this.y); g.drawString("X", this.x, this.y);
} } // called to draw the widget
// add your widget
WIDGETS["mywidget"]={
area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right)
width: 28, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout
draw:draw // called to draw the widget
}; };
})() })()

View File

@ -1 +1,5 @@
0.01: Beta version for Bangle 2 (2021/11/28) 0.01: Beta version for Bangle 2 (2021/11/28)
0.02: Shows night time on the map (2022/12/28)
0.03: Add 1 minute timer with upper taps (2023/01/05)
1.00: Page to set up custom time zones (2023/01/06)
1.01: Minor code improvements

View File

@ -2,14 +2,17 @@
* Works with Bangle 2 * Works with Bangle 2
* Timer * Timer
* Right tap: start/increase by 10 minutes; Left tap: decrease by 5 minutes * Top Right tap: increase by 1 minute
* Top Left tap: decrease by 1 minute
* Bottom Right tap: increase by 10 minutes
* Bottom Left tap: decrease by 5 minutes
* Short buzz at T-30, T-20, T-10 ; Double buzz at T * Short buzz at T-30, T-20, T-10 ; Double buzz at T
* Other time zones * Other time zones
* Currently hardcoded to Paris and Tokyo (this will be customizable in a future version) * Showing Paris and Tokyo by default, but you can customize this using the dedicated configuration page on the app store
* World Map * World Map
* The yellow line shows the position of the sun * The map shows day and night on Earth and the position of the Sun (yellow line)
![](screenshot.png) ![](screenshot-1.png) ![](screenshot.png)
## Creator ## Creator
[@alainsaas](https://github.com/alainsaas) [@alainsaas](https://github.com/alainsaas)

View File

@ -2,7 +2,7 @@
function getImg() { function getImg() {
return require("heatshrink").decompress(atob("2FRgP/ABnxBRP5BJH+gEfBZHghnAv4JFmA+Bj0PBIn3//4h3An4oDAQJWEEIf8AwMEuFOCofAh/QjAWEg4VEwEAnw2DDoKEHEYPwAoUBmgrDhgUHS4XgAwUD/gVC/g+FAAZgEwEf4YqC/EQFQ4NDFgV/4Z3C/EcCo1974VCLAV/V4d7Co9/Co0PCoX+vk4Ko/HCosCRYX5nwTFkEAr/nCokICoL+B/aCGCoMHCoq3EdoraGCosPz4HBcILEJCocBwEHOwQrIgQrHgoHCFYMEgwVJYoMBsEnCofAnkMNQJXH4D4EbQMPkF/xwrEj+/HIkAoAVDj8QueHCoorDCoUDLwd96J0BKwgrHh4VDv+9CosDx6QCCo4HB//8VwvvXgQVDJIYSBCo/sBwaZBgF/NoYVHgH8V4qYDAwUYlAVFEYbFDDgwAGConogf9Zg8DCpP4cIh0Dg0BGAgVE+gVIgUA+AVI+wVE/xAEh5HDEgn+CpEAbgJCCHQoVBn4VJ/ED4ANDAAQVJ4EPPQPAt4VF4BeDColgj/8h/gFYwJBCpF//k//ANDCAYVIcgP+CpH/54VHCAIVB/4VIwYECCocIAwIVBx4VG9+AMITbCYAYJB34VG/UAj4VI7/9Cgw9CJYXAmBtDMAQsIfYhvCCofyvywGB4QFFgYGC/d+agYVLSgf8+ArG/APBD4QVBgh0CAwNwv/fCo4PCCo94s7VDCohnDAoI7Enlv8BZECoRCDAggAB3/3/gzDMAIVFY4IVE4IPBOoZ9DCpXwCoMvCqKxB//3bYywD4BtFAAPfDooVFFYIVGw4VFB4KZFngNE/uPCovgFYgEBuK+Fg4zFCoIrFCovwgQVF+AVFgPxEYzFEbgQVD4EDCoozBYogVCgYVE8bpGCo4HDCoPzBgoVIL4fAg4MGgAIHCofgCszND8BOHK4x2BCofwXgv4h6vGCps/Co6uDAA/7RgIjDDwTaDABPA//9FaAtDCop0FC5YVDLwoAH8//94GD/wVNCYKNECpwPBQggVPNggVBNp4VFFZwAGCquHCqnzCB4")); return require("heatshrink").decompress(atob("2FRgP/ABnxBRP5BJH+gEfBZHghnAv4JFmA+Bj0PBIn3//4h3An4oDAQJWEEIf8AwMEuFOCofAh/QjAWEg4VEwEAnw2DDoKEHEYPwAoUBmgrDhgUHS4XgAwUD/gVC/g+FAAZgEwEf4YqC/EQFQ4NDFgV/4Z3C/EcCo1974VCLAV/V4d7Co9/Co0PCoX+vk4Ko/HCosCRYX5nwTFkEAr/nCokICoL+B/aCGCoMHCoq3EdoraGCosPz4HBcILEJCocBwEHOwQrIgQrHgoHCFYMEgwVJYoMBsEnCofAnkMNQJXH4D4EbQMPkF/xwrEj+/HIkAoAVDj8QueHCoorDCoUDLwd96J0BKwgrHh4VDv+9CosDx6QCCo4HB//8VwvvXgQVDJIYSBCo/sBwaZBgF/NoYVHgH8V4qYDAwUYlAVFEYbFDDgwAGConogf9Zg8DCpP4cIh0Dg0BGAgVE+gVIgUA+AVI+wVE/xAEh5HDEgn+CpEAbgJCCHQoVBn4VJ/ED4ANDAAQVJ4EPPQPAt4VF4BeDColgj/8h/gFYwJBCpF//k//ANDCAYVIcgP+CpH/54VHCAIVB/4VIwYECCocIAwIVBx4VG9+AMITbCYAYJB34VG/UAj4VI7/9Cgw9CJYXAmBtDMAQsIfYhvCCofyvywGB4QFFgYGC/d+agYVLSgf8+ArG/APBD4QVBgh0CAwNwv/fCo4PCCo94s7VDCohnDAoI7Enlv8BZECoRCDAggAB3/3/gzDMAIVFY4IVE4IPBOoZ9DCpXwCoMvCqKxB//3bYywD4BtFAAPfDooVFFYIVGw4VFB4KZFngNE/uPCovgFYgEBuK+Fg4zFCoIrFCovwgQVF+AVFgPxEYzFEbgQVD4EDCoozBYogVCgYVE8bpGCo4HDCoPzBgoVIL4fAg4MGgAIHCofgCszND8BOHK4x2BCofwXgv4h6vGCps/Co6uDAA/7RgIjDDwTaDABPA//9FaAtDCop0FC5YVDLwoAH8//94GD/wVNCYKNECpwPBQggVPNggVBNp4VFFZwAGCquHCqnzCB4"));
} }
var IMAGEWIDTH = 176; //var IMAGEWIDTH = 176;
var IMAGEHEIGHT = 81; var IMAGEHEIGHT = 81;
Graphics.prototype.setFontMichroma36 = function() { Graphics.prototype.setFontMichroma36 = function() {
@ -18,19 +18,29 @@ var timervalue = 0;
var istimeron = false; var istimeron = false;
var timertick; var timertick;
Bangle.on('touch',t=>{ Bangle.on('touch',(touchside, touchdata)=>{
if (t == 1) { if (touchside == 1) {
Bangle.buzz(30); Bangle.buzz(30);
if (timervalue < 5*60) { timervalue = 1 ; } var changevalue = 0;
else { timervalue -= 5*60; } if(touchdata.y > 88) {
changevalue += 60*5;
} else {
changevalue += 60*1;
} }
else if (t == 2) { if (timervalue < changevalue) { timervalue = 1 ; }
else { timervalue -= changevalue; }
}
else if (touchside == 2) {
Bangle.buzz(30); Bangle.buzz(30);
if (!istimeron) { if (!istimeron) {
istimeron = true; istimeron = true;
timertick = setInterval(countDown, 1000); timertick = setInterval(countDown, 1000);
} }
if(touchdata.y > 88) {
timervalue += 60*10; timervalue += 60*10;
} else {
timervalue += 60*1;
}
} }
}); });
@ -73,12 +83,13 @@ function countDown() {
function showWelcomeMessage() { function showWelcomeMessage() {
g.reset().clearRect(0, 76, 44+44, g.getHeight()/2+6); g.reset().clearRect(0, 76, 44+44, g.getHeight()/2+6);
g.setFontAlign(0, 0).setFont("6x8"); g.setFontAlign(0, 0).setFont("6x8");
g.drawString("Touch right to", 44, 80); g.drawString("Tap right to", 44, 80);
g.drawString("start timer", 44, 88); g.drawString("start timer", 44, 88);
setTimeout(function(){ g.reset().clearRect(0, 76, 44+44, g.getHeight()/2+6); }, 8000); setTimeout(function(){ g.reset().clearRect(0, 76, 44+44, g.getHeight()/2+6); }, 8000);
} }
// time // time
var offsets = require("Storage").readJSON("a_clock_timer.settings.json") || [ ["PAR",1], ["TYO",9] ];
var drawTimeout; var drawTimeout;
function getGmt() { function getGmt() {
@ -103,10 +114,24 @@ function draw() {
g.reset().clearRect(0,24,g.getWidth(),g.getHeight()-IMAGEHEIGHT); g.reset().clearRect(0,24,g.getWidth(),g.getHeight()-IMAGEHEIGHT);
g.drawImage(getImg(),0,g.getHeight()-IMAGEHEIGHT); g.drawImage(getImg(),0,g.getHeight()-IMAGEHEIGHT);
var x_sun = 176 - (getGmt().getHours() / 24 * 176 + 4); var gmtHours = getGmt().getHours();
var x_sun = 176 - (gmtHours / 24 * 176 + 4);
g.setColor('#ff0').drawLine(x_sun, g.getHeight()-IMAGEHEIGHT, x_sun, g.getHeight()); g.setColor('#ff0').drawLine(x_sun, g.getHeight()-IMAGEHEIGHT, x_sun, g.getHeight());
g.reset(); g.reset();
var x_night_start = (176 - (((gmtHours-6)%24) / 24 * 176 + 4)) % 176;
var x_night_end = 176 - (((gmtHours+6)%24) / 24 * 176 + 4);
g.setColor('#000');
for (let x = x_night_start; x < (x_night_end < x_night_start ? 176 : x_night_end); x+=2) {
g.drawLine(x, g.getHeight()-IMAGEHEIGHT, x, g.getHeight());
}
if (x_night_end < x_night_start) {
for (let x = 0; x < x_night_end; x+=2) {
g.drawLine(x, g.getHeight()-IMAGEHEIGHT, x, g.getHeight());
}
}
var locale = require("locale"); var locale = require("locale");
var date = new Date(); var date = new Date();
@ -114,8 +139,8 @@ function draw() {
g.setFont("Michroma36").drawString(locale.time(date,1), g.getWidth()/2, 46); g.setFont("Michroma36").drawString(locale.time(date,1), g.getWidth()/2, 46);
g.setFont("6x8"); g.setFont("6x8");
g.drawString(locale.date(new Date(),1), 125, 68); g.drawString(locale.date(new Date(),1), 125, 68);
g.drawString("PAR "+locale.time(getTimeFromTimezone(1),1), 125, 80); g.drawString(offsets[0][0]+" "+locale.time(getTimeFromTimezone(offsets[0][1]),1), 125, 80);
g.drawString("TYO "+locale.time(getTimeFromTimezone(9),1), 125, 88); g.drawString(offsets[1][0]+" "+locale.time(getTimeFromTimezone(offsets[1][1]),1), 125, 88);
queueNextDraw(); queueNextDraw();
} }

View File

@ -0,0 +1,58 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<p>You can set the 2 additional timezones displayed by the clock.</p>
<table id="a_clock_timer-offsets">
<tr>
<th>Name</th>
<th>UTC Offset (Hours)</th>
</tr>
</table>
<p>Click <button id="upload" class="btn btn-primary">Upload</button></p>
<script src="../../core/lib/customize.js"></script>
<script>
var offsets=[];
try{
var stored = localStorage.getItem('a_clock_timer-offset-list')
if(stored) offsets = JSON.parse(stored);
if (!offsets || offsets.length!=2) {
throw "Offsets invalid";
}
} catch(e){
offsets=[
["PAR",1],
["TYO",9],
];
}
console.log(offsets);
var tbl=document.getElementById("a_clock_timer-offsets");
for (var i=0; i<2; i++) {
var $offset = document.createElement('tr')
$offset.innerHTML = `
<td><input type="text" size="4" maxlength="3" id="name_${i}" value="${offsets[i][0]}"></td>
<td><input type="number" id="offset_${i}" value="${offsets[i][1]}"></td>`
tbl.append($offset);
}
document.getElementById("upload").addEventListener("click", function() {
var storage_offsets=[];
var app_offsets=[];
for (var i=0; i<2; i++) {
var name=document.getElementById("name_"+i).value;
var offset=document.getElementById("offset_"+i).value;
app_offsets.push([name,offset]);
storage_offsets.push([name,offset]);
}
console.log(storage_offsets);
console.log(app_offsets);
localStorage.setItem('a_clock_timer-offset-list',JSON.stringify(storage_offsets));
sendCustomizedApp({
storage:[
{name:"a_clock_timer.settings.json", content:JSON.stringify(app_offsets)},
]
});
});
</script>
</body>
</html>

View File

@ -1,17 +1,19 @@
{ {
"id": "a_clock_timer", "id": "a_clock_timer",
"name": "A Clock with Timer", "name": "A Clock with Timer",
"version": "0.01", "version": "1.01",
"description": "A Clock with Timer, Map and Time Zones", "description": "A Clock with Timer, Map and Time Zones",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"},{"url":"screenshot-1.png"}],
"type": "clock", "type": "clock",
"tags": "clock", "tags": "clock",
"supports": ["BANGLEJS2"], "supports": ["BANGLEJS2"],
"allow_emulator": true, "allow_emulator": true,
"readme": "README.md", "readme": "README.md",
"custom": "custom.html",
"storage": [ "storage": [
{"name":"a_clock_timer.app.js","url":"app.js"}, {"name":"a_clock_timer.app.js","url":"app.js"},
{"name":"a_clock_timer.img","url":"app-icon.js","evaluate":true} {"name":"a_clock_timer.img","url":"app-icon.js","evaluate":true}
] ],
"data": [{"name":"a_clock_timer.settings.json"}]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,2 @@
0.01: Initial version
0.02: Add settings page; Add line break to update message

View File

@ -0,0 +1,16 @@
# a_dndtoggle - Toggle Quiet Mode of the watch
When Quiet mode is off, just start this app to set quiet mode. Start it again to turn off quiet mode.
Use the app settings to choose which quiet mode you prefer ("Alarms" or "Silent"). Default is "Silent".
Work in progress.
#ToDo
Current status indicator
## Creator
Hank - contact at http://forum.espruino.com

View File

@ -0,0 +1,46 @@
const modeNames = [/*LANG*/"Noisy", /*LANG*/"Alarms", /*LANG*/"Silent"];
let bSettings = require('Storage').readJSON('setting.json',true)||{};
let current = 0|bSettings.quiet;
//0 off
//1 alarms
//2 silent
const dndSettings =
require('Storage').readJSON("a_dndtoggle.settings.json", true) || {};
console.log("old: " + current);
switch (current) {
case 0:
bSettings.quiet = dndSettings.mode || 2;
Bangle.buzz();
setTimeout('Bangle.buzz();',500);
break;
case 1:
bSettings.quiet = 0;
Bangle.buzz();
break;
case 2:
bSettings.quiet = 0;
Bangle.buzz();
break;
default:
bSettings.quiet = 0;
Bangle.buzz();
}
console.log("new: " + bSettings.quiet);
E.showMessage(modeNames[current] + " -> \n" + modeNames[bSettings.quiet]);
setTimeout('exitApp();', 2000);
function exitApp(){
require("Storage").writeJSON("setting.json", bSettings);
// reload clocks with new theme, otherwise just wait for user to switch apps
load()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwJC/AAl/Agf/AAUAgIFDwEHAofgh/g/0Ag/wj+AnwVB/EegEfEIN4nkAh+AgE8vgVBAoV4Aoce/EAgfADQIFcjwpFHYIFCnxBFJopZBn5ZCMopxFPoqJFSowA/gA="))

View File

@ -0,0 +1,20 @@
{
"id": "a_dndtoggle",
"name": "a_dndtoggle - Toggle Quiet Mode of the watch",
"shortName": "A_DND Toggle",
"version": "0.02",
"description": "Toggle Quiet Mode of the watch just by starting this app.",
"icon": "a_dndtoggle.png",
"type": "app",
"tags": "tool",
"supports": ["BANGLEJS","BANGLEJS2"],
"data" : [
{"name":"a_dndtoggle.settings.json"}
],
"storage": [
{"name":"a_dndtoggle.app.js","url":"a_dndtoggle.app.js"},
{"name":"a_dndtoggle.settings.js","url":"settings.js"},
{"name":"a_dndtoggle.img","url":"app-icon.js","evaluate":true}
],
"readme": "README.md"
}

View File

@ -0,0 +1,32 @@
(function(back) {
const settings =
require('Storage').readJSON("a_dndtoggle.settings.json", true) || {};
function updateSettings() {
require('Storage').writeJSON("a_dndtoggle.settings.json", settings);
}
function buildMainMenu(){
// 0-Noisy is only a placeholder so that the other values map to the Bangle quiet mode options
const modes = [/*LANG*/"Noisy",/*LANG*/"Alarms",/*LANG*/"Silent"];
let mainmenu = {
'': { 'title': 'A_DND Toggle' },
'< Back': back,
/*LANG*/"Quiet Mode": {
value: settings.mode || 2,
min: 1, // don't allow choosing 0-Noisy
max: modes.length - 1,
format: v => modes[v],
onchange: v => {
settings.mode = v;
updateSettings();
}
}
};
return mainmenu;
}
E.showMenu(buildMainMenu());
})

View File

@ -1,2 +1,4 @@
1.00: Release (2021/12/01) 1.00: Release (2021/12/01)
1.01: Grey font when timer is frozen (2021/12/04) 1.01: Grey font when timer is frozen (2021/12/04)
1.02: Force light theme, since the app is not designed for dark theme (2022/12/28)
1.03: Minor code improvements

View File

@ -124,7 +124,6 @@ Bangle.on('swipe',(swiperight, swipedown)=>{
} }
}); });
var drawTimeout;
var showInstructions = true; var showInstructions = true;
function draw() { function draw() {
@ -166,6 +165,7 @@ function draw() {
g.drawRect(88+8,138-24, 176-10, 138+22); g.drawRect(88+8,138-24, 176-10, 138+22);
} }
g.setTheme({bg:"#fff",fg:"#000",dark:false}).clear();
require("FontHaxorNarrow7x17").add(Graphics); require("FontHaxorNarrow7x17").add(Graphics);
g.clear(); g.clear();
Bangle.loadWidgets(); Bangle.loadWidgets();

Some files were not shown because too many files have changed in this diff Show More