Added emojuino v0.01
parent
30a51228ba
commit
537842a321
15
apps.json
15
apps.json
|
|
@ -4215,5 +4215,20 @@
|
||||||
{ "name": "qalarm.wid.js", "url": "widget.js" }
|
{ "name": "qalarm.wid.js", "url": "widget.js" }
|
||||||
],
|
],
|
||||||
"data": [{ "name": "qalarm.json" }]
|
"data": [{ "name": "qalarm.json" }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "emojuno",
|
||||||
|
"name": "Emoji Broadcaster",
|
||||||
|
"shortName": "Emojuino",
|
||||||
|
"version": "0.01",
|
||||||
|
"description": "Emojis & Espruino: advertise Unicode emojis via BLE",
|
||||||
|
"icon": "emojuino.png",
|
||||||
|
"tags": "emoji",
|
||||||
|
"supports" : [ "BANGLEJS2" ],
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{ "name": "emojuno.app.js", "url": "emojuino.js" },
|
||||||
|
{ "name": "emojuno.img", "url": "emojuino-icon.js", "evaluate": true }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Emojuino
|
||||||
|
|
||||||
|
Emojis & Espruino!
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Select an emoji and then tap to transmit!
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
Currently implements a tiny subset of possible Unicode emojis.
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
Swipe left/right to select the emoji to broadcast. Tap the screen to initiate the broadcast. Emoji will flash while broadcasting.
|
||||||
|
|
||||||
|
## Requests
|
||||||
|
|
||||||
|
[Contact reelyActive](https://www.reelyactive.com/contact/) for support/updates.
|
||||||
|
|
||||||
|
## Creator
|
||||||
|
|
||||||
|
Developed by [jeffyactive](https://github.com/jeffyactive) of [reelyActive](https://www.reelyactive.com)
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwkBiIAHkUoxGIwUiBxAAGiQVCAAeCkIWNCooADDBYWKDBYWEkc////+cyDBhxDCoQAD+YLDCw0YBQQVFAAYYCwIXFHQRDElGCJYgOCFw8vBwPyOgoJFGAg4BIoQWGDAhJCIwoLBHgYAGJQIjCIwguCnCRFRoeDGAZICAgOPFwaRGDAQfB/AwDBAYuCX44wDAgTrDBoIDBGYP/manBmYFBFYQPDwJeBD4iRGRoQ/FC4QqBEYIbERooTBCAeBNAIjBBQIDDAAggBG4IDDwQXBEQIDDUAgcCHASaBAYQTFMQpcFDYp+EEII9DAARRDFIIfDHIwXBVISlDC4YzD9wA0osFpwIF8lQqgWK8kAgEEBItABIIhGAAfgBoMABIoIChwX0jwED8oNBgoXFqAJBrwHD8IXEBwQNEEIYgFC4wAQ8MRC6sRC+BgULwIwHSINVpwuLC43kaAQABqgaHC4bZHAAkFqhGHGAovFAAYyDCwgwFL4IwGFxAwNFxIwG8lVCoSTEFw7bPCxAYNCxT0LIpIxMCpoyHFhI"))
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
/**
|
||||||
|
* Copyright reelyActive 2021
|
||||||
|
* We believe in an open Internet of Things
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Emojis are integer pairs with the form [ image, Unicode code point ]
|
||||||
|
// For code points see https://unicode.org/emoji/charts/emoji-list.html
|
||||||
|
const EMOJIS = [
|
||||||
|
[ ':)', 0x1f642 ], // Slightly smiling
|
||||||
|
[ ':|', 0x1f610 ], // Neutral
|
||||||
|
[ ':(', 0x1f641 ], // Slightly frowning
|
||||||
|
[ '+1', 0x1f44d ], // Thumbs up
|
||||||
|
[ '-1', 0x1f44e ], // Thumbs down
|
||||||
|
[ '<3', 0x02764 ], // Heart
|
||||||
|
];
|
||||||
|
const EMOJI_TRANSMISSION_MILLISECONDS = 5000;
|
||||||
|
const BLINK_PERIOD_MILLISECONDS = 500;
|
||||||
|
const TRANSMIT_BUZZ_MILLISECONDS = 200;
|
||||||
|
const CYCLE_BUZZ_MILLISECONDS = 50;
|
||||||
|
|
||||||
|
// Non-user-configurable constants
|
||||||
|
const IMAGE_INDEX = 0;
|
||||||
|
const CODE_POINT_INDEX = 1;
|
||||||
|
const BTN_WATCH_OPTIONS = { repeat: true, debounce: 20, edge: "falling" };
|
||||||
|
const UNICODE_CODE_POINT_ELIDED_UUID = [ 0x49, 0x6f, 0x49, 0x44, 0x55,
|
||||||
|
0x54, 0x46, 0x2d, 0x33, 0x32 ];
|
||||||
|
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
let emojiIndex = 0;
|
||||||
|
let isToggleOn = false;
|
||||||
|
let isTransmitting = false;
|
||||||
|
let lastDragX = 0;
|
||||||
|
let lastDragY = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// Cycle through emojis
|
||||||
|
function cycleEmoji(isForward) {
|
||||||
|
if(isTransmitting) { return; }
|
||||||
|
|
||||||
|
if(isForward) {
|
||||||
|
emojiIndex = (emojiIndex + 1) % EMOJIS.length;
|
||||||
|
}
|
||||||
|
else if(--emojiIndex < 0) {
|
||||||
|
emojiIndex = EMOJIS.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawImage(EMOJIS[emojiIndex][IMAGE_INDEX]);
|
||||||
|
Bangle.buzz(CYCLE_BUZZ_MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handle a touch: transmit displayed emoji
|
||||||
|
function handleTouch(zone, event) {
|
||||||
|
if(isTransmitting) { return; }
|
||||||
|
|
||||||
|
let emoji = EMOJIS[emojiIndex];
|
||||||
|
transmitEmoji(emoji[IMAGE_INDEX], emoji[CODE_POINT_INDEX],
|
||||||
|
EMOJI_TRANSMISSION_MILLISECONDS);
|
||||||
|
Bangle.buzz(TRANSMIT_BUZZ_MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transmit the given code point for the given duration in milliseconds,
|
||||||
|
// blinking the image once per second.
|
||||||
|
function transmitEmoji(image, codePoint, duration) {
|
||||||
|
let instance = [ 0x00, 0x00, (codePoint >> 24) & 0xff,
|
||||||
|
(codePoint >> 16) & 0xff, (codePoint >> 8) & 0xff,
|
||||||
|
codePoint & 0xff ];
|
||||||
|
|
||||||
|
require('ble_eddystone_uid').advertise(UNICODE_CODE_POINT_ELIDED_UUID,
|
||||||
|
instance);
|
||||||
|
isTransmitting = true;
|
||||||
|
|
||||||
|
let displayIntervalId = setInterval(toggleImage, BLINK_PERIOD_MILLISECONDS,
|
||||||
|
image);
|
||||||
|
|
||||||
|
setTimeout(terminateEmoji, duration, displayIntervalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Terminate the emoji transmission
|
||||||
|
function terminateEmoji(displayIntervalId) {
|
||||||
|
NRF.setAdvertising({ });
|
||||||
|
isTransmitting = false;
|
||||||
|
clearInterval(displayIntervalId);
|
||||||
|
drawImage(EMOJIS[emojiIndex][IMAGE_INDEX]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Toggle the display between image/off
|
||||||
|
function toggleImage(image) {
|
||||||
|
if(isToggleOn) {
|
||||||
|
drawImage(EMOJIS[emojiIndex][IMAGE_INDEX]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.clear();
|
||||||
|
}
|
||||||
|
isToggleOn = !isToggleOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Draw the given emoji
|
||||||
|
function drawImage(image) {
|
||||||
|
g.clear();
|
||||||
|
g.drawString(image, g.getWidth() / 2, g.getHeight() / 2);
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handle a drag event
|
||||||
|
function handleDrag(event) {
|
||||||
|
let isFingerReleased = (event.b === 0);
|
||||||
|
|
||||||
|
if(isFingerReleased) {
|
||||||
|
let isHorizontalDrag = (Math.abs(lastDragX) >= Math.abs(lastDragY)) &&
|
||||||
|
(lastDragX !== 0);
|
||||||
|
|
||||||
|
if(isHorizontalDrag) {
|
||||||
|
cycleEmoji(lastDragX > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastDragX = event.dx;
|
||||||
|
lastDragY = event.dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Special function to handle display switch on
|
||||||
|
Bangle.on('lcdPower', (on) => {
|
||||||
|
if(on) {
|
||||||
|
drawImage(EMOJIS[emojiIndex][IMAGE_INDEX]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// On start: display the first emoji and handle drag and touch events
|
||||||
|
g.clear();
|
||||||
|
g.setFont('Vector', 80);
|
||||||
|
g.setFontAlign(0, 0);
|
||||||
|
drawImage(EMOJIS[emojiIndex][IMAGE_INDEX]);
|
||||||
|
Bangle.on('touch', handleTouch);
|
||||||
|
Bangle.on('drag', handleDrag);
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
Loading…
Reference in New Issue