2023-07-07 16:51:40 +00:00
|
|
|
/**
|
|
|
|
* Copyright 2023 SHOGEL
|
|
|
|
* We believe in Finnish
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Constants
|
|
|
|
let SWAP_SIDE_BUZZ_MILLISECONDS = 50;
|
|
|
|
let CARD_DATA_FILE = "flashcards.data.json";
|
2023-07-07 20:11:31 +00:00
|
|
|
let CARD_EMPTY = "found no cards";
|
2023-07-07 18:44:29 +00:00
|
|
|
let CARD_LINE_LENGTH = 8;
|
2023-07-07 16:51:40 +00:00
|
|
|
let CARD_LINE_FONT = "20%";
|
|
|
|
|
2023-07-07 17:43:16 +00:00
|
|
|
// Modules
|
|
|
|
var Layout = require("Layout");
|
|
|
|
var locale = require("locale");
|
|
|
|
var storage = require("Storage");
|
2023-07-07 16:51:40 +00:00
|
|
|
|
2023-07-07 17:43:16 +00:00
|
|
|
// Global variables
|
|
|
|
var cards = [];
|
|
|
|
var cardIndex = 0;
|
|
|
|
var backSide = false;
|
2023-07-07 16:51:40 +00:00
|
|
|
|
|
|
|
// Cards data
|
|
|
|
function wordWrap(str, maxLength) {
|
|
|
|
if (maxLength == undefined) {
|
|
|
|
maxLength = CARD_LINE_LENGTH;
|
|
|
|
}
|
|
|
|
let res = '';
|
|
|
|
while (str.length > maxLength) {
|
|
|
|
let found = false;
|
|
|
|
// Inserts new line at first whitespace of the line
|
|
|
|
for (i = maxLength - 1; i >= 0; i--) {
|
|
|
|
if (str.charAt(i)==' ') {
|
|
|
|
res = res + [str.slice(0, i), "\n"].join('');
|
|
|
|
str = str.slice(i + 1);
|
|
|
|
found = true;
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res + str;
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadLocalCards() {
|
2023-07-07 17:43:16 +00:00
|
|
|
var cardsJSON = "";
|
2023-07-07 16:51:40 +00:00
|
|
|
if (storage.read(CARD_DATA_FILE))
|
|
|
|
{
|
2023-07-07 17:43:16 +00:00
|
|
|
cardsJSON = storage.readJSON(CARD_DATA_FILE, 1) || {};
|
2023-07-07 16:51:40 +00:00
|
|
|
}
|
2023-07-07 17:43:16 +00:00
|
|
|
refreshCards(cardsJSON,false);
|
2023-07-07 16:51:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function refreshCards(cardsJSON,showMsg)
|
|
|
|
{
|
|
|
|
cardIndex = 0;
|
|
|
|
backSide = false;
|
|
|
|
cards = [];
|
|
|
|
|
|
|
|
if (cardsJSON && cardsJSON.length) {
|
|
|
|
cardsJSON.forEach(card => {
|
|
|
|
cards.push([ wordWrap(card.name), wordWrap(card.desc) ]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
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 drawTimeout;
|
|
|
|
let queueDraw = function() {
|
|
|
|
let timeout = 60000;
|
|
|
|
if (drawTimeout) clearTimeout(drawTimeout);
|
|
|
|
drawTimeout = setTimeout(function() {
|
|
|
|
drawTimeout = undefined;
|
|
|
|
draw();
|
|
|
|
}, timeout - (Date.now() % timeout));
|
|
|
|
};
|
|
|
|
|
|
|
|
var cardLayout = new Layout( {
|
|
|
|
type:"v", c: [
|
|
|
|
{type:"txt", font:"6x8:3", label:"", id:"widgets", fillx:1 },
|
2023-07-07 18:48:06 +00:00
|
|
|
{type:"txt", font:CARD_LINE_FONT, label:"ABCDEFGHIJ KLMNOPQRST UVWXYZÅÖÄ", filly:1, fillx:1, id:"card" },
|
2023-07-07 16:51:40 +00:00
|
|
|
{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();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle a touch: swap card side
|
|
|
|
function handleTouch(zone, event) {
|
|
|
|
backSide = !backSide;
|
|
|
|
drawCard();
|
|
|
|
Bangle.buzz(SWAP_SIDE_BUZZ_MILLISECONDS);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle a drag event: cycle cards
|
|
|
|
function handleDrag(event) {
|
|
|
|
let first_x = event.xy[0];
|
|
|
|
let last_x = event.xy[event.xy.length - 2];
|
|
|
|
let xdiff = last_x - first_x;
|
|
|
|
/*
|
|
|
|
let first_y = event.xy[1];
|
|
|
|
let last_y = event.xy[event.xy.length - 1];
|
|
|
|
let ydiff = last_y - first_y;
|
|
|
|
*/
|
|
|
|
if(xdiff > 0) {
|
|
|
|
cardIndex = (cardIndex + 1) % cards.length;
|
|
|
|
}
|
|
|
|
else if(--cardIndex < 0) {
|
|
|
|
cardIndex = cards.length - 1;
|
|
|
|
}
|
|
|
|
drawCard();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initialize
|
|
|
|
loadLocalCards();
|
|
|
|
cardLayout.update();
|
|
|
|
Bangle.loadWidgets();
|
|
|
|
Bangle.on("touch", handleTouch);
|
|
|
|
Bangle.on("stroke", handleDrag);
|
|
|
|
|
|
|
|
// On start: display the first card
|
|
|
|
g.clear();
|
|
|
|
draw();
|
|
|
|
|
|
|
|
// cleanup
|
|
|
|
Bangle.setUI({mode:"clock", remove:function() {
|
|
|
|
if (drawTimeout) clearTimeout(drawTimeout);
|
|
|
|
drawTimeout = undefined;
|
|
|
|
Bangle.removeListener("touch", handleTouch);
|
|
|
|
Bangle.removeListener("stroke", handleDrag);
|
|
|
|
}});
|