mirror of https://github.com/espruino/BangleApps
Merge pull request #2440 from thyttan/bwclock-fontless
[BW Clock Lite] New version using bitmap font making it quickerpull/2637/head
commit
4f8717c772
|
@ -0,0 +1,36 @@
|
|||
0.01: New App.
|
||||
0.02: Use build in function for steps and other improvements.
|
||||
0.03: Adapt colors based on the theme of the user.
|
||||
0.04: Steps can be hidden now such that the time is even larger.
|
||||
0.05: Included icons for information.
|
||||
0.06: Design and usability improvements.
|
||||
0.07: Improved positioning.
|
||||
0.08: Select the color of widgets correctly. Additional settings to hide colon.
|
||||
0.09: Larger font size if colon is hidden to improve readability further.
|
||||
0.10: HomeAssistant integration if HomeAssistant is installed.
|
||||
0.11: Performance improvements.
|
||||
0.12: Implements a 2D menu.
|
||||
0.13: Clicks < 24px are for widgets, if fullscreen mode is disabled.
|
||||
0.14: Adds humidity to weather data.
|
||||
0.15: Added option for a dynamic mode to show widgets only if unlocked.
|
||||
0.16: You can now show your agenda if your calendar is synced with Gadgetbridge.
|
||||
0.17: Fix - Step count was no more shown in the menu.
|
||||
0.18: Set timer for an agenda entry by simply clicking in the middle of the screen. Only one timer can be set.
|
||||
0.19: Fix - Compatibility with "Digital clock widget"
|
||||
0.20: Better handling of async data such as getPressure.
|
||||
0.21: On the default menu the week of year can be shown.
|
||||
0.22: Use the new clkinfo module for the menu.
|
||||
0.23: Feedback of apps after run is now optional and decided by the corresponding clkinfo.
|
||||
0.24: Update clock_info to avoid a redraw
|
||||
0.25: Use Bangle.setUI({remove:...}) to allow loading the launcher without a full reset on fw2v16.
|
||||
ClockInfo Fix: Use .get instead of .show as .show is not implemented for weather etc.
|
||||
0.26: Use clkinfo.addInteractive instead of a custom implementation
|
||||
0.27: Clean out some leftovers in the remove function after switching to
|
||||
clkinfo.addInteractive that would cause ReferenceError.
|
||||
0.28: Option to show (1) time only and (2) week of year.
|
||||
0.29: use setItem of clockInfoMenu to change the active item
|
||||
0.30: Use widget_utils
|
||||
0.31: Use clock_info module as an app
|
||||
0.32: Diverge from BW Clock. Change out the custom font for a standard bitmap one to speed up loading times.
|
||||
Remove invertion of theme as this doesn'twork very well with fastloading.
|
||||
Do an quick inital fillRect on theclock info area.
|
|
@ -0,0 +1,30 @@
|
|||
# BW Clock Lite
|
||||
This is a fork of a very minimalistic clock.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
The BW clock implements features that are exposed by other apps through the `clkinfo` module.
|
||||
For example, if you install the Simple Timer app, this menu item will be shown if you first
|
||||
touch the bottom of the screen and then swipe left/right to the Simple Timer menu. To select
|
||||
sub-items simply swipe up/down. To run an action (e.g. add 5 min), simply select the clkinfo (border) and touch on the item again. See also the screenshot below:
|
||||
|
||||

