Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Application Setting (Setting API) Color Select

ANSWERED

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

 

Best Answer
0 Votes
1 BEST ANSWER

Accepted Solutions

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.

View best answer in original post

Best Answer
0 Votes
32 REPLIES 32

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.

 

https://github.com/Fitbit/sdk-moment

Best Answer
0 Votes

Thanks 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
0 Votes

 

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.

 

Capture.PNG

 

I would really appreciate any help with this problem as I am unsure where I have gone wrong.

 

Thanks

Best Answer
0 Votes

Can you paste the contents of your settings/index.jsx file?

Best Answer
0 Votes

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>
<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
0 Votes

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 Answer
0 Votes

Thank 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 Answer
0 Votes

I have now sorted out so the color selection now displays. But I am getting an error when I try to change the color.

 

Capture 2.PNG

 Capture 3.PNG

 Thanks for all of your help.

 

 

 

Best Answer
0 Votes

I think you will have to post the code for anyone to comment on this.

 

John

Best Answer
0 Votes

app/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 Answer
0 Votes

app/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 Answer
0 Votes

I 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 Answer
0 Votes

I 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&colon;image/png;base64, <base-64 image data goes here>",\"imageSize\":{\"width\":\"300\",\"height\":\"300\"}}","oldValue":null}

*/

 

Best Answer
0 Votes
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);

This is the code within my app/index.js

Best Answer
0 Votes
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);

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 Answer
0 Votes

As 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 Answer
0 Votes

I 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 Answer
0 Votes

Can 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 Answer
0 Votes

I 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.

 

Capture 4.PNG

 

 

I have on idea where I am going wrong.

Best Answer
0 Votes