├── LICENSE
├── README.md
├── app
└── index.js
├── common
└── utils.js
├── companion
└── index.js
├── package.json
├── resources
├── index.gui
├── styles.css
└── widgets.gui
├── screenshot.png
└── settings
└── index.jsx
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Fitbit, Inc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SDK Photo Picker
2 |
3 | Fitbit SDK example clock face which demonstrates the ImagePicker component from
4 | the Settings API.
5 |
6 | 
7 |
8 | Find out more information on the
9 | [Fitbit Developer Website](https://dev.fitbit.com).
10 |
11 | ## License
12 |
13 | This example is licensed under the [MIT License](./LICENSE).
--------------------------------------------------------------------------------
/app/index.js:
--------------------------------------------------------------------------------
1 | import { me } from "appbit";
2 | import clock from "clock";
3 | import { display } from "display";
4 | import document from "document";
5 | import * as fs from "fs";
6 | import { inbox } from "file-transfer";
7 | import { preferences } from "user-settings";
8 |
9 | import * as util from "../common/utils";
10 |
11 | const SETTINGS_FILE = "settings.cbor";
12 | const SETTINGS_TYPE = "cbor";
13 |
14 | const labelTime = document.getElementById("labelTime");
15 | const labelTimeShadow = document.getElementById("labelTimeShadow");
16 | const imageBackground = document.getElementById("imageBackground");
17 |
18 | let mySettings;
19 | loadSettings();
20 | me.onunload = saveSettings;
21 |
22 | clock.granularity = "minutes";
23 |
24 | clock.ontick = evt => {
25 | let today = evt.date;
26 | let hours = today.getHours();
27 | if (preferences.clockDisplay === "12h") {
28 | hours = hours % 12 || 12;
29 | } else {
30 | hours = util.zeroPad(hours);
31 | }
32 | let mins = util.zeroPad(today.getMinutes());
33 | let timeString = `${hours}:${mins}`;
34 | labelTime.text = timeString;
35 | labelTimeShadow.text = timeString;
36 | };
37 |
38 | inbox.onnewfile = () => {
39 | let fileName;
40 | do {
41 | fileName = inbox.nextFile();
42 | if (fileName) {
43 | if (mySettings.bg && mySettings.bg !== "") {
44 | fs.unlinkSync(mySettings.bg);
45 | }
46 | mySettings.bg = `/private/data/${fileName}`;
47 | applySettings();
48 | }
49 | } while (fileName);
50 | };
51 |
52 | function loadSettings() {
53 | try {
54 | mySettings = fs.readFileSync(SETTINGS_FILE, SETTINGS_TYPE);
55 | } catch (ex) {
56 | mySettings = {};
57 | }
58 | applySettings();
59 | }
60 |
61 | function saveSettings() {
62 | fs.writeFileSync(SETTINGS_FILE, mySettings, SETTINGS_TYPE);
63 | }
64 |
65 | function applySettings() {
66 | if (mySettings.bg) {
67 | imageBackground.image = mySettings.bg;
68 | }
69 | display.on = true;
70 | }
71 |
--------------------------------------------------------------------------------
/common/utils.js:
--------------------------------------------------------------------------------
1 | // Add zero in front of numbers < 10
2 | export function zeroPad(i) {
3 | if (i < 10) {
4 | i = "0" + i;
5 | }
6 | return i;
7 | }
8 |
--------------------------------------------------------------------------------
/companion/index.js:
--------------------------------------------------------------------------------
1 | import { outbox } from "file-transfer";
2 | import { Image } from "image";
3 | import { device } from "peer";
4 | import { settingsStorage } from "settings";
5 |
6 | settingsStorage.setItem("screenWidth", device.screen.width);
7 | settingsStorage.setItem("screenHeight", device.screen.height);
8 |
9 | settingsStorage.onchange = function(evt) {
10 | if (evt.key === "background-image") {
11 | compressAndTransferImage(evt.newValue);
12 | }
13 | };
14 |
15 | function compressAndTransferImage(settingsValue) {
16 | const imageData = JSON.parse(settingsValue);
17 | Image.from(imageData.imageUri)
18 | .then(image =>
19 | image.export("image/jpeg", {
20 | background: "#FFFFFF",
21 | quality: 40
22 | })
23 | )
24 | .then(buffer => outbox.enqueue(`${Date.now()}.jpg`, buffer))
25 | .then(fileTransfer => {
26 | console.log(`Enqueued ${fileTransfer.name}`);
27 | });
28 | }
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "fitbit": {
3 | "appType": "clockface",
4 | "appDisplayName": "sdk-photo-picker",
5 | "iconFile": "resources/icon.png",
6 | "wipeColor": "",
7 | "requestedPermissions": [],
8 | "buildTargets": [
9 | "higgs",
10 | "meson"
11 | ],
12 | "i18n": {
13 | "en": {
14 | "name": "sdk-photo-picker"
15 | }
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/resources/index.gui:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/resources/styles.css:
--------------------------------------------------------------------------------
1 | .background {
2 | viewport-fill: #444444;
3 | }
4 |
5 | .time {
6 | font-size: 60;
7 | font-family: Colfax-Black;
8 | text-length: 32;
9 | text-anchor: end;
10 | x: 100%-8;
11 | y: 50;
12 | fill: white;
13 | }
14 |
15 | .time-shadow {
16 | x: 100%-6;
17 | y: 52;
18 | fill: black;
19 | }
20 |
--------------------------------------------------------------------------------
/resources/widgets.gui:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Fitbit/sdk-photo-picker/4b75d68c06e25e0431b5282ff6a49f6da2512cf4/screenshot.png
--------------------------------------------------------------------------------
/settings/index.jsx:
--------------------------------------------------------------------------------
1 | function mySettings(props) {
2 | let screenWidth = props.settingsStorage.getItem("screenWidth");
3 | let screenHeight = props.settingsStorage.getItem("screenHeight");
4 |
5 | return (
6 |
7 |
16 |
17 | );
18 | }
19 |
20 | registerSettingsPage(mySettings);
21 |
--------------------------------------------------------------------------------