aiclock -- support clkinfo module and updated icons of some clkinfos...

pull/2349/head
David Peer 2022-12-04 16:42:24 +01:00
parent 11e5dc5905
commit fa70e5354c
18 changed files with 270 additions and 50 deletions

View File

@ -2,3 +2,4 @@
0.02: Design improvements and fixes.
0.03: Indicate battery level through line occurrence.
0.04: Use widget_utils module.
0.05: Support for clkinfo.

View File

@ -10,7 +10,9 @@ The original output of stable diffusion is shown here:
My implementation is shown below. Note that horizontal lines occur randomly, but the
probability is correlated with the battery level. So if your screen contains only
a few lines its time to charge your bangle again ;)
a few lines its time to charge your bangle again ;) Also note that the upper text
implementes the clkinfo module and can be configured via touch left/right/up/down.
Touch at the center to trigger the selected action.
![](impl.png)

View File

@ -1,6 +1,14 @@
/**
/************************************************
* AI Clock
*/
const storage = require('Storage');
const clock_info = require("clock_info");
/************************************************
* Assets
*/
require("Font7x11Numeric7Seg").add(Graphics);
Graphics.prototype.setFontGochiHand = function(scale) {
// Actual height 27 (29 - 3)
@ -13,7 +21,7 @@ Graphics.prototype.setFontGochiHand = function(scale) {
return this;
}
/*
/************************************************
* Set some important constants such as width, height and center
*/
var W = g.getWidth(),R=W/2;
@ -21,6 +29,120 @@ var H = g.getHeight();
var cx = W/2;
var cy = H/2;
var drawTimeout;
var lock_input = false;
/************************************************
* SETTINGS
*/
const SETTINGS_FILE = "aiclock.setting.json";
let settings = {
menuPosX: 0,
menuPosY: 0,
};
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
for (const key in saved_settings) {
settings[key] = saved_settings[key]
}
/************************************************
* Menu
*/
function getDate(){
var date = new Date();
return ("0"+date.getDate()).substr(-2) + "/" + ("0"+(date.getMonth()+1)).substr(-2)
}
// Custom clockItems menu - therefore, its added here and not in a clkinfo.js file.
var clockItems = {
name: getDate(),
img: null,
items: [
{ name: "Week",
get: () => ({ text: "Week " + weekOfYear(), img: null}),
show: function() { clockItems.items[0].emit("redraw"); },
hide: function () {}
},
]
};
function weekOfYear() {
var 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.
var 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);
}
// Load menu
var menu = clock_info.load();
menu = menu.concat(clockItems);
// Ensure that our settings are still in range (e.g. app uninstall). Otherwise reset the position it.
if(settings.menuPosX >= menu.length || settings.menuPosY > menu[settings.menuPosX].items.length ){
settings.menuPosX = 0;
settings.menuPosY = 0;
}
// Set draw functions for each item
menu.forEach((menuItm, x) => {
menuItm.items.forEach((item, y) => {
function drawItem() {
// For the clock, we have a special case, as we don't wanna redraw
// immediately when something changes. Instead, we update data each minute
// to save some battery etc. Therefore, we hide (and disable the listener)
// immedeately after redraw...
item.hide();
// After drawing the item, we enable inputs again...
lock_input = false;
var info = item.get();
drawMenuItem(info.text, info.img);
}
item.on('redraw', drawItem);
})
});
function canRunMenuItem(){
if(settings.menuPosY == 0){
return false;
}
var menuEntry = menu[settings.menuPosX];
var item = menuEntry.items[settings.menuPosY-1];
return item.run !== undefined;
}
function runMenuItem(){
if(settings.menuPosY == 0){
return;
}
var menuEntry = menu[settings.menuPosX];
var item = menuEntry.items[settings.menuPosY-1];
try{
var ret = item.run();
if(ret){
Bangle.buzz(300, 0.6);
}
} catch (ex) {
// Simply ignore it...
}
}
/*
* Based on the great multi clock from https://github.com/jeffmer/BangleApps/
@ -76,7 +198,50 @@ function toAngle(a){
return a
}
function drawMenuItem(text, image){
if(text == null){
drawTime();
return
}
// image = atob("GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA==");
text = String(text);
g.reset().setBgColor("#fff").setColor("#000");
g.setFontAlign(0,0);
g.setFont("Vector", 20);
var imgWidth = image == null ? 0 : 24;
var strWidth = g.stringWidth(text);
var strHeight = text.split('\n').length > 1 ? 40 : Math.max(24, imgWidth+2);
var w = imgWidth + strWidth;
g.clearRect(cx-w/2-8, 40-strHeight/2-1, cx+w/2+4, 40+strHeight/2)
// Draw right line as designed by stable diffusion
g.drawLine(cx+w/2+5, 40-strHeight/2-1, cx+w/2+5, 40+strHeight/2);
g.drawLine(cx+w/2+6, 40-strHeight/2-1, cx+w/2+6, 40+strHeight/2);
g.drawLine(cx+w/2+7, 40-strHeight/2-1, cx+w/2+7, 40+strHeight/2);
// And finally the text
g.drawString(text, cx+imgWidth/2, 42);
g.drawString(text, cx+1+imgWidth/2, 41);
if(image != null) {
var scale = image.width ? imgWidth / image.width : 1;
g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 41-12, {scale: scale});
}
drawTime();
}
function drawTime(){
// Draw digital time first
drawDigits();
// And now the analog time
var drawHourHand = g.drawRotRect.bind(g,8,12,R-38);
var drawMinuteHand = g.drawRotRect.bind(g,6,12,R-12 );
@ -90,13 +255,6 @@ function drawTime(){
h += date.getMinutes()/60.0;
h = parseInt(h*360/12);
// Draw minute and hour bg
g.setColor(g.theme.bg);
drawHourHand(toAngle(h-3));
drawHourHand(toAngle(h+3));
drawMinuteHand(toAngle(m-2));
drawMinuteHand(toAngle(m+3));
// Draw minute and hour fg
g.setColor(g.theme.fg);
drawHourHand(h);
@ -104,28 +262,6 @@ function drawTime(){
}
function drawDate(){
var date = new Date();
g.setFontAlign(0,0);
g.setFontGochiHand();
var text = ("0"+date.getDate()).substr(-2) + "/" + ("0"+(date.getMonth()+1)).substr(-2);
var w = g.stringWidth(text);
g.setColor(g.theme.bg);
g.fillRect(cx-w/2-4, 20, cx+w/2+4, 40+12);
g.setColor(g.theme.fg);
// Draw right line as designed by stable diffusion
g.drawLine(cx+w/2+5, 20, cx+w/2+5, 40+12);
g.drawLine(cx+w/2+6, 20, cx+w/2+6, 40+12);
g.drawLine(cx+w/2+7, 20, cx+w/2+7, 40+12);
// And finally the text
g.drawString(text, cx, 40);
}
function drawDigits(){
var date = new Date();
@ -156,20 +292,35 @@ function drawDigits(){
}
function drawDate(){
var menuEntry = menu[settings.menuPosX];
// The first entry is the overview...
if(settings.menuPosY == 0){
drawMenuItem(menuEntry.name, menuEntry.img);
return;
}
// Draw item if needed
lock_input = true;
var item = menuEntry.items[settings.menuPosY-1];
item.show();
}
function draw(){
// Queue draw in one minute
queueDraw();
g.reset();
g.clearRect(0, 0, g.getWidth(), g.getHeight());
g.setColor(1,1,1);
drawBackground();
drawDate();
drawDigits();
drawTime();
drawCircle(Bangle.isLocked());
}
@ -190,6 +341,68 @@ Bangle.on('lock', function(isLocked) {
drawCircle(isLocked);
});
Bangle.on('touch', function(btn, e){
var left = parseInt(g.getWidth() * 0.22);
var right = g.getWidth() - left;
var upper = parseInt(g.getHeight() * 0.22);
var lower = g.getHeight() - upper;
var is_upper = e.y < upper;
var is_lower = e.y > lower;
var is_left = e.x < left && !is_upper && !is_lower;
var is_right = e.x > right && !is_upper && !is_lower;
var is_center = !is_upper && !is_lower && !is_left && !is_right;
if(lock_input){
return;
}
if(is_lower){
Bangle.buzz(40, 0.6);
settings.menuPosY = (settings.menuPosY+1) % (menu[settings.menuPosX].items.length+1);
draw();
}
if(is_upper){
Bangle.buzz(40, 0.6);
settings.menuPosY = settings.menuPosY-1;
settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length : settings.menuPosY;
draw();
}
if(is_right){
Bangle.buzz(40, 0.6);
settings.menuPosX = (settings.menuPosX+1) % menu.length;
settings.menuPosY = 0;
draw();
}
if(is_left){
Bangle.buzz(40, 0.6);
settings.menuPosY = 0;
settings.menuPosX = settings.menuPosX-1;
settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX;
draw();
}
if(is_center){
if(canRunMenuItem()){
runMenuItem();
}
}
});
E.on("kill", function(){
try{
storage.write(SETTINGS_FILE, settings);
} catch(ex){
// If this fails, we still kill the app...
}
});
/*
* Some helpers
@ -203,7 +416,6 @@ function queueDraw() {
}
/*
* Lets start widgets, listen for btn etc.
*/
@ -216,6 +428,7 @@ Bangle.loadWidgets();
* area to the top bar doesn't get cleared.
*/
require('widget_utils').hide();
// Clear the screen once, at startup and draw clock
g.setTheme({bg:"#fff",fg:"#000",dark:false}).clear();
draw();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
apps/aiclock/impl_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
apps/aiclock/impl_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -3,7 +3,7 @@
"name": "AI Clock",
"shortName":"AI Clock",
"icon": "aiclock.png",
"version":"0.04",
"version":"0.05",
"readme": "README.md",
"supports": ["BANGLEJS2"],
"description": "A watch face that was designed by an AI (stable diffusion) and implemented by a human.",
@ -11,7 +11,9 @@
"tags": "clock",
"screenshots": [
{"url":"orig.png"},
{"url":"impl.png"}
{"url":"impl.png"},
{"url":"impl_2.png"},
{"url":"impl_3.png"},
],
"storage": [
{"name":"aiclock.app.js","url":"aiclock.app.js"},

View File

@ -3,3 +3,4 @@
0.03: Added clkinfo for clocks.
0.04: Feedback if clkinfo run is called.
0.05: Clkinfo improvements.
0.06: Updated clkinfo icon.

View File

@ -4,7 +4,7 @@
var haItems = {
name: "Home",
img: atob("GBiBAf/////////n///D//+B//8A//48T/wkD/gkD/A8D+AYB8AYA4eZ4QyZMOyZN+fb5+D/B+B+B+A8B+AYB+AYB+AYB+AYB+A8Bw=="),
img: atob("GBiBAAAAAAAAAAAAAAAYAAA+AAB+AADD4AHb4APD4Afn8A/n+BxmOD0mnA0ksAwAMA+B8A/D8A/n8A/n8A/n8A/n8AAAAAAAAAAAAA=="),
items: []
};

View File

@ -1,7 +1,7 @@
{
"id": "ha",
"name": "HomeAssistant",
"version": "0.05",
"version": "0.06",
"description": "Integrates your BangleJS into HomeAssistant.",
"icon": "ha.png",
"type": "app",

View File

@ -2,3 +2,4 @@
0.02: Rewrite with new interface
0.03: Added clock infos to expose timer functionality to clocks.
0.04: Improvements of clock infos.
0.05: Updated clkinfo icon.

View File

@ -63,10 +63,9 @@
} catch(ex){ }
}
var img = atob("GBiBAeAAB+AAB/v/3/v/3/v/3/v/3/v/n/n/H/z+P/48//85//+b//+b//8p//4E//yCP/kBH/oAn/oAX/oAX/oAX/oAX+AAB+AABw==")
var smpltmrItems = {
name: "Timer",
img: img,
img: atob("GBiBAAB+AAB+AAAYAAAYAAB+AA3/sA+B8A4AcAwMMBgPGBgPmDAPjDAPzDAPzDP/zDP/zDH/jBn/mBj/GAw8MA4AcAeB4AH/gAB+AA=="),
items: [
{
name: null,

View File

@ -2,7 +2,7 @@
"id": "smpltmr",
"name": "Simple Timer",
"shortName": "Simple Timer",
"version": "0.04",
"version": "0.05",
"description": "A very simple app to start a timer.",
"icon": "app.png",
"tags": "tool,alarm,timer,clkinfo",

View File

@ -17,3 +17,4 @@
0.18: Added hasRange to clkinfo.
0.19: Added weather condition to clkinfo.
0.20: Added weather condition with temperature to clkinfo.
0.21: Updated clkinfo icon.

View File

@ -28,7 +28,7 @@
//FIXME ranges are somehow arbitrary
var weatherItems = {
name: "Weather",
img: atob("GBiBAf+///u5//n7//8f/9wHP8gDf/gB//AB/7AH/5AcP/AQH/DwD/uAD84AD/4AA/wAAfAAAfAAAfAAAfgAA/////+bP/+zf/+zfw=="),
img: atob("GBiBAABAAARGAAYEAADgACP4wDf8gAf+AA/+AE/4AG/jwA/v4A8P8AR/8DH/8AH//AP//g///g///g///gf//AAAAABkwABMgABMgA=="),
items: [
{
name: "conditionWithTemperature",

View File

@ -1,7 +1,7 @@
{
"id": "weather",
"name": "Weather",
"version": "0.20",
"version": "0.21",
"description": "Show Gadgetbridge weather report",
"icon": "icon.png",
"screenshots": [{"url":"screenshot.png"}],

2
core

@ -1 +1 @@
Subproject commit 3a953179b7bb9f574d4e77d5f34b6b7deee1e884
Subproject commit 76419750083a88ee7a569db3975ae1bdd6dc155a

View File

@ -77,7 +77,7 @@ exports.load = function() {
// actual menu
var menu = [{
name: "Bangle",
img: atob("GBiBAf8B//4B//4B//4B//4A//x4//n+f/P/P+fPn+fPn+fP3+/Px+/Px+fn3+fzn+f/n/P/P/n+f/x4//4A//4B//4B//4B//8B/w=="),
img: atob("GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA=="),
items: [
{ name : "Battery",
hasRange : true,