Skip to content

Commit

Permalink
Add versa support, handle denied permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
rootasjey committed Nov 17, 2018
1 parent 2e5244e commit 23046bf
Show file tree
Hide file tree
Showing 24 changed files with 228 additions and 111 deletions.
40 changes: 26 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
# metrix-fitbit
A Fitbit Ionic clock face showing metrics activities.
A Fitbit Ionic & Versa clock face showing metrics activities.

You can change each metric to one of the 9 available. You can even have the same activity multiple times and showing different states value.
You can change each metric to one of the 9 available. You can even have the same activity multiple times and showing different stats format.

For example, for steps, you could show both:

* the total steps value
* percentage achievement goal of steps
* the total steps
* percentage achievement goal

![metrix.gif](metrix.gif)

![metrix.png](metrix.png)
| Ionic | Versa |
|----------|:-------------:|
| ![ionic.png](screenshots/ionic.png) | ![versa.png](screenshots/versa.png) |
| ![ionic2.png](screenshots/ionic2.png) | ![versa2.png](screenshots/versa2.png) |
| ![ionic.gif](screenshots/ionic.gif) |![versa.gif](screenshots/versa.gif) |

## Changelog

15/11/18
### 17/11/18

* Now support Versa
* Handle missing permissions (in case you deny some of them)

### 15/11/18
* Add weather metric
* Make the mode (stats/switch) button bigger
* Fix save color for clock
Expand Down Expand Up @@ -48,13 +55,13 @@ Because this clock face shows personal goals, heart rate and weather data, it us
* Heart rate sensor
* **GPS location** for the weather

No data is keep nor send to first or third parties entities, companies or individuals. You can check by looking at the source code.
No data is kept nor send to first or third parties entities, companies or individuals. You can check by looking at the source code.

When installing the clock face, it'll ask you for these permissions. You can deny all, some or none. The non-functional activities metrics won't show on the clock face in that case.

## Ionic vs. Versa

Soon.
The clock face support both Ionic & Versa with a layout adaptation.

## Settings

Expand All @@ -68,9 +75,9 @@ You can change the refresh time rate in the settings. By default, the cache last

Weather data is only updated when the clock face is active (i.e. screen turned on) and is not updated in background every X time. This is because there's a usage limite of the API.

As I pay for any extra usage of the DarkSky API, feel free to support the clock face if you use this daily.
As I pay for for the DarkSky API usage, I can't afford all API requests. Feel free to support the clock face if you use this daily.

_Because there's a API usage limit and I pay for extra queries, the weather data may not update right away. This will depend on the amount of users this clock face has._
_Because there's a API usage limit, the weather data may not update right away. This will depend on the amount of users using this clock face._

## Contributing

Expand All @@ -80,14 +87,19 @@ Feel free to contribute to this project by:
* Openning an issue if
* you want to propose a new feature
* or if you encounter a problem
* Pay me a tea

## Resources

Thanks for the following:
Acitivities icons are provided by:

