commit
e52e89f204
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: New config options such as step, meridian, short/long formats, custom prefix/suffix
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ Here's what an example configuration might look like:
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"customBox": { //
|
"customBox": {
|
||||||
"string": "Your text here",
|
"string": "Your text here",
|
||||||
"font": "CustomFont", // Custom fonts must be removed in setUI
|
"font": "CustomFont", // Custom fonts must be removed in setUI
|
||||||
"fontSize": 1,
|
"fontSize": 1,
|
||||||
|
|
@ -34,15 +34,23 @@ Here's what an example configuration might look like:
|
||||||
"yPadding": -4,
|
"yPadding": -4,
|
||||||
"xOffset": 0,
|
"xOffset": 0,
|
||||||
"yOffset": 3,
|
"yOffset": 3,
|
||||||
"boxPos": { "x": 0.5, "y": 0.5 }
|
"boxPos": { "x": 0.5, "y": 0.5 },
|
||||||
|
"prefix": "", // Adds a string to the beginning of the main string
|
||||||
|
"suffix": "", // Adds a string to the end of the main string
|
||||||
|
"disableSuffix": true, // Only used to remove the DayOfMonth suffix
|
||||||
|
"short": false // Gets long format value of time, meridian, date, or DoW
|
||||||
|
|
||||||
},
|
},
|
||||||
"bg": { // Can also be removed for no background
|
"bg": { // Can also be removed for no background
|
||||||
"img": "YourImageName.img"
|
"img": "YourImageName.img"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
__Breakdown of Parameters:__
|
__Breakdown of Parameters:__
|
||||||
|
|
||||||
|
* **Box Name:** The name of your text box. Box Clock includes functional support for "time", "date", "meridian" (AM/PM), "dow" (Day of Week), "batt" (Battery), and "step" (Step count). You can add additional custom boxes with unique titles.
|
||||||
|
|
||||||
* **string:** The text string to be displayed inside the box.
|
* **string:** The text string to be displayed inside the box.
|
||||||
|
|
||||||
* **font:** The font name given to g.setFont()
|
* **font:** The font name given to g.setFont()
|
||||||
|
|
@ -63,6 +71,14 @@ __Breakdown of Parameters:__
|
||||||
|
|
||||||
* **boxPos:** Initial position of the box on the screen. Values are fractions of the screen width (x) and height (y), so { "x": 0.5, "y": 0.5 } would be in the middle of the screen.
|
* **boxPos:** Initial position of the box on the screen. Values are fractions of the screen width (x) and height (y), so { "x": 0.5, "y": 0.5 } would be in the middle of the screen.
|
||||||
|
|
||||||
|
* **prefix:** Adds a string to the beginning of the main string. For example, you can set "prefix": "Steps: " to display "Steps: 100" for the step count.
|
||||||
|
|
||||||
|
* **suffix:** Adds a string to the end of the main string. For example, you can set "suffix": "%" to display "80%" for the battery percentage.
|
||||||
|
|
||||||
|
* **disableSuffix:** Applies only to the "date" box. Set to true to disable the DayOfMonth suffix. This is used to remove the "st","nd","rd", or "th" from the DayOfMonth number
|
||||||
|
|
||||||
|
* **short:** Set to false to get the long format value of time, meridian, date, or DayOfWeek. Short formats are used by default,
|
||||||
|
|
||||||
* **bg:** This specifies a custom background image, with the img property defining the name of the image file on the Bangle.js storage.
|
* **bg:** This specifies a custom background image, with the img property defining the name of the image file on the Bangle.js storage.
|
||||||
|
|
||||||
## Multiple Configurations
|
## Multiple Configurations
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
let w = g.getWidth();
|
let w = g.getWidth();
|
||||||
let h = g.getHeight();
|
let h = g.getHeight();
|
||||||
let totalWidth, totalHeight;
|
let totalWidth, totalHeight;
|
||||||
let enableSuffix = true;
|
|
||||||
let drawTimeout;
|
let drawTimeout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -165,13 +164,17 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
* 7. Date and time related functions
|
* 7. String forming helper functions
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
let getDate = function() {
|
let isBool = function(val, defaultVal) {
|
||||||
|
return typeof val !== 'undefined' ? Boolean(val) : defaultVal;
|
||||||
|
};
|
||||||
|
|
||||||
|
let getDate = function(short, disableSuffix) {
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
const dayOfMonth = date.getDate();
|
const dayOfMonth = date.getDate();
|
||||||
const month = locale.month(date, 1);
|
const month = short ? locale.month(date, 0) : locale.month(date, 1);
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
let suffix;
|
let suffix;
|
||||||
if ([1, 21, 31].includes(dayOfMonth)) {
|
if ([1, 21, 31].includes(dayOfMonth)) {
|
||||||
|
|
@ -183,12 +186,24 @@
|
||||||
} else {
|
} else {
|
||||||
suffix = "th";
|
suffix = "th";
|
||||||
}
|
}
|
||||||
let dayOfMonthStr = enableSuffix ? dayOfMonth + suffix : dayOfMonth;
|
let dayOfMonthStr = disableSuffix ? dayOfMonth : dayOfMonth + suffix;
|
||||||
return month + " " + dayOfMonthStr + ", " + year;
|
return month + " " + dayOfMonthStr + (short ? '' : (", " + year)); // not including year for short version
|
||||||
};
|
};
|
||||||
|
|
||||||
let getDayOfWeek = function(date) {
|
let getDayOfWeek = function(date, short) {
|
||||||
return locale.dow(date, 0);
|
return locale.dow(date, short ? 1 : 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
locale.meridian = function(date, short) {
|
||||||
|
let hours = date.getHours();
|
||||||
|
let meridian = hours >= 12 ? 'PM' : 'AM';
|
||||||
|
return short ? meridian[0] : meridian;
|
||||||
|
};
|
||||||
|
|
||||||
|
let modString = function(boxItem, data) {
|
||||||
|
let prefix = boxItem.prefix || '';
|
||||||
|
let suffix = boxItem.suffix || '';
|
||||||
|
return prefix + data + suffix;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -196,44 +211,56 @@
|
||||||
* 8. Main draw function
|
* 8. Main draw function
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
let draw = function(boxes) {
|
let draw = (function() {
|
||||||
date = new Date();
|
let updatePerMinute = true; // variable to track the state of time display
|
||||||
g.clear();
|
|
||||||
if (bgImage) {
|
return function(boxes) {
|
||||||
g.drawImage(bgImage, 0, 0);
|
date = new Date();
|
||||||
}
|
g.clear();
|
||||||
if (boxes.time) {
|
if (bgImage) {
|
||||||
boxes.time.string = locale.time(date, 1);
|
g.drawImage(bgImage, 0, 0);
|
||||||
}
|
|
||||||
if (boxes.date) {
|
|
||||||
boxes.date.string = getDate();
|
|
||||||
}
|
|
||||||
if (boxes.dow) {
|
|
||||||
boxes.dow.string = getDayOfWeek(date);
|
|
||||||
}
|
|
||||||
if (boxes.batt) {
|
|
||||||
boxes.batt.string = E.getBattery() + "%";
|
|
||||||
}
|
|
||||||
boxKeys.forEach((boxKey) => {
|
|
||||||
let boxItem = boxes[boxKey];
|
|
||||||
calcBoxSize(boxItem);
|
|
||||||
const pos = calcBoxPos(boxKey);
|
|
||||||
if (isDragging[boxKey]) {
|
|
||||||
g.setColor(boxItem.border);
|
|
||||||
g.drawRect(pos.x1, pos.y1, pos.x2, pos.y2);
|
|
||||||
}
|
}
|
||||||
g.drawString(
|
if (boxes.time) {
|
||||||
boxItem,
|
boxes.time.string = modString(boxes.time, locale.time(date, isBool(boxes.time.short, true) ? 1 : 0));
|
||||||
boxItem.string,
|
updatePerMinute = isBool(boxes.time.short, true);
|
||||||
boxPos[boxKey].x + boxItem.xOffset,
|
}
|
||||||
boxPos[boxKey].y + boxItem.yOffset
|
if (boxes.meridian) {
|
||||||
);
|
boxes.meridian.string = modString(boxes.meridian, locale.meridian(date, isBool(boxes.meridian.short, true)));
|
||||||
});
|
}
|
||||||
if (!Object.values(isDragging).some(Boolean)) {
|
if (boxes.date) {
|
||||||
if (drawTimeout) clearTimeout(drawTimeout);
|
boxes.date.string = modString(boxes.date, getDate(isBool(boxes.date.short, true), isBool(boxes.date.disableSuffix, false)));
|
||||||
drawTimeout = setTimeout(() => draw(boxes), 60000 - (Date.now() % 60000));
|
}
|
||||||
}
|
if (boxes.dow) {
|
||||||
};
|
boxes.dow.string = modString(boxes.dow, getDayOfWeek(date, isBool(boxes.dow.short, true)));
|
||||||
|
}
|
||||||
|
if (boxes.batt) {
|
||||||
|
boxes.batt.string = modString(boxes.batt, E.getBattery());
|
||||||
|
}
|
||||||
|
if (boxes.step) {
|
||||||
|
boxes.step.string = modString(boxes.step, Bangle.getStepCount());
|
||||||
|
}
|
||||||
|
boxKeys.forEach((boxKey) => {
|
||||||
|
let boxItem = boxes[boxKey];
|
||||||
|
calcBoxSize(boxItem);
|
||||||
|
const pos = calcBoxPos(boxKey);
|
||||||
|
if (isDragging[boxKey]) {
|
||||||
|
g.setColor(boxItem.border);
|
||||||
|
g.drawRect(pos.x1, pos.y1, pos.x2, pos.y2);
|
||||||
|
}
|
||||||
|
g.drawString(
|
||||||
|
boxItem,
|
||||||
|
boxItem.string,
|
||||||
|
boxPos[boxKey].x + boxItem.xOffset,
|
||||||
|
boxPos[boxKey].y + boxItem.yOffset
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (!Object.values(isDragging).some(Boolean)) {
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
let interval = updatePerMinute ? 60000 - (Date.now() % 60000) : 1000;
|
||||||
|
drawTimeout = setTimeout(() => draw(boxes), interval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@
|
||||||
"yPadding": 0.5,
|
"yPadding": 0.5,
|
||||||
"xOffset": 1,
|
"xOffset": 1,
|
||||||
"yOffset": 1,
|
"yOffset": 1,
|
||||||
"boxPos": { "x": 0.633, "y": 0.3 }
|
"boxPos": { "x": 0.633, "y": 0.3 },
|
||||||
|
"short": false
|
||||||
},
|
},
|
||||||
"date": {
|
"date": {
|
||||||
"font": "6x8",
|
"font": "6x8",
|
||||||
|
|
@ -36,7 +37,8 @@
|
||||||
"yPadding": 0.5,
|
"yPadding": 0.5,
|
||||||
"xOffset": 1,
|
"xOffset": 1,
|
||||||
"yOffset": 1,
|
"yOffset": 1,
|
||||||
"boxPos": { "x": 0.633, "y": 0.39 }
|
"boxPos": { "x": 0.633, "y": 0.39 },
|
||||||
|
"short": false
|
||||||
},
|
},
|
||||||
"batt": {
|
"batt": {
|
||||||
"font": "4x6",
|
"font": "4x6",
|
||||||
|
|
@ -47,9 +49,10 @@
|
||||||
"border": "#fff",
|
"border": "#fff",
|
||||||
"xPadding": -0.5,
|
"xPadding": -0.5,
|
||||||
"yPadding": -0.5,
|
"yPadding": -0.5,
|
||||||
"xOffset": 2,
|
"xOffset": 1,
|
||||||
"yOffset": 1,
|
"yOffset": 1,
|
||||||
"boxPos": { "x": 0.92, "y": 0.95 }
|
"boxPos": { "x": 0.9, "y": 0.95 },
|
||||||
|
"suffix": "%"
|
||||||
},
|
},
|
||||||
"bg": {
|
"bg": {
|
||||||
"img": "boxclk.beachhouse.img"
|
"img": "boxclk.beachhouse.img"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "boxclk",
|
"id": "boxclk",
|
||||||
"name": "Box Clock",
|
"name": "Box Clock",
|
||||||
"version": "0.01",
|
"version": "0.02",
|
||||||
"description": "A customizable clock with configurable text boxes that can be positioned to show your favorite background",
|
"description": "A customizable clock with configurable text boxes that can be positioned to show your favorite background",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"screenshots": [
|
"screenshots": [
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,11 @@
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let configFiles = [];
|
||||||
storage.list().forEach(file => {
|
storage.list().forEach(file => {
|
||||||
let match = file.match(fileRegex);
|
let match = file.match(fileRegex);
|
||||||
if (match) {
|
if (match) {
|
||||||
let configNumber = match[1];
|
configFiles.push({ file: file, number: parseInt(match[1]) });
|
||||||
configs[configNumber] = handleSelection(configNumber);
|
|
||||||
} else if (file === "boxclk.json") {
|
} else if (file === "boxclk.json") {
|
||||||
hasDefaultConfig = true;
|
hasDefaultConfig = true;
|
||||||
let defaultConfig = storage.readJSON(file, 1);
|
let defaultConfig = storage.readJSON(file, 1);
|
||||||
|
|
@ -56,6 +56,13 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sort the config files by number
|
||||||
|
configFiles.sort((a, b) => a.number - b.number);
|
||||||
|
|
||||||
|
configFiles.forEach(configFile => {
|
||||||
|
configs[configFile.number] = handleSelection(configFile.number);
|
||||||
|
});
|
||||||
|
|
||||||
if (!selectedConfig) {
|
if (!selectedConfig) {
|
||||||
if (hasDefaultConfig) {
|
if (hasDefaultConfig) {
|
||||||
selectedConfig = "Default";
|
selectedConfig = "Default";
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue