08-27-2018 09:11
08-27-2018 09:11
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.
09-14-2018 04:41 - edited 09-14-2018 07:25
09-14-2018 04:41 - edited 09-14-2018 07:25
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!]
09-14-2018 07:18 - edited 09-14-2018 07:37
09-14-2018 07:18 - edited 09-14-2018 07:37
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.
09-14-2018 07:39 - edited 09-14-2018 07:44
09-14-2018 07:39 - edited 09-14-2018 07:44
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"
09-14-2018 07:48 - edited 09-14-2018 07:54
09-14-2018 07:48 - edited 09-14-2018 07:54
I have changed the "test-text1" to "timeLabel" and there is no change it still will not change the color of the time element.
09-15-2018 03:32
09-15-2018 03:32
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);
09-15-2018 08:32 - edited 09-15-2018 08:34
09-15-2018 08:32 - edited 09-15-2018 08:34
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);
09-15-2018 10:19
09-15-2018 10:19
I'm still having no luck.
Thank you for all your help.
09-15-2018 10:36
09-15-2018 10:36
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();
09-15-2018 18:22 - edited 09-15-2018 23:31
09-15-2018 18:22 - edited 09-15-2018 23:31
// 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) {
09-16-2018 02:07 - edited 09-16-2018 02:18
09-16-2018 02:07 - edited 09-16-2018 02:18
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%; }
09-16-2018 02:24 - edited 09-16-2018 02:26
09-16-2018 02:24 - edited 09-16-2018 02:26
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.
09-16-2018 02:38
09-16-2018 02:38
Thank you so much for all your help.
All of the color select functions are working correctly.
09-16-2018 02:57
09-16-2018 02:57
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! 🙂