* [Fitbit's icons](https://github.com/Fitbit/sdk-design-assets)

The following assets are from [www.flaticon.com](https://www.flaticon.com/") and is licensed by [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0).
Weather API wrapper is provided by:

* [fitbit-weather](https://github.com/gregoiresage/fitbit-weather)

Weather icons are from [www.flaticon.com](https://www.flaticon.com/"), is licensed by [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0), and provided by:

* [Good Ware](https://www.flaticon.com/authors/good-ware)
* [Freepik](https://www.freepik.com)
Expand Down
5 changes: 3 additions & 2 deletions app/activities.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import * as settings from './settings';

import { activeMinutes } from './activities/activeMinutes';
import { calories } from './activities/calories';
import { clock } from './activities/clock';
Expand All @@ -10,6 +8,9 @@ import { hr } from './activities/hr';
import { steps } from './activities/steps';
import { weather } from './activities/weather';

/**
* All activities displayable on screen.
*/
export const activities = [
activeMinutes,
calories,
Expand Down
7 changes: 2 additions & 5 deletions app/activities/activeMinutes.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import document from 'document';

import * as util from '../../common/utils';

import document from 'document';
import { getActivityValue } from '../userActivity';
import * as util from '../../common/utils';

import { onClickActivity,
saveActivitySettings,
switchToNextActivity,

} from '../activityActions';

export const activeMinutes = {
Expand Down
7 changes: 2 additions & 5 deletions app/activities/calories.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import document from 'document';

import * as util from '../../common/utils';

import document from 'document';
import { getActivityValue } from '../userActivity';
import * as util from '../../common/utils';

import { onClickActivity,
saveActivitySettings,
switchToNextActivity,

} from '../activityActions';

export const calories = {
Expand Down
5 changes: 2 additions & 3 deletions app/activities/date.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import document from 'document';

import * as util from '../../common/utils';
import document from 'document';
import * as util from '../../common/utils';

import { onClickActivity,
saveActivitySettings,
Expand Down
6 changes: 2 additions & 4 deletions app/activities/distance.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import document from 'document';

import * as util from '../../common/utils';

import document from 'document';
import * as util from '../../common/utils';
import { getActivityValue } from '../userActivity';

import { onClickActivity,
Expand Down
6 changes: 2 additions & 4 deletions app/activities/elevationGain.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import document from 'document';

import * as util from '../../common/utils';

import document from 'document';
import * as util from '../../common/utils';
import { getActivityValue } from '../userActivity';

import { onClickActivity,
Expand Down
6 changes: 2 additions & 4 deletions app/activities/steps.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import document from 'document';

import * as util from '../../common/utils';

import document from 'document';
import * as util from '../../common/utils';
import { getActivityValue } from '../userActivity';

import { onClickActivity,
Expand Down
15 changes: 6 additions & 9 deletions app/activities/weather.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import document from 'document';
import document from 'document';

import * as util from '../../common/utils';
import * as colors from '../../common/colors';

import * as settings from '../settings';

import * as api from '../../lib/fitbit-weather/app';
import * as api from '../../lib/fitbit-weather/app';
import * as colors from '../../common/colors';
import * as settings from '../settings';
import * as util from '../../common/utils';

import { getWeatherIcon } from '../../common/icons';

Expand Down Expand Up @@ -59,10 +57,9 @@ export const weather = {
const refreshTime = weatherRefreshTime ?
parseInt(weatherRefreshTime.values[0].name) : 60;

// return the cached value if it is less than 30 minutes old by default
// return the cached value if it is less than 60 minutes old by default
api.fetch(weatherRefreshTime * 60 * 1000)
.then(data => {
// console.log(JSON.stringify(data));
const format = this.format;

metricElem.text = `${getText({ data, format, imperialUnit })}`;
Expand Down
64 changes: 35 additions & 29 deletions app/data.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import * as messaging from "messaging";
import document from 'document';

import document from 'document';

import { activities } from './activities';
import { metrics } from './metrics';
import * as settings from './settings';

let _weatherFetched = false;
import { activities } from './activities';
import * as layout from './layout';
import { metrics } from './metrics';
import * as settings from './settings';
import * as permissions from './permissions';

export function initialize() {
metrics.map(metric => {
initActivity({ metric });
metric.initActivity = initActivity;
metric.activityCount = activities.length;
});

bindSwitchTapMode();
}

Expand All @@ -34,15 +32,16 @@ export function reinitialize({ activityName }) {

function bindSwitchTapMode() {
const icon = document.getElementById('action-switcher-img');

const tapMode = settings.getData('tapMode') || 'stats';


icon.y = layout.getModeIconY();
icon.href = tapMode === 'cycles' ? 'icons/cycles.png' : 'icons/stats.png';

icon.onclick = (e) => {
tapMode = tapMode === 'stats' ? 'cycles' : 'stats';
icon.href = tapMode === 'cycles' ? 'icons/cycles.png' : 'icons/stats.png';

settings.update({ key: 'tapMode', value: tapMode });
}
}
Expand All @@ -55,42 +54,48 @@ function bindSwitchTapMode() {
function initActivity({ metric, asked }) {
if (!asked) {
const savedData = settings.getData(`metric${metric.metricNumber}`);

if (savedData) {
metric.activity = savedData.activity ?
metric.activity = savedData.activity ?
savedData.activity : metric.activity;

metric.format = savedData.format ?
metric.format = savedData.format ?
savedData.format : metric.format;

metric.color = savedData.color ?
metric.color = savedData.color ?
savedData.color : metric.color;
}
}


// Permission check
metric.activity = permissions.getNextAllowedActivity(metric.activity);

const activity = activities[metric.activity];

const textElem = document.getElementById(`metric${metric.metricNumber}`)
const icon = document.getElementById(`metric${metric.metricNumber}-img`);

if (activity.icon) {
icon.style.visibility = 'visible';
icon.style.opacity = 1;
textElem.x = 280;
textElem.x = layout.getTextX({ icon: true });

icon.href = activity.icon;
icon.style.fill = activity.iconFill ? activity.iconFill : 'white';


icon.x = layout.getIconX();
icon.y = layout.getIconY({ metricNumber: metric.metricNumber });

} else {
icon.style.visibility = 'hidden';
textElem.x = 320;
textElem.x = layout.getTextX({ icon: false });
}

if (metric.color) {
icon.style.fill = metric.color;
textElem.style.fill = metric.color;
}

textElem.text = '--';
textElem.style.fill = metric.color ? metric.color : activity.textFill ? activity.textFill : 'white';
textElem.style.fontSize = metric.fontSize ? metric.fontSize : 50;
Expand All @@ -104,19 +109,20 @@ function initActivity({ metric, asked }) {
metric.switchToNext = activity.switchToNext;
metric.saveSettings = activity.saveSettings;
metric.update = activity.update;

textElem.onclick = () => metric.onClick(metric)
}

// Listen to settings changes
settings.initialize(data => {
if (!data) return;

if (data.backgroundColor) {
const bg = document.getElementById('background');
bg.style.fill = data.backgroundColor;
}
});

settings.bindReinitialize(({ activityName }) => {
settings.bindReinitialize(({ activityName }) => {
reinitialize({ activityName })
});
10 changes: 4 additions & 6 deletions app/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import clock from "clock";
import { display } from "display";

import * as data from './data';

import { HeartRateSensor } from "heart-rate";
import clock from "clock";
import * as data from './data';
import { display } from "display";
import { HeartRateSensor } from "heart-rate";

const hrm = new HeartRateSensor();

Expand Down
Loading

0 comments on commit 23046bf

Please sign in to comment.