├── .gitignore
├── CONTRIBUTING.txt
├── DCO.txt
├── LICENCE
├── README.md
├── app
├── index.js
├── views.js
└── views
│ ├── view-1.js
│ ├── view-2.js
│ └── view-3.js
├── package.json
├── resources
├── index.gui
├── styles.css
├── views
│ ├── view-1.gui
│ ├── view-2.gui
│ └── view-3.gui
└── widgets.gui
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | build
3 | node_modules
4 | package-lock.json
5 | yarn.lock
--------------------------------------------------------------------------------
/CONTRIBUTING.txt:
--------------------------------------------------------------------------------
1 | The current version of our contributing guide can be found at https://dev.fitbit.com/community/contributing/.
2 |
--------------------------------------------------------------------------------
/DCO.txt:
--------------------------------------------------------------------------------
1 | Developer Certificate of Origin
2 | Version 1.1
3 |
4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
5 | 1 Letterman Drive
6 | Suite D4700
7 | San Francisco, CA, 94129
8 |
9 | Everyone is permitted to copy and distribute verbatim copies of this
10 | license document, but changing it is not allowed.
11 |
12 | Developer's Certificate of Origin 1.1
13 |
14 | By making a contribution to this project, I certify that:
15 |
16 | (a) The contribution was created in whole or in part by me and I
17 | have the right to submit it under the open source license
18 | indicated in the file; or
19 |
20 | (b) The contribution is based upon previous work that, to the best
21 | of my knowledge, is covered under an appropriate open source
22 | license and I have the right under that license to submit that
23 | work with modifications, whether created in whole or in part
24 | by me, under the same open source license (unless I am
25 | permitted to submit under a different license), as indicated
26 | in the file; or
27 |
28 | (c) The contribution was provided directly to me by some other
29 | person who certified (a), (b) or (c) and I have not modified
30 | it.
31 |
32 | (d) I understand and agree that this project and the contribution
33 | are public and that a record of the contribution (including all
34 | personal information I submit with it, including my sign-off) is
35 | maintained indefinitely and may be redistributed consistent with
36 | this project or the open source license(s) involved.
37 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 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-multi-view
2 |
3 | SDK example application which demonstrates the usage of multi-view SVG that was
4 | added in Fitbit OS 4.0.
5 |
6 | ## Structure
7 |
8 | `/resources/views/` contains an SVG file for each view in the application.
9 | `/app/views/` contains a JavaScript file for each view in the application.
10 | `/app/index.js` initializes the list of views.
11 |
12 | When `views.navigate()` is called, the current view is unloaded and all event
13 | handlers are unregistered. The JavaScript for the selected view is dynamically
14 | loaded, and the document for the selected view is loaded.
15 |
16 | The `BACK` button can be used to navigate to the previous view.
17 |
--------------------------------------------------------------------------------
/app/index.js:
--------------------------------------------------------------------------------
1 | import { init } from "./views";
2 |
3 | /**
4 | * Definition for each view in the resources/views folder, and the associated
5 | * JavaScript module is lazily loaded alongside its view.
6 | */
7 | const views = init(
8 | [
9 | ["view-1", () => import("./views/view-1")],
10 | ["view-2", () => import("./views/view-2")],
11 | ["view-3", () => import("./views/view-3")]
12 | ],
13 | "./resources/views/"
14 | );
15 |
16 | // Select the first view (view-1) after 1 second
17 | setTimeout(() => {
18 | views.navigate("view-1");
19 | }, 1000);
20 |
--------------------------------------------------------------------------------
/app/views.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A basic module to simplify navigation within multi-view applications.
3 | */
4 | import document from "document";
5 |
6 | /**
7 | * Initialize the views module with views from a specific folder.
8 | * @param {Object[]} _views An array of views containing the view filename excluding
9 | * its file extension, and an associated JavaScript `import()`.
10 | * @param {string} _prefix The folder name where the view files reside.
11 | */
12 | export function init(_views, _prefix) {
13 | let views = _views;
14 | let viewsPrefix = _prefix;
15 | const viewsSuffix = ".gui";
16 | let viewSelected;
17 |
18 | /**
19 | * Select a specific view by its index. The view's associated JavaScript is
20 | * loaded and executed, and the current view is replaced by the selected one.
21 | * @param {number} _index The array position of the view to be selected.
22 | */
23 | const select = _index => {
24 | const [viewGUI, viewJSLoader] = views[_index];
25 | viewSelected = viewGUI;
26 | viewJSLoader()
27 | .then(({ init }) => {
28 | document.replaceSync(`${viewsPrefix}${viewGUI}${viewsSuffix}`);
29 | init({ navigate });
30 | })
31 | .catch(() => {
32 | console.error(`Failed to load view JS: ${viewGUI}`);
33 | });
34 | };
35 |
36 | /**
37 | * Navigate to a specific view using its view name.
38 | * @param {string} _viewName The name of a .gui file, excluding its path or
39 | * file extension.
40 | */
41 | const navigate = _viewName => {
42 | const index = views.indexOf(views.filter(el => el[0] == _viewName)[0]);
43 | select(index);
44 | };
45 |
46 | return {
47 | navigate,
48 | viewSelected: () => viewSelected
49 | };
50 | }
51 |
--------------------------------------------------------------------------------
/app/views/view-1.js:
--------------------------------------------------------------------------------
1 | import document from "document";
2 |
3 | let views;
4 |
5 | export function init(_views) {
6 | views = _views;
7 | console.log("view-1 init()");
8 | onMount();
9 | }
10 |
11 | /**
12 | * When this view is mounted, setup elements and events.
13 | */
14 | function onMount() {
15 | let btn = document.getElementById("v1-button");
16 | btn.addEventListener("click", clickHandler);
17 | }
18 |
19 | /**
20 | * Sample button click with navigation.
21 | */
22 | function clickHandler(_evt) {
23 | console.log("view-1 Button Clicked!");
24 | /* Navigate to another screen */
25 | views.navigate("view-2");
26 | }
27 |
--------------------------------------------------------------------------------
/app/views/view-2.js:
--------------------------------------------------------------------------------
1 | import document from "document";
2 |
3 | let views;
4 |
5 | export function init(_views) {
6 | views = _views;
7 | console.log("view-2 init()");
8 | onMount();
9 | }
10 |
11 | /**
12 | * When this view is mounted, setup elements and events.
13 | */
14 | function onMount() {
15 | let btn = document.getElementById("v2-button");
16 | btn.addEventListener("click", clickHandler);
17 | document.addEventListener("keypress", keyHandler);
18 | }
19 |
20 | /**
21 | * Sample button click with navigation.
22 | */
23 | function clickHandler(_evt) {
24 | console.log("view-2 Button Clicked!");
25 | /* Navigate to another screen */
26 | views.navigate("view-3");
27 | }
28 |
29 | /**
30 | * Sample keypress handler to navigate backwards.
31 | */
32 | function keyHandler(evt) {
33 | if (evt.key === "back") {
34 | evt.preventDefault();
35 | views.navigate("view-1");
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/views/view-3.js:
--------------------------------------------------------------------------------
1 | import document from "document";
2 |
3 | let views;
4 |
5 | export function init(_views) {
6 | views = _views;
7 | console.log("view-3 init()");
8 | onMount();
9 | }
10 |
11 | /**
12 | * When this view is mounted, setup elements and events.
13 | */
14 | function onMount() {
15 | let btn = document.getElementById("v3-button");
16 | btn.addEventListener("click", clickHandler);
17 | document.addEventListener("keypress", keyHandler);
18 | }
19 |
20 | /**
21 | * Sample button click with navigation.
22 | */
23 | function clickHandler(_evt) {
24 | console.log("view-3 Button Clicked!");
25 | /* Navigate to another screen */
26 | views.navigate("view-1");
27 | }
28 |
29 | /**
30 | * Sample keypress handler to navigate backwards.
31 | */
32 | function keyHandler(evt) {
33 | if (evt.key === "back") {
34 | evt.preventDefault();
35 | views.navigate("view-2");
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sdk-multi-view",
3 | "version": "0.1.0",
4 | "private": true,
5 | "license": "UNLICENSED",
6 | "devDependencies": {
7 | "@fitbit/sdk": "~4.0.0",
8 | "@fitbit/sdk-cli": "^1.7.0"
9 | },
10 | "fitbit": {
11 | "appUUID": "3bcad842-5fb8-4540-9bc1-ec9f6f0467fb",
12 | "appType": "app",
13 | "appDisplayName": "SDK MultiView",
14 | "iconFile": "resources/icon.png",
15 | "wipeColor": "#ffffff",
16 | "requestedPermissions": [],
17 | "buildTargets": [
18 | "higgs",
19 | "meson",
20 | "gemini",
21 | "mira"
22 | ],
23 | "i18n": {},
24 | "defaultLanguage": "en-US"
25 | },
26 | "scripts": {
27 | "build": "fitbit-build",
28 | "debug": "fitbit"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/resources/index.gui:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/resources/styles.css:
--------------------------------------------------------------------------------
1 | .title {
2 | x: 50%;
3 | y: 50%+15;
4 | fill: fb-yellow;
5 | font-family: System-Regular;
6 | font-size: 40;
7 | font-weight: bold;
8 | text-anchor: middle;
9 | }
10 |
11 | .btn {
12 | y: 100%-60;
13 | height: 60;
14 | fill: fb-red;
15 | font-family: System-Regular;
16 | font-size: 40;
17 | }
18 |
19 | #text {
20 | y: 12;
21 | fill: white;
22 | }
--------------------------------------------------------------------------------
/resources/views/view-1.gui:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/resources/views/view-2.gui:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/resources/views/view-3.gui:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/resources/widgets.gui:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/@fitbit/sdk/sdk-tsconfig.json"
3 | }
4 |
--------------------------------------------------------------------------------