let secondInterval; let showRealTime = false; let currentFormatter; const utils = { random: function(items) { return items[~~(items.length * Math.random())]; }, oneIn: function(chance) { return Math.floor(Math.random() * Math.floor(chance + 1)) === chance; }, hours2Word: function(hours, minutes) { const numbers = [ 'twelve', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', ]; let adjustedHours = hours; if (minutes > 40) { adjustedHours += 1; } if (adjustedHours > 12) { adjustedHours -= 12; } return numbers[adjustedHours]; }, print: function(str) { let fontSize = 4; const width = g.getWidth(); const height = g.getHeight() - 48; const lines = str.split(`\n`).length; let totalHeight; do { g.setFont("6x8", fontSize); totalHeight = g.getFontHeight() * lines; if (fontSize === 1 || (g.stringWidth(str) < width && totalHeight < height)) { break; } fontSize--; } while (true); const x = width / 2; const y = (g.getHeight() / 2) - (g.getFontHeight() * ((lines - 1) / 2)); g.drawString(str, x, y < 25 ? 24 : y); } }; const words = { approx: ['\'Bout', 'About', 'Around', `Summat\nlike`, 'Near', 'Close to'], approach: ['Nearly', `Coming\nup to`, 'Approaching', `A touch\nbefore`], past: [`A shade\nafter`, `A whisker\nafter`, 'Just gone'], quarter: ['A quarter', 'Quarter'], half: ['Half', 'Half past'], exactly: ['exactly', 'on the dot', 'o\' clock'], ish: ['-ish', `\n(ish)`, `\nand change`, `\nand some`, `\nor`, `\nor\nthereabouts`] }; function switchMode() { currentFormatter = null; showRealTime = !showRealTime; refreshTime(); } function drawRealTime(date) { const pad = (number) => `0${number}`.substr(-2); const hours = pad(date.getHours()); const minutes = pad(date.getMinutes()); g.setFontAlign(0,1); g.setFont("6x8", 8); g.drawString(`${hours}:${minutes}`, g.getWidth() / 2, g.getHeight() / 2); g.setFont("6x8", 3); g.setFontAlign(0, -1); g.drawString(date.toISOString().split('T')[0], g.getWidth() / 2, g.getHeight() / 2); } const makeApprox = (str, template) => { let _template = template || 'approx'; if (utils.oneIn(2)) { _template = 'approx'; if (utils.oneIn(words.approx.length)) { const ish = utils.random(words.ish); return `${str}${ish}`; } } const approx = `${utils.random(words[_template])} `; return `${approx}\n${str.toLowerCase()}`; }; const formatters = { 'onTheHour': (hoursAsWord) => { const exactly = utils.random(words.exactly); return `${hoursAsWord}\n${exactly}`; }, 'nearTheHour': (hoursAsWord, minutes) => { const template = (minutes < 10) ? 'past' : 'approach'; return makeApprox(hoursAsWord, template); }, 'nearQuarter': (hoursAsWord, minutes) => { const direction = (minutes > 30) ? 'to' : 'past'; const quarter = utils.random(words.quarter); const formatted = `${quarter} ${direction}\n${hoursAsWord}`; return (minutes === 15 || minutes === 45) ? formatted : makeApprox(formatted); }, 'nearHalf': (hoursAsWord, minutes) => { const half = utils.random(words.half); const formatted = `${half}\n${hoursAsWord}`; const template = (minutes > 30) ? 'past' : 'approach'; return (minutes === 30) ? formatted : makeApprox(formatted, template); }, }; function getFormatter(hours, minutes) { if (minutes === 0) { return 'onTheHour'; } else if (minutes > 50 || minutes < 10) { return 'nearTheHour'; } else if (minutes > 40|| minutes < 20) { return 'nearQuarter'; } return 'nearHalf'; } function drawDumbTime(hours, minutes, formatter) { function formatTime(hours, minutes, formatter) { const hoursAsWord = utils.hours2Word(hours, minutes); return formatter(hoursAsWord, minutes); } utils.print(formatTime(hours, minutes, formatter)); } function cancelTimeout() { if (secondInterval) { clearTimeout(secondInterval); } secondInterval = undefined; } function refreshTime(force) { function clearForRefresh() { g.clearRect(0, 24, g.getWidth(), g.getHeight()-24); g.reset(); g.setFontAlign(0,0); } function setRefreshInterval(time) { const secondsTillRefresh = 60 - time.getSeconds(); secondInterval = setTimeout(refreshTime, secondsTillRefresh * 1000); return secondInterval; } force = force === true; cancelTimeout(); const time = new Date(); if (showRealTime) { clearForRefresh(); drawRealTime(time); return setRefreshInterval(time); } const hours = time.getHours(); const minutes = time.getMinutes(); const formatter = getFormatter(hours, minutes); if (formatter !== currentFormatter) { clearForRefresh(); currentFormatter = formatter; drawDumbTime(hours, minutes, formatters[formatter]); } return setRefreshInterval(time); } function startClock() { const secondsToRefresh = refreshTime(); } function addEvents() { Bangle.on('lcdPower', (on) => { cancelTimeout(); currentFormatter = null; if (on) { startClock(); } }); // Show launcher when button pressed Bangle.setUI("clockupdown", btn=>{ if (btn<0) switchMode(); if (btn>0) { currentFormatter = null; refreshTime(); } }); } function init() { g.clear(); startClock(); Bangle.loadWidgets(); Bangle.drawWidgets(); addEvents(); } init();