Skip to content

mosaic-plus #3864

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions apps/mosaic-plus/ChangeLog
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
0.01: First release
0.02: Use locale time
0.03: Change for fast loading, use widget_utils to hide widgets
0.04: Minor code improvements
0.05: Forked from mosaic. Added battery gauge and weekday.
22 changes: 22 additions & 0 deletions apps/mosaic-plus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Mosaic Clock +

A fabulously colourful clock, now with battery bar and day of the week!

Based on Mosaic Clock by [Sir Indy](https://github.com/sir-indy), with some slight modifcations.

Original features:
* Clearly shows the time on a colourful background that changes every minute.
* Dark and Light theme compatible, with a setting to override the digit colour scheme.
* Show or hide widgets with a setting (default hides widgets, swipe down to show them thanks to `widget_utils`).

PLUS:
* Battery bar
* Three-digit weekday

![](mosaic-plus-scr0.png)
![](mosaic-plus-scr1.png)

This clock is inspired by the mosaic watchface for pebble: https://apps.rebble.io/en_US/application/55386bcd2aead62b16000028

Written by: [Sir Indy](https://github.com/sir-indy)
Modified by: [steeb-k](https://github.com/steeb-k)
22 changes: 22 additions & 0 deletions apps/mosaic-plus/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"id":"mosaic-plus",
"name":"Mosaic Clock +",
"shortName": "Mosaic Clock +",
"version": "0.05",
"description": "A fabulously colourful clock - plus weekday and battery bar.",
"readme": "README.md",
"icon":"mosaic-plus.png",
"screenshots": [{"url":"mosaic-plus-scr0.png"},{"url":"mosaic-plus-scr1.png"}],
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS2"],
"allow_emulator": true,
"storage": [
{"name":"mosaic-plus.app.js","url":"mosaic-plus.app.js"},
{"name":"mosaic-plus.settings.js","url":"mosaic-plus.settings.js"},
{"name":"mosaic-plus.img","url":"mosaic-plus.icon.js","evaluate":true}
],
"data": [
{"name":"mosaic-plus.settings.json"}
]
}
Binary file added apps/mosaic-plus/mosaic-plus-scr0.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/mosaic-plus/mosaic-plus-scr1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
196 changes: 196 additions & 0 deletions apps/mosaic-plus/mosaic-plus.app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
Array.prototype.sample = function(){
return this[Math.floor(Math.random()*this.length)];
};

{
const SETTINGS_FILE = "mosaic.settings.json";
let settings;
let theme;
let timeout = 60;
let drawTimeout;
let colours = [
'#f00', '#00f', '#0f0', '#ff0', '#f0f', '#0ff',
'#8f0', '#f08', '#f80', '#80f', '#0f8', '#08f',
];
let digits = [
E.toArrayBuffer(atob("BQcB/Gtax+A=")),
E.toArrayBuffer(atob("BQeCAX9c1zXNc1zX9A==")),
E.toArrayBuffer(atob("BQcB/Hsbx+A=")),
E.toArrayBuffer(atob("BQcB/Hsex+A=")),
E.toArrayBuffer(atob("BQeCAf/zPM8D/Nc1/A==")),
E.toArrayBuffer(atob("BQcB/G8ex+A=")),
E.toArrayBuffer(atob("BQcB/G8ax+A=")),
E.toArrayBuffer(atob("BQeCAf/wP81zXNc1/A==")),
E.toArrayBuffer(atob("BQcB/Gsax+A=")),
E.toArrayBuffer(atob("BQcB/Gsex+A="))
];

// Day of week abbreviations
const days = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];

let loadSettings = function() {
settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'showWidgets': false, 'theme':'System'};
}

let loadThemeColors = function() {
theme = {fg: g.theme.fg, bg: g.theme.bg};
if (settings.theme === "Dark") {
theme.fg = g.toColor(1,1,1);
theme.bg = g.toColor(0,0,0);
}
else if (settings.theme === "Light") {
theme.fg = g.toColor(0,0,0);
theme.bg = g.toColor(1,1,1);
}
}

let queueDraw = function(seconds) {
let millisecs = seconds * 1000;
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw();
}, millisecs - (Date.now() % millisecs));
}

let draw = function() {
// draw colourful grid
for (let i_x = 0; i_x < num_squares_w; i_x++) {
for (let i_y = 0; i_y < num_squares_h; i_y++) {
g.setColor(colours.sample()).fillRect(
o_w+i_x*s, o_h+i_y*s, o_w+i_x*s+s, o_h+i_y*s+s
);
}
}

let now = new Date();
let t = require("locale").time(now, 1);
let hour = parseInt(t.split(":")[0]);
let minute = parseInt(t.split(":")[1]);
let dayOfWeek = days[now.getDay()];

// Draw time (shifted left)
g.setBgColor(theme.fg);
g.setColor(theme.bg);
g.drawImage(digits[Math.floor(hour/10)], (mid_x-7)*s+o_w, (mid_y-7)*s+o_h, {scale:s});
g.drawImage(digits[hour % 10], (mid_x-1)*s+o_w, (mid_y-7)*s+o_h, {scale:s});
g.drawImage(digits[Math.floor(minute/10)], (mid_x-7)*s+o_w, (mid_y+1)*s+o_h, {scale:s});
g.drawImage(digits[minute % 10], (mid_x-1)*s+o_w, (mid_y+1)*s+o_h, {scale:s});

// Draw day of week (vertical to the right of time)
g.setFontAlign(0, 0);
g.setFont("Vector", 30); // Scalable vector font, clean and large

// Calculate position for each character
let dayX = (mid_x + 7) * s + o_w; // unchanged
let lineSpacing = 3 * s;
let timeBottom = (mid_y + 1) * s + o_h + 7 * s;
let dayY = timeBottom - (dayOfWeek.length * lineSpacing) + lineSpacing / 2;

// Draw each character vertically with matching time style
for (let i = 0; i < dayOfWeek.length; i++) {
let y = dayY + i * 3 * s;
// Draw filled background box
g.setColor(theme.bg);
g.fillRect(dayX - 15, y - 16, dayX + 10, y + 14); // Adjust box size as needed
// Draw character
g.setColor(theme.fg);
//drawBoldText(dayOfWeek[i], dayX, y);
g.drawString(dayOfWeek[i], dayX, y);
}
const boxLeft = dayX - 15;
const boxRight = dayX + 10;
//const boxWidth = boxRight - boxLeft;

let batt = E.getBattery(); // battery %
batt = Math.max(10, batt); // clamp to 10% minimum for visibility

//let batteryGap = 0;
let padding = 4;

// Box dimensions
let batteryTop = (mid_y - 7) * s + o_h; // top of time digits
let batteryBottom = dayY - lineSpacing + 6; // above top of day text

// Ensure correct vertical direction
let topY = Math.min(batteryTop, batteryBottom);
let bottomY = Math.max(batteryTop, batteryBottom);
//let batteryHeight = bottomY - topY;

let innerTop = topY + padding;
let innerBottom = bottomY - padding;
let innerHeight = innerBottom - innerTop;
let batteryFillHeight = Math.round((batt / 100) * innerHeight);

// Choose battery color
let fillColor =
batt > 75 ? "#0F0" : // Green
batt > 25 ? "#FF0" : // Yellow
"#F00"; // Red

// Outer white background
g.setColor(theme.bg);
g.fillRect(boxLeft, topY, boxRight, bottomY);

// Border
g.setColor(theme.bg);
g.drawRect(boxLeft, topY, boxRight, bottomY);

// Inner fill (bottom-up)
g.setColor(fillColor);
g.fillRect(
boxLeft + padding,
innerBottom - batteryFillHeight,
boxRight - padding,
innerBottom
);


queueDraw(timeout);
}

g.clear();
loadSettings();
loadThemeColors();

const offset_widgets = settings.showWidgets ? 24 : 0;
let available_height = g.getHeight() - offset_widgets;

// Calculate grid size and offsets
let s = Math.floor(available_height/17);
let num_squares_w = Math.round(g.getWidth()/s) - 1;
let num_squares_h = Math.round(available_height/s) - 1;
let o_w = Math.floor((g.getWidth() - num_squares_w * s)/2);
let o_h = Math.floor((g.getHeight() - num_squares_h * s+offset_widgets)/2);
let mid_x = Math.floor(num_squares_w/2);
let mid_y = Math.floor((num_squares_h-1)/2);

Bangle.on('lcdPower',on=>{
if (on) {
draw(); // draw immediately, queue redraw
} else { // stop draw timer
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
}
});

Bangle.setUI({
mode : 'clock',
remove : function() {
// Called to unload all of the clock app
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
delete Array.prototype.sample;
require('widget_utils').show(); // re-show widgets
}
});

Bangle.loadWidgets();
if (settings.showWidgets) {
Bangle.drawWidgets();
} else {
require("widget_utils").swipeOn(); // hide widgets, make them visible with a swipe
}

draw();
}
1 change: 1 addition & 0 deletions apps/mosaic-plus/mosaic-plus.icon.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added apps/mosaic-plus/mosaic-plus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions apps/mosaic-plus/mosaic-plus.settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
(function(back) {
const SETTINGS_FILE = "mosaic.settings.json";

// initialize with default settings...
let s = {'showWidgets': false, 'theme':'System'}

// ...and overwrite them with any saved values
// This way saved values are preserved if a new version adds more settings
const storage = require('Storage')
let settings = storage.readJSON(SETTINGS_FILE, 1) || s;
const saved = settings || {}
for (const key in saved) {
s[key] = saved[key]
}

function save() {
settings = s
storage.write(SETTINGS_FILE, settings)
}

var theme_options = ['System', 'Light', 'Dark'];

E.showMenu({
'': { 'title': 'Mosaic Clock' },
'< Back': back,
'Show Widgets': {
value: settings.showWidgets,
onchange: () => {
settings.showWidgets = !settings.showWidgets;
save();
}
},
'Theme': {
value: 0 | theme_options.indexOf(s.theme),
min: 0, max: theme_options.length - 1,
format: v => theme_options[v],
onchange: v => {
s.theme = theme_options[v];
save();
}
},
});
})
Binary file added apps/mosaic-plus/pixel digits.xcf
Binary file not shown.