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.
give 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 Answer
Fitbit Developers oversee the SDK and API forums. We're here to answer questions about Fitbit developer tools, assist with projects, and make sure your voice is heard by the development team.
Take a look at the Moment example.
It has some colors in the settings page, a generic approach to sending those settings via the companion, and also demostrates how to use them on the device, as well as persisting them on the device too.
Best AnswerThanks this has been really helpful.
I have run into a small issue that when I run a simulation of the watch face the settings display blank.
It might be that I have missed out something really obvious which is causing the problem.
Best Answer
This is what displays when a run my watch face. The settings are blank even though I have code in place that should generate and display settings.
I would really appreciate any help with this problem as I am unsure where I have gone wrong.
Thanks
Best Answer
Fitbit Developers oversee the SDK and API forums. We're here to answer questions about Fitbit developer tools, assist with projects, and make sure your voice is heard by the development team.
Can you paste the contents of your settings/index.jsx file?
Best Answerconst colorSet = [
{color: "white"},
{color: "black"},
{color: "grey"},
{color: "navy"},
{color: "blue"},
{color: "cyan"},
{color: "olive"},
{color: "darkgreen"},
{color: "springgreen"},
{color: "slate blue"},
{color: "khaki"},
{color: "yellow"},
{color: "lemonchiffon"},
{color: "coral"},
{color: "lightpink"},
{color: "red"},
{color: "crimson"}
];
const options = [
['Time Color', 'colorTime'],
['Dividers Color', 'colorDividers'],
['Steps Color', 'colorSteps'],
['Day Color', 'colorDay'],
['Month Color', 'colorMonth']
];
function mySettings(props) {
return (
<Page>
<Section
title={<Text bold align="center">Time Colour</Text>}>
<ColorSelect
settingsKey={colorTime}
colors={colorSet} />
</Section>
<Section
title={<Text bold align="center">Divider Colour</Text>}>
<ColorSelect
settingsKey={colorDividers}
colors={colorSet} />
</Section>
<Section
title={<Text bold align="centre">Steps Colour</Text>}>
<ColorSelect
settingsKey={colorSteps}
colors={colorSet} />
</Section>
<Section
title={<Text bold align="centre">Day Colour</Text>}>
<ColorSelect
settingsKey={colorDay}
colors={colorSet} />
</Section>
<Section
title={<Text bold align= "center">Month Colour</Text>}>
<ColorSelect
settingsKey={colorMonth}
colors={colorSet} />
</Section>
</Page>
);
}
registerSettingsPage(mySettings);
Best Answer
Fitbit Developers oversee the SDK and API forums. We're here to answer questions about Fitbit developer tools, assist with projects, and make sure your voice is heard by the development team.
That's not quite right.
colorTime and colorSet aren't variables.
<ColorSelect
settingsKey={colorTime}
colors={colorSet} />
</Section>
You should just be able to do this to build color options for each of the items in the options array:
const colorSet = [
{color: "white"},
{color: "black"},
{color: "grey"},
{color: "navy"},
{color: "blue"},
{color: "cyan"},
{color: "olive"},
{color: "darkgreen"},
{color: "springgreen"},
{color: "slate blue"},
{color: "khaki"},
{color: "yellow"},
{color: "lemonchiffon"},
{color: "coral"},
{color: "lightpink"},
{color: "red"},
{color: "crimson"}
];
const options = [
['Time Color', 'colorTime'],
['Dividers Color', 'colorDividers'],
['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 AnswerThank you. I have now edited my code. It displayed the color selection settings for a short time but after I started to change the colors in the color set it then displayed blank again.
Sorry about this. I haven't got a great understanding of coding. This is the first watch face that I have created.
Best AnswerI have now sorted out so the color selection now displays. But I am getting an error when I try to change the color.
Thanks for all of your help.
Best Answerapp/index.js
import * as simpleSettings from "./simple/device-settings.js";
function settingsCallback(data) {
if (!data) {
return;
}
if (data.colorDividers) {
dividers.forEach(item => {
item.style.fill = data.colorDividers;
});
}
if (data.colorTime) {
timeLabel.style.fill = data.colorTime;
}
if (data.colorSteps) {
stepsLabel.style.fill = data.colorSteps;
}
if (data.colorDay) {
DayLabel.style.fill = data.colorDay;
}
if (data.colorMonth) {
MonthLabel.style.fill = data.colorMonth;
}
}
simpleSettings.initialize(settingsCallback);
app/simple/device-settings.js
import { me as device } from "device";
import * as fs from "fs";
import * as messaging from "messaging";
const SETTINGS_TYPE = "cbor";
const SETTINGS_FILE = "settings.cbor";
let settings, onsettingschange;
export function initialize(callback) {
settings = loadSettings();
onsettingschange = callback;
onsettingschange(settings);
}
// Received message containing settings data
messaging.peerSocket.addEventListener("message", function(evt) {
settings[evt.data.key] = evt.data.value;
onsettingschange(settings);
})
// Register for the unload event
me.addEventListener("unload", saveSettings);
// Load settings from filesystem
function loadSettings() {
try {
return fs.readFileSync(SETTINGS_FILE, SETTINGS_TYPE);
} catch (ex) {
return {};
}
}
// Save settings to the filesystem
function saveSettings() {
fs.writeFileSync(SETTINGS_FILE, settings, SETTINGS_TYPE);
}
settings/index.jsx
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'],
['Dividers Color', 'colorDividers'],
['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 Answerapp/simple/device-settings.js
import { me } from "appbit";
import { me as device } from "device";
import * as fs from "fs";
import * as messaging from "messaging";
const SETTINGS_TYPE = "cbor";
const SETTINGS_FILE = "settings.cbor";
let settings, onsettingschange;
export function initialize(callback) {
settings = loadSettings();
onsettingschange = callback;
onsettingschange(settings);
}
// Received message containing settings data
messaging.peerSocket.addEventListener("message", function(evt) {
settings[evt.data.key] = evt.data.value;
onsettingschange(settings);
})
// Register for the unload event
me.addEventListener("unload", saveSettings);
// Load settings from filesystem
function loadSettings() {
try {
return fs.readFileSync(SETTINGS_FILE, SETTINGS_TYPE);
} catch (ex) {
return {};
}
}
// Save settings to the filesystem
function saveSettings() {
fs.writeFileSync(SETTINGS_FILE, settings, SETTINGS_TYPE);
}
Best AnswerI do not see any reference in your code to colorTime variable that is giving the error. Also, if you copy your code, then select the </> symbol in the formatting section, you can paste your code in there and it will show in an easier to read format.
Best AnswerI can't see how you use the value that comes in from the companion app but here is what I do with colours
peerSocket.onmessage = evt => {
newColour = JSON.parse(evt.data.newValue);
...
...
}
// extract from my code, for your info ...
/*
The user changed a setting in the companion UI
The format of the received data is:
------------------------------------
Toggle
{"isTrusted":false,"key":"tglKeyName","newValue":"false","oldValue":"true"}
Slide
{"isTrusted":false,"key":"sldKeyName","newValue":"2","oldValue":"1"}
ColorSelect
{"isTrusted":false,"key":"clrKeyName","newValue":"\"#FF0000\"","oldValue":"\"#33FF33\""}
Select
{"isTrusted":false,"key":"selKeyName","newValue":"{\"selected\":[2],\"values\":[{\"name\":\"Calories\"}]}","oldValue":"{\"selected\":[0],\"values\":[{}]}"}
Image picker
{"isTrusted":false,"key":"imgBackground","newValue":"{\"imageUri\":\"data:image/png;base64, <base-64 image data goes here>",\"imageSize\":{\"width\":\"300\",\"height\":\"300\"}}","oldValue":null}
*/
Best Answerimport * as simpleSettings from "./simple/device-settings.js";
function settingsCallback(data) {
if (!data) {
return;
}
if (data.colorDividers) {
dividers.forEach(item => {
item.style.fill = data.colorDividers;
});
}
if (data.colorTime) {
timeLabel.style.fill = data.colorTime;
}
if (data.colorSteps) {
stepsLabel.style.fill = data.colorSteps;
}
if (data.colorDay) {
DayLabel.style.fill = data.colorDay;
}
if (data.colorMonth) {
MonthLabel.style.fill = data.colorMonth;
}
}
simpleSettings.initialize(settingsCallback);
This is the code within my app/index.js
Best Answerconst options = [
['Time Color', 'colorTime'],
['Dividers Color', 'colorDividers'],
['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);This is the code in my settings/index.jsx
It currently will not change the color of any of the elements that I have set. It just comes up with the error. The error that appears always links back to this line of code (app/simpe/device-settings.js:24,3):
// Received message containing settings data
messaging.peerSocket.addEventListener("message", function(evt) {
settings[evt.data.key] = evt.data.value;
onsettingschange(settings);
})
Best AnswerAs a novice programmer myself, I came across a similar problem. Check the value you are trying to assign as a color, it may not be properly formatted. On mine, I was having problems on the first pass and had to strip off the quotes for it to work. I just did an error catch and removed them.
In my app/index.js
} catch (error) {
if (loadColor !== undefined) {
//on first run-through there are still quotes on the color
loadColor = util.myColor(loadColor);
console.log("Refine loadColor <" + loadColor + ">");then in common/util.js
//get the color without quotes
export function myColor(str) {
return str.substring(1,str.length - 1);
}I hope this helps.
Best AnswerI have just run the simulator and it no longer displays the error when I click on the color options. But it is still not changing the color of the selected area.
These are the id for the elements that I want to change color.
index.gui
<text id="timeLabel" />
<text id="stepsLabel" />
<text id= "dayLabel" />
<text id= "monthLabel"/>
<rect class="divider divider-top" />
<rect class="divider divider-btm" />
settings/index.jsx
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'],
['Dividers Color', 'colorDividers'],
['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);app/index.js
unction settingsCallback(data) {
if (!data) {
return;
}
if (data.colorDividers) {
dividers.forEach(item => {
item.style.fill = data.colorDividers;
});
}
if (data.colorTime) {
timeLabel.style.fill = data.colorTime;
}
if (data.colorSteps) {
stepsLabel.style.fill = data.colorSteps;
}
if (data.colorDay) {
dayLabel.style.fill = data.colorDay;
}
if (data.colorMonth) {
monthLabel.style.fill = data.colorMonth;
}
}
simpleSettings.initialize(settingsCallback);Is this because I am not referencing the elements using the correct terms?
Sorry if this is a really silly question. I haven't got a great understanding of coding. I have been using the guides and this forum to find out how to create the code for the elements that I want to have within my watch face.
Best AnswerCan you please try using this code (changes are in bold)
messaging.peerSocket.onmessage = (evt) => {
let newColour = JSON.parse(evt.data.newValue);
console.log(`new colour: ${newColour}`);
setting[evt.data.key] = newColour;
onsettingsChange(settings);
}instead of
// Received message containing settings data
messaging.peerSocket.addEventListener("message", function(evt) {
settings[evt.data.key] = evt.data.value;
onsettingschange(settings);
})
Best AnswerI have just replaced the code and I am still having the same problem. The color I select in the settings is still not applying to the specified area.
As you can see here I have selected the color of the time to be grey and there has been no change.
I have on idea where I am going wrong.
Best Answer