I have been looking into adding customizable settings to my watch face. (I am really new to creating watch faces and coding)
I have been struggling to get the specific element of the watch face to be customizable.
My watch face has labels in styles.css for the time, steps, day and month which I would like to make the color customizable. Also within my index.gui I have two lines which I would also like to make customizable to the user.
I would really appreciate any help that can be given.
Thanks
Answered! Go to the Best Answer.
I added your colour selectors and colour array into my settings\index.js.
I then added the following code to catch the event and change the colour of a textbox ("test-text1") in my index.gui.
The code below works and changes the colour whenever the user picks a new one in the Settings UI
// no need to have this inside the event handler
let tt = document.getElementById("test-text1");
peerSocket.onmessage = (evt) => {
console.log(`handleMessages(): ${JSON.stringify(evt)}`);
if (evt.data.key == 'colorTime') {
// for debugging only
let s = JSON.parse(evt.data.newValue);
console.log(`colour is ${s}`);
tt.style.fill = JSON.parse(evt.data.newValue);
}
}
[Updated to correct typing error!]
Best AnswerI have placed the code into my index.gui and it hasn't worked.
It displays in all white text which doesn't seem right.
Thanks for the suggestion.
Best Answerdid you mean app\index.js?
Also, the line
let tt = document.getElementById("test-text1");
needs to be changed to reference your component ID, for example "dayLabel"
Best Answer
I have changed the "test-text1" to "timeLabel" and there is no change it still will not change the color of the time element.
Best AnswerI have created a small project that works.
All of the source is included below.
Please let me know if this solves the problem.
app\index.js
import document from "document"; import * as messaging from "messaging";
let stepsLabel = document.getElementById("stepsLabel"); let timeLabel = document.getElementById("timeLabel"); let dayLabel = document.getElementById("dayLabel"); let monthLabel = document.getElementById("monthLabel"); messaging.peerSocket.onmessage = (evt) => { let newColour; console.log(`handleMessages(): ${JSON.stringify(evt)}`); switch(evt.data.key) { case 'colorSteps': stepsLabel.style.fill = evt.data.value; break; case 'colorTime': timeLabel.style.fill = evt.data.value; break; case 'colorDay': dayLabel.style.fill = evt.data.value; break; case 'colorMonth': monthLabel.style.fill = evt.data.value; break; } }
companion\index.js (extracted from a Fitbit sample project)
import { settingsStorage } from "settings";
import * as messaging from "messaging";
// Settings have been changed
settingsStorage.onchange = function(evt) {
if (evt.newValue !== evt.oldValue) {
sendValue(evt.key, evt.newValue);
}
}
// Send key/value pair
function sendValue(key, val) {
if (!key || !val) {
return;
};
sendSettingData({
key: key,
value: JSON.parse(val)
});
}
// Send JSON object
function sendSettingData(data) {
if (messaging.peerSocket.readyState === messaging.peerSocket.OPEN) {
messaging.peerSocket.send(data);
} else {
console.log("No peerSocket connection");
}
}resources\index.gui (based on your UI)
<svg class="background">
<svg >
<text id="timeLabel" class="my-text">Time</text>
<text id="stepsLabel" class="my-text">Steps</text>
<text id="dayLabel" class="my-text">Day</text>
<text id="monthLabel" class="my-text">Month</text>
</svg>
</svg>styles.css
.background {
viewport-fill: black;
}
.my-text {
font-size: 24;
fill: white;
}
#timeLabel {
x: 10;
y: 30;
}
#stepsLabel {
x: 10;
y: 70;
}
#dayLabel {
x: 10;
y: 110;
}
#monthLabel {
x: 10;
y: 150;
}widgets.gui
<svg>
<defs>
<link rel="stylesheet" href="styles.css" />
<link rel="import" href="/mnt/sysassets/widgets_common.gui" />
<link rel="import" href="/mnt/sysassets/widgets/square_button_widget.gui" />
</defs>
</svg>settings\index.jsx (partial. based on your UI)
const colorSet = [
{color: "white"},
{color: "grey"},
{color: "silver"},
{color: "lightgrey"},
{color: "navy"},
{color: "dodgerblue"},
{color: "deepskyblue"},
{color: "lightskyblue"},
{color: "teal"},
{color: "lightgreen"},
{color: "olivedrab"},
{color: "seagreen"},
{color: "darkgreen"},
{color: "#B8FC68"},
{color: "yellow"},
{color: "#FFCC33"},
{color: "orange"},
{color: "orangered"},
{color: "pink"},
{color: "lightpink"},
{color: "crimson"},
{color: "#F83C40"},
{color: "red"},
];
const options = [
['Time Color', 'colorTime'],
['Steps Color', 'colorSteps'],
['Day Color', 'colorDay'],
['Month Color', 'colorMonth']
];
function mySettings(props) {
return (
<Page>
{options.map(([title, settingsKey]) =>
<Section
title={title}>
<ColorSelect
settingsKey={settingsKey}
colors={colorSet} />
</Section>
)}
</Page>
);
}
registerSettingsPage(mySettings);
Best AnswerI am still having no luck.
This is what I have within my app/index.js, companion/index.js, resources/index.gui, resources/styles.css and settings/index.jsx.
app/index.js
import clock from "clock";
import document from "document";
import { preferences } from "user-settings";
import { zeroPad, } from "../common/utils";
import userActivity from "user-activity";
import { me } from "appbit";
import { me as device } from "device";
import * as fs from "fs";
import * as messaging from "messaging";
// Update the clock every minute
clock.granularity = "minutes";
// Get a handle on the <text> elements specified in the index.gui file
const timeHandle = document.getElementById("timeLabel");
const stepsHandle = document.getElementById("stepsLabel");
const dayHandle = document.getElementById ("dayLabel");
const monthHandle = document.getElementById ("monthLabel");
const divider = document.getElementsByClassName("divider");
// Update the <text> element every tick with the current time
clock.ontick = (evt) => {
let today = new Date();
let monthnum = today.getMonth();
let day = today.getDate();
var month = new Array();
month[0] = "Jan";
month[1] = "Feb";
month[2] = "Mar";
month[3] = "Apr";
month[4] = "May";
month[5] = "Jun";
month[6] = "Jul";
month[7] = "Aug";
month[8] = "Sep";
month[9] = "Oct";
month[10] = "Nov";
month[11] = "Dec";
let monthname = month[monthnum];
const now = evt.date;
let hours = now.getHours();
let mins = now.getMinutes();
if (preferences.clockDisplay === "12h") {
hours = hours % 12 || 12;
} else {
hours = zeroPad(hours);
}
let minsZeroed = zeroPad(mins);
timeHandle.text = `${hours}:${minsZeroed}`;
monthHandle.text = `${monthname}`;
dayHandle.text = `${day}`;
// Activity Values: adjusted type
let stepsValue = (userActivity.today.adjusted["steps"] || 0);
let stepsString = stepsValue + ' steps';
stepsHandle.text = stepsString;
}
/* -------- SETTINGS -------- */
const SETTINGS_TYPE = "cbor";
const SETTINGS_FILE = "settings.cbor";
let settings, onsettingschange;
let stepsLabel = document.getElementById("stepsLabel");
let timeLabel = document.getElementById("timeLabel");
let dayLabel = document.getElementById("dayLabel");
let monthLabel = documnet.getElementById("monthLabel");
let dividers = document.getElementById ("divider");
messaging.peerSocket.onmessage = (evt) => {
let newColor;
consol.log('handleMessages(): $JSON.stringify(evt)}');
switch(evt.data.key) {
case 'colorSteps':
stepsLabel.style.fill = evt.data.value;
break;
case 'colorTime':
timelabel.style.fill = evt.data.value;
break;
case 'colorDay':
dayLabel.style.fill = evt.data.value;
break;
case 'colorMonth':
monthLabel.style.fill = evt.data.value;
break;
case 'colorDivider':
divider.style.fill = evt.data.value;
break;
}
}
companion/index.js
import * as messaging from "messaging";
import { settingsStorage } from "settings";
settingStorage.onchnage = function(evt) {
if (evt.newValue !== Evt.oldValue) {
sendValue(evt.key, evt.newValue);
}
}
function sendValue(key, val) {
if (!key || !val) {
return;
};
sendSettingData({
key: key,
value: JSON.parse(val)
});
}
function sendSettingData(data) {
if (messaging.peerSocket.readyState === messaging.peerSocket.OPEN) {
messaging.peerSocket.send(data);
} else {
console.log("No peerSocket connection");
}
}resources/index.gui
<svg class="background"> <text id="timeLabel" /> <text id="stepsLabel" /> <text id= "dayLabel" /> <text id= "monthLabel"/> <rect class="divider divider-top" /> <rect class="divider divider-btm" />
resources/styles.css
.background {
viewport-fill: black;
}
#timeLabel {
font-size: 170;
font-family: Tungsten-Medium;
text-length: 5;
text-anchor: middle;
letter-spacing: 15;
x: 50%;
y: 70%;
fill: white;
}
#stepsLabel {
font-size: 45;
font-family: Fabrikat-Black;
text-length: 10;
text-anchor: middle;
letter-spacing: 3;
x: 50%;
y: 93%;
fill: white;
}
#monthLabel {
font-size: 50;
font-family: Fabrikat-Black;
text-length: 10;
text-anchor: middle;
letter-spacing: 4;
x: 63%;
y: 17%;
fill: white;
}
#dayLabel {
font-size: 50;
font-family: Fabrikat-Black;
text-length: 2;
text-anchor: start;
letter-spacing: 5;
x: 21%;
y: 17%;
fill: white;
}
.divider {
x: 2%;
width: 286;
height: 5;
fill: teal;
}
.divider-top {
y: 24%;
}
.divider-btm {
y: 75%;
}setting/index.jsx
const colorSet = [
{color: "white"},
{color: "grey"},
{color: "silver"},
{color: "lightgrey"},
{color: "dodgerblue"},
{color: "deepskyblue"},
{color: "lightskyblue"},
{color: "teal"},
{color: "seagreen"},
{color: "olivedrab"},
{color: "yellowgreen"},
{color: "lightgreen"},
{color: "#B8FC68"},
{color: "#E4FA3C"},
{color: "yellow"},
{color: "#FFCC33"},
{color: "orange"},
{color: "orangered"},
{color: "red"},
{color: "#F83C40"},
{color: "crimson"},
{color: "lightpink"},
{color: "mistyrose"},
];
const options = [
['Time Color', 'colorTime'],
['Divider Color', 'colorDivider'],
['Steps Color', 'colorSteps'],
['Day Color', 'colorDay'],
['Month Color', 'colorMonth']
];
function mySettings(props) {
return (
<Page>
{options.map(([title, settingsKey]) =>
<Section
title={title}>
<ColorSelect
settingsKey={settingsKey}
colors={colorSet} />
</Section>
)}
</Page>
);
}
registerSettingsPage(mySettings);
Best AnswerThis is what I have in my app/index.js
import clock from "clock";
import document from "document";
import { preferences } from "user-settings";
import { zeroPad, } from "../common/utils";
import userActivity from "user-activity";
import { me } from "appbit";
import { me as device } from "device";
import * as fs from "fs";
import * as messaging from "messaging";
// required imports
import * as kpay from './kpay/release/kpay.js';
import * as kpay_common from '../common/kpay/kpay_common.js';
import './kpay/release/kpay_filetransfer.js';
import './kpay/release/kpay_dialogs.js'; // remove if you handle KPay dialogs yourself
import './kpay/release/kpay_time_trial.js'; // remove if you do not want a time based trial
import './kpay/release/kpay_msg_validation.js';
/**** KPAY INIT - REQUIRED ***/
kpay.initialize();
// Update the clock every minute
clock.granularity = "minutes";
// Get a handle on the <text> elements specified in the index.gui file
const timeHandle = document.getElementById("timeLabel");
const stepsHandle = document.getElementById("stepsLabel");
const dayHandle = document.getElementById ("dayLabel");
const monthHandle = document.getElementById ("monthLabel");
const divider = document.getElementsByClassName("divider");
// Update the <text> element every tick with the current time
clock.ontick = (evt) => {
let today = new Date();
let monthnum = today.getMonth();
let day = today.getDate();
var month = new Array();
month[0] = "Jan";
month[1] = "Feb";
month[2] = "Mar";
month[3] = "Apr";
month[4] = "May";
month[5] = "Jun";
month[6] = "Jul";
month[7] = "Aug";
month[8] = "Sep";
month[9] = "Oct";
month[10] = "Nov";
month[11] = "Dec";
let monthname = month[monthnum];
const now = evt.date;
let hours = now.getHours();
let mins = now.getMinutes();
if (preferences.clockDisplay === "12h") {
hours = hours % 12 || 12;
} else {
hours = zeroPad(hours);
}
let minsZeroed = zeroPad(mins);
timeHandle.text = `${hours}:${minsZeroed}`;
monthHandle.text = `${monthname}`;
dayHandle.text = `${day}`;
// Activity Values: adjusted type
let stepsValue = (userActivity.today.adjusted["steps"] || 0);
let stepsString = stepsValue + ' steps';
stepsHandle.text = stepsString;
}
/* -------- SETTINGS -------- */
const SETTINGS_TYPE = "cbor";
const SETTINGS_FILE = "settings.cbor";
let settings, onsettingschange;
let stepsLabel = document.getElementById("stepsLabel");
let timeLabel = document.getElementById("timeLabel");
let dayLabel = document.getElementById("dayLabel");
let monthLabel = document.getElementById("monthLabel");
let dividers = document.getElementById ("divider");
messaging.peerSocket.onmessage = (evt) => {
let newColor;
consol.log('handleMessages(): $JSON.stringify(evt)}');
switch(evt.data.key) {
case 'colorSteps':
stepsLabel.style.fill = evt.data.value;
break;
case 'colorTime':
timelabel.style.fill = evt.data.value;
break;
case 'colorDay':
dayLabel.style.fill = evt.data.value;
break;
case 'colorMonth':
monthLabel.style.fill = evt.data.value;
break;
case 'colorDivider':
divider.style.fill = evt.data.value;
break;
}
}This is what I have in my companion/index.js
import * as kpay from './kpay/release/kpay_companion.js';
import * as kpay_common from '../common/kpay/kpay_common.js';
import { settingsStorage } from "settings";
import * as messaging from "messaging";
// Settings have been changed
settingsStorage.onchnage = function(evt) {
if (evt.newValue !== Evt.oldValue) {
sendValue(evt.key, evt.newValue);
}
}
function sendValue(key, val) {
if (!key || !val) {
return;
};
sendSettingData({
key: key,
value: JSON.parse(val)
});
}
function sendSettingData(data) {
if (messaging.peerSocket.readyState === messaging.peerSocket.OPEN) {
messaging.peerSocket.send(data);
} else {
console.log("No peerSocket connection");
}
}
/**** KPAY INIT - REQUIRED ***/
kpay.initialize();
Best Answer// typo in event name. It should be onchange
settingsStorage.onchnage = function(evt) {
// js is case-sensitive, so you need to use 'evt' instead of 'Evt' if (evt.newValue !== Evt.oldValue) {
Best AnswerThe time, steps, day and month label will now all change color thank you so much.
The dividers will not change color and returns this error.
unhandled TypeError: Cannot set property 'fill' of undefined
index.gui
<rect class="divider divider-top" /> <rect class="divider divider-btm" />
index.js
let divider = document.getElementsByClassName ("divider");styles.css
.divider {
x: 2%;
width: 286;
height: 5;
fill: teal;
}
.divider-top {
y: 24%;
}
.divider-btm {
y: 75%;
}
Best Answergive each divider a unique ID, so you can access them directly
(classes also work but I am trying to keep this simple)
index.gui
<rect id="top-divider" class="divider divider-top" /> <rect id="btm-divider" class="divider divider-btm" />
app\index.js
let dividerTop = document.getElementById ("top-divider");
let dividerBtm = document.getElementById ("btm-divider");
// then further down
case 'colorDivider':
dividerTop.style.fill = evt.data.value;
dividerBtm.style.fill = evt.data.value;[UPDATE]: changed ID names to avoid confusion.
Best AnswerThank you so much for all your help.
All of the color select functions are working correctly.
Best Answer