|
||||
|
||||
Note: Check out the settings to change different themes.
|
||||
|
||||
## Settings
|
||||
- Screen: Normal (widgets shown), Dynamic (widgets shown if unlocked) or Full (widgets are hidden).
|
||||
- Enable/disable lock icon in the settings. Useful if fullscreen mode is on.
|
||||
- The colon (e.g. 7:35 = 735) can be hidden in the settings for an even larger time font to improve readability further.
|
||||
- Your bangle uses the sys color settings so you can change the color too.
|
||||
|
||||
## Thanks to
|
||||
- Thanks to Gordon Williams not only for the great BangleJs, but specifically also for the implementation of `clkinfo` which simplified the BWClock a lot and moved complexety to the apps where it should be located.
|
||||
- <a href="https://www.flaticon.com/free-icons/" title="Icons">Icons created by Flaticon</a>
|
||||
|
||||
## Creator
|
||||
[David Peer](https://github.com/peerdavid)
|
||||
|
||||
## Contributors
|
||||
thyttan
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwgIcah0EgEB/H8iFsAoOY4kMBYMDhmGgXkAoUGiWkAoQQBoAFCjgnCAoM4hgFDuEI+wpC8EKyg1C/0eAoMAsEAiQvBAAeAApQAB/4Ao+P4v/wn0P8Pgn/wnkH4Pjv/j/nn9PH//n/nj/IFF4F88AXBAoM88EcAoPHj//jlDAoOf/+Y+YFHjnnjAjBEIIjD+BHDO9IALA=="))
|
|
@ -0,0 +1,331 @@
|
|||
{ // must be inside our own scope here so that when we are unloaded everything disappears
|
||||
|
||||
/************************************************
|
||||
* Includes
|
||||
*/
|
||||
const locale = require('locale');
|
||||
const storage = require('Storage');
|
||||
const clock_info = require("clock_info");
|
||||
const widget_utils = require("widget_utils");
|
||||
|
||||
/************************************************
|
||||
* Globals
|
||||
*/
|
||||
const SETTINGS_FILE = "bwclklite.setting.json";
|
||||
const W = g.getWidth();
|
||||
const H = g.getHeight();
|
||||
|
||||
/************************************************
|
||||
* Settings
|
||||
*/
|
||||
let settings = {
|
||||
screen: "Normal",
|
||||
showLock: true,
|
||||
hideColon: false,
|
||||
menuPosX: 0,
|
||||
menuPosY: 0,
|
||||
};
|
||||
|
||||
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
|
||||
for (const key in saved_settings) {
|
||||
settings[key] = saved_settings[key];
|
||||
}
|
||||
|
||||
let isFullscreen = function() {
|
||||
let s = settings.screen.toLowerCase();
|
||||
if(s == "dynamic"){
|
||||
return Bangle.isLocked();
|
||||
} else {
|
||||
return s == "full";
|
||||
}
|
||||
};
|
||||
|
||||
let getLineY = function(){
|
||||
return H/5*2 + (isFullscreen() ? 0 : 8);
|
||||
};
|
||||
|
||||
/************************************************
|
||||
* Assets
|
||||
*/
|
||||
let imgLock = function() {
|
||||
return {
|
||||
width : 16, height : 16, bpp : 1,
|
||||
transparent : 0,
|
||||
buffer : E.toArrayBuffer(atob("A8AH4A5wDDAYGBgYP/w//D/8Pnw+fD58Pnw//D/8P/w="))
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/************************************************
|
||||
* Clock Info
|
||||
*/
|
||||
let clockInfoItems = clock_info.load();
|
||||
|
||||
// Add some custom clock-infos
|
||||
let weekOfYear = function() {
|
||||
let date = new Date();
|
||||
date.setHours(0, 0, 0, 0);
|
||||
// Thursday in current week decides the year.
|
||||
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
|
||||
// January 4 is always in week 1.
|
||||
let week1 = new Date(date.getFullYear(), 0, 4);
|
||||
// Adjust to Thursday in week 1 and count number of weeks from date to week1.
|
||||
return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000
|
||||
- 3 + (week1.getDay() + 6) % 7) / 7);
|
||||
};
|
||||
|
||||
clockInfoItems[0].items.unshift({ name : "weekofyear",
|
||||
get : function() { return { text : "Week " + weekOfYear(),
|
||||
img : null};},
|
||||
show : function() {},
|
||||
hide : function() {},
|
||||
});
|
||||
|
||||
// Empty for large time
|
||||
clockInfoItems[0].items.unshift({ name : "nop",
|
||||
get : function() { return { text : null,
|
||||
img : null};},
|
||||
show : function() {},
|
||||
hide : function() {},
|
||||
});
|
||||
|
||||
|
||||
|
||||
let clockInfoMenu = clock_info.addInteractive(clockInfoItems, {
|
||||
app: "bwclklite",
|
||||
x : 0,
|
||||
y: 135,
|
||||
w: W,
|
||||
h: H-135,
|
||||
draw : (itm, info, options) => {
|
||||
let hideClkInfo = info.text == null;
|
||||
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(options.x, options.y, options.x+options.w, options.y+options.h);
|
||||
|
||||
g.setFontAlign(0,0);
|
||||
g.setColor(g.theme.bg);
|
||||
|
||||
if (options.focus){
|
||||
let y = hideClkInfo ? options.y+20 : options.y+2;
|
||||
let h = hideClkInfo ? options.h-20 : options.h-2;
|
||||
g.drawRect(options.x, y, options.x+options.w-2, y+h-1); // show if focused
|
||||
g.drawRect(options.x+1, y+1, options.x+options.w-3, y+h-2); // show if focused
|
||||
}
|
||||
|
||||
// In case we hide the clkinfo, we show the time again as the time should
|
||||
// be drawn larger.
|
||||
if(hideClkInfo){
|
||||
drawTime();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set text and font
|
||||
let image = info.img;
|
||||
let text = String(info.text);
|
||||
if(text.split('\n').length > 1){
|
||||
g.setFont("6x8"); //g.setMiniFont();
|
||||
} else {
|
||||
g.setFont("6x8:3"); //g.setSmallFont();
|
||||
}
|
||||
|
||||
// Compute sizes
|
||||
let strWidth = g.stringWidth(text);
|
||||
let imgWidth = image == null ? 0 : 24;
|
||||
let midx = options.x+options.w/2;
|
||||
|
||||
// Draw
|
||||
if (image) {
|
||||
let scale = imgWidth / image.width;
|
||||
g.drawImage(image, midx-parseInt(imgWidth*1.3/2)-parseInt(strWidth/2), options.y+6, {scale: scale});
|
||||
}
|
||||
g.drawString(text, midx+parseInt(imgWidth*1.3/2), options.y+20);
|
||||
|
||||
// In case we are in focus and the focus box changes (fullscreen yes/no)
|
||||
// we draw the time again. Otherwise it could happen that a while line is
|
||||
// not cleared correctly.
|
||||
if(options.focus) drawTime();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/************************************************
|
||||
* Draw
|
||||
*/
|
||||
let draw = function() {
|
||||
// Queue draw again
|
||||
queueDraw();
|
||||
|
||||
// Draw clock
|
||||
drawDate();
|
||||
drawTime();
|
||||
drawLock();
|
||||
drawWidgets();
|
||||
};
|
||||
|
||||
|
||||
let drawDate = function() {
|
||||
// Draw background
|
||||
let y = getLineY();
|
||||
g.reset().clearRect(0,0,W,y);
|
||||
|
||||
// Draw date
|
||||
y = parseInt(y/2)+4;
|
||||
y += isFullscreen() ? 0 : 8;
|
||||
let date = new Date();
|
||||
let dateStr = date.getDate();
|
||||
dateStr = ("0" + dateStr).substr(-2);
|
||||
g.setFont("6x8:4"); //g.setMediumFont(); // Needed to compute the width correctly
|
||||
let dateW = g.stringWidth(dateStr);
|
||||
|
||||
g.setFont("6x8:3"); //g.setSmallFont();
|
||||
let dayStr = locale.dow(date, true);
|
||||
let monthStr = locale.month(date, 1);
|
||||
let dayW = Math.max(g.stringWidth(dayStr), g.stringWidth(monthStr));
|
||||
let fullDateW = dateW + 10 + dayW;
|
||||
|
||||
g.setFontAlign(-1,0);
|
||||
g.drawString(dayStr, W/2 - fullDateW/2 + 10 + dateW, y-12);
|
||||
g.drawString(monthStr, W/2 - fullDateW/2 + 10 + dateW, y+11);
|
||||
|
||||
g.setFont("6x8:4"); //g.setMediumFont();
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawString(dateStr, W/2 - fullDateW / 2, y+2);
|
||||
};
|
||||
|
||||
|
||||
let drawTime = function() {
|
||||
let hideClkInfo = clockInfoMenu.menuA == 0 && clockInfoMenu.menuB == 0;
|
||||
|
||||
// Draw background
|
||||
let y1 = getLineY();
|
||||
let y = y1;
|
||||
let date = new Date();
|
||||
|
||||
let hours = String(date.getHours());
|
||||
let minutes = date.getMinutes();
|
||||
minutes = minutes < 10 ? String("0") + minutes : minutes;
|
||||
let colon = settings.hideColon ? "" : ":";
|
||||
let timeStr = hours + colon + minutes;
|
||||
|
||||
// Set y coordinates correctly
|
||||
y += parseInt((H - y)/2) + 5;
|
||||
|
||||
if (hideClkInfo){
|
||||
g.setFont("6x8:5"); //g.setLargeFont();
|
||||
} else {
|
||||
y -= 15;
|
||||
g.setFont("6x8:4"); //g.setMediumFont();
|
||||
}
|
||||
|
||||
// Clear region and draw time
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(0,y1,W,y+20 + (hideClkInfo ? 1 : 0) + (isFullscreen() ? 3 : 0));
|
||||
|
||||
g.setColor(g.theme.bg);
|
||||
g.setFontAlign(0,0);
|
||||
g.drawString(timeStr, W/2, y);
|
||||
};
|
||||
|
||||
|
||||
let drawLock = function() {
|
||||
if(settings.showLock && Bangle.isLocked()){
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawImage(imgLock(), W-16, 2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let drawWidgets = function() {
|
||||
if(isFullscreen()){
|
||||
widget_utils.hide();
|
||||
} else {
|
||||
Bangle.drawWidgets();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/************************************************
|
||||
* Listener
|
||||
*/
|
||||
// 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));
|
||||
};
|
||||
|
||||
|
||||
// Stop updates when LCD is off, restart when on
|
||||
let lcdListenerBw = function(on) {
|
||||
if (on) {
|
||||
draw(); // draw immediately, queue redraw
|
||||
} else { // stop draw timer
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
}
|
||||
};
|
||||
Bangle.on('lcdPower', lcdListenerBw);
|
||||
|
||||
let lockListenerBw = function(isLocked) {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
|
||||
if(!isLocked && settings.screen.toLowerCase() == "dynamic"){
|
||||
// If we have to show the widgets again, we load it from our
|
||||
// cache and not through Bangle.loadWidgets as its much faster!
|
||||
widget_utils.show();
|
||||
}
|
||||
|
||||
draw();
|
||||
};
|
||||
Bangle.on('lock', lockListenerBw);
|
||||
|
||||
let charging = function(charging){
|
||||
// Jump to battery
|
||||
clockInfoMenu.setItem(0, 2);
|
||||
drawTime();
|
||||
};
|
||||
Bangle.on('charging', charging);
|
||||
|
||||
let kill = function(){
|
||||
clockInfoMenu.remove();
|
||||
delete clockInfoMenu;
|
||||
};
|
||||
E.on("kill", kill);
|
||||
|
||||
/************************************************
|
||||
* Startup Clock
|
||||
*/
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI({
|
||||
mode : "clock",
|
||||
remove : function() {
|
||||
// Called to unload all of the clock app
|
||||
Bangle.removeListener('lcdPower', lcdListenerBw);
|
||||
Bangle.removeListener('lock', lockListenerBw);
|
||||
Bangle.removeListener('charging', charging);
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
// save settings
|
||||
kill();
|
||||
E.removeListener("kill", kill);
|
||||
Bangle.removeListener('charging', charging);
|
||||
widget_utils.show();
|
||||
}
|
||||
});
|
||||
|
||||
// Load widgets and draw clock the first time
|
||||
Bangle.loadWidgets();
|
||||
|
||||
// Draw first time
|
||||
g.setColor(g.theme.fg).fillRect(0,135,W,H); // Otherwise this rect will wait for clock_info before updating
|
||||
draw();
|
||||
|
||||
} // End of app scope
|
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"id": "bwclklite",
|
||||
"name": "BW Clock Lite",
|
||||
"version": "0.32",
|
||||
"description": "A very minimalistic clock. This version of BW Clock is quicker at the cost of the custom font.",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
"screenshots": [
|
||||
{
|
||||
"url": "screenshot.png"
|
||||
},
|
||||
{
|
||||
"url": "screenshot_2.png"
|
||||
},
|
||||
{
|
||||
"url": "screenshot_3.png"
|
||||
}
|
||||
],
|
||||
"type": "clock",
|
||||
"tags": "clock,clkinfo",
|
||||
"supports": [
|
||||
"BANGLEJS2"
|
||||
],
|
||||
"dependencies": {
|
||||
"clock_info": "module"
|
||||
},
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{
|
||||
"name": "bwclklite.app.js",
|
||||
"url": "app.js"
|
||||
},
|
||||
{
|
||||
"name": "bwclklite.img",
|
||||
"url": "app-icon.js",
|
||||
"evaluate": true
|
||||
},
|
||||
{
|
||||
"name": "bwclklite.settings.js",
|
||||
"url": "settings.js"
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,50 @@
|
|||
(function(back) {
|
||||
const SETTINGS_FILE = "bwclklite.setting.json";
|
||||
|
||||
// initialize with default settings...
|
||||
const storage = require('Storage')
|
||||
let settings = {
|
||||
screen: "Normal",
|
||||
showLock: true,
|
||||
hideColon: false,
|
||||
};
|
||||
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
|
||||
for (const key in saved_settings) {
|
||||
settings[key] = saved_settings[key]
|
||||
}
|
||||
|
||||
function save() {
|
||||
storage.write(SETTINGS_FILE, settings)
|
||||
}
|
||||
|
||||
var screenOptions = ["Normal", "Dynamic", "Full"];
|
||||
E.showMenu({
|
||||
'': { 'title': 'BW Clock' },
|
||||
'< Back': back,
|
||||
'Screen': {
|
||||
value: 0 | screenOptions.indexOf(settings.screen),
|
||||
min: 0, max: 2,
|
||||
format: v => screenOptions[v],
|
||||
onchange: v => {
|
||||
settings.screen = screenOptions[v];
|
||||
save();
|
||||
},
|
||||
},
|
||||
'Show Lock': {
|
||||
value: settings.showLock,
|
||||
format: () => (settings.showLock ? 'Yes' : 'No'),
|
||||
onchange: () => {
|
||||
settings.showLock = !settings.showLock;
|
||||
save();
|
||||
},
|
||||
},
|
||||
'Hide Colon': {
|
||||
value: settings.hideColon,
|
||||
format: () => (settings.hideColon ? 'Yes' : 'No'),
|
||||
onchange: () => {
|
||||
settings.hideColon = !settings.hideColon;
|
||||
save();
|
||||
},
|
||||
}
|
||||
});
|
||||
})
|
Loading…
Reference in New Issue