08-04-2018 10:29
08-04-2018 10:29
I'm trying to build a watch face and came up against what I assume is a common problem of allowing users to select colours in settings.
I wanted to allow users to pick any possible HSL colour using the hsl() CSS function, rather than an arbitrarily short list of colours. I figured a nice way to do this would be to have 3 Sliders for Hue, Saturation and Lightness and store each value in a separate settingsKey - which kind of works (more on that later).
The next challenge I came up against was finding a way to show the colour produced by the user's selection; which is difficult since the only component available in Settings for which the API allows programmatically controlling colour is the colour picker (we just "picked" the colour with the sliders).
Ideally it would be nice to be able to control the backgroundColor of some other element, like Text, for conveying a user's selection. For the time being I've chosen to use a Color Picker with a single option, which also kind of works except clicking the color picker with one option gets an error:
[6:22:50 PM]TypeError: Invalid attempt to destructure non-iterable instance
[6:22:50 PM]Uncaught TypeError: Invalid attempt to destructure non-iterable instance
The issue I have is that the Sliders are almost completely unresponsive. Trying to drag them on both the simulator and iOS app is like pulling a refridgerator with an oily rope, the sliders just barely move and then get "dropped". I assume it's something to do with rerendering the page when a value changes?
/common/HSLPicker.js
import { toHSLString } from './utils'; export default (props) => { const { settingsKey, settings, settingsStorage } = props console.log(JSON.stringify(settings)) return ( <Text> <Slider label="Hue" value={settings[settingsKey+".h"]} onChange={value => settingsStorage.setItem(settingsKey+".h", value)} min="0" max="360" /> <Slider label="Saturation" value={settings[settingsKey+".s"]} onChange={value => settingsStorage.setItem(settingsKey+".s", value)} min="0" max="100" /> <Slider label="Lightness" value={settings[settingsKey+".l"]} onChange={value => settingsStorage.setItem(settingsKey+".l", value)} min="0" max="100" /> <ColorSelect colors={[ {color: toHSLString(settings, settingsKey)} ]} /> </Text> ); }
/common/utils.js:
export function withSettings (Component, settings, settingsStorage) { return (props) => { return (<Component settings={settings} settingsStorage={settingsStorage} {...props} />); }; } export function toHSLString(settings, settingsKey) { if (!settings[settingsKey+".h"] || !settings[settingsKey+".s"] || !settings[settingsKey+".l"]) { return 'hsl(0,0%,0%)' } return "hsl("+ settings[settingsKey+".h"] + "," + settings[settingsKey+".s"] + "%," + settings[settingsKey+".l"] + "%" + ")"; }
/settings/index.js
import { withSettings } from '../common/utils' import hslPicker from '../common/HSLPicker' const SettingsMain = (props) => { const HSLPicker = withSettings(hslPicker, props.settings, props.settingsStorage); return (<Page> <Section title={<Text bold align="center">Demo Settings</Text>} > <HSLPicker settingsKey="backgroundColor" /> </Section> </Page>) } registerSettingsPage(SettingsMain)
Hopefully I'm not missing anything obvious, I guess this may become a feature request.
Cheers!
Kev
08-07-2018 17:25
08-07-2018 17:25
I wonder if you should allow users to change the sliders, but the color is only applied when a button is pressed, instead of for each value onchange?