mirror of https://github.com/espruino/BangleApps
Fix fast-loading support
parent
a4632726a8
commit
98fb9ff018
|
@ -1,4 +1,5 @@
|
||||||
1.0: Local cards data
|
1.00: Local cards data
|
||||||
1.1: Download cards data from Trello public board
|
1.10: Download cards data from Trello public board
|
||||||
1.2: Configuration instructions added and card layout optimized
|
1.20: Configuration instructions added and card layout optimized
|
||||||
1.3: Font size can be changed in Settings
|
1.30: Font size can be changed in Settings
|
||||||
|
1.31: Fix for fast-loading support
|
|
@ -10,7 +10,7 @@ Configuration:
|
||||||
4. Add ".json" to the end of the Trello board URL and refresh page
|
4. Add ".json" to the end of the Trello board URL and refresh page
|
||||||
5. Find your list ID
|
5. Find your list ID
|
||||||
6. Save list ID to the "flashcards.settings.json" file on your watch, e.g.:
|
6. Save list ID to the "flashcards.settings.json" file on your watch, e.g.:
|
||||||
{"listId":"65942f7b27z68000996ddc00","fontSize":1,"cardWidth":9,"swipeGesture":0}
|
{"listId":"65942f7b27z68000996ddc00","fontSize":1,"cardWidth":9,"swipeGesture":1}
|
||||||
7. Connect phone with Gadgetbridge to the watch
|
7. Connect phone with Gadgetbridge to the watch
|
||||||
8. Enable "Allow Internet Access" in Gadgetbridge
|
8. Enable "Allow Internet Access" in Gadgetbridge
|
||||||
9. On the watch go to Settings -> Apps -> Flash Cards -> Get from Trello
|
9. On the watch go to Settings -> Apps -> Flash Cards -> Get from Trello
|
||||||
|
|
|
@ -2,186 +2,185 @@
|
||||||
* Copyright 2023 Crisp Advice
|
* Copyright 2023 Crisp Advice
|
||||||
* We believe in Finnish
|
* We believe in Finnish
|
||||||
*/
|
*/
|
||||||
|
{
|
||||||
|
// Modules
|
||||||
|
let Layout = require("Layout");
|
||||||
|
let locale = require("locale");
|
||||||
|
let storage = require("Storage");
|
||||||
|
|
||||||
// Modules
|
// Global variables
|
||||||
var Layout = require("Layout");
|
const SWAP_SIDE_BUZZ_MILLISECONDS = 50;
|
||||||
var locale = require("locale");
|
const CARD_DATA_FILE = "flashcards.data.json";
|
||||||
var storage = require("Storage");
|
const CARD_SETTINGS_FILE = "flashcards.settings.json";
|
||||||
|
const CARD_EMPTY = "no cards found";
|
||||||
|
|
||||||
// Global variables
|
let cards = [];
|
||||||
let SWAP_SIDE_BUZZ_MILLISECONDS = 50;
|
let cardIndex = 0;
|
||||||
let CARD_DATA_FILE = "flashcards.data.json";
|
let backSide = false;
|
||||||
let CARD_SETTINGS_FILE = "flashcards.settings.json";
|
let drawTimeout;
|
||||||
let CARD_EMPTY = "no cards found";
|
let fontSizes = ["15%","20%","25%"];
|
||||||
let cards = [];
|
let lastDragX = 0;
|
||||||
let cardIndex = 0;
|
let lastDragY = 0;
|
||||||
let backSide = false;
|
|
||||||
let drawTimeout;
|
|
||||||
let fontSizes = ["15%","20%","25%"];
|
|
||||||
let lastDragX = 0;
|
|
||||||
let lastDragY = 0;
|
|
||||||
|
|
||||||
let settings = Object.assign({
|
let settings = Object.assign({
|
||||||
listId: "",
|
listId: "",
|
||||||
fontSize: 1,
|
fontSize: 1,
|
||||||
cardWidth: 9,
|
cardWidth: 9,
|
||||||
swipeGesture: 0
|
swipeGesture: 1
|
||||||
}, storage.readJSON(CARD_SETTINGS_FILE, true) || {});
|
}, storage.readJSON(CARD_SETTINGS_FILE, true) || {});
|
||||||
|
|
||||||
// Cards data
|
// Cards data
|
||||||
function wordWrap(textStr, maxLength) {
|
let wordWrap = function (textStr, maxLength) {
|
||||||
if (maxLength == undefined) {
|
if (maxLength == undefined) {
|
||||||
maxLength = settings.cardWidth;
|
maxLength = settings.cardWidth;
|
||||||
}
|
}
|
||||||
let res = '';
|
let res = '';
|
||||||
let str = textStr.trim();
|
let str = textStr.trim();
|
||||||
while (str.length > maxLength) {
|
while (str.length > maxLength) {
|
||||||
let found = false;
|
let found = false;
|
||||||
// Inserts new line at first whitespace of the line
|
// Inserts new line at first whitespace of the line
|
||||||
for (i = maxLength - 1; i > 0; i--) {
|
for (i = maxLength - 1; i > 0; i--) {
|
||||||
if (str.charAt(i)==' ') {
|
if (str.charAt(i)==' ') {
|
||||||
res = res + [str.slice(0, i), "\n"].join('');
|
res = res + [str.slice(0, i), "\n"].join('');
|
||||||
str = str.slice(i + 1);
|
str = str.slice(i + 1);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Inserts new line at MAX_LENGTH position, the word is too long to wrap
|
||||||
|
if (!found) {
|
||||||
|
res += [str.slice(0, maxLength), "\n"].join('');
|
||||||
|
str = str.slice(maxLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Inserts new line at MAX_LENGTH position, the word is too long to wrap
|
return res + str;
|
||||||
if (!found) {
|
|
||||||
res += [str.slice(0, maxLength), "\n"].join('');
|
|
||||||
str = str.slice(maxLength);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return res + str;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadLocalCards() {
|
let loadLocalCards = function() {
|
||||||
var cardsJSON = "";
|
var cardsJSON = "";
|
||||||
if (storage.read(CARD_DATA_FILE))
|
if (storage.read(CARD_DATA_FILE))
|
||||||
|
{
|
||||||
|
cardsJSON = storage.readJSON(CARD_DATA_FILE, 1) || {};
|
||||||
|
}
|
||||||
|
refreshCards(cardsJSON,false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let refreshCards = function(cardsJSON,showMsg)
|
||||||
{
|
{
|
||||||
cardsJSON = storage.readJSON(CARD_DATA_FILE, 1) || {};
|
cardIndex = 0;
|
||||||
}
|
backSide = false;
|
||||||
refreshCards(cardsJSON,false);
|
cards = [];
|
||||||
}
|
|
||||||
|
|
||||||
function refreshCards(cardsJSON,showMsg)
|
if (cardsJSON && cardsJSON.length) {
|
||||||
{
|
cardsJSON.forEach(card => {
|
||||||
cardIndex = 0;
|
cards.push([ wordWrap(card.name), wordWrap(card.desc) ]);
|
||||||
backSide = false;
|
});
|
||||||
cards = [];
|
}
|
||||||
|
|
||||||
if (cardsJSON && cardsJSON.length) {
|
if (!cards.length) {
|
||||||
cardsJSON.forEach(card => {
|
cards.push([ wordWrap(CARD_EMPTY), wordWrap(CARD_EMPTY) ]);
|
||||||
cards.push([ wordWrap(card.name), wordWrap(card.desc) ]);
|
drawMessage("e: cards not found");
|
||||||
});
|
} else if (showMsg) {
|
||||||
}
|
drawMessage("i: cards refreshed");
|
||||||
|
|
||||||
if (!cards.length) {
|
|
||||||
cards.push([ wordWrap(CARD_EMPTY), wordWrap(CARD_EMPTY) ]);
|
|
||||||
drawMessage("e: cards not found");
|
|
||||||
} else if (showMsg) {
|
|
||||||
drawMessage("i: cards refreshed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drawing a card
|
|
||||||
let queueDraw = function() {
|
|
||||||
let timeout = 60000;
|
|
||||||
if (drawTimeout) clearTimeout(drawTimeout);
|
|
||||||
drawTimeout = setTimeout(function() {
|
|
||||||
drawTimeout = undefined;
|
|
||||||
draw();
|
|
||||||
}, timeout - (Date.now() % timeout));
|
|
||||||
};
|
|
||||||
|
|
||||||
let cardLayout = new Layout( {
|
|
||||||
type:"v", c: [
|
|
||||||
{type:"txt", font:"6x8:3", label:"", id:"widgets", fillx:1 },
|
|
||||||
{type:"txt", font:fontSizes[settings.fontSize], label:"ABCDEFGHIJ KLMNOPQRST UVWXYZÅÖÄ", filly:1, fillx:1, id:"card" },
|
|
||||||
{type:"txt", font:"6x8:2", label:"00:00", id:"clock", fillx:1, bgCol:g.theme.fg, col:g.theme.bg }
|
|
||||||
]
|
|
||||||
}, {lazy:true});
|
|
||||||
|
|
||||||
function drawCard() {
|
|
||||||
cardLayout.card.label = cards[cardIndex][backSide ? 1 : 0];
|
|
||||||
cardLayout.clock.label = locale.time(new Date(),1);
|
|
||||||
cardLayout.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawMessage(msg) {
|
|
||||||
cardLayout.card.label = wordWrap(msg);
|
|
||||||
cardLayout.render();
|
|
||||||
console.log(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw() {
|
|
||||||
drawCard();
|
|
||||||
Bangle.drawWidgets();
|
|
||||||
queueDraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
function swipeCard(forward)
|
|
||||||
{
|
|
||||||
if(forward) {
|
|
||||||
cardIndex = (cardIndex + 1) % cards.length;
|
|
||||||
}
|
|
||||||
else if(--cardIndex < 0) {
|
|
||||||
cardIndex = cards.length - 1;
|
|
||||||
}
|
|
||||||
drawCard();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a touch: swap card side
|
|
||||||
function handleTouch(zone, event) {
|
|
||||||
backSide = !backSide;
|
|
||||||
drawCard();
|
|
||||||
Bangle.buzz(SWAP_SIDE_BUZZ_MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a stroke event: cycle cards
|
|
||||||
function handleStroke(event) {
|
|
||||||
let first_x = event.xy[0];
|
|
||||||
let last_x = event.xy[event.xy.length - 2];
|
|
||||||
swipeCard((last_x - first_x) > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a drag event: cycle cards
|
|
||||||
function handleDrag(event) {
|
|
||||||
let isFingerReleased = (event.b === 0);
|
|
||||||
if(isFingerReleased) {
|
|
||||||
let isHorizontalDrag = (Math.abs(lastDragX) >= Math.abs(lastDragY)) &&
|
|
||||||
(lastDragX !== 0);
|
|
||||||
if(isHorizontalDrag) {
|
|
||||||
swipeCard(lastDragX > 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
lastDragX = event.dx;
|
// Drawing a card
|
||||||
lastDragY = event.dy;
|
let queueDraw = function() {
|
||||||
|
let timeout = 60000;
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = setTimeout(function() {
|
||||||
|
drawTimeout = undefined;
|
||||||
|
draw();
|
||||||
|
}, timeout - (Date.now() % timeout));
|
||||||
|
};
|
||||||
|
|
||||||
|
let cardLayout = new Layout( {
|
||||||
|
type:"v", c: [
|
||||||
|
{type:"txt", font:"6x8:3", label:"", id:"widgets", fillx:1 },
|
||||||
|
{type:"txt", font:fontSizes[settings.fontSize], label:"ABCDEFGHIJ KLMNOPQRST UVWXYZÅÖÄ", filly:1, fillx:1, id:"card" },
|
||||||
|
{type:"txt", font:"6x8:2", label:"00:00", id:"clock", fillx:1, bgCol:g.theme.fg, col:g.theme.bg }
|
||||||
|
]
|
||||||
|
}, {lazy:true});
|
||||||
|
|
||||||
|
let drawCard = function() {
|
||||||
|
cardLayout.card.label = cards[cardIndex][backSide ? 1 : 0];
|
||||||
|
cardLayout.clock.label = locale.time(new Date(),1);
|
||||||
|
cardLayout.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let drawMessage = function(msg) {
|
||||||
|
cardLayout.card.label = wordWrap(msg);
|
||||||
|
cardLayout.render();
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let draw = function() {
|
||||||
|
drawCard();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
queueDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
let swipeCard = function(forward)
|
||||||
|
{
|
||||||
|
if(forward) {
|
||||||
|
cardIndex = (cardIndex + 1) % cards.length;
|
||||||
|
}
|
||||||
|
else if(--cardIndex < 0) {
|
||||||
|
cardIndex = cards.length - 1;
|
||||||
|
}
|
||||||
|
drawCard();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle a touch: swap card side
|
||||||
|
let handleTouch = function(zone, event) {
|
||||||
|
backSide = !backSide;
|
||||||
|
drawCard();
|
||||||
|
Bangle.buzz(SWAP_SIDE_BUZZ_MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle a stroke event: cycle cards
|
||||||
|
let handleStroke = function(event) {
|
||||||
|
let first_x = event.xy[0];
|
||||||
|
let last_x = event.xy[event.xy.length - 2];
|
||||||
|
swipeCard((last_x - first_x) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle a drag event: cycle cards
|
||||||
|
let handleDrag = function(event) {
|
||||||
|
let isFingerReleased = (event.b === 0);
|
||||||
|
if(isFingerReleased) {
|
||||||
|
let isHorizontalDrag = (Math.abs(lastDragX) >= Math.abs(lastDragY)) &&
|
||||||
|
(lastDragX !== 0);
|
||||||
|
if(isHorizontalDrag) {
|
||||||
|
swipeCard(lastDragX > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastDragX = event.dx;
|
||||||
|
lastDragY = event.dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure pressing the button goes to the launcher (by making this seem like a clock?)
|
||||||
|
Bangle.setUI({mode:"clock", remove:function() {
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = undefined;
|
||||||
|
Bangle.removeListener("touch", handleTouch);
|
||||||
|
if (settings.swipeGesture) { Bangle.removeListener("drag", handleDrag);} else { Bangle.removeListener("stroke", handleStroke); }
|
||||||
|
}});
|
||||||
|
|
||||||
|
// initialize
|
||||||
|
cardLayout.update();
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
loadLocalCards();
|
||||||
|
|
||||||
|
Bangle.on("touch", handleTouch);
|
||||||
|
if (settings.swipeGesture) { Bangle.on("drag", handleDrag); } else { Bangle.on("stroke", handleStroke); }
|
||||||
|
|
||||||
|
// On start: display the first card
|
||||||
|
g.clear();
|
||||||
|
draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure pressing the button goes to the launcher (by making this seem like a clock?)
|
|
||||||
Bangle.setUI({mode:"clock"/*, remove:function() {
|
|
||||||
// Code to enable fast load. NOTE: this doesn't work on this app because all
|
|
||||||
// functions and vars are declared global: https://www.espruino.com/Bangle.js+Fast+Load
|
|
||||||
if (drawTimeout) clearTimeout(drawTimeout);
|
|
||||||
drawTimeout = undefined;
|
|
||||||
Bangle.removeListener("touch", handleTouch);
|
|
||||||
if (settings.swipeGesture) { Bangle.removeListener("drag", handleDrag);} else { Bangle.removeListener("stroke", handleStroke); }
|
|
||||||
}*/});
|
|
||||||
|
|
||||||
// initialize
|
|
||||||
cardLayout.update();
|
|
||||||
Bangle.loadWidgets();
|
|
||||||
loadLocalCards();
|
|
||||||
|
|
||||||
Bangle.on("touch", handleTouch);
|
|
||||||
if (settings.swipeGesture) { Bangle.on("drag", handleDrag); } else { Bangle.on("stroke", handleStroke); }
|
|
||||||
|
|
||||||
// On start: display the first card
|
|
||||||
g.clear();
|
|
||||||
draw();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"listId":"","fontSize":1,"cardWidth":9,"swipeGesture":0}
|
{"listId":"","fontSize":1,"cardWidth":9,"swipeGesture":1}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "flashcards",
|
"id": "flashcards",
|
||||||
"name": "Flash Cards",
|
"name": "Flash Cards",
|
||||||
"shortName": "Flash Cards",
|
"shortName": "Flash Cards",
|
||||||
"version": "1.3",
|
"version": "1.31",
|
||||||
"description": "Flash cards based on public Trello board",
|
"description": "Flash cards based on public Trello board",
|
||||||
"readme":"README.md",
|
"readme":"README.md",
|
||||||
"screenshots" : [ { "url":"screenshot.png" }],
|
"screenshots" : [ { "url":"screenshot.png" }],
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
listId: "",
|
listId: "",
|
||||||
fontSize: 1,
|
fontSize: 1,
|
||||||
cardWidth: 9,
|
cardWidth: 9,
|
||||||
swipeGesture: 0
|
swipeGesture: 1
|
||||||
}, storage.readJSON(settingsFile, true) || {});
|
}, storage.readJSON(settingsFile, true) || {});
|
||||||
|
|
||||||
function writeSettings() {
|
function writeSettings() {
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
"< Back" : () => back(),
|
"< Back" : () => back(),
|
||||||
/*LANG*/"Get from Trello": () => {
|
/*LANG*/"Get from Trello": () => {
|
||||||
if (!storage.read(settingsFile)) { writeSettings();}
|
if (!storage.read(settingsFile)) { writeSettings();}
|
||||||
E.showPrompt("Download cards?").then((v) => {
|
E.showPrompt(/*LANG*/"Download cards?").then((v) => {
|
||||||
let delay = 500;
|
let delay = 500;
|
||||||
if (v) {
|
if (v) {
|
||||||
if (Bangle.http)
|
if (Bangle.http)
|
||||||
|
|
Loading…
Reference in New Issue