Settings API
Overview
Fitbit developers can make their application configurable by users, by creating application settings.
Application settings are written using JSX.
A compiled settings.js
file is registered into the Fitbit mobile application
during the application installation process.
General Tips
settingsKey
will manage the settings storage and retrieval for you, but you
can still manage them yourself. The following are equivalent:
<ColorSelect
settingsKey="color"
/>
<ColorSelect
value={props.settings.color}
onChange={value => props.settingsStorage.setItem('color', value)}
/>
Components
The Settings API provides a number of predefined components.
Section
Creates an element which can be used as a container section for other elements.
Basic Usage
<Section
description={<Text> Description <Link source="/">here</Link></Text>}
title={<Text bold align="center">Demo Settings</Text>}>
<Text>
This is a very basic demo settings page to show off some of the current
capabilities of the Companion Settings library.
</Text>
</Section>
Properties
title
takes a string, the text that appears above the content block.description
takes a string, the subtext that appears below the content block.
Link
Create a hyperlink to an anchor or URL.
Basic Usage
<Link source="...">InnerHTML</Link>
Properties
source
takes a string, the web address to link to.
Example Use Cases
External links, must be HTTP/HTTPS:
<Link source="https://www.google.com">Google</Link>
Tip: Use with the
<Text>
element for additional formatting options.
Text
Create a paragraph of text. Supports rich formatting.
Basic Usage
<Text>Your Text Here</Text>
Properties
bold
if present, the inner text will appear bold.italic
if present, the inner text will appear italic.align
:left | center | right
, sets the horizontal alignment of text.
Example Use Cases
<Text align="right">This text will align to the right side</Text>
<Text italic>This text is italicized.</Text>
<Text align="center">This text will be centered and <Text bold>bold</Text></Text>
Tip: Text is intended to appear inside a
<Section>
or<List>
.
TextImageRow
Creates a row containing a label
, sublabel
, and optional icon
image.
Basic Usage
<TextImageRow
label="Example"
sublabel="here it is"
/>
Properties
label
takes a string, appears as the main text.sublabel
takes a string, appears as the gray subtext under the label.icon
takes a string, URL for the icon image
Example Use Cases
<TextImageRow
label="San Francisco"
sublabel="CA"
icon="https://tinyurl.com/ybbmpxxq"
/>
Tip: Intended for use in a
<List>
or<Select>
.
Button
Creates a simple button, similar to the
Basic Usage
<Button
label="Button"
onClick={() => console.log("Clicked!")}
/>
Properties
label
takes a string, the text that appears inside the buttonlist
if present, the button will be styled to fit into a ListonClick
a function that is called every time the button is clicked. Passes the SyntheticEvent(https://facebook.github.io/react/docs/events.html) as the first argument.
Example Use Cases
<Button
list
label="Clear Settings Storage"
onClick={() => props.settingsStorage.clear()}
/>
Toggle
Creates a simple toggle on/off button.
Basic Usage
<Toggle
settingsKey="toggle"
label="example"
/>
Properties
label
takes a string, the text that appears to the left of the toggle.settingsKey
takes a string, the key associated with this setting.onChange
a function that is called every time the toggle is changed. Passes the new value of the toggle as the first argument (the booleantrue
for on,false
for off).
Example Use Cases
<Toggle
settingsKey="toggle"
/>
<Toggle
settingsKey="toggle"
label={`Toggle Switch: ${settings.toggle === 'true' ? 'on' : 'off'}`}
/>
<Toggle
settingsKey="toggle"
label="Toggle Switch"
/>
{ JSON.parse(settings.toggle || 'false') && <Toggle settingsKey="hiddenToggle" /> }
Slider
Creates a range slider control.
Basic Usage
<Slider
label="Example"
settingsKey="slider"
min="0"
max="60"
/>
Properties
label
takes a string, the text that appears above the slider.settingsKey
takes a string, the key associated with this setting.min
takes a string representation of a number, the minimum value for the slider.max
takes a string representation of a number, the maximum value for the slider.step
takes a string representation of a number, the interval for slider values.onChange
a function that is called every time the slider value is changed. Passes the new value of the toggle as the first argument (the string representation of the numerical value).
TextInput
Basic Usage
<TextInput
label="example"
settingsKey="text"
/>
Properties
title
takes a string, the text that appears above the section and in the navbar titlelabel
takes a string, the text that appears on the TextInput button as well above the text input boxplaceholder
takes a string, the text that appears inside the text input box when no value is present, defaults tolabel
action
takes a string, the text that appears in the save button if presenttype
takes a string, the type of input field, defaults to "text"disabled
if present, the textInput is disabled and cannot be clicked onsettingsKey
takes a string, the key associated with this settingonChange
a function that is called every time the text value is saved by the user. Takes the new value of the text as an argumentrenderItem
a function that takes in the value of one option and returns the JSX to render that item in a list. By default, thename
field is wrapped in a<Text>
component.onAutocomplete
a function that is called every time the text value is changed by the user. Takes the new value of the text as an argument and returns a list of autocomplete options to render. Each option is rendered usingrenderItem
and must include aname
field.renderAutocomplete
a function that takes in one option and the input value and returns the JSX to render that item in a list. By default usesrenderItem
.
Example use cases
<TextInput
label="Example"
title="Text Input"
settingsKey="textInput"
disabled={!(props.settings.toggleTextInput === "true")}
/>
<Toggle
label="Enable Text Input"
settingsKey="toggleTextInput"
/>
<TextInput
title="Add List Item"
label="Item Name"
placeholder="Type something"
action="Add Item"
onAutocomplete={(value) => {
const autoValues = [
{ name: "red", value: "1" },
{ name: "orange", value: "2" },
{ name: "yellow", value: "3" },
{ name: "green", value: "4" },
{ name: "blue", value: "5" },
{ name: "purple", value: "6" }];
return autoValues.filter((option) => option.name.startsWith(value));
}}
/>
Tip: This component is still being developed and will soon include support for autocomplete
ColorSelect
Basic Usage
<ColorSelect
settingsKey="color"
colors={[
{color: 'tomato'},
{color: 'sandybrown'},
{color: 'gold'},
{color: 'aquamarine'},
{color: 'deepskyblue'},
{color: 'plum'}
]}
/>
Properties
settingsKey
takes a string, the key associated with this setting.colors
takes an array of objects. Each object must have a field namedcolor
, whose value is a valid string representation of a CSS color. For examples, see https://www.w3schools.com/cssref/css_colors_legal.asp. Each object can also include an optionalvalue
field, which is what will be stored in settings and passed toonSelection
. Ifvalue
is not defined, the value ofcolor
will be used by default.centered
if present, the color circles will be center aligned. Otherwise, they are left aligned.onSelection
a function that is called every time a color is selected. Passes the new value of the selected color as the first argument (the string representation of the value).
Example Use Cases
<ColorSelect
centered={true}
settingsKey="color"
colors={[
{color: 'tomato', value: '1'},
{color: 'sandybrown', value: '2'},
{color: 'gold', value: '3'},
{color: 'aquamarine', value: '4'},
{color: 'deepskyblue',value: '5'},
{color: 'plum', value: '6'},
{color: 'tomato', value: '7'},
{color: 'sandybrown', value: '12'},
{color: 'gold', value: '13'},
{color: 'aquamarine', value: '14'},
{color: 'deepskyblue',value: '15'}
]}
onSelection={(value) => console.log(value)}
/>
<ColorSelect
settingsKey="color"
colors={[
{color: 'tomato', value: {align: 'left', number: '1'}},
{color: 'sandybrown', value: {align: 'right', number: '2'}}
]}
/>
Tip: If you specify fewer than
6
colors, the circles will stretch to fill the row
Select
Creates a selection picker.
Basic Usage
<Select
label={`Selection`}
settingsKey="selection"
options={[
{name:"One"},
{name:"Two"},
{name:"Three"}
]}
/>
Properties
title
takes a string, the text that appears above the List block.selectViewTitle
takes a string, the text that appears as the title of the select view or modal.label
takes a string, the text that appears on the select button.settingsKey
takes a string, the key associated with this setting.options
takes an array of objects. Each object must have a field namedname
, whose value is a string. Each object can also include an optionalvalue
field, which will be stored in settings along withname
.multiple
if present, the user can select multiple items from the list, toggling them on and off by selecting them.disabled
if present, the select element will be disabled.renderItem
a function that takes in the value of one option and returns the JSX to render that item in a list. By default, thename
field is wrapped in a<Text>
component.onSelection
a function that is called every time an option is selected. Passes an object as an argument:{selected: Array, values: Array}
, whereselected
is an array of indices that map to the selected options, andvalues
is an array of the values of those selected options.
Note that the selected option within a <Select>
is recalled by the option's
index in the options
array, not by the option's name
or value
. If you
update your application to rearrange or remove options within a <Select>
,
you must manually migrate the corresponding settingsKey
in your companion
code. Otherwise, existing users will see their selections changed or cleared
unexpectedly during the update. Alternatively, you may manually manage the
value of the <Select>
via the onSelection
event and selected
property.
Example Use Cases
<Select
label={`Multi-Selection`}
multiple
settingsKey="multiselection"
options={[
{name:"One", value:"1"},
{name:"Two", value:"2"},
{name:"Three", value:"3"},
{name:"Four", value:"4"},
{name:"Five", value:"5"},
{name:"Six", value:"6"},
{name:"Seven", value:"7"},
{name:"Eight", value:"8"},
{name:"Nine", value:"9"},
{name:"Ten", value:"10"},
{name:"Eleven", value:"11"},
{name:"Twelve", value:"12"},
{name:"Thirteen", value:"13"},
{name:"Fourteen", value:"14"},
{name:"Fifteen", value:"15"}
]}
renderItem={
(option) =>
<TextImageRow
label={option.name}
sublabel="Sub-Label"
icon="https://tinyurl.com/ybbmpxxq"
/>
}
onSelection={(selection) => console.log(selection)}
/>
Tip: We recommend using
<TextImageRow>
as the rendering function for renderItem when including icons or sublabels. For a simple text item, use<Text>
.
Additive List
Creates a list which users can add items to by selecting from a list of options.
Basic Usage
Additive List with a Text Input:
<AdditiveList
settingsKey="additive"
/>
Additive List with a Select Input:
<AdditiveList
settingsKey="additive"
addAction={
<Select
label="Add Item"
options={[
{ name: 'Label1'},
{ name: 'Label2'},
{ name: 'Label3'},
{ name: 'Label4'},
{ name: 'Label5'}
]}
/>
}
/>
Properties
title
takes a string, the text that appears above the List block.description
takes a string, the subtext that appears below the List block.settingsKey
takes a string, the key associated with this setting.minItems
the minimum number of items allowed in the list.maxItems
the maximum number of items allowed in the list.renderItem
a function that takes in the value of one option and returns the JSX to render that item in a list. By default, thename
field is wrapped in a<Text>
component.addAction
a component that will be used to render the input style for this list. Should be a component that allows for input, such asSelect
orTextInput
.onListChange
a function that is called every time the list is changed from adding, deleting or reordering. Passes an array as an argument containing all the items in the list in their current order
Example Use Cases
<AdditiveList
title="A list of TextImageRow"
settingsKey="select-list"
maxItems="5"
renderItem={
({ name, value }) =>
<TextImageRow
label={name}
sublabel={value.location}
icon={value.icon}
/>
}
addAction={
<Select
label="Add Item"
options={[
{ name: 'Label1', required: true, value: {location: 'Sub-Label', icon: 'https://tinyurl.com/ybbmpxxq'} },
{ name: 'Label2', value: {location: 'Sub-Label', icon: 'https://tinyurl.com/ybbmpxxq'} },
{ name: 'Label3', required: true, value: {location: 'Sub-Label', icon: 'https://tinyurl.com/ybbmpxxq'} },
{ name: 'Label4', value: {location: 'Sub-Label', icon: 'https://tinyurl.com/ybbmpxxq'} },
{ name: 'Label5', required: false, value: {location: 'Sub-Label', icon: 'https://tinyurl.com/ybbmpxxq'} }
]}
/>
}
/>
<AdditiveList
title="A list with Autocomplete"
settingsKey="autocomplete-list"
maxItems="5"
addAction={
<TextInput
title="Add List Item"
label="Item Name"
placeholder="Type something"
action="Add Item"
onAutocomplete={(value) => {
const autoValues = [
{ name: "red", value: "1" },
{ name: "orange", value: "2" },
{ name: "yellow", value: "3" },
{ name: "green", value: "4" },
{ name: "blue", value: "5" },
{ name: "purple", value: "6" }];
return autoValues.filter((option) => option.name.startsWith(value));
}}
/>
}
/>
OAuth Button
Creates a generic OAuth button that provides two stage authorization code flow by default.
Note: Most OAuth providers require you to specify the
redirect_url
domain or full path that you will be using with their service. We have provided a special URL to automatically handle the redirection. Please use:https://app-settings.fitbitdevelopercontent.com/simple-redirect.html
Basic Usage
<Oauth
settingsKey="oauth"
title="OAuth Login"
label="OAuth"
status="Login"
authorizeUrl="https://accounts.google.com/o/oauth2/v2/auth"
requestTokenUrl="https://www.googleapis.com/oauth2/v4/token"
clientId="11111"
clientSecret="asdfxxx"
scope="profile"
pkce
/>
Properties
title
takes a string, the text that appears above the List block.label
takes a string, the text that appears on the left of the Button.status
takes a string, the text that appears on the right of the Button.description
takes a string, the subtext that appears below the List block.settingsKey
takes a string, the key associated with this setting.authorizeUrl
takes a string, the user authorization grant url.requestTokenUrl
takes a string, the request token url.clientId
takes a string, the clientId specified on your OAuth provider account.clientSecret
takes a string, the clientSecret specified on your OAuth prvoder account.scope
takes a string, the scopes that are being requested.pkce
takes a boolean, enables Proof Key for Code Exchange for OAuth providers that support PKCE.onAccessToken
a function that receives the accessToken and anything the OAuth provides with it like refresh token and expiration.
Example Use Cases
<Oauth
settingsKey="oauth"
title="Fitbit Login"
label="Fitbit"
status="Login"
authorizeUrl="https://www.fitbit.com/oauth2/authorize"
requestTokenUrl="https://api.fitbit.com/oauth2/token"
clientId="11111"
clientSecret="asdfxxx"
scope="profile"
onAccessToken={async (data) => {
console.log(data);
}}
/>
Strava Login Button
Creates a Strava login button that takes in Strava OAuth options and allows the user to log in.
Note: For Strava API Application registration you need to set the domain that is used redirect to after a user authenticates at Strava. That domain currently should be:
fitbitdevelopercontent.com
and is likely to change in the future when we provide a more robust redirect OAuth service.
Basic Usage
<StravaLogin
title="Strava Login"
settingsKey="strava"
clientId="11111"
clientSecret="asdfxxx"
/>
Properties
title
takes a string, the text that appears above the List block.description
takes a string, the subtext that appears below the List block.settingsKey
takes a string, the key associated with this setting.clientId
takes a string, the clientId specified on your Strava account.clientSecret
takes a string, the clientSecret specified on your Strava account.onAccessToken
a function that receives the accessToken and Strava userInfo when the auth flow returns with a valid code. It will only run once after coming back from the auth flow.
Example Use Cases
<StravaLogin
title="Strava Login"
settingsKey="strava"
clientId="11111"
clientSecret="asdfxxx"
onAccessToken={async (accessToken, userInfo) => {
const profile = await getProfile(accessToken);
settingsStorage.setItem('user', JSON.stringify(profile));
}}
/>
Image Picker
Creates a component that facilitates the user picking a photo from their phone to be used within your application. Once an image is picked, it will be either stored and/or passed to your handler function as a base64 encoded string.
Basic Usage
<ImagePicker
title="Image Picker"
description="Pick an image to use in this app"
label="Pick an Image"
sublabel="Settings image picker"
settingsKey="image"
imageWidth="300"
imageHeight="300"
/>
Properties
title
takes a string, the text that appears above the List block.description
takes a string, the subtext that appears below the List block.label
takes a string, the text that appears as the main action the Button.sublabel
takes a string, the text that appears under the label on the Button.pickerTitle
takes a string, the title of the image picker page.pickerImageTitle
takes a string, the title above the already picked image.pickerLabel
takes a string, the text that appears as the main action on the picker page.settingsKey
takes a string, the key associated with this setting. Note: If you provide asettingsKey
the image data will be stored and available under the key name you provide as JSON serialized as a string. Stored as a JSON serialized string with the following properties:imageUri
- base64 data URIimageSize.width
- definedimageWidth
imageSize.height
- definedimageHeight
imageWidth
takes a string or integer, set to348
by default, the desired width of the picked image.imageHeight
takes a string, set to250
by default, the desired height of the picked image.showIcon
takes a boolean, set totrue
by default, if set tofalse
it will not show the picked image as an icon next to the button.disabled
takes a boolean, disable the button.onImagePicked
takes a function, when an image is picked the image data is passed to the definedonImagePicked
handler. Passes an object with the following properties:imageUri
- base64 data URIimage.imageString
- base64 string image dataimage.type
- image mime-typeimageSize.width
- definedimageWidth
imageSize.height
- definedimageHeight
Example Use Cases
<ImagePicker
title="Image Picker"
description="Pick an image to use in this app"
label="Pick an Image"
sublabel="Settings image picker"
imageWidth="300"
imageHeight="300"
onImagePicked={({ image, imageSize }) => doSomethingWithImage(image, imageSize)}
/>