Skip to content

[AIClock] Added clkinfos #2349

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/aiclock/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -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.
4 changes: 3 additions & 1 deletion apps/aiclock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
285 changes: 249 additions & 36 deletions apps/aiclock/aiclock.app.js
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -13,14 +21,128 @@ Graphics.prototype.setFontGochiHand = function(scale) {
return this;
}

/*
/************************************************
* Set some important constants such as width, height and center
*/
var W = g.getWidth(),R=W/2;
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/
Expand Down Expand Up @@ -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 );

Expand All @@ -90,42 +255,13 @@ 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);
drawMinuteHand(m);
}



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();

Expand Down Expand Up @@ -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());
}

Expand All @@ -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
Expand All @@ -203,7 +416,6 @@ function queueDraw() {
}



/*
* Lets start widgets, listen for btn etc.
*/
Expand All @@ -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();
Expand Down
Binary file modified apps/aiclock/impl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/aiclock/impl_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/aiclock/impl_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading