BangleApps/apps/shadowclk/interface.html

380 lines
12 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="../../css/spectre.min.css">
<link href="https://fonts.googleapis.com/css2?family=Londrina+Solid&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Londrina+Shadow&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=DotGothic16&display=swap" rel="stylesheet">
<title>3-Bit Color Picker</title>
<style>
.main-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.color-button {
width: 30px;
height: 30px;
border: 1px solid black;
margin: 5px;
cursor: pointer;
}
.color-0 {
background: #000
}
.color-1 {
background: #f00
}
.color-2 {
background: #0f0
}
.color-3 {
background: #ff0
}
.color-4 {
background: #00f
}
.color-5 {
background: #f0f
}
.color-6 {
background: #0ff
}
.color-7 {
background: #fff
}
#preview-box {
width: 176px;
height: 176px;
border: 1px solid black;
margin-top: 20px;
display: flex;
align-items: center;
justify-content: center;
background: white;
}
#preview-canvas {
display: block;
}
#toggle-bg {
margin-top: 20px;
}
#upload {
margin-top: 20px;
}
#message-container {
height: 40px;
margin-top: 20px;
text-align: center;
}
</style>
</head>
<body>
<script src="../../core/lib/interface.js"></script>
<div class="main-container">
<h1>3-Bit Color Picker</h1>
<div id="color-buttons-container"></div>
<button id="toggle-bg" class="btn btn-primary" onclick="toggleBackground()">Light/Dark</button>
<div id="preview-box">
<canvas id="preview-canvas" width="176" height="176"></canvas>
</div>
<button id="upload" class="btn btn-primary">Upload</button>
<div id="message-container">
<div id="message"></div>
</div>
</div>
<script>
const messageDiv = document.getElementById('message');
// Create and add color buttons to the UI
let colors = ['#000', '#f00', '#0f0', '#ff0', '#00f', '#f0f', '#0ff', '#fff'];
let colorButtonsContainer = document.getElementById('color-buttons-container');
colors.forEach((color, i) => {
let button = document.createElement('button');
button.className = `color-button color-${i}`;
button.dataset.color = color;
colorButtonsContainer.appendChild(button);
});
document.querySelectorAll(".color-button").forEach(button => {
button.addEventListener("click", () => {
selectedColor = button.dataset.color;
drawText(selectedColor);
});
});
// Format the current time in the desired format
function formatTime(date) {
let hours = date.getHours();
let minutes = date.getMinutes();
let formattedHours = hours < 10 ? `${hours}` : `${hours}`;
let formattedMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
return `${formattedHours}:${formattedMinutes}`;
}
// Get the current date as a formatted string
function getCurrentDate() {
let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
let suffixes = ["st", "nd", "rd", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th", "th", "st"];
let date = new Date();
let month = months[date.getMonth()];
let day = date.getDate();
let suffix = suffixes[day - 1];
let year = date.getFullYear();
return `${month} ${day}${suffix}, ${year}`;
}
// Get the current day of the week as a string
function getCurrentDay() {
let days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
let date = new Date();
return days[date.getDay()];
}
// Toggle the background color between dark and light
function toggleBackground() {
isDarkBg = !isDarkBg; // Toggle the background state
let previewBox = document.getElementById("preview-box");
previewBox.style.backgroundColor = isDarkBg ? "black" : "white";
drawText(selectedColor); // Redraw the text with updated color
}
// Draw the time, date, and day of the week on the canvas
function drawText(color) {
let canvas = document.getElementById("preview-canvas");
let ctx = canvas.getContext("2d");
let previewBox = document.getElementById("preview-box");
previewBox.style.backgroundColor = isDarkBg ? "black" : "white";
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Set the base font and selected color
ctx.font = "81px Londrina Solid";
ctx.fillStyle = color;
// Get the current local system time
let currentTime = formatTime(new Date());
// Measure the text width and calculate the horizontal position
let timeWidth = ctx.measureText(currentTime).width;
let xPos = (canvas.width - timeWidth) / 2;
// Measure the text height based on the font size and calculate the vertical position
let timeHeight = ctx.measureText('M').actualBoundingBoxAscent + ctx.measureText('M').actualBoundingBoxDescent;
let yPos = (canvas.height + timeHeight) / 2;
// Draw the time
ctx.fillText(currentTime, xPos, yPos);
// Set the outline font and color
ctx.font = "81px Londrina Shadow";
// Set the text color based on the background state
if (isDarkBg) {
ctx.fillStyle = "#fff";
} else {
ctx.fillStyle = "#000";
}
// Draw the time again
ctx.fillText(currentTime, xPos, yPos);
// Set the font for the date
ctx.font = "19px DotGothic16";
// Get the current date
let currentDate = getCurrentDate();
// Measure the date width and calculate the horizontal position
let dateWidth = ctx.measureText(currentDate).width;
xPos = (canvas.width - dateWidth) / 2;
// Draw the date
yPos += 20;
ctx.fillText(currentDate, xPos, yPos);
// Get the current day of the week
let currentDay = getCurrentDay();
// Measure the day width and calculate the horizontal position
let dayWidth = ctx.measureText(currentDay).width;
xPos = (canvas.width - dayWidth) / 2;
// Draw the day of the week
ctx.fillText(currentDay, xPos, yPos + 20);
}
// Converts a hexadecimal color code to a 16-bit integer value.
// If the input hex string is in short format (#rgb), it's converted to long format (#rrggbb) first.
// Returns the 16-bit integer value representing the color.
function hexToDec(hex) {
if (hex.length === 4) {
hex = `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`;
}
let r = parseInt(hex.slice(1, 3), 16) >> 3;
let g = parseInt(hex.slice(3, 5), 16) >> 2;
let b = parseInt(hex.slice(5, 7), 16) >> 3;
return (r << 11) | (g << 5) | b;
}
// Colors from 'Light BW' and 'Dark BW' themes
function createThemeColors(isDarkBg) {
return isDarkBg ? {
fg: hexToDec("#fff"),
bg: hexToDec("#000"),
fg2: hexToDec("#fff"),
bg2: hexToDec("#004"),
fgH: hexToDec("#fff"),
bgH: hexToDec("#00f"),
dark: true
} : {
fg: hexToDec("#000"),
bg: hexToDec("#fff"),
fg2: hexToDec("#000"),
bg2: hexToDec("#cff"),
fgH: hexToDec("#000"),
bgH: hexToDec("#0ff"),
dark: false
};
}
// Save the provided theme to Bangle.js storage and set Shadow Clock as the default clock
function saveThemeToSettings(theme) {
Puck.eval('[require("Storage").readJSON("setting.json", true)]', (dataArray) => {
let data = dataArray ? dataArray[0] : null;
if (data) {
// Ensure that data.theme exists
if (!data.theme) {
data.theme = {};
}
// Save all theme values
for (let key in theme) {
data.theme[key] = theme[key];
}
data.clock = "shadowclk.app.js"; // Set Shadow Clock as default
Puck.write(`require("Storage").write("setting.json", ${JSON.stringify(data)});\n`, (result) => {
console.log('Theme saved:', result);
});
}
});
}
// Initialize color and theme settings
let selectedColor = "#0ff";
let isDarkBg = false;
// Load settings from Bangle.js storage
function loadSettings(callback) {
// Set a timeout for loading the settings
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error("Timeout occurred")), 1000)
);
// Load settings from Bangle.js storage
const loadSettingsFromStorage = new Promise((resolve) => {
Puck.eval('[require("Storage").readJSON("shadowclk.json", true)]', (dataArray) => {
let data = dataArray ? dataArray[0] : null;
if (data) {
// Apply color and theme from JSON
const { color, theme } = data;
selectedColor = color;
isDarkBg = theme === "dark";
displayMessage("Previous settings loaded.", 3000);
} else {
// Use default values if there is no data for color and theme
selectedColor = "#0ff";
isDarkBg = false;
}
resolve();
});
});
// Execute the callback after loading the settings, or use default values in case of a timeout or error
Promise.race([loadSettingsFromStorage, timeout])
.then(() => callback())
.catch((error) => {
console.error(error);
// Use default values in case of a timeout or error
selectedColor = "#0ff";
isDarkBg = false;
callback();
});
}
// Update the time display every second
function updateTime() {
setInterval(() => {
drawText(selectedColor);
}, 1000);
}
// Display a message for a given duration and then remove it
function displayMessage(text, timeout) {
// Remove any existing message
while (messageDiv.firstChild) {
messageDiv.removeChild(messageDiv.firstChild);
}
// Create a new message element
const message = document.createElement('p');
message.innerHTML = text; // Use innerHTML instead of textContent
message.style.fontSize = '24px';
messageDiv.appendChild(message);
// Remove the message element after the timeout
setTimeout(() => {
messageDiv.removeChild(message);
}, timeout);
}
// Attach an event listener to the 'upload' button to save theme and color settings to Bangle.js storage
document.getElementById("upload").addEventListener("click", function () {
// Save theme settings to Bangle.js
let themeColors = createThemeColors(isDarkBg);
saveThemeToSettings(themeColors);
// Save Shadow Clock color setting
let data = {
color: selectedColor,
theme: isDarkBg ? "dark" : "light"
};
Puck.write(`require("Storage").write("shadowclk.json", ${JSON.stringify(data)});\n`, (result) => {
console.log('Color saved:', result);
});
// Display the message using displayMessage function
displayMessage('Configuration sent...<br>Hold button on Bangle.js', 5000);
});
// Load required fonts for the application
function loadFonts() {
return Promise.all([
document.fonts.load('81px Londrina Solid'),
document.fonts.load('81px Londrina Shadow'),
document.fonts.load('19px DotGothic16')
]);
}
async function init() {
await loadFonts(); // Load fonts before drawing for the first time
loadSettings(updateTime); // Pass updateTime as the callback function to loadSettings
}
init();
</script>
</body>
</html>