mirror of https://github.com/espruino/BangleApps
Use fewer predefined element types and instead rely on datasources
parent
80e5eff3bd
commit
299a66b0c7
|
@ -3,13 +3,13 @@
|
||||||
This app is a highly customizable watchface. To use it, you need to select
|
This app is a highly customizable watchface. To use it, you need to select
|
||||||
a watchface from another source.
|
a watchface from another source.
|
||||||
|
|
||||||
## Usage
|
# Usage
|
||||||
|
|
||||||
Choose the folder which contains the watchface, then clock "Upload to watch".
|
Choose the folder which contains the watchface, then clock "Upload to watch".
|
||||||
|
|
||||||
## Design watch faces
|
# Design watch faces
|
||||||
|
|
||||||
### Folder structure
|
## Folder structure
|
||||||
|
|
||||||
|
|
||||||
* watchfacename
|
* watchfacename
|
||||||
|
@ -18,21 +18,169 @@ Choose the folder which contains the watchface, then clock "Upload to watch".
|
||||||
* info.json
|
* info.json
|
||||||
|
|
||||||
|
|
||||||
#### resources
|
### resources
|
||||||
|
|
||||||
This folder contains image files. It can have subfolders. These files will
|
This folder contains image files. It can have subfolders. These files will
|
||||||
be read and converted into a resource bundle used by the clock
|
be read and converted into a resource bundle used by the clock
|
||||||
|
|
||||||
#### face.json
|
Folder types:
|
||||||
|
|
||||||
This file contains the description of the watch face elements.
|
* Number
|
||||||
|
* Contains files named 0.ext to 9.ext and minus.ext
|
||||||
|
* WeatherIcon
|
||||||
|
* Contains files named with 3 digits for openweathermap weather codes, i.e. 721.ext
|
||||||
|
* Icon
|
||||||
|
* Notifications: sound.ext, silent.ext, vibrate.ext
|
||||||
|
* other status icons: on.ext, off.ext
|
||||||
|
* Scale
|
||||||
|
* Contains the components of the scale, named 0.ext to y.ext, y beeing the last element of the scale
|
||||||
|
|
||||||
#### info.json
|
### face.json
|
||||||
|
|
||||||
|
This file contains the description of the watch face elements.
|
||||||
|
|
||||||
|
#### Object types:
|
||||||
|
|
||||||
|
##### Properties
|
||||||
|
```
|
||||||
|
Properties: {
|
||||||
|
"Redraw": {
|
||||||
|
"Unlocked": 5000,
|
||||||
|
"Locked": 6000
|
||||||
|
}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
##### Images
|
||||||
|
```
|
||||||
|
Image: {
|
||||||
|
"X": 0,
|
||||||
|
"Y": 0,
|
||||||
|
ImagePath: [ "path", "in", "resources", "file" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Coded Images
|
||||||
|
```
|
||||||
|
CodedImage: {
|
||||||
|
"X": 0,
|
||||||
|
"Y": 0,
|
||||||
|
"Value": "WeatherCode",
|
||||||
|
ImagePath: [ "path", "in", "resources", "file" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `Value` field is one of the implemented numerical values.
|
||||||
|
|
||||||
|
##### Number
|
||||||
|
|
||||||
|
Can bottom right, or top left aligned. Will currently force all numbers to
|
||||||
|
be integer.
|
||||||
|
|
||||||
|
```
|
||||||
|
"Number": {
|
||||||
|
"X": 123,
|
||||||
|
"Y": 123,
|
||||||
|
"Alignment": "BottomRight",
|
||||||
|
"Value": "Temperature",
|
||||||
|
"Spacing": 1,
|
||||||
|
"ImagePath": [ "path", "to", "numbers", "folder" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `Value` field is one of the implemented numerical values.
|
||||||
|
`Alignment` is either `BottomRight` or `TopLeft`
|
||||||
|
|
||||||
|
##### Scale
|
||||||
|
|
||||||
|
```
|
||||||
|
"Scale": {
|
||||||
|
"X": 123,
|
||||||
|
"Y": 123,
|
||||||
|
"Value": "Temperature",
|
||||||
|
"MinValue": "-20",
|
||||||
|
"MaxValue": "50",
|
||||||
|
"ImagePath": [ "path", "to", "scale", "folder" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `Value` field is one of the implemented numerical values.
|
||||||
|
`MaxValue` and `MinValue` set the start and endpoints of the scale.
|
||||||
|
|
||||||
|
##### MultiState
|
||||||
|
|
||||||
|
```
|
||||||
|
"MultiState": {
|
||||||
|
"X": 0,
|
||||||
|
"Y": 0,
|
||||||
|
"Value": "Lock",
|
||||||
|
"ImagePath": ["icons", "status", "lock"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `Value` field is one of the implemented multi state values.
|
||||||
|
|
||||||
|
##### Nesting
|
||||||
|
```
|
||||||
|
Container: {
|
||||||
|
"X": 10,
|
||||||
|
"Y": 10,
|
||||||
|
OtherContainer: {
|
||||||
|
"X": 5,
|
||||||
|
"Y": 5,
|
||||||
|
SomeElement: {
|
||||||
|
"X": 2,
|
||||||
|
"Y": 2,
|
||||||
|
<Content>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`SomeElement` will be drawn at X- and Y-position 2+5+10=17, because positions are relative to parent element.
|
||||||
|
Container names can be everything but other object names.
|
||||||
|
|
||||||
|
#### Implemented data sources
|
||||||
|
|
||||||
|
##### For Number objects
|
||||||
|
|
||||||
|
* Hour
|
||||||
|
* HourTens
|
||||||
|
* HourOnes
|
||||||
|
* Minute
|
||||||
|
* MinuteTens
|
||||||
|
* MinuteOnes
|
||||||
|
* Day
|
||||||
|
* DayTens
|
||||||
|
* DayOnes
|
||||||
|
* Month
|
||||||
|
* MonthTens
|
||||||
|
* MonthOnes
|
||||||
|
* Pulse
|
||||||
|
* Steps
|
||||||
|
* Temperature
|
||||||
|
* Pressure
|
||||||
|
* Altitude
|
||||||
|
* BatteryPercentage
|
||||||
|
* BatteryVoltage
|
||||||
|
* WeatherCode
|
||||||
|
* WeatherTemperature
|
||||||
|
|
||||||
|
##### For MultiState
|
||||||
|
|
||||||
|
* on/off
|
||||||
|
* Lock
|
||||||
|
* Charge
|
||||||
|
* Alarm
|
||||||
|
* Bluetooth
|
||||||
|
* BluetoothPeripheral
|
||||||
|
* HRM
|
||||||
|
* Barometer
|
||||||
|
* Compass
|
||||||
|
* GPS
|
||||||
|
* on/off/vibrate
|
||||||
|
* Notifications
|
||||||
|
|
||||||
|
### info.json
|
||||||
|
|
||||||
This file contains information for the conversion process, it will not be
|
This file contains information for the conversion process, it will not be
|
||||||
stored on the watch
|
stored on the watch
|
||||||
|
|
||||||
## TODO
|
# TODO
|
||||||
|
|
||||||
* Performance improvements
|
* Performance improvements
|
||||||
* Mark elements with how often they need to be redrawn
|
* Mark elements with how often they need to be redrawn
|
||||||
|
@ -44,6 +192,6 @@ stored on the watch
|
||||||
* Description of the file format
|
* Description of the file format
|
||||||
* Allow additional files for upload declared in info.json
|
* Allow additional files for upload declared in info.json
|
||||||
|
|
||||||
## Creator
|
# Creator
|
||||||
|
|
||||||
[halemmerich](https://github.com/halemmerich)
|
[halemmerich](https://github.com/halemmerich)
|
||||||
|
|
|
@ -40,8 +40,15 @@ function splitNumberToDigits(num){
|
||||||
return String(num).split('').map(item => Number(item));
|
return String(num).split('').map(item => Number(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawNumber(element, offset, number){
|
function drawNumber(element, offset){
|
||||||
//print("drawNumber: ", element, number);
|
var number = numbers[element.Value]();
|
||||||
|
//print("drawNumber: ", number, element, offset);
|
||||||
|
if (number) number = number.toFixed(0);
|
||||||
|
|
||||||
|
|
||||||
|
//var numberOffset = updateOffset(element, offset);
|
||||||
|
var numberOffset = offset;
|
||||||
|
|
||||||
var isNegative;
|
var isNegative;
|
||||||
var digits;
|
var digits;
|
||||||
if (number == undefined){
|
if (number == undefined){
|
||||||
|
@ -56,8 +63,8 @@ function drawNumber(element, offset, number){
|
||||||
//print("digits: ", digits);
|
//print("digits: ", digits);
|
||||||
var numberOfDigits = element.Digits;
|
var numberOfDigits = element.Digits;
|
||||||
if (!numberOfDigits) numberOfDigits = digits.length;
|
if (!numberOfDigits) numberOfDigits = digits.length;
|
||||||
var firstDigitX = element.TopLeftX;
|
var firstDigitX = element.X;
|
||||||
var firstDigitY = element.TopLeftY;
|
var firstDigitY = element.Y;
|
||||||
var firstImage = getByPath(resources, element.ImagePath, 0);
|
var firstImage = getByPath(resources, element.ImagePath, 0);
|
||||||
|
|
||||||
if (element.Alignment == "BottomRight"){
|
if (element.Alignment == "BottomRight"){
|
||||||
|
@ -67,14 +74,14 @@ function drawNumber(element, offset, number){
|
||||||
numberWidth += firstImage.width + element.Spacing;
|
numberWidth += firstImage.width + element.Spacing;
|
||||||
}
|
}
|
||||||
//print("Number width: ", numberWidth, firstImage.width, element.Spacing);
|
//print("Number width: ", numberWidth, firstImage.width, element.Spacing);
|
||||||
firstDigitX = element.BottomRightX - numberWidth + 1;
|
firstDigitX = element.X - numberWidth + 1;
|
||||||
firstDigitY = element.BottomRightY - firstImage.height + 1;
|
firstDigitY = element.Y - firstImage.height + 1;
|
||||||
//print("Calculated start " + firstDigitX + "," + firstDigitY + " From:" + element.BottomRightX + " " + firstImage.width + " " + element.Spacing);
|
//print("Calculated start " + firstDigitX + "," + firstDigitY + " From:" + element.BottomRightX + " " + firstImage.width + " " + element.Spacing);
|
||||||
}
|
}
|
||||||
var currentX = firstDigitX;
|
var currentX = firstDigitX;
|
||||||
|
|
||||||
if (isNegative){
|
if (isNegative){
|
||||||
drawElement({X:currentX,Y:firstDigitY}, offset, element.ImagePath, "minus");
|
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, "minus");
|
||||||
currentX += firstImage.width + element.Spacing;
|
currentX += firstImage.width + element.Spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +94,7 @@ function drawNumber(element, offset, number){
|
||||||
currentDigit = 0;
|
currentDigit = 0;
|
||||||
}
|
}
|
||||||
//print("Digit " + currentDigit + " " + currentX);
|
//print("Digit " + currentDigit + " " + currentX);
|
||||||
drawElement({X:currentX,Y:firstDigitY}, offset, element.ImagePath, currentDigit);
|
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, currentDigit);
|
||||||
currentX += firstImage.width + element.Spacing;
|
currentX += firstImage.width + element.Spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,19 +106,37 @@ function setColors(properties){
|
||||||
|
|
||||||
function drawElement(pos, offset, path, lastElem){
|
function drawElement(pos, offset, path, lastElem){
|
||||||
//print("drawElement ",pos, offset, path, lastElem);
|
//print("drawElement ",pos, offset, path, lastElem);
|
||||||
var image = getByPath(resources, path, lastElem);
|
var resource = getByPath(resources, path, lastElem);
|
||||||
if (image){
|
if (resource){
|
||||||
setColors(offset);
|
var image = getImg(resource);
|
||||||
g.drawImage(getImg(image),offset.X + pos.X,offset.Y + pos.Y);
|
if (image){
|
||||||
|
setColors(offset);
|
||||||
|
//print("drawImage from drawElement", image, pos, offset);
|
||||||
|
g.drawImage(image ,offset.X + pos.X,offset.Y + pos.Y);
|
||||||
|
} else {
|
||||||
|
//print("Could not create image from", resource);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
print("Could not create image from", path, lastElem);
|
//print("Could not get resource from", path, lastElem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawScale(scale, offset, value){
|
function drawScale(scale, offset){
|
||||||
|
//print("drawScale", scale, offset);
|
||||||
var segments = scale.Segments;
|
var segments = scale.Segments;
|
||||||
|
var value = numbers[scale.Value]();
|
||||||
|
var maxValue = scale.MaxValue ? scale.MaxValue : 1;
|
||||||
|
var minValue = scale.MinValue ? scale.MinValue : 0;
|
||||||
|
|
||||||
|
value = value/maxValue;
|
||||||
|
value -= minValue;
|
||||||
|
|
||||||
|
//print("Value is ", value, "(", maxValue, ",", minValue, ")");
|
||||||
|
|
||||||
|
var scaleOffset = updateOffset(scale, offset);
|
||||||
|
|
||||||
for (var i = 0; i < value * segments.length; i++){
|
for (var i = 0; i < value * segments.length; i++){
|
||||||
drawElement(segments[i], offset, scale.ImagePath, i);
|
drawElement(segments[i], scaleOffset, scale.ImagePath, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,18 +144,6 @@ function drawDigit(element, offset, digit){
|
||||||
drawElement(element, offset, element.ImagePath, digit);
|
drawElement(element, offset, element.ImagePath, digit);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawMonthAndDay(element, offset){
|
|
||||||
var date = new Date();
|
|
||||||
|
|
||||||
var dateOffset = updateOffset(element, offset);
|
|
||||||
|
|
||||||
if (element.Separate){
|
|
||||||
var separateOffset = updateOffset(element.Separate, dateOffset);
|
|
||||||
drawNumber(element.Separate.Month, separateOffset, date.getMonth() + 1);
|
|
||||||
drawNumber(element.Separate.Day, separateOffset, date.getDate());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawImage(image, offset, name){
|
function drawImage(image, offset, name){
|
||||||
if (image.ImagePath) {
|
if (image.ImagePath) {
|
||||||
//print("drawImage", image, offset, name);
|
//print("drawImage", image, offset, name);
|
||||||
|
@ -142,42 +155,49 @@ function drawImage(image, offset, name){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawWeather(element, offset){
|
function drawCodedImage(image, offset){
|
||||||
var jsonWeather = require("Storage").readJSON('weather.json');
|
var code = numbers[image.Value]();
|
||||||
var weather = jsonWeather && jsonWeather.weather ? jsonWeather.weather : undefined;
|
//print("drawCodedImage", image, offset, code);
|
||||||
|
if (image.ImagePath) {
|
||||||
var weatherOffset = updateOffset(element, offset);
|
var factor = 1;
|
||||||
|
var currentCode = code;
|
||||||
var iconOffset = updateOffset(element.Icon, weatherOffset);
|
while (code / factor > 1){
|
||||||
if (weather && weather.code && element.Icon){
|
currentCode = Math.floor(currentCode/factor)*factor;
|
||||||
var weathercode = weather.code;
|
//print("currentCode", currentCode);
|
||||||
//print(getByPath(resources, element.Icon.CustomIcon.ImagePath, weathercode));
|
if (getByPath(resources, image.ImagePath, currentCode)){
|
||||||
if (!getByPath(resources, element.Icon.CustomIcon.ImagePath, weathercode)){
|
break;
|
||||||
weathercode = Math.floor(weathercode/10)*10;
|
}
|
||||||
//print("Weathercode ", weathercode);
|
factor *= 10;
|
||||||
}
|
}
|
||||||
if (!getByPath(resources, element.Icon.CustomIcon.ImagePath, weathercode)){
|
if (code / factor > 1){
|
||||||
weathercode = Math.floor(weathercode/100)*100;
|
//print("found match");
|
||||||
//print("Weathercode ", weathercode);
|
drawImage(image, offset, currentCode);
|
||||||
}
|
|
||||||
if (getByPath(resources, element.Icon.CustomIcon.ImagePath, weathercode)){
|
|
||||||
//print("Weathercode ", weathercode);
|
|
||||||
drawImage(element.Icon.CustomIcon, offset, weathercode);
|
|
||||||
}
|
|
||||||
} else if (getByPath(resources, element.Icon.CustomIcon.ImagePath, "000")) {
|
|
||||||
drawImage(element.Icon.CustomIcon, iconOffset, "000");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.Temperature){
|
|
||||||
var tempOffset = updateOffset(element.Temperature, weatherOffset);
|
|
||||||
if (weather && weather.temp && element.Temperature){
|
|
||||||
drawNumber(element.Temperature.Current.Number, tempOffset, (weather.temp - 273.15).toFixed(0));
|
|
||||||
} else {
|
} else {
|
||||||
drawNumber(element.Temperature.Current.Number, tempOffset);
|
//print("fallback");
|
||||||
|
drawImage(image, offset, "fallback");
|
||||||
}
|
}
|
||||||
drawImage(element.Temperature.Current, tempOffset, "centigrade");
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWeatherCode(){
|
||||||
|
var jsonWeather = require("Storage").readJSON('weather.json');
|
||||||
|
var weather = (jsonWeather && jsonWeather.weather) ? jsonWeather.weather : undefined;
|
||||||
|
|
||||||
|
if (weather && weather.code){
|
||||||
|
return weather.code;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWeatherTemperature(){
|
||||||
|
var jsonWeather = require("Storage").readJSON('weather.json');
|
||||||
|
var weather = (jsonWeather && jsonWeather.weather) ? jsonWeather.weather : undefined;
|
||||||
|
|
||||||
|
if (weather && weather.temp){
|
||||||
|
//print("Weather temp is", weather.temp);
|
||||||
|
return weather.temp - 273.15;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateOffset(element, offset){
|
function updateOffset(element, offset){
|
||||||
|
@ -190,58 +210,60 @@ function updateOffset(element, offset){
|
||||||
return newOffset;
|
return newOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawTime(element, offset){
|
var numbers = {};
|
||||||
var date = new Date();
|
numbers.Hour = () => { return new Date().getHours(); };
|
||||||
var hours = date.getHours();
|
numbers.HourTens = () => { return Math.floor(new Date().getHours()/10); };
|
||||||
var minutes = date.getMinutes();
|
numbers.HourOnes = () => { return Math.floor(new Date().getHours()%10); };
|
||||||
|
numbers.Hour12 = () => { return new Date().getHours()%12; };
|
||||||
var offsetTime = updateOffset(element, offset);
|
numbers.Hour12Tens = () => { return Math.floor((new Date().getHours()%12)/10); };
|
||||||
|
numbers.Hour12Ones = () => { return Math.floor((new Date().getHours()%12)%10); };
|
||||||
|
numbers.Minute = () => { return new Date().getMinutes(); };
|
||||||
|
numbers.MinuteTens = () => { return Math.floor(new Date().getMinutes()/10); };
|
||||||
|
numbers.MinuteOnes = () => { return Math.floor(new Date().getMinutes()%10); };
|
||||||
|
numbers.Second = () => { return new Date().getSeconds(); };
|
||||||
|
numbers.SecondTens = () => { return Math.floor(new Date().getSeconds()/10); };
|
||||||
|
numbers.SecondOnes = () => { return Math.floor(new Date().getSeconds()%10); };
|
||||||
|
numbers.Day = () => { return new Date().getDate(); };
|
||||||
|
numbers.DayTens = () => { return Math.floor(new Date().getDate()/10); };
|
||||||
|
numbers.DayOnes = () => { return Math.floor(new Date().getDate()%10); };
|
||||||
|
numbers.Month = () => { return new Date().getMonth() + 1; };
|
||||||
|
numbers.MonthTens = () => { return Math.floor((new Date().getMonth() + 1)/10); };
|
||||||
|
numbers.MonthOnes = () => { return Math.floor((new Date().getMonth() + 1)%10); };
|
||||||
|
numbers.Pulse = () => { return pulse; };
|
||||||
|
numbers.Steps = () => { return Bangle.getHealthStatus ? Bangle.getHealthStatus("day").steps : undefined; };
|
||||||
|
numbers.Temperature = () => { return temp; };
|
||||||
|
numbers.Pressure = () => { return press; };
|
||||||
|
numbers.Altitude = () => { return alt; };
|
||||||
|
numbers.BatteryPercentage = () => { return E.getBattery(); };
|
||||||
|
numbers.BatteryVoltage = () => { return NRF.getBattery(); };
|
||||||
|
numbers.WeatherCode = () => getWeatherCode();
|
||||||
|
numbers.WeatherTemperature = () => getWeatherTemperature();
|
||||||
|
|
||||||
var offsetHours = updateOffset(element.Hours, offsetTime);
|
var multistates = {};
|
||||||
if (element.Hours.Tens) {
|
multistates.Lock = () => { return Bangle.isLocked() ? "on" : "off"; };
|
||||||
drawDigit(element.Hours.Tens, offsetHours, Math.floor(hours/10));
|
multistates.Charge = () => { return Bangle.isCharging() ? "on" : "off"; };
|
||||||
}
|
multistates.Notifications = () => { return ((require("Storage").readJSON("setting.json", 1) || {}).quiet|0) ? "off" : "vibrate"; };
|
||||||
|
multistates.Alarm = () => { return (require('Storage').readJSON('alarm.json',1)||[]).some(alarm=>alarm.on) ? "on" : "off"; };
|
||||||
|
multistates.Bluetooth = () => { return NRF.getSecurityStatus().connected ? "on" : "off"; };
|
||||||
|
//TODO: Implement peripheral connection status
|
||||||
|
multistates.BluetoothPeripheral = () => { return NRF.getSecurityStatus().connected ? "on" : "off"; };
|
||||||
|
multistates.HRM = () => { return Bangle.isHRMOn ? "on" : "off"; };
|
||||||
|
multistates.Barometer = () => { return Bangle.isBarometerOn() ? "on" : "off"; };
|
||||||
|
multistates.Compass = () => { return Bangle.isCompassOn() ? "on" : "off"; };
|
||||||
|
multistates.GPS = () => { return Bangle.isGPSOn() ? "on" : "off"; };
|
||||||
|
|
||||||
if (element.Hours.Ones) {
|
function drawMultiState(element, offset){
|
||||||
drawDigit(element.Hours.Ones, offsetHours, hours % 10);
|
//print("drawMultiState", element, offset);
|
||||||
}
|
drawImage(element, offset, multistates[element.Value]());
|
||||||
|
|
||||||
var offsetMinutes = updateOffset(element.Minutes, offsetTime);
|
|
||||||
if (element.Minutes.Tens) {
|
|
||||||
drawDigit(element.Minutes.Tens, offsetMinutes, Math.floor(minutes/10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.Minutes.Ones) {
|
|
||||||
drawDigit(element.Minutes.Ones, offsetMinutes, minutes % 10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawSteps(element, offset){
|
var drawing = false;
|
||||||
//print("drawSteps", element, offset);
|
|
||||||
if (Bangle.getHealthStatus) {
|
|
||||||
drawNumber(element.Number, offset, Bangle.getHealthStatus("day").steps);
|
|
||||||
} else {
|
|
||||||
drawNumber(element.Number, offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawBattery(element, offset){
|
|
||||||
if (element.Scale){
|
|
||||||
drawScale(element.Scale, offset, E.getBattery()/100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawStatus(element, offset){
|
|
||||||
var statusOffset = updateOffset(element, offset);
|
|
||||||
if (element.Lock) drawImage(element.Lock, statusOffset, Bangle.isLocked() ? "on" : "off");
|
|
||||||
if (element.Charge) drawImage(element.Charge, statusOffset, Bangle.isCharging() ? "on" : "off");
|
|
||||||
if (element.Bluetooth) drawImage(element.Bluetooth, statusOffset, NRF.getSecurityStatus().connected ? "on" : "off");
|
|
||||||
if (element.Alarm) drawImage(element.Alarm, statusOffset, (require('Storage').readJSON('alarm.json',1)||[]).some(alarm=>alarm.on) ? "on" : "off");
|
|
||||||
if (element.Notifications) drawImage(element.Notifications, statusOffset, ((require("Storage").readJSON("setting.json", 1) || {}).quiet|0) ? "soundoff" : "vibrate");
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw(element, offset){
|
function draw(element, offset){
|
||||||
if (!element){
|
var initial = !element;
|
||||||
|
if (initial){
|
||||||
|
if (drawing) return;
|
||||||
|
drawing = true;
|
||||||
element = face;
|
element = face;
|
||||||
g.clear();
|
g.clear();
|
||||||
}
|
}
|
||||||
|
@ -252,57 +274,46 @@ function draw(element, offset){
|
||||||
setColors(elementOffset);
|
setColors(elementOffset);
|
||||||
//print("Using offset", elementOffset);
|
//print("Using offset", elementOffset);
|
||||||
|
|
||||||
//print("Starting drawing loop", element);
|
|
||||||
for (var current in element){
|
for (var current in element){
|
||||||
//print("Handling ", current, " with offset ", elementOffset);
|
//print("Handling ", current, " with offset ", elementOffset);
|
||||||
var currentElement = element[current];
|
var currentElement = element[current];
|
||||||
switch(current){
|
try {
|
||||||
case "X":
|
switch(current){
|
||||||
case "Y":
|
case "X":
|
||||||
case "Properties":
|
case "Y":
|
||||||
case "ForegroundColor":
|
case "Properties":
|
||||||
case "BackgroundColor":
|
case "ForegroundColor":
|
||||||
//Nothing to draw for these
|
case "BackgroundColor":
|
||||||
break;
|
//Nothing to draw for these
|
||||||
case "Background":
|
break;
|
||||||
drawImage(currentElement, elementOffset);
|
case "MultiState":
|
||||||
break;
|
drawMultiState(currentElement, elementOffset);
|
||||||
case "Time":
|
break;
|
||||||
drawTime(currentElement, elementOffset);
|
case "Image":
|
||||||
break;
|
drawImage(currentElement, elementOffset);
|
||||||
case "Battery":
|
break;
|
||||||
drawBattery(currentElement, elementOffset);
|
case "CodedImage":
|
||||||
break;
|
drawCodedImage(currentElement, elementOffset);
|
||||||
case "Steps":
|
break;
|
||||||
drawSteps(currentElement, elementOffset);
|
case "Number":
|
||||||
break;
|
drawNumber(currentElement, elementOffset);
|
||||||
case "Pulse":
|
break;
|
||||||
if (pulse) drawNumber(currentElement.Number, elementOffset, pulse);
|
case "Scale":
|
||||||
break;
|
drawScale(currentElement, elementOffset);
|
||||||
case "Pressure":
|
break;
|
||||||
if (press) drawNumber(currentElement.Number, elementOffset, press.toFixed(0));
|
default:
|
||||||
break;
|
//print("Enter next level", elementOffset);
|
||||||
case "Altitude":
|
draw(currentElement, elementOffset);
|
||||||
if (alt) drawNumber(currentElement.Number, elementOffset, alt.toFixed(0));
|
//print("Done next level");
|
||||||
break;
|
}
|
||||||
case "Temperature":
|
} catch (e){
|
||||||
if (temp) drawNumber(currentElement.Number, elementOffset, temp.toFixed(0));
|
print("Error during drawing of", current, "in", element, e);
|
||||||
break;
|
|
||||||
case "MonthAndDay":
|
|
||||||
drawMonthAndDay(currentElement, elementOffset);
|
|
||||||
break;
|
|
||||||
case "Weather":
|
|
||||||
drawWeather(currentElement, elementOffset);
|
|
||||||
break;
|
|
||||||
case "Status":
|
|
||||||
drawStatus(currentElement, elementOffset);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
//print("Enter next level", currentElement, elementOffset);
|
|
||||||
draw(currentElement, elementOffset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//print("Finished drawing loop");
|
//print("Finished drawing loop");
|
||||||
|
if (initial){
|
||||||
|
drawing = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pulse,alt,temp,press;
|
var pulse,alt,temp,press;
|
||||||
|
@ -311,9 +322,12 @@ var pulse,alt,temp,press;
|
||||||
var zeroOffset={X:0,Y:0};
|
var zeroOffset={X:0,Y:0};
|
||||||
|
|
||||||
|
|
||||||
|
function initialDraw(){ draw(undefined, zeroOffset); }
|
||||||
|
|
||||||
function handleHrm(e){
|
function handleHrm(e){
|
||||||
if (e.confidence > 70){
|
if (e.confidence > 70){
|
||||||
pulse = e.bpm;
|
pulse = e.bpm;
|
||||||
|
initialDraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,6 +335,7 @@ function handlePressure(e){
|
||||||
alt = e.altitude;
|
alt = e.altitude;
|
||||||
temp = e.temperature;
|
temp = e.temperature;
|
||||||
press = e.pressure;
|
press = e.pressure;
|
||||||
|
initialDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -334,28 +349,30 @@ function handleLock(isLocked){
|
||||||
Bangle.setHRMPower(1, "imageclock");
|
Bangle.setHRMPower(1, "imageclock");
|
||||||
Bangle.setBarometerPower(1, 'imageclock');
|
Bangle.setBarometerPower(1, 'imageclock');
|
||||||
unlockedDrawInterval = setInterval(()=>{
|
unlockedDrawInterval = setInterval(()=>{
|
||||||
draw(face, zeroOffset);
|
initialDraw();
|
||||||
},unlockedRedraw?unlockedRedraw:1000);
|
},unlockedRedraw?unlockedRedraw:1000);
|
||||||
draw(face, zeroOffset);
|
draw(face, zeroOffset);
|
||||||
} else {
|
} else {
|
||||||
Bangle.setHRMPower(0, "imageclock");
|
Bangle.setHRMPower(0, "imageclock");
|
||||||
Bangle.setBarometerPower(0, 'imageclock');
|
Bangle.setBarometerPower(0, 'imageclock');
|
||||||
clearInterval(unlockedDrawInterval);
|
if (unlockedDrawInterval) clearInterval(unlockedDrawInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bangle.setUI("clock");
|
Bangle.setUI("clock");
|
||||||
|
|
||||||
|
Bangle.on('GPS', initialDraw);
|
||||||
|
Bangle.on('charging', initialDraw);
|
||||||
|
Bangle.on('mag', initialDraw);
|
||||||
|
Bangle.on('health', initialDraw);
|
||||||
Bangle.on('pressure', handlePressure);
|
Bangle.on('pressure', handlePressure);
|
||||||
Bangle.on('HRM', handleHrm);
|
Bangle.on('HRM', handleHrm);
|
||||||
Bangle.on('lock', handleLock);
|
Bangle.on('lock', handleLock);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
draw(face, zeroOffset);
|
|
||||||
|
|
||||||
|
|
||||||
setInterval(()=>{
|
setInterval(()=>{
|
||||||
draw(face, zeroOffset);
|
initialDraw();
|
||||||
}, lockedRedraw ? lockedRedraw : 6000);
|
}, lockedRedraw ? lockedRedraw : 60000);
|
||||||
|
|
||||||
|
initialDraw();
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue