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
32 REPLIES 32

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

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

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

 

I have changed the "test-text1" to "timeLabel" and there is no change it still will not change the color of the time element.

 

Capture 5.PNG

 

Best Answer
0 Votes

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

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

I'm still having no luck.

 

Thank you for all your help.

Best Answer
0 Votes

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

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

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

Thank you so much for all your help. 

 

All of the color select functions are working correctly.

Best Answer
0 Votes

No problem at all.

 

Looking back at some of my posts, I realised that I'd made some mistakes, so I just had to make sure it works in the end! 🙂

 

 

Best Answer