├── .ruby-version
├── .watchmanconfig
├── src
├── declarations.d.ts
├── assets
│ ├── google_fit.png
│ ├── health_kit.png
│ ├── launcher.png
│ ├── launcher_screen.png
│ ├── ios_icons
│ │ └── iOS
│ │ │ └── AppIcon.appiconset
│ │ │ ├── launcher-20.png
│ │ │ ├── launcher-29.png
│ │ │ ├── launcher-40.png
│ │ │ ├── launcher-512.png
│ │ │ ├── launcher-76.png
│ │ │ ├── launcher-1024.png
│ │ │ ├── launcher-20@2x.png
│ │ │ ├── launcher-20@3x.png
│ │ │ ├── launcher-29@2x.png
│ │ │ ├── launcher-29@3x.png
│ │ │ ├── launcher-40@2x.png
│ │ │ ├── launcher-40@3x.png
│ │ │ ├── launcher-60@2x.png
│ │ │ ├── launcher-60@3x.png
│ │ │ ├── launcher-76@2x.png
│ │ │ ├── launcher-83.5@2x.png
│ │ │ └── Contents.json
│ ├── home_connected_icon.svg
│ ├── vitals_logo.svg
│ ├── launcher.svg
│ └── logo_title.svg
├── globals.d.ts
├── api
│ ├── auth.ts
│ └── central.ts
├── progress.d.ts
├── hooks
│ ├── bluetoothHooks.tsx
│ ├── auth.ts
│ ├── layout.ts
│ └── common.ts
├── health
│ ├── custom
│ │ └── phone.ts
│ └── manufacterMap.ts
├── components
│ ├── buttons.tsx
│ ├── appbar.tsx
│ ├── footer.tsx
│ ├── qrcodeMask.tsx
│ ├── utils.tsx
│ ├── typography.tsx
│ └── insightDrawer.tsx
├── styles.ts
├── contexts
│ ├── auth.tsx
│ ├── ui.tsx
│ └── config.tsx
├── utils.ts
├── models.ts
├── App.tsx
├── screens
│ ├── providers.tsx
│ └── welcome.tsx
└── types.ts
├── app.json
├── .bundle
└── config
├── media
├── home.png
├── ios.gif
├── login.png
├── scan.png
├── android.gif
├── numeric.png
├── qrcode.png
├── insight.jpeg
├── modelid_1.png
├── modelid_2.png
├── permission.png
├── authorization.png
├── google_fit_sync.png
├── scan_simulated.png
├── sync_options.jpeg
├── creds_generator_1.png
├── creds_generator_2.png
├── device_connect_1.png
├── device_connect_2.png
├── device_connect_3.png
├── device_connect_4.png
├── edit_dashboard_1.png
├── edit_dashboard_2.png
├── simulated_result.png
├── Google_Fit.json
├── HealthDevice.json
└── Apple_HealthKit.json
├── android
├── app
│ ├── .settings
│ │ └── org.eclipse.buildship.core.prefs
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ ├── drawable-v24
│ │ │ │ │ └── ic_launcher_foreground.xml
│ │ │ │ └── drawable
│ │ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── ic_launcher-web.png
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── cpm
│ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ └── MainApplication.java
│ │ │ └── AndroidManifest.xml
│ │ └── debug
│ │ │ └── AndroidManifest.xml
│ ├── .classpath
│ ├── proguard-rules.pro
│ ├── build_defs.bzl
│ └── BUCK
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── .settings
│ └── org.eclipse.buildship.core.prefs
├── settings.gradle
├── .project
├── gradle.properties
├── build.gradle
└── gradlew.bat
├── ios
├── cpm
│ ├── Images.xcassets
│ │ ├── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── launcher-1024.png
│ │ │ ├── launcher-20.png
│ │ │ ├── launcher-29.png
│ │ │ ├── launcher-40.png
│ │ │ ├── launcher-76.png
│ │ │ ├── launcher-20@2x.png
│ │ │ ├── launcher-20@3x.png
│ │ │ ├── launcher-29@2x.png
│ │ │ ├── launcher-29@3x.png
│ │ │ ├── launcher-40@2x.png
│ │ │ ├── launcher-40@3x.png
│ │ │ ├── launcher-60@2x.png
│ │ │ ├── launcher-60@3x.png
│ │ │ ├── launcher-76@2x.png
│ │ │ ├── launcher-83.5@2x.png
│ │ │ └── Contents.json
│ │ ├── SplashIcon.imageset
│ │ │ ├── launcher_screen-1.png
│ │ │ ├── launcher_screen-2.png
│ │ │ ├── launcher_screen.png
│ │ │ └── Contents.json
│ │ └── LaunchImage.launchimage
│ │ │ ├── LaunchImage-1792x828.png
│ │ │ ├── LaunchImage-320x480.png
│ │ │ ├── LaunchImage-640x1136.png
│ │ │ ├── LaunchImage-640x960.png
│ │ │ ├── LaunchImage-750x1334.png
│ │ │ ├── LaunchImage-828x1792.png
│ │ │ ├── LaunchImage-1125x2436.png
│ │ │ ├── LaunchImage-1242x2208.png
│ │ │ ├── LaunchImage-1242x2688.png
│ │ │ ├── LaunchImage-2208x1242.png
│ │ │ ├── LaunchImage-2436x1125.png
│ │ │ ├── LaunchImage-2688x1242.png
│ │ │ ├── LaunchImage-640x1136-1.png
│ │ │ ├── LaunchImage-640x960-1.png
│ │ │ └── Contents.json
│ ├── main.m
│ ├── cpmDebug.entitlements
│ ├── cpm.entitlements
│ ├── AppDelegate.h
│ ├── cpmRelease.entitlements
│ ├── Info.plist
│ ├── AppDelegate.mm
│ └── LaunchScreen.storyboard
├── cpm-Bridging-Header.h
├── cpm.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── cpm.xcscheme
├── BLE.swift
├── Charts.swift
├── cpm.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── .xcode.env
├── cpmTests
│ ├── Info.plist
│ └── cpmTests.m
├── Podfile
└── LaunchScreen.xib
├── .buckconfig
├── creds-generator
├── .gitignore
├── server
│ ├── dist
│ │ └── public
│ │ │ ├── assets
│ │ │ ├── favicon.gif
│ │ │ └── background.jpg
│ │ │ ├── fonts
│ │ │ ├── poppins
│ │ │ │ ├── Poppins-Bold.ttf
│ │ │ │ ├── Poppins-Thin.ttf
│ │ │ │ ├── Poppins-Black.ttf
│ │ │ │ ├── Poppins-Italic.ttf
│ │ │ │ ├── Poppins-Light.ttf
│ │ │ │ ├── Poppins-Medium.ttf
│ │ │ │ ├── Poppins-ExtraBold.ttf
│ │ │ │ ├── Poppins-Regular.ttf
│ │ │ │ ├── Poppins-SemiBold.ttf
│ │ │ │ ├── Poppins-BlackItalic.ttf
│ │ │ │ ├── Poppins-BoldItalic.ttf
│ │ │ │ ├── Poppins-ExtraLight.ttf
│ │ │ │ ├── Poppins-LightItalic.ttf
│ │ │ │ ├── Poppins-ThinItalic.ttf
│ │ │ │ ├── Poppins-MediumItalic.ttf
│ │ │ │ ├── Poppins-SemiBoldItalic.ttf
│ │ │ │ ├── Poppins-ExtraBoldItalic.ttf
│ │ │ │ └── Poppins-ExtraLightItalic.ttf
│ │ │ ├── font-awesome-4.7.0
│ │ │ │ ├── less
│ │ │ │ │ ├── screen-reader.less
│ │ │ │ │ ├── fixed-width.less
│ │ │ │ │ ├── larger.less
│ │ │ │ │ ├── list.less
│ │ │ │ │ ├── core.less
│ │ │ │ │ ├── stacked.less
│ │ │ │ │ ├── font-awesome.less
│ │ │ │ │ ├── bordered-pulled.less
│ │ │ │ │ ├── rotated-flipped.less
│ │ │ │ │ ├── path.less
│ │ │ │ │ ├── animated.less
│ │ │ │ │ └── mixins.less
│ │ │ │ ├── fonts
│ │ │ │ │ ├── FontAwesome.otf
│ │ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ │ ├── fontawesome-webfont.woff
│ │ │ │ │ └── fontawesome-webfont.woff2
│ │ │ │ ├── scss
│ │ │ │ │ ├── _fixed-width.scss
│ │ │ │ │ ├── _screen-reader.scss
│ │ │ │ │ ├── _larger.scss
│ │ │ │ │ ├── _list.scss
│ │ │ │ │ ├── _core.scss
│ │ │ │ │ ├── font-awesome.scss
│ │ │ │ │ ├── _stacked.scss
│ │ │ │ │ ├── _bordered-pulled.scss
│ │ │ │ │ ├── _rotated-flipped.scss
│ │ │ │ │ ├── _path.scss
│ │ │ │ │ ├── _animated.scss
│ │ │ │ │ └── _mixins.scss
│ │ │ │ └── HELP-US-OUT.txt
│ │ │ └── Linearicons-Free-v1.0.0
│ │ │ │ └── WebFont
│ │ │ │ ├── Linearicons-Free.eot
│ │ │ │ ├── Linearicons-Free.ttf
│ │ │ │ ├── Linearicons-Free.woff
│ │ │ │ └── Linearicons-Free.woff2
│ │ │ └── index.html
│ └── src
│ │ └── index.ts
└── package.json
├── .prettierrc.js
├── Gemfile
├── wdyr.js
├── appcenter-pre-build.sh
├── pre-packager.js
├── createReleaseFile.sh
├── release-ios.sh
├── index.js
├── .eslintrc.json
├── .azuredevops
├── node-build.yml
└── resign.yml
├── podinstall.js
├── docs
├── insight.md
├── walkthrough.md
├── data_format.md
├── google_fit.md
└── simulation.md
├── metro.config.js
├── appcenter-post-build.sh
├── tsconfig.json
├── ExportOptions.plist
├── babel.config.js
├── LICENSE
├── .gitignore
├── bumpVersion.sh
├── .flowconfig
├── patches
└── react-native+0.69.1.patch
├── Gemfile.lock
└── package.json
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.7.5
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/src/declarations.d.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cpm",
3 | "displayName": "cpm"
4 | }
--------------------------------------------------------------------------------
/.bundle/config:
--------------------------------------------------------------------------------
1 | ---
2 | BUNDLE_RETRY: "3"
3 | BUNDLE_JOBS: "4"
4 |
--------------------------------------------------------------------------------
/media/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/home.png
--------------------------------------------------------------------------------
/media/ios.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/ios.gif
--------------------------------------------------------------------------------
/media/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/login.png
--------------------------------------------------------------------------------
/media/scan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/scan.png
--------------------------------------------------------------------------------
/media/android.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/android.gif
--------------------------------------------------------------------------------
/media/numeric.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/numeric.png
--------------------------------------------------------------------------------
/media/qrcode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/qrcode.png
--------------------------------------------------------------------------------
/media/insight.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/insight.jpeg
--------------------------------------------------------------------------------
/media/modelid_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/modelid_1.png
--------------------------------------------------------------------------------
/media/modelid_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/modelid_2.png
--------------------------------------------------------------------------------
/media/permission.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/permission.png
--------------------------------------------------------------------------------
/media/authorization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/authorization.png
--------------------------------------------------------------------------------
/media/google_fit_sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/google_fit_sync.png
--------------------------------------------------------------------------------
/media/scan_simulated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/scan_simulated.png
--------------------------------------------------------------------------------
/media/sync_options.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/sync_options.jpeg
--------------------------------------------------------------------------------
/src/assets/google_fit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/google_fit.png
--------------------------------------------------------------------------------
/src/assets/health_kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/health_kit.png
--------------------------------------------------------------------------------
/src/assets/launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/launcher.png
--------------------------------------------------------------------------------
/android/app/.settings/org.eclipse.buildship.core.prefs:
--------------------------------------------------------------------------------
1 | connection.project.dir=..
2 | eclipse.preferences.version=1
3 |
--------------------------------------------------------------------------------
/media/creds_generator_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/creds_generator_1.png
--------------------------------------------------------------------------------
/media/creds_generator_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/creds_generator_2.png
--------------------------------------------------------------------------------
/media/device_connect_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/device_connect_1.png
--------------------------------------------------------------------------------
/media/device_connect_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/device_connect_2.png
--------------------------------------------------------------------------------
/media/device_connect_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/device_connect_3.png
--------------------------------------------------------------------------------
/media/device_connect_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/device_connect_4.png
--------------------------------------------------------------------------------
/media/edit_dashboard_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/edit_dashboard_1.png
--------------------------------------------------------------------------------
/media/edit_dashboard_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/edit_dashboard_2.png
--------------------------------------------------------------------------------
/media/simulated_result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/media/simulated_result.png
--------------------------------------------------------------------------------
/src/assets/launcher_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/launcher_screen.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | IoT Central CPM
3 |
4 |
--------------------------------------------------------------------------------
/android/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/ios/cpm-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
--------------------------------------------------------------------------------
/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/ios/cpm.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/creds-generator/.gitignore:
--------------------------------------------------------------------------------
1 | # node
2 | node_modules/
3 | server/**/*.js
4 | server/**/db.json
5 | server/**/*.d.ts
6 |
7 | # vscode
8 | .vscode
9 | .deployment
10 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/assets/favicon.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/assets/favicon.gif
--------------------------------------------------------------------------------
/src/globals.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.svg' {
2 | import {SvgProps} from 'react-native-svg';
3 | const content: React.FC;
4 | export default content;
5 | }
6 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/assets/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/assets/background.jpg
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | arrowParens: 'avoid',
3 | bracketSameLine: true,
4 | bracketSpacing: false,
5 | singleQuote: true,
6 | trailingComma: 'all',
7 | };
8 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-1024.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-20.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-29.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-40.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-76.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-20.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-29.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-40.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-512.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-76.png
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
3 | ruby '~> 2.7.5'
4 | gem 'cocoapods', '~> 1.11', '>= 1.11.2'
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-20@2x.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-20@3x.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-29@2x.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-29@3x.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-40@2x.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-40@3x.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-60@2x.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-60@3x.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-76@2x.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-1024.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-20@2x.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-20@3x.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-29@2x.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-29@3x.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-40@2x.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-40@3x.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-60@2x.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-60@3x.png
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-76@2x.png
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-Bold.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-Thin.ttf
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/AppIcon.appiconset/launcher-83.5@2x.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/SplashIcon.imageset/launcher_screen-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/SplashIcon.imageset/launcher_screen-1.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/SplashIcon.imageset/launcher_screen-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/SplashIcon.imageset/launcher_screen-2.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/SplashIcon.imageset/launcher_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/SplashIcon.imageset/launcher_screen.png
--------------------------------------------------------------------------------
/src/api/auth.ts:
--------------------------------------------------------------------------------
1 | export async function login(
2 | username: string,
3 | password: string,
4 | ): Promise {
5 | //TODO: return authentication code
6 | return password;
7 | }
8 |
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/src/assets/ios_icons/iOS/AppIcon.appiconset/launcher-83.5@2x.png
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-Black.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-Italic.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-Light.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-Medium.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-ExtraBold.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-Regular.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-SemiBold.ttf
--------------------------------------------------------------------------------
/ios/BLE.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BLE.swift
3 | // cpm
4 | //
5 | // Created by Luca Druda on 25/02/2020.
6 | // Copyright © 2020 Facebook. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
--------------------------------------------------------------------------------
/src/progress.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'react-native-progress/CircleSnail' {
2 | import React from 'react';
3 | export default class CircleSnail extends React.Component {}
4 | }
5 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-BlackItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-BlackItalic.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-BoldItalic.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-ExtraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-ExtraLight.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-LightItalic.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-ThinItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-ThinItalic.ttf
--------------------------------------------------------------------------------
/ios/Charts.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Charts.swift
3 | // cpm
4 | //
5 | // Created by Luca Druda on 02/03/2020.
6 | // Copyright © 2020 Facebook. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-1792x828.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-1792x828.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-320x480.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-320x480.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x1136.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x1136.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x960.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x960.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-750x1334.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-750x1334.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-828x1792.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-828x1792.png
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-MediumItalic.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-SemiBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-SemiBoldItalic.ttf
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-1125x2436.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-1125x2436.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-1242x2208.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-1242x2208.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-1242x2688.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-1242x2688.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-2208x1242.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-2208x1242.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-2436x1125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-2436x1125.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-2688x1242.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-2688x1242.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x1136-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x1136-1.png
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x960-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/ios/cpm/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x960-1.png
--------------------------------------------------------------------------------
/wdyr.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | if (__DEV__) {
3 | console.log(`Tracing active`);
4 | const whyDidYouRender = require('@welldone-software/why-did-you-render');
5 | whyDidYouRender(React);
6 | }
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-ExtraBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-ExtraBoldItalic.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/poppins/Poppins-ExtraLightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/poppins/Poppins-ExtraLightItalic.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/screen-reader.less:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { .sr-only(); }
5 | .sr-only-focusable { .sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/fixed-width.less:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .@{fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_fixed-width.scss:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .#{$fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_screen-reader.scss:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { @include sr-only(); }
5 | .sr-only-focusable { @include sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/appcenter-pre-build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | if [ "$APP_CENTER_CURRENT_PLATFORM" == "android" ]
3 | then
4 | cd android
5 | ./gradlew increment
6 | cd ..
7 | else
8 | #iOS
9 | cd ./ios
10 | pod install
11 | fi
12 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/Linearicons-Free-v1.0.0/WebFont/Linearicons-Free.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/Linearicons-Free-v1.0.0/WebFont/Linearicons-Free.eot
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/Linearicons-Free-v1.0.0/WebFont/Linearicons-Free.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/Linearicons-Free-v1.0.0/WebFont/Linearicons-Free.ttf
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/Linearicons-Free-v1.0.0/WebFont/Linearicons-Free.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/Linearicons-Free-v1.0.0/WebFont/Linearicons-Free.woff
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/Linearicons-Free-v1.0.0/WebFont/Linearicons-Free.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iot-for-all/iotc-cpm-sample/HEAD/creds-generator/server/dist/public/fonts/Linearicons-Free-v1.0.0/WebFont/Linearicons-Free.woff2
--------------------------------------------------------------------------------
/pre-packager.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | const path = './env.json';
4 | try {
5 | if (!fs.existsSync(path)) {
6 | fs.writeFileSync(path, '{}');
7 | }
8 | }
9 | catch (err) {
10 | console.error(err);
11 | }
12 |
--------------------------------------------------------------------------------
/ios/cpm/main.m:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char * argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/createReleaseFile.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CURRENT_TAG=$(git tag -l --sort=-v:refname | sed -n 2p)
4 | echo "Current Tag: $CURRENT_TAG"
5 |
6 | CHANGES=$(git log --pretty=format:"- %s" ...$CURRENT_TAG)
7 |
8 | echo -e "**$BUILD_BUILDNUMBER**\n\n$CHANGES" > CHANGELOG.md
--------------------------------------------------------------------------------
/release-ios.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | xcodebuild -scheme cpm -workspace ios/cpm.xcworkspace -destination generic/platform=iOS build
4 |
5 | xcodebuild -workspace ios/cpm.xcworkspace -scheme cpm -sdk iphoneos -configuration Enterprise archive -archivePath $PWD/ios/build/cpm.xcarchive
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Jul 13 16:03:47 CEST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
7 |
--------------------------------------------------------------------------------
/ios/cpm.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/cpm.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 | import './wdyr';
5 |
6 | import 'react-native-gesture-handler';
7 | import {AppRegistry} from 'react-native';
8 | import App from './src/App';
9 | import {name as appName} from './app.json';
10 | import 'react-native-get-random-values';
11 |
12 | AppRegistry.registerComponent(appName, () => App);
13 |
--------------------------------------------------------------------------------
/ios/cpm/cpmDebug.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.healthkit
6 |
7 | com.apple.developer.healthkit.access
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/android/app/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/HELP-US-OUT.txt:
--------------------------------------------------------------------------------
1 | I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project,
2 | Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome,
3 | comprehensive icon sets or copy and paste your own.
4 |
5 | Please. Check it out.
6 |
7 | -Dave Gandy
8 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "parserOptions": {
4 | "jsx": true,
5 | "useJSXTextNode": true,
6 | "ecmaVersion": 6,
7 | "sourceType": "module",
8 | "ecmaFeatures": {
9 | "jsx": true
10 | }
11 | },
12 | "plugins": [
13 | "react-hooks"
14 | ],
15 | "rules": {
16 | "react-hooks/rules-of-hooks": "error",
17 | "react-hooks/exhaustive-deps": "error"
18 | }
19 | }
--------------------------------------------------------------------------------
/ios/cpm/cpm.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.healthkit
6 |
7 | com.apple.developer.healthkit.access
8 |
9 | com.apple.developer.healthkit.background-delivery
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/android/.settings/org.eclipse.buildship.core.prefs:
--------------------------------------------------------------------------------
1 | arguments=
2 | auto.sync=false
3 | build.scans.enabled=false
4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
5 | connection.project.dir=
6 | eclipse.preferences.version=1
7 | gradle.user.home=
8 | java.home=/usr/lib/jvm/java-16-openjdk-amd64
9 | jvm.arguments=
10 | offline.mode=false
11 | override.workspace.settings=true
12 | show.console.view=true
13 | show.executions.view=true
14 |
--------------------------------------------------------------------------------
/ios/cpm/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (nonatomic, strong) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/larger.less:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .@{fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .@{fa-css-prefix}-2x { font-size: 2em; }
11 | .@{fa-css-prefix}-3x { font-size: 3em; }
12 | .@{fa-css-prefix}-4x { font-size: 4em; }
13 | .@{fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_larger.scss:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .#{$fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .#{$fa-css-prefix}-2x { font-size: 2em; }
11 | .#{$fa-css-prefix}-3x { font-size: 3em; }
12 | .#{$fa-css-prefix}-4x { font-size: 4em; }
13 | .#{$fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/ios/cpm/cpmRelease.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.healthkit
6 |
7 | com.apple.developer.healthkit.access
8 |
9 | health-records
10 |
11 | com.apple.developer.healthkit.background-delivery
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | # This `.xcode.env` file is versioned and is used to source the environment
2 | # used when running script phases inside Xcode.
3 | # To customize your local environment, you can create an `.xcode.env.local`
4 | # file that is not versioned.
5 | # NODE_BINARY variable contains the PATH to the node executable.
6 | #
7 | # Customize the NODE_BINARY variable here.
8 | # For example, to use nvm with brew, add the following line
9 | # . "$(brew --prefix nvm)/nvm.sh" --no-use
10 | export NODE_BINARY=$(command -v node)
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/list.less:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: @fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .@{fa-css-prefix}-li {
11 | position: absolute;
12 | left: -@fa-li-width;
13 | width: @fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.@{fa-css-prefix}-lg {
17 | left: (-@fa-li-width + (4em / 14));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_list.scss:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: $fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .#{$fa-css-prefix}-li {
11 | position: absolute;
12 | left: -$fa-li-width;
13 | width: $fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.#{$fa-css-prefix}-lg {
17 | left: -$fa-li-width + (4em / 14);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.azuredevops/node-build.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - task: NodeTool@0
3 | inputs:
4 | versionSpec: "16.14.0"
5 | displayName: "Install Node"
6 |
7 | - script: npm install
8 | workingDirectory: .
9 | displayName: "Install node dependencies"
10 |
11 | - script: npm version prerelease --preid "$(Build.BuildNumber)" --no-git-tag-version
12 | workingDirectory: .
13 | displayName: "Increment version in package.json"
14 |
15 | - task: ShellScript@2
16 | inputs:
17 | scriptPath: "$(System.DefaultWorkingDirectory)/bumpVersion.sh"
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/SplashIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "launcher_screen.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "launcher_screen-1.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "launcher_screen-2.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/core.less:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .@{fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_core.scss:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/font-awesome.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables";
7 | @import "mixins";
8 | @import "path";
9 | @import "core";
10 | @import "larger";
11 | @import "fixed-width";
12 | @import "list";
13 | @import "bordered-pulled";
14 | @import "animated";
15 | @import "rotated-flipped";
16 | @import "stacked";
17 | @import "icons";
18 | @import "screen-reader";
19 |
--------------------------------------------------------------------------------
/src/hooks/bluetoothHooks.tsx:
--------------------------------------------------------------------------------
1 | import {useEffect, useState, useContext} from 'react';
2 | import {ConfigContext} from '../contexts/config';
3 | import {SimulatedHealthManager} from '../health/simulated';
4 |
5 | export function useSimulated(): boolean {
6 | const {state} = useContext(ConfigContext);
7 | const [simulated, setSimulated] = useState(
8 | state.healthManager instanceof SimulatedHealthManager,
9 | );
10 |
11 | useEffect(() => {
12 | setSimulated(state.healthManager instanceof SimulatedHealthManager);
13 | }, [state.healthManager]);
14 |
15 | return simulated;
16 | }
17 |
--------------------------------------------------------------------------------
/podinstall.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const exec = require('child_process').exec;
3 | const path = require('path');
4 |
5 | switch (process.platform) {
6 | case 'darwin':
7 | exec('bundle install && pod install', { cwd: path.join(__dirname, 'ios') }, (err, stdout, stderr) => {
8 | if (err) {
9 | console.error(err);
10 | }
11 | if (stderr) {
12 | console.error(stderr);
13 | }
14 | if (stdout) {
15 | console.log(stdout);
16 | }
17 | });
18 | break;
19 | default:
20 | break;
21 | }
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/stacked.less:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; }
21 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_stacked.scss:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; }
21 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/font-awesome.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables.less";
7 | @import "mixins.less";
8 | @import "path.less";
9 | @import "core.less";
10 | @import "larger.less";
11 | @import "fixed-width.less";
12 | @import "list.less";
13 | @import "bordered-pulled.less";
14 | @import "animated.less";
15 | @import "rotated-flipped.less";
16 | @import "stacked.less";
17 | @import "icons.less";
18 | @import "screen-reader.less";
19 |
--------------------------------------------------------------------------------
/docs/insight.md:
--------------------------------------------------------------------------------
1 | # Data Insight
2 |
3 | The insight screen shows a preview of telemetry data streamed from bluetooth device (either real or simulated) or from one of the platform provider (Apple Health, Google Fit).
4 |
5 | Insight | Sync Options
6 | :-------------------------:|:-------------------------:
7 |  | 
8 |
9 | Data shown can be controlled using side menu that can be activated by tapping on "Sync options" or on the 3-dots icon on top-right in header bar.
10 |
11 | Unselecting an item also stops telemetry delivery to IoT Central, if connected, for it.
12 |
13 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'cpm'
2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
3 | include ':app'
4 | includeBuild('../node_modules/react-native-gradle-plugin')
5 | if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
6 | include(":ReactAndroid")
7 | project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
8 | include(":ReactAndroid:hermes-engine")
9 | project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine')
10 | }
11 |
--------------------------------------------------------------------------------
/metro.config.js:
--------------------------------------------------------------------------------
1 | const { getDefaultConfig } = require('metro-config');
2 |
3 | module.exports = (async () => {
4 | const {
5 | resolver: { sourceExts, assetExts },
6 | } = await getDefaultConfig();
7 | return {
8 | transformer: {
9 | getTransformOptions: async () => ({
10 | transform: {
11 | experimentalImportSupport: false,
12 | inlineRequires: true,
13 | },
14 | }),
15 | babelTransformerPath: require.resolve('react-native-svg-transformer'),
16 | },
17 | resolver: {
18 | assetExts: assetExts.filter(ext => ext !== 'svg'),
19 | sourceExts: [...sourceExts, 'svg'],
20 | },
21 | };
22 | })();
--------------------------------------------------------------------------------
/appcenter-post-build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | if [ "$APPCENTER_BRANCH" != "master" ]; then
3 | echo "Not on master. Exiting..."
4 | exit 1
5 | fi
6 |
7 | if [ "$AGENT_JOBSTATUS" == "Succeeded" ]; then
8 | cd android
9 | ./gradlew -q increment
10 | VERSION=`./gradlew -q printVersion | tail -n 1`
11 | echo $VERSION
12 | git config user.email "$GIT_EMAIL"
13 | git config user.name "$GIT_USER"
14 | git add ./gradle.properties
15 | git commit -m "Android Release v$VERSION" --author="$GIT_USER <$GIT_EMAIL>"
16 | git remote set-url --push origin https://$GIT_TOKEN@github.com/$GIT_USER/cpm-poc.git
17 | git push origin master
18 | cd ..
19 | fi
--------------------------------------------------------------------------------
/android/app/build_defs.bzl:
--------------------------------------------------------------------------------
1 | """Helper definitions to glob .aar and .jar targets"""
2 |
3 | def create_aar_targets(aarfiles):
4 | for aarfile in aarfiles:
5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
6 | lib_deps.append(":" + name)
7 | android_prebuilt_aar(
8 | name = name,
9 | aar = aarfile,
10 | )
11 |
12 | def create_jar_targets(jarfiles):
13 | for jarfile in jarfiles:
14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
15 | lib_deps.append(":" + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
--------------------------------------------------------------------------------
/src/hooks/auth.ts:
--------------------------------------------------------------------------------
1 | import {IUser, AuthContext} from '../contexts/auth';
2 | import {useContext} from 'react';
3 |
4 | type UserDispatch = (value: IUser | null) => Promise;
5 |
6 | export function useUser(): [IUser | null, UserDispatch] {
7 | const {state, dispatch} = useContext(AuthContext);
8 |
9 | const setUser: UserDispatch = async function (value: IUser | null) {
10 | if (value == null) {
11 | dispatch({
12 | type: 'LOGOUT',
13 | payload: {user: null, initialized: true},
14 | });
15 | } else {
16 | dispatch({
17 | type: 'LOGIN',
18 | payload: {user: value, initialized: true},
19 | });
20 | }
21 | };
22 |
23 | return [state.user, setUser];
24 | }
25 |
--------------------------------------------------------------------------------
/src/api/central.ts:
--------------------------------------------------------------------------------
1 | import {IIoTCClient} from 'react-native-azure-iotcentral-client';
2 | import {bleToIoTCName} from '../utils';
3 |
4 | export async function getCredentialsFromNumericCode(
5 | numeric: string,
6 | ): Promise {
7 | return (
8 | await fetch(
9 | `https://cpm-cred-server.azurewebsites.net/numeric?numeric=${numeric}`,
10 | )
11 | ).text();
12 | }
13 |
14 | export async function sendTelemetryData(
15 | centralClient: IIoTCClient,
16 | normalize: boolean,
17 | itemData: {itemId: string; value: any; itemName: string},
18 | ): Promise {
19 | const itemKey = normalize ? bleToIoTCName(itemData.itemId) : itemData.itemId;
20 | await centralClient.sendTelemetry({[itemKey]: itemData.value});
21 | }
22 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "allowSyntheticDefaultImports": true,
5 | "esModuleInterop": true,
6 | "isolatedModules": true,
7 | "sourceMap": true,
8 | "jsx": "react-native",
9 | "lib": [
10 | "es6"
11 | ],
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "noEmit": true,
15 | "strict": true,
16 | "noUnusedLocals": true,
17 | "module": "commonjs",
18 | "target": "es2017",
19 | "skipLibCheck": true,
20 | "baseUrl": "./src"
21 | },
22 | "exclude": [
23 | "node_modules",
24 | "src/sensors/health/**/*.ts*",
25 | "babel.config.js",
26 | "metro.config.js",
27 | "jest.config.js",
28 | "creds-generator"
29 | ]
30 | }
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/bordered-pulled.less:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em @fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .@{fa-css-prefix}-pull-left { float: left; }
11 | .@{fa-css-prefix}-pull-right { float: right; }
12 |
13 | .@{fa-css-prefix} {
14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
18 | /* Deprecated as of 4.4.0 */
19 | .pull-right { float: right; }
20 | .pull-left { float: left; }
21 |
22 | .@{fa-css-prefix} {
23 | &.pull-left { margin-right: .3em; }
24 | &.pull-right { margin-left: .3em; }
25 | }
26 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/rotated-flipped.less:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
7 |
8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .@{fa-css-prefix}-rotate-90,
15 | :root .@{fa-css-prefix}-rotate-180,
16 | :root .@{fa-css-prefix}-rotate-270,
17 | :root .@{fa-css-prefix}-flip-horizontal,
18 | :root .@{fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_bordered-pulled.scss:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em $fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .#{$fa-css-prefix}-pull-left { float: left; }
11 | .#{$fa-css-prefix}-pull-right { float: right; }
12 |
13 | .#{$fa-css-prefix} {
14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
18 | /* Deprecated as of 4.4.0 */
19 | .pull-right { float: right; }
20 | .pull-left { float: left; }
21 |
22 | .#{$fa-css-prefix} {
23 | &.pull-left { margin-right: .3em; }
24 | &.pull-right { margin-left: .3em; }
25 | }
26 |
--------------------------------------------------------------------------------
/ExportOptions.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | destination
6 | export
7 | method
8 | enterprise
9 | provisioningProfiles
10 |
11 | com.microsoft.CPM-df
12 | ff754a3e-0e2a-4204-b08f-2db96c8d18a8
13 |
14 | signingCertificate
15 | iPhone Distribution
16 | signingStyle
17 | manual
18 | teamID
19 | 9KBH5RKYEW
20 | compileBitcode
21 |
22 | uploadSymbols
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | plugins: [
4 | ["module-resolver", {
5 | "root": ["./src"],
6 | "extensions": [
7 | '.ios.ts',
8 | '.android.ts',
9 | '.ts',
10 | '.ios.tsx',
11 | '.android.tsx',
12 | '.tsx',
13 | '.jsx',
14 | '.js',
15 | '.json',
16 | ],
17 | "alias": {
18 | "tools": "./src/tools",
19 | "hooks": "./src/hooks",
20 | "properties": "./src/properties",
21 | "contexts": "./src/contexts",
22 | "sensors": "./src/sensors",
23 | "types": "./src/types",
24 | "components": "./src/components"
25 | }
26 | }],
27 | 'react-native-reanimated/plugin'
28 | ]
29 | };
30 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_rotated-flipped.scss:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); }
5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }
6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }
7 |
8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }
9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .#{$fa-css-prefix}-rotate-90,
15 | :root .#{$fa-css-prefix}-rotate-180,
16 | :root .#{$fa-css-prefix}-rotate-270,
17 | :root .#{$fa-css-prefix}-flip-horizontal,
18 | :root .#{$fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/ios/cpmTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/android/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | cpm
4 | Project android created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.buildship.core.gradleprojectbuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.buildship.core.gradleprojectnature
16 |
17 |
18 |
19 | 1617023572750
20 |
21 | 30
22 |
23 | org.eclipse.core.resources.regexFilterMatcher
24 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/path.less:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_path.scss:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/src/assets/home_connected_icon.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | #Thu Jul 23 15:19:15 GMT 2020
2 | FLIPPER_VERSION=0.125.0
3 | # Use this property to specify which architecture you want to build.
4 | # You can also override it from the CLI using
5 | # ./gradlew -PreactNativeArchitectures=x86_64
6 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
7 | # Use this property to enable support to the new architecture.
8 | # This will allow you to use TurboModules and the Fabric render in
9 | # your application. You should enable this flag either if you want
10 | # to write custom TurboModules/Fabric components OR use libraries that
11 | # are providing them.
12 | newArchEnabled=false
13 | android.enableJetifier=true
14 | VERSION_NAME=1.1.5
15 | android.useAndroidX=true
16 | org.gradle.daemon=true
17 | org.gradle.configureondemand=true
18 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
19 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
20 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/animated.less:
--------------------------------------------------------------------------------
1 | // Animated Icons
2 | // --------------------------
3 |
4 | .@{fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .@{fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_animated.scss:
--------------------------------------------------------------------------------
1 | // Spinning Icons
2 | // --------------------------
3 |
4 | .#{$fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .#{$fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/health/custom/phone.ts:
--------------------------------------------------------------------------------
1 | import {BleDevice} from '../ble';
2 | import {IHealthDevice} from '../../models';
3 | import {Characteristic} from 'react-native-ble-plx';
4 | import {ManufacturerMap} from '../manufacterMap';
5 |
6 | export class PhonePeripheralDevice extends BleDevice implements IHealthDevice {
7 | getValue(characteristic: Characteristic) {
8 | if (characteristic.value == null) {
9 | return null;
10 | }
11 | const val = Buffer.from(characteristic.value, 'base64');
12 |
13 | if (
14 | characteristic.uuid.toLowerCase() ===
15 | '00002a1c-0000-1000-8000-00805f9b34fb'
16 | ) {
17 | if (val.length === 5) {
18 | return 0;
19 | }
20 | }
21 | const intval = val.readInt8();
22 | return intval;
23 | }
24 | }
25 |
26 | ManufacturerMap.addManufacturer(
27 | 'phone',
28 | [
29 | '0000180f-0000-1000-8000-00805f9b34fb',
30 | '00001809-0000-1000-8000-00805f9b34fb',
31 | ],
32 | PhonePeripheralDevice,
33 | );
34 |
--------------------------------------------------------------------------------
/src/health/manufacterMap.ts:
--------------------------------------------------------------------------------
1 | export class ManufacturerMap {
2 | static mMap: {
3 | [ManufacturerId: string]: {
4 | ids: string[];
5 | deviceCtr: any;
6 | };
7 | } = {};
8 |
9 | static addManufacturer(name: string, ids: string[], deviceCtr: any): void {
10 | if (!this.mMap[name]) {
11 | this.mMap[name] = {
12 | ids,
13 | deviceCtr,
14 | };
15 | }
16 | }
17 |
18 | static getManufacturerConstructor(name: string) {
19 | if (!this.mMap[name]) {
20 | return null;
21 | }
22 | return this.mMap[name].deviceCtr;
23 | }
24 |
25 | static getManufacturers() {
26 | return Object.keys(this.mMap);
27 | }
28 |
29 | static getManufacturerIds(name: string): string[] | null {
30 | if (this.mMap[name]) {
31 | return this.mMap[name].ids;
32 | }
33 | return null;
34 | }
35 |
36 | static removeManufacturer(name: string) {
37 | if (this.mMap[name]) {
38 | delete this.mMap[name];
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/buttons.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Button, useTheme} from 'react-native-paper';
3 | import {StyleProp, ViewStyle} from 'react-native';
4 | import DefaultStyles from '../styles';
5 |
6 | export type CPMButtonProps = {
7 | children: React.ReactNode;
8 | onPress?: () => void;
9 | mode?: 'text' | 'outlined' | 'contained';
10 | style?: StyleProp;
11 | };
12 |
13 | export function CPMButton(props: CPMButtonProps) {
14 | const {mode, children, style, onPress} = props;
15 | const theme = useTheme();
16 | const textColor = theme.colors.text;
17 |
18 | return (
19 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/src/assets/vitals_logo.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 iot-for-all
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.
--------------------------------------------------------------------------------
/media/Google_Fit.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "@id": "dtmi:cpm:GoogleFit_5r4;1",
4 | "@type": "Interface",
5 | "contents": [
6 | {
7 | "@id": "dtmi:cpm:GoogleFit_5r4:steps;1",
8 | "@type": "Telemetry",
9 | "displayName": {
10 | "en": "Steps"
11 | },
12 | "name": "steps",
13 | "schema": "double"
14 | },
15 | {
16 | "@id": "dtmi:cpm:GoogleFit_5r4:BloodPressureSystolic;1",
17 | "@type": "Telemetry",
18 | "displayName": {
19 | "en": "Blood Pressure Systolic"
20 | },
21 | "name": "BloodPressureSystolic",
22 | "schema": "double"
23 | },
24 | {
25 | "@id": "dtmi:cpm:GoogleFit_5r4:BloodPressureDiastolic;1",
26 | "@type": "Telemetry",
27 | "displayName": {
28 | "en": "Blood Pressure Diastolic"
29 | },
30 | "name": "BloodPressureDiastolic",
31 | "schema": "double"
32 | }
33 | ],
34 | "displayName": {
35 | "en": "Google Fit"
36 | },
37 | "@context": [
38 | "dtmi:iotcentral:context;2",
39 | "dtmi:dtdl:context;2"
40 | ]
41 | }
42 | ]
--------------------------------------------------------------------------------
/src/assets/launcher.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/styles.ts:
--------------------------------------------------------------------------------
1 | import {TextStyle, ViewStyle, Platform} from 'react-native';
2 |
3 | const DefaultStyles: {
4 | header: TextStyle;
5 | centerFragment: ViewStyle;
6 | centeredButton: ViewStyle;
7 | elevated: ViewStyle;
8 | itemName: TextStyle;
9 | itemDetail: TextStyle;
10 | } = {
11 | header: {
12 | fontWeight: 'bold',
13 | fontSize: 24,
14 | },
15 | centerFragment: {
16 | flex: 1,
17 | justifyContent: 'center',
18 | alignItems: 'center',
19 | },
20 | centeredButton: {
21 | width: 230,
22 | height: 50,
23 | marginVertical: 20,
24 | justifyContent: 'center',
25 | },
26 | elevated: {
27 | ...Platform.select({
28 | ios: {
29 | shadowColor: "'rgba(0, 0, 0, 0.14)'",
30 | shadowOffset: {
31 | width: 0,
32 | height: 3,
33 | },
34 | shadowOpacity: 0.25,
35 | shadowRadius: 3.84,
36 | elevation: 5,
37 | },
38 | android: {
39 | elevation: 2,
40 | },
41 | }),
42 | },
43 | itemName: {
44 | fontWeight: 'bold',
45 | fontSize: 16,
46 | },
47 | itemDetail: {
48 | fontSize: 14,
49 | },
50 | };
51 | export default DefaultStyles;
52 |
--------------------------------------------------------------------------------
/src/hooks/layout.ts:
--------------------------------------------------------------------------------
1 | import {useState, useEffect, useCallback} from 'react';
2 | import {Dimensions, ScaledSize} from 'react-native';
3 |
4 | type Orientation = 'portrait' | 'landscape';
5 | function getOrientation(width: number, height: number): Orientation {
6 | if (width > height) {
7 | return 'landscape';
8 | }
9 | return 'portrait';
10 | }
11 |
12 | export function useScreenDimensions() {
13 | const [screenData, setScreenData] = useState(Dimensions.get('screen'));
14 | const [orientation, setOrientation] = useState(
15 | getOrientation(screenData.width, screenData.height),
16 | );
17 |
18 | const onChange = useCallback(
19 | (result: {window: ScaledSize; screen: ScaledSize}) => {
20 | setScreenData(result.screen);
21 | setOrientation(getOrientation(result.screen.width, result.screen.height));
22 | },
23 | [],
24 | );
25 |
26 | useEffect(() => {
27 | const dimsub = Dimensions.addEventListener('change', onChange);
28 | return () => {
29 | // @ts-ignore
30 | // typings for 0.65.x not available yet
31 | dimsub?.remove();
32 | };
33 | }, [orientation, onChange]);
34 | return {screen: screenData, orientation};
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/appbar.tsx:
--------------------------------------------------------------------------------
1 | import React, {useContext, memo} from 'react';
2 | import {Appbar} from 'react-native-paper';
3 | import {Platform} from 'react-native';
4 | import {UIContext} from '../contexts/ui';
5 |
6 | export interface IAppBarProps {
7 | title: string;
8 | hasPrevious?: boolean;
9 | goBack: (count?: number) => void;
10 | }
11 |
12 | const ApplicationBar = memo(function (props: IAppBarProps) {
13 | const {title, hasPrevious, goBack} = props;
14 | const {state: uiState} = useContext(UIContext);
15 | let leftIcon = 'menu';
16 | let leftAction = uiState.headersActions?.left;
17 | let rightAction = uiState.headersActions?.right;
18 | if (hasPrevious) {
19 | leftIcon = 'arrow-left';
20 | leftAction = function () {
21 | goBack(title === 'Insight' ? 2 : 1);
22 | };
23 | }
24 | const rightIcon = Platform.select({
25 | android: 'dots-vertical',
26 | ios: 'dots-horizontal',
27 | }) as string;
28 |
29 | return (
30 |
31 |
32 |
33 |
34 |
35 | );
36 | });
37 |
38 | export default ApplicationBar;
39 |
--------------------------------------------------------------------------------
/src/contexts/auth.tsx:
--------------------------------------------------------------------------------
1 | import React, {useReducer} from 'react';
2 |
3 | export interface IUser {
4 | id: string;
5 | }
6 |
7 | export interface IAuthState {
8 | user: IUser | null;
9 | initialized: boolean;
10 | }
11 |
12 | export interface IAuthAction {
13 | type: 'LOGIN' | 'LOGOUT';
14 | payload: IAuthState;
15 | }
16 |
17 | export type IAuthContext = {
18 | state: IAuthState;
19 | dispatch: React.Dispatch;
20 | };
21 |
22 | export const authReducer = (state: IAuthState, action: IAuthAction) => {
23 | switch (action.type) {
24 | case 'LOGIN':
25 | case 'LOGOUT':
26 | return {...state, ...action.payload};
27 | default:
28 | return state;
29 | }
30 | };
31 |
32 | const initialState: IAuthState = {
33 | user: null,
34 | initialized: false,
35 | };
36 |
37 | export const AuthContext = React.createContext({
38 | state: initialState,
39 | dispatch: () => {},
40 | });
41 | const {Provider} = AuthContext;
42 |
43 | const AuthProvider: React.FC<{children: React.ReactNode}> = ({children}) => {
44 | const [state, dispatch] = useReducer(authReducer, initialState);
45 |
46 | return {children};
47 | };
48 |
49 | export default AuthProvider;
50 |
--------------------------------------------------------------------------------
/creds-generator/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "creds-generator",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "server/dist/index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "watch::client": "./node_modules/.bin/tsc -w -p client/tsconfig.json",
9 | "watch::server": "./node_modules/.bin/tsc -w -p server/tsconfig.json",
10 | "build::client": "./node_modules/.bin/tsc -p client/tsconfig.json",
11 | "build::server": "./node_modules/.bin/tsc -p server/tsconfig.json",
12 | "build": "npm run build::client && npm run build::server",
13 | "start": "node server/dist/index.js",
14 | "prepare": "npm run build",
15 | "live-server": "five-server"
16 | },
17 | "author": "",
18 | "license": "ISC",
19 | "devDependencies": {
20 | "@types/crypto-js": "^3.1.47",
21 | "@types/express": "^4.17.13",
22 | "@types/qrcode": "^1.4.2",
23 | "@types/react": "^16.14.21",
24 | "@types/react-dom": "^16.9.14",
25 | "csstype": "^2.6.19",
26 | "five-server": "^0.1.3",
27 | "typescript": "^3.9.10"
28 | },
29 | "dependencies": {
30 | "body-parser": "^1.19.1",
31 | "crypto-js": "^4.1.1",
32 | "express": "^4.17.2",
33 | "qrcode": "^1.5.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | ios/.xcode.env.local
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 | java_pid*
33 | android/app/.project
34 | *.hprof
35 |
36 | # node.js
37 | #
38 | node_modules/
39 | npm-debug.log
40 | yarn-error.log
41 | .npmrc
42 |
43 | # BUCK
44 | buck-out/
45 | \.buckd/
46 | *.keystore
47 | debug.keystore
48 |
49 | # fastlane
50 | #
51 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
52 | # screenshots whenever they are needed.
53 | # For more information about the recommended setup visit:
54 | # https://docs.fastlane.tools/best-practices/source-control/
55 |
56 | **/fastlane/report.xml
57 | **/fastlane/Preview.html
58 | **/fastlane/screenshots
59 | **/fastlane/test_output
60 |
61 | # Bundle artifact
62 | *.jsbundle
63 |
64 | # Ruby / CocoaPods
65 | /ios/Pods/
66 | /vendor/bundle/
67 |
68 | # vscode
69 | .vscode
70 |
71 | # envs
72 | env.json
--------------------------------------------------------------------------------
/src/contexts/ui.tsx:
--------------------------------------------------------------------------------
1 | import React, {useReducer} from 'react';
2 |
3 | interface HeadersActions {
4 | left?(): void;
5 | right?(): void;
6 | }
7 |
8 | export interface IUIState {
9 | headersActions: HeadersActions | null;
10 | }
11 |
12 | type IHeaderAction = {
13 | type: 'SET';
14 | payload: HeadersActions;
15 | };
16 |
17 | type IUIAction = IHeaderAction;
18 |
19 | export type IUIContext = {
20 | state: IUIState;
21 | dispatch: React.Dispatch;
22 | };
23 |
24 | export const uiReducer = (state: IUIState, action: IUIAction) => {
25 | switch (action.type) {
26 | case 'SET':
27 | return {
28 | ...state,
29 | headersActions: {...state.headersActions, ...action.payload},
30 | };
31 | default:
32 | return state;
33 | }
34 | };
35 |
36 | const initialState: IUIState = {
37 | headersActions: null,
38 | };
39 |
40 | export const UIContext = React.createContext({
41 | state: initialState,
42 | dispatch: () => {},
43 | });
44 | const {Provider} = UIContext;
45 |
46 | const UIProvider: React.FC<{children: React.ReactNode}> = ({children}) => {
47 | const [state, dispatch] = useReducer(uiReducer, initialState);
48 | return {children};
49 | };
50 |
51 | export default UIProvider;
52 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/cpm/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.cpm;
2 |
3 | import com.facebook.react.ReactActivity;
4 | import com.facebook.react.ReactActivityDelegate;
5 | import com.facebook.react.ReactRootView;
6 |
7 | public class MainActivity extends ReactActivity {
8 |
9 | /**
10 | * Returns the name of the main component registered from JavaScript. This is used to schedule
11 | * rendering of the component.
12 | */
13 | @Override
14 | protected String getMainComponentName() {
15 | return "cpm";
16 | }
17 |
18 | /**
19 | * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
20 | * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
21 | * (Paper).
22 | */
23 | @Override
24 | protected ReactActivityDelegate createReactActivityDelegate() {
25 | return new MainActivityDelegate(this, getMainComponentName());
26 | }
27 | public static class MainActivityDelegate extends ReactActivityDelegate {
28 | public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
29 | super(activity, mainComponentName);
30 | }
31 | @Override
32 | protected ReactRootView createRootView() {
33 | ReactRootView reactRootView = new ReactRootView(getContext());
34 | return reactRootView;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/bumpVersion.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | ARGS_LENGTH=$#
3 |
4 | while test $ARGS_LENGTH -gt 0; do
5 | case "$1" in
6 | -m|--marketing-version)
7 | shift
8 | CUSTOM_MARKETING="$1"
9 | shift
10 | ;;
11 | -b|--bundle-version)
12 | shift
13 | CUSTOM_BUNDLE="$1"
14 | shift
15 | ;;
16 | *)
17 | break
18 | ;;
19 | esac
20 | done
21 |
22 | if [ -z $CUSTOM_BUNDLE ]; then
23 | BUILD_NAME="$BUILD_BUILDNUMBER"
24 | else
25 | BUILD_NAME="$CUSTOM_BUNDLE"
26 | fi
27 |
28 | echo "Build Name: $BUILD_NAME"
29 | echo "Version Name: $CUSTOM_MARKETING"
30 |
31 |
32 | if [ "$AGENT_OS" == "Darwin" ] # iOS build
33 | then
34 | # iOS
35 | cd ios
36 | CUR_VER_STRING=`agvtool what-marketing-version -terse1`
37 | IFS='.' read -ra CUR_VER_NUMB <<< "$CUR_VER_STRING"
38 | echo "Current Marketing Version: ${CUR_VER_NUMB[0]}.${CUR_VER_NUMB[1]}.${CUR_VER_NUMB[2]}"
39 |
40 | agvtool new-version -all $BUILD_NAME
41 | # if [ "$BUILD_SOURCEBRANCHNAME" == "master" ]; then
42 | # if [ -z "$CUSTOM_MARKETING" ]; then
43 | # NEW_MINOR=$(( ${CUR_VER_NUMB[2]} + 1 ))
44 | # agvtool new-marketing-version "${CUR_VER_NUMB[0]}.${CUR_VER_NUMB[1]}.${NEW_MINOR}"
45 | # else
46 | # agvtool new-marketing-version "$CUSTOM_MARKETING"
47 | # fi
48 | # fi
49 | fi
--------------------------------------------------------------------------------
/android/app/BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
12 |
13 | lib_deps = []
14 |
15 | create_aar_targets(glob(["libs/*.aar"]))
16 |
17 | create_jar_targets(glob(["libs/*.jar"]))
18 |
19 | android_library(
20 | name = "all-libs",
21 | exported_deps = lib_deps,
22 | )
23 |
24 | android_library(
25 | name = "app-code",
26 | srcs = glob([
27 | "src/main/java/**/*.java",
28 | ]),
29 | deps = [
30 | ":all-libs",
31 | ":build_config",
32 | ":res",
33 | ],
34 | )
35 |
36 | android_build_config(
37 | name = "build_config",
38 | package = "com.cpm",
39 | )
40 |
41 | android_resource(
42 | name = "res",
43 | package = "com.cpm",
44 | res = "src/main/res",
45 | )
46 |
47 | android_binary(
48 | name = "app",
49 | keystore = "//android/keystores:debug",
50 | manifest = "src/main/AndroidManifest.xml",
51 | package_type = "debug",
52 | deps = [
53 | ":app-code",
54 | ],
55 | )
56 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/docs/walkthrough.md:
--------------------------------------------------------------------------------
1 | # Walkthrough
2 |
3 | ## 1. Authorization
4 | 
5 | 
6 |
7 | Scan QR Code to connect to a device in IoT Central.
8 |
9 | To skip this, tap on "Use simulation". The application will still read data from BLE devices or health providers and show it on insight chart but it will not generate telemetry data for IoT Central.
10 |
11 | ## 3. Home
12 | 
13 |
14 |
15 | Select one of the options.
16 | - __Pair device__: allows to connect to a real or simulated BLE device.
17 | - __Sync with platform__: allows to read data from health platforms (Apple Health when running on iOS, Google Fit when on Android).
18 |
19 | ## 4. Scan devices
20 | 
21 | 
22 | 
23 |
24 |
25 | Scans for nearby devices. By selecting "Use simulated device" you can skip connecting a real device and use one of the simulated ones which generates sample data every 5 seconds. Simulated devices are mapped to models in the CPM application template (see [docs](https://docs.microsoft.com/en-us/azure/iot-central/healthcare/tutorial-continuous-patient-monitoring)).
26 |
27 | ## 5. Insight
28 | 
29 |
30 | Data from BLE device or platforms are shown in the chart. Legend is at bottom.
31 | Detail message is hardcoded. The developer can change that text accordingly to read data.
32 |
33 | More details at [Insight.](./insight.md)
--------------------------------------------------------------------------------
/docs/data_format.md:
--------------------------------------------------------------------------------
1 | # Data Format
2 | By default, the application only converts raw data to standard integers or floating point number using usual conversion from bytes.
3 |
4 | For non-standard data formats or to add data pre-processing features you can add your own custom device implementation.
5 |
6 | To enable a quick integration with custom devices, this sample is organized to support inheritance: it is sufficient to extend the BleDevice class and add the custom class to the ManufacturerMap.
7 |
8 | The _getValue_ function must be implemented. It accepts a ble characteristic instance and returns a number.
9 |
10 | health/custom/mydevice.ts
11 | ```ts
12 | class MyDevice extends BleDevice implements IHealthDevice {
13 | getValue(characteristic: Characteristic) {
14 | if (characteristic.value == null) {
15 | return null;
16 | }
17 | const val = Buffer.from(characteristic.value, 'base64');
18 |
19 | const intval = val.readInt8();
20 | return intval;
21 | }
22 | }
23 |
24 | ManufacturerMap.addManufacturer('MyDevice', ['0000180f-0000-1000-8000-00805f9b34fb', '00001809-0000-1000-8000-00805f9b34fb'], MyDevice);
25 | ```
26 |
27 | The BleManager will create specific device instances based on available services. A list of service ids must be provided to the Manufacturers Map in order to create the right device instance.
28 |
29 | However multiple devices can provide the same service with different data format. To overcome this issue just create one custom virtual device and put logic into the _getValue_ function.
30 |
31 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
12 |
13 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/components/footer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {View, StyleSheet, ViewStyle, Platform} from 'react-native';
3 | import {IconButton} from 'react-native-paper';
4 | import {useState} from 'react';
5 | import {CPMText} from './typography';
6 |
7 | const defaultTitle = 'Learn more about this technology';
8 | export interface IFooterProps {
9 | text: string;
10 | title?: string;
11 | style?: ViewStyle;
12 | textColor?: string;
13 | }
14 | export function Footer(props: IFooterProps) {
15 | const [expanded, setExpanded] = useState(false);
16 | return (
17 |
18 | {
21 | setExpanded(current => !current);
22 | }}
23 | size={20}
24 | color={props.textColor}
25 | />
26 | {expanded ? (
27 |
33 | {props.text}
34 |
35 | ) : (
36 |
37 | {props.title ? props.title : defaultTitle}
38 |
39 | )}
40 |
41 | );
42 | }
43 |
44 | const style = StyleSheet.create({
45 | container: {
46 | justifyContent: 'center',
47 | alignItems: 'center',
48 | marginBottom: Platform.select({
49 | android: 10,
50 | ios: 30,
51 | }),
52 | marginHorizontal: 30,
53 | },
54 | });
55 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | import {Dimensions, Platform, PixelRatio} from 'react-native';
2 |
3 | const {width: SCREEN_WIDTH} = Dimensions.get('window');
4 |
5 | // based on iphone 5s's scale
6 | const scale = SCREEN_WIDTH / 350;
7 |
8 | export function normalize(size: number) {
9 | const newSize = size * scale;
10 | if (Platform.OS === 'ios') {
11 | return Math.round(PixelRatio.roundToNearestPixel(newSize)) - 1;
12 | } else {
13 | return Math.round(PixelRatio.roundToNearestPixel(newSize)) - 2;
14 | }
15 | }
16 |
17 | export function camelToName(text: string): string {
18 | return (
19 | text
20 | // insert a space before all caps
21 | .replace(/([A-Z])/g, ' $1')
22 | // uppercase the first character
23 | .replace(/^./, function (str) {
24 | return str.toUpperCase();
25 | })
26 | );
27 | }
28 |
29 | export function snakeToName(text: string): string {
30 | return (
31 | text
32 | .toLowerCase()
33 | // insert a space for every underscore
34 | .replace(/([_])/g, ' ')
35 | // uppercase the first character
36 | .replace(/^./, function (str) {
37 | return str.toUpperCase();
38 | })
39 | );
40 | }
41 |
42 | export function dottedToName(text: string): string {
43 | return (
44 | text
45 | .toLowerCase()
46 | // insert a space for every underscore
47 | .replace(/([.])/g, ' ')
48 | // uppercase the first character
49 | .replace(/^./, function (str) {
50 | return str.toUpperCase();
51 | })
52 | );
53 | }
54 |
55 | export function bleToIoTCName(text: string): string {
56 | return text.replace(/[-]/g, '').replace(/^./, function (str) {
57 | return `ble${str}`;
58 | });
59 | }
60 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | ; We fork some components by platform
3 | .*/*[.]android.js
4 |
5 | ; Ignore "BUCK" generated dirs
6 | /\.buckd/
7 |
8 | ; Ignore polyfills
9 | node_modules/react-native/Libraries/polyfills/.*
10 |
11 | ; Flow doesn't support platforms
12 | .*/Libraries/Utilities/LoadingView.js
13 |
14 |
15 | .*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$
16 |
17 | [untyped]
18 | .*/node_modules/@react-native-community/cli/.*/.*
19 |
20 | [include]
21 |
22 | [libs]
23 | node_modules/react-native/interface.js
24 | node_modules/react-native/flow/
25 |
26 | [options]
27 | emoji=true
28 |
29 | exact_by_default=true
30 |
31 | format.bracket_spacing=false
32 |
33 | module.file_ext=.js
34 | module.file_ext=.json
35 | module.file_ext=.ios.js
36 |
37 | munge_underscores=true
38 |
39 | module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1'
40 | module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub'
41 |
42 | suppress_type=$FlowIssue
43 | suppress_type=$FlowFixMe
44 | suppress_type=$FlowFixMeProps
45 | suppress_type=$FlowFixMeState
46 |
47 | [lints]
48 | sketchy-null-number=warn
49 | sketchy-null-mixed=warn
50 | sketchy-number=warn
51 | untyped-type-import=warn
52 | nonstrict-import=warn
53 | deprecated-type=warn
54 | unsafe-getters-setters=warn
55 | unnecessary-invariant=warn
56 | signature-verification-failure=warn
57 |
58 | [strict]
59 | deprecated-type
60 | nonstrict-import
61 | sketchy-null
62 | unclear-type
63 | unsafe-getters-setters
64 | untyped-import
65 | untyped-type-import
66 |
67 | [version]
68 | ^0.176.3
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | require_relative '../node_modules/react-native/scripts/react_native_pods'
2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
3 |
4 | platform :ios, '12.4'
5 | install! 'cocoapods', :deterministic_uuids => false
6 |
7 | permissions_path = '../node_modules/react-native-permissions/ios'
8 | pod 'Permission-Camera', :path => "#{permissions_path}/Camera"
9 | pod 'RNCharts', :path => '../node_modules/react-native-charts-wrapper'
10 |
11 | target 'cpm' do
12 | config = use_native_modules!
13 |
14 | # Flags change depending on the env values.
15 | flags = get_default_flags()
16 |
17 | use_react_native!(
18 | :path => config[:reactNativePath],
19 | # to enable hermes on iOS, change `false` to `true` and then install pods
20 | :hermes_enabled => flags[:hermes_enabled],
21 | :fabric_enabled => flags[:fabric_enabled],
22 | # An absolute path to your application root.
23 | :app_path => "#{Pod::Config.instance.installation_root}/.."
24 | )
25 |
26 | target 'cpmTests' do
27 | inherit! :complete
28 | # Pods for testing
29 | end
30 |
31 | # Enables Flipper.
32 | #
33 | # Note that if you have use_frameworks! enabled, Flipper will not work and
34 | # you should disable the next line.
35 | use_flipper!()
36 |
37 | post_install do |installer|
38 | react_native_post_install(installer)
39 | __apply_Xcode_12_5_M1_post_install_workaround(installer)
40 | # Error when archiving. Workaround.
41 | # Opened issue: https://github.com/facebook/react-native/issues/30335
42 | installer.pods_project.targets.each do |target|
43 | if target.name == "React-Core.common-AccessibilityResources"
44 | target.remove_from_project
45 | end
46 | end
47 | # End of workaround
48 | end
49 | end
--------------------------------------------------------------------------------
/src/models.ts:
--------------------------------------------------------------------------------
1 | export type DataAvailableCallback = (
2 | itemId: string,
3 | value: any,
4 | itemName?: string,
5 | ) => void;
6 | export interface IHealthManager {
7 | startScan(onDeviceFound: (device: IHealthDevice) => void): void;
8 | stopScan(): void;
9 | connect(deviceId: string): Promise;
10 | }
11 |
12 | export type DeviceType = 'real' | 'simulated' | 'platform';
13 | export interface IHealthDevice {
14 | name: string;
15 | id: string;
16 | paired: boolean;
17 | connected: boolean;
18 | type: DeviceType;
19 | fetch(): Promise;
20 | disconnect(): Promise;
21 | items?: IHealthItem[];
22 | addListener(
23 | eventType: string,
24 | listener: (...args: any[]) => any,
25 | context?: any,
26 | ): void;
27 | removeListener(eventType: string, listener: (...args: any[]) => any): void;
28 | }
29 |
30 | export interface IHealthItem {
31 | id: string;
32 | name?: string;
33 | parentId?: string;
34 | value: any | undefined;
35 | enabled: boolean;
36 | enable(status: boolean): Promise;
37 | getData?(): any;
38 | }
39 |
40 | export type ItemData = {
41 | itemId: string;
42 | itemName?: string;
43 | value: any;
44 | };
45 |
46 | export type MonitoredDevice = IHealthDevice & {
47 | monitorIds: {
48 | [itemId: string]: number; // the value is the id for the setInterval loop. Used to clear it
49 | };
50 | };
51 |
52 | const bluetoothHealthServices = [
53 | '180d',
54 | '1810',
55 | '181f',
56 | '1808',
57 | '1809',
58 | '180d',
59 | '183a',
60 | '181d',
61 | ];
62 |
63 | export function isHealthService(serviceUUID: string) {
64 | if (
65 | bluetoothHealthServices.indexOf(serviceUUID.substring(4, 8).toLowerCase()) >
66 | -1
67 | ) {
68 | return true;
69 | }
70 | return false;
71 | }
72 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/less/mixins.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | .fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
14 | .fa-icon-rotate(@degrees, @rotation) {
15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
16 | -webkit-transform: rotate(@degrees);
17 | -ms-transform: rotate(@degrees);
18 | transform: rotate(@degrees);
19 | }
20 |
21 | .fa-icon-flip(@horiz, @vert, @rotation) {
22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
23 | -webkit-transform: scale(@horiz, @vert);
24 | -ms-transform: scale(@horiz, @vert);
25 | transform: scale(@horiz, @vert);
26 | }
27 |
28 |
29 | // Only display content to screen readers. A la Bootstrap 4.
30 | //
31 | // See: http://a11yproject.com/posts/how-to-hide-content/
32 |
33 | .sr-only() {
34 | position: absolute;
35 | width: 1px;
36 | height: 1px;
37 | padding: 0;
38 | margin: -1px;
39 | overflow: hidden;
40 | clip: rect(0,0,0,0);
41 | border: 0;
42 | }
43 |
44 | // Use in conjunction with .sr-only to only display content when it's focused.
45 | //
46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
47 | //
48 | // Credit: HTML5 Boilerplate
49 |
50 | .sr-only-focusable() {
51 | &:active,
52 | &:focus {
53 | position: static;
54 | width: auto;
55 | height: auto;
56 | margin: 0;
57 | overflow: visible;
58 | clip: auto;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext {
5 | buildToolsVersion = '31.0.0'
6 | minSdkVersion = 21
7 | compileSdkVersion = 31
8 | targetSdkVersion = 31
9 | if (System.properties['os.arch'] == "aarch64") {
10 | // For M1 Users we need to use the NDK 24 which added support for aarch64
11 | ndkVersion = "24.0.8215888"
12 | } else {
13 | // Otherwise we default to the side-by-side NDK version from AGP.
14 | ndkVersion = "21.4.7075529"
15 | }
16 | }
17 | repositories {
18 | google()
19 | mavenCentral()
20 | }
21 | dependencies {
22 | classpath('com.android.tools.build:gradle:7.1.2')
23 | classpath("com.facebook.react:react-native-gradle-plugin")
24 | classpath("de.undercouch:gradle-download-task:5.0.1")
25 |
26 | // NOTE: Do not place your application dependencies here; they belong
27 | // in the individual module build.gradle files
28 | }
29 | }
30 |
31 | allprojects {
32 | repositories {
33 | mavenCentral()
34 | mavenLocal()
35 | maven {
36 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
37 | url("$rootDir/../node_modules/react-native/android")
38 | }
39 | maven {
40 | // Android JSC is installed from npm
41 | url("$rootDir/../node_modules/jsc-android/dist")
42 | }
43 | mavenCentral {
44 | // We don't want to fetch react-native from Maven Central as there are
45 | // older versions over there.
46 | content {
47 | excludeGroup "com.facebook.react"
48 | }
49 | }
50 | google()
51 | maven { url 'https://www.jitpack.io' }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/components/qrcodeMask.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {View} from 'react-native';
3 | import {useScreenDimensions} from '../hooks/layout';
4 | export default function QRCodeMask() {
5 | const {screen} = useScreenDimensions();
6 |
7 | const markerWidth = Math.floor(screen.width / 2);
8 | const sectorWidth = Math.floor(markerWidth / 5);
9 | return (
10 |
17 |
29 |
41 |
53 |
65 |
66 | );
67 | }
68 |
--------------------------------------------------------------------------------
/creds-generator/server/dist/public/fonts/font-awesome-4.7.0/scss/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | @mixin fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
14 | @mixin fa-icon-rotate($degrees, $rotation) {
15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})";
16 | -webkit-transform: rotate($degrees);
17 | -ms-transform: rotate($degrees);
18 | transform: rotate($degrees);
19 | }
20 |
21 | @mixin fa-icon-flip($horiz, $vert, $rotation) {
22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)";
23 | -webkit-transform: scale($horiz, $vert);
24 | -ms-transform: scale($horiz, $vert);
25 | transform: scale($horiz, $vert);
26 | }
27 |
28 |
29 | // Only display content to screen readers. A la Bootstrap 4.
30 | //
31 | // See: http://a11yproject.com/posts/how-to-hide-content/
32 |
33 | @mixin sr-only {
34 | position: absolute;
35 | width: 1px;
36 | height: 1px;
37 | padding: 0;
38 | margin: -1px;
39 | overflow: hidden;
40 | clip: rect(0,0,0,0);
41 | border: 0;
42 | }
43 |
44 | // Use in conjunction with .sr-only to only display content when it's focused.
45 | //
46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
47 | //
48 | // Credit: HTML5 Boilerplate
49 |
50 | @mixin sr-only-focusable {
51 | &:active,
52 | &:focus {
53 | position: static;
54 | width: auto;
55 | height: auto;
56 | margin: 0;
57 | overflow: visible;
58 | clip: auto;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/media/HealthDevice.json:
--------------------------------------------------------------------------------
1 | {
2 | "@id": "urn:lucacpm:HealthDevice:1",
3 | "@type": "CapabilityModel",
4 | "implements": [
5 | {
6 | "@id": "urn:lucacpm:HealthDevice:m0bszgacs:1",
7 | "@type": "InterfaceInstance",
8 | "displayName": {
9 | "en": "Telemetry"
10 | },
11 | "name": "telemetry",
12 | "schema": {
13 | "@id": "urn:lucacpm:HealthDevice:telemetry:2",
14 | "@type": "Interface",
15 | "displayName": {
16 | "en": "Telemetry"
17 | },
18 | "contents": [
19 | {
20 | "@id": "urn:lucacpm:HealthDevice:temperature:1",
21 | "@type": [
22 | "Telemetry",
23 | "SemanticType/Temperature"
24 | ],
25 | "displayName": {
26 | "en": "Temperature"
27 | },
28 | "name": "ble00002A1C00001000800000805f9b34fb",
29 | "schema": "double"
30 | },
31 | {
32 | "@id": "urn:lucacpm:HealthDevice:heartrate:1",
33 | "@type": "Telemetry",
34 | "displayName": {
35 | "en": "Heart Rate"
36 | },
37 | "name": "ble00002A3700001000800000805f9b34fb",
38 | "displayUnit": {
39 | "en": "BPM"
40 | },
41 | "schema": "double"
42 | },
43 | {
44 | "@id": "urn:lucacpm:HealthDevice:pressure:1",
45 | "@type": [
46 | "Telemetry",
47 | "SemanticType/Pressure"
48 | ],
49 | "displayName": {
50 | "en": "Blood Pressure"
51 | },
52 | "name": "ble00002A3500001000800000805f9b34fb",
53 | "schema": "double"
54 | }
55 | ]
56 | }
57 | }
58 | ],
59 | "displayName": {
60 | "en": "HealthDevice"
61 | },
62 | "@context": [
63 | "http://azureiot.com/v1/contexts/IoTModel.json"
64 | ]
65 | }
--------------------------------------------------------------------------------
/patches/react-native+0.69.1.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/react-native/index.js b/node_modules/react-native/index.js
2 | index d59ba34..1bc8c9d 100644
3 | --- a/node_modules/react-native/index.js
4 | +++ b/node_modules/react-native/index.js
5 | @@ -435,32 +435,16 @@ module.exports = {
6 | },
7 | // Deprecated Prop Types
8 | get ColorPropType(): $FlowFixMe {
9 | - invariant(
10 | - false,
11 | - 'ColorPropType has been removed from React Native. Migrate to ' +
12 | - "ColorPropType exported from 'deprecated-react-native-prop-types'.",
13 | - );
14 | + return require('deprecated-react-native-prop-types').ColorPropType;
15 | },
16 | get EdgeInsetsPropType(): $FlowFixMe {
17 | - invariant(
18 | - false,
19 | - 'EdgeInsetsPropType has been removed from React Native. Migrate to ' +
20 | - "EdgeInsetsPropType exported from 'deprecated-react-native-prop-types'.",
21 | - );
22 | + return require('deprecated-react-native-prop-types').EdgeInsetsPropType;
23 | },
24 | get PointPropType(): $FlowFixMe {
25 | - invariant(
26 | - false,
27 | - 'PointPropType has been removed from React Native. Migrate to ' +
28 | - "PointPropType exported from 'deprecated-react-native-prop-types'.",
29 | - );
30 | + return require('deprecated-react-native-prop-types').PointPropType;
31 | },
32 | get ViewPropTypes(): $FlowFixMe {
33 | - invariant(
34 | - false,
35 | - 'ViewPropTypes has been removed from React Native. Migrate to ' +
36 | - "ViewPropTypes exported from 'deprecated-react-native-prop-types'.",
37 | - );
38 | + return require('deprecated-react-native-prop-types').ViewPropTypes;
39 | },
40 | };
41 |
42 | diff --git a/node_modules/react-native/scripts/.packager.env b/node_modules/react-native/scripts/.packager.env
43 | new file mode 100644
44 | index 0000000..361f5fb
45 | --- /dev/null
46 | +++ b/node_modules/react-native/scripts/.packager.env
47 | @@ -0,0 +1 @@
48 | +export RCT_METRO_PORT=8081
49 |
--------------------------------------------------------------------------------
/src/components/utils.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {View, processColor} from 'react-native';
3 | import {ActivityIndicator, Portal, Dialog, Button} from 'react-native-paper';
4 | import {Detail, Headline} from './typography';
5 | import DefaultStyles from '../styles';
6 | import GetConnected from '../assets/home_connected_icon.svg';
7 | import {ReactDispatch} from '../types';
8 |
9 | export function Loading() {
10 | return (
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | export function ErrorDialog(props: {
18 | visible: boolean;
19 | setVisible: ReactDispatch;
20 | title: string;
21 | text: string;
22 | }) {
23 | const {visible, setVisible, text, title} = props;
24 | return (
25 |
26 |
35 |
36 | );
37 | }
38 |
39 | export function GetConnectedHeader() {
40 | const header = 'Get connected';
41 | const sub = 'Pair a device or sync your data';
42 | return (
43 |
44 |
45 |
46 | {header}
47 | {sub}
48 |
49 |
50 | );
51 | }
52 |
53 | export function getRandomColor() {
54 | return processColor(
55 | `rgb(${Math.floor(Math.random() * 256)},${Math.floor(
56 | Math.random() * 256,
57 | )},${Math.floor(Math.random() * 256)})`,
58 | );
59 | }
60 |
--------------------------------------------------------------------------------
/ios/cpmTests/cpmTests.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | #import
5 | #import
6 |
7 | #define TIMEOUT_SECONDS 600
8 | #define TEXT_TO_LOOK_FOR @"Welcome to React"
9 |
10 | @interface cpmTests : XCTestCase
11 |
12 | @end
13 |
14 | @implementation cpmTests
15 |
16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
17 | {
18 | if (test(view)) {
19 | return YES;
20 | }
21 | for (UIView *subview in [view subviews]) {
22 | if ([self findSubviewInView:subview matching:test]) {
23 | return YES;
24 | }
25 | }
26 | return NO;
27 | }
28 |
29 | - (void)testRendersWelcomeScreen
30 | {
31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
33 | BOOL foundElement = NO;
34 |
35 | __block NSString *redboxError = nil;
36 | #ifdef DEBUG
37 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
38 | if (level >= RCTLogLevelError) {
39 | redboxError = message;
40 | }
41 | });
42 | #endif
43 |
44 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
45 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
46 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
47 |
48 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
49 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
50 | return YES;
51 | }
52 | return NO;
53 | }];
54 | }
55 |
56 | #ifdef DEBUG
57 | RCTSetLogFunction(RCTDefaultLogFunction);
58 | #endif
59 |
60 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
61 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
62 | }
63 |
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/ios/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {enableScreens} from 'react-native-screens';
3 | import {
4 | Provider as PaperProvider,
5 | DefaultTheme,
6 | configureFonts,
7 | } from 'react-native-paper';
8 | import Welcome from './screens/welcome';
9 | import ConfigProvider, {ConfigContext} from './contexts/config';
10 | import Registration from './screens/registration';
11 | import Main from './screens/main';
12 | import {StatusBar} from 'react-native';
13 | import {NavigationContainer} from '@react-navigation/native';
14 | import AuthProvider from './contexts/auth';
15 | import UIProvider from './contexts/ui';
16 | import {useContext} from 'react';
17 |
18 | enableScreens();
19 |
20 | const fontConfig: {} = {
21 | default: {
22 | regular: {
23 | fontFamily: 'Roboto',
24 | fontWeight: 'normal',
25 | fontSize: 14,
26 | },
27 | medium: {
28 | fontFamily: 'sans-serif-medium',
29 | fontWeight: 'normal',
30 | },
31 | light: {
32 | fontFamily: 'sans-serif-light',
33 | fontWeight: 'normal',
34 | },
35 | thin: {
36 | fontFamily: 'sans-serif-thin',
37 | fontWeight: 'normal',
38 | },
39 | },
40 | };
41 |
42 | const theme = {
43 | ...DefaultTheme,
44 | roundness: 2,
45 | colors: {
46 | ...DefaultTheme.colors,
47 | accent: '#75FBFD',
48 | primary: '#3783c5',
49 | background: 'transparent',
50 | text: '#1F529D',
51 | placeholder: '#1F529D',
52 | },
53 | fonts: configureFonts(fontConfig),
54 | };
55 |
56 | export default function App() {
57 | return (
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | );
71 | }
72 |
73 | const Root = React.memo(() => {
74 | const {state} = useContext(ConfigContext);
75 | if (state.centralClient !== undefined) {
76 | return ;
77 | } else if (state.initialized) {
78 | return ;
79 | }
80 | return ;
81 | });
82 |
--------------------------------------------------------------------------------
/src/components/typography.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Text} from 'react-native-paper';
3 | import {TextProps} from 'react-native';
4 | import {normalize} from '../utils';
5 |
6 | interface Props extends TextProps {
7 | children?: any;
8 | theme?: any;
9 | }
10 |
11 | export function Headline(props: Props) {
12 | const {children, style, ...textProps} = props;
13 | return (
14 |
18 | {props.children}
19 |
20 | );
21 | }
22 |
23 | export function CPMText(props: Props) {
24 | const {children, style, ...textProps} = props;
25 | return (
26 |
30 | {props.children}
31 |
32 | );
33 | }
34 |
35 | export function Name(props: Props) {
36 | const {children, style, ...textProps} = props;
37 | return (
38 |
50 | {props.children}
51 |
52 | );
53 | }
54 |
55 | export function Item(props: Props) {
56 | const {children, style, ...textProps} = props;
57 | return (
58 |
65 | {props.children}
66 |
67 | );
68 | }
69 |
70 | export function Detail(props: Props) {
71 | const {children, style, ...textProps} = props;
72 |
73 | return (
74 |
78 | {props.children}
79 |
80 | );
81 | }
82 |
83 | export function Action(props: Props) {
84 | const {children, style, ...textProps} = props;
85 |
86 | return (
87 |
91 | {props.children}
92 |
93 | );
94 | }
95 |
--------------------------------------------------------------------------------
/src/hooks/common.ts:
--------------------------------------------------------------------------------
1 | import {useRef, useEffect, useState} from 'react';
2 | import {useIsFocused, useNavigation} from '@react-navigation/native';
3 | import {NavigationProperty} from 'types';
4 |
5 | export type EnvironmentVariables = {
6 | GoogleFit?: boolean;
7 | AppleHealth?: boolean;
8 | } & {[x: string]: any};
9 |
10 | export function usePrevious(value: T) {
11 | // The ref object is a generic container whose current property is mutable ...
12 | // ... and can hold any value, similar to an instance property on a class
13 | const ref = useRef();
14 |
15 | // Store current value in ref
16 | useEffect(() => {
17 | ref.current = value;
18 | }, [value]); // Only re-run if value changes
19 |
20 | // Return previous value (happens before update in useEffect above)
21 | return ref.current;
22 | }
23 |
24 | export function useEnv() {
25 | const [variables, setVariables] = useState({
26 | GoogleFit: true,
27 | AppleHealth: true,
28 | });
29 |
30 | const readEnv = async function () {
31 | try {
32 | const envvars = (await import('../../env.json')).default;
33 | console.log(`Envvars: ${JSON.stringify(envvars)}`);
34 | setVariables(vars => ({...vars, ...envvars}));
35 | } catch (e) {
36 | setVariables(vars => ({
37 | ...vars,
38 | ...{
39 | GoogleFit: true,
40 | AppleHealth: true,
41 | },
42 | }));
43 | }
44 | };
45 | useEffect(() => {
46 | readEnv();
47 | }, []);
48 |
49 | return variables;
50 | }
51 |
52 | /**
53 | * Get a timer returning 'true' when triggers.
54 | * @param seconds Number of seconds before timer triggers.
55 | */
56 | export function useTimer(seconds: number) {
57 | const [done, setDone] = useState(false);
58 | useEffect(() => {
59 | setTimeout(() => {
60 | setDone(true);
61 | }, seconds);
62 | }, [seconds]);
63 | return done;
64 | }
65 |
66 | export function useHeaderTitle(title: string): void {
67 | const isFocused = useIsFocused();
68 | const navigation = useNavigation();
69 | const counter = useRef(0);
70 |
71 | useEffect(() => {
72 | if (isFocused) {
73 | counter.current++;
74 | navigation.setParams({title});
75 | }
76 | }, [navigation, title, isFocused]);
77 | }
78 |
--------------------------------------------------------------------------------
/src/contexts/config.tsx:
--------------------------------------------------------------------------------
1 | import React, {useReducer} from 'react';
2 | import {IIoTCClient} from 'react-native-azure-iotcentral-client';
3 | import {IHealthManager, IHealthDevice} from '../models';
4 | import {ChartUpdateCallback} from '../types';
5 |
6 | export interface IConfigState {
7 | initialized: boolean;
8 | device: IHealthDevice | null;
9 | centralClient?: IIoTCClient | null;
10 | healthManager: IHealthManager | null;
11 | insightUpdate: ChartUpdateCallback | null;
12 | }
13 |
14 | type CommonAction = {
15 | type: 'INIT';
16 | payload: boolean;
17 | };
18 |
19 | type IIoTCAction = {
20 | type: 'CONNECT' | 'DISCONNECT';
21 | payload: IIoTCClient | null;
22 | };
23 | type IHealthAction = {
24 | type: 'ACTIVATE' | 'UNACTIVATE';
25 | payload: IHealthManager | null;
26 | };
27 |
28 | type IDeviceAction = {
29 | type: 'HEALTH_CONNECT' | 'HEALTH_DISCONNECT';
30 | payload: IHealthDevice | null;
31 | };
32 |
33 | type IConfigAction = IDeviceAction | IHealthAction | IIoTCAction | CommonAction;
34 |
35 | export type IConfigContext = {
36 | state: IConfigState;
37 | dispatch: React.Dispatch;
38 | };
39 |
40 | export const configReducer = (state: IConfigState, action: IConfigAction) => {
41 | switch (action.type) {
42 | case 'INIT':
43 | return {...state, initialized: action.payload};
44 | case 'CONNECT':
45 | case 'DISCONNECT':
46 | return {...state, centralClient: action.payload};
47 | case 'HEALTH_CONNECT':
48 | case 'HEALTH_DISCONNECT':
49 | return {...state, device: action.payload};
50 | case 'ACTIVATE':
51 | case 'UNACTIVATE':
52 | return {...state, healthManager: action.payload};
53 | default:
54 | return state;
55 | }
56 | };
57 |
58 | const initialState: IConfigState = {
59 | initialized: false,
60 | device: null,
61 | centralClient: undefined,
62 | healthManager: null,
63 | insightUpdate: null,
64 | };
65 |
66 | export const ConfigContext = React.createContext({
67 | state: initialState,
68 | dispatch: () => {},
69 | });
70 | const {Provider} = ConfigContext;
71 |
72 | const ConfigProvider: React.FC<{children: React.ReactNode}> = ({children}) => {
73 | const [state, dispatch] = useReducer(configReducer, initialState);
74 | return {children};
75 | };
76 |
77 | export default ConfigProvider;
78 |
--------------------------------------------------------------------------------
/src/screens/providers.tsx:
--------------------------------------------------------------------------------
1 | import React, {useContext, useEffect} from 'react';
2 | import {ConfigContext} from '../contexts/config';
3 | import {Loading} from '../components/utils';
4 | import {Platform, View} from 'react-native';
5 | import {AppleHealthManager} from '../health/appleHealth';
6 | import {IHealthManager} from '../models';
7 | import {GoogleFitManager} from '../health/googleFit';
8 | import {Headline} from '../components/typography';
9 | import {useNavigation} from '@react-navigation/native';
10 | import {NavigationProperty, Screens} from '../types';
11 | import {DATA_AVAILABLE_EVENT} from '../health/ble';
12 | import {sendTelemetryData} from '../api/central';
13 |
14 | const Manager = Platform.select<
15 | typeof AppleHealthManager | typeof GoogleFitManager
16 | >({
17 | android: GoogleFitManager,
18 | ios: AppleHealthManager,
19 | }) as typeof AppleHealthManager | typeof GoogleFitManager;
20 |
21 | export default function Providers() {
22 | const {state, dispatch} = useContext(ConfigContext);
23 | const {navigate} = useNavigation();
24 |
25 | useEffect(() => {
26 | const initManager = async () => {
27 | if (state.healthManager) {
28 | state.healthManager.startScan(async device => {
29 | const dev = await (state.healthManager as IHealthManager).connect('');
30 | navigate(Screens.INSIGHT_SCREEN);
31 | await dev.fetch();
32 |
33 | if (state.centralClient) {
34 | dev.addListener(
35 | DATA_AVAILABLE_EVENT,
36 | sendTelemetryData.bind(null, state.centralClient, false),
37 | );
38 | }
39 | dispatch({
40 | type: 'HEALTH_CONNECT',
41 | payload: dev,
42 | });
43 | });
44 | } else {
45 | const payload = new Manager();
46 | dispatch({
47 | type: 'ACTIVATE',
48 | payload,
49 | });
50 | }
51 | };
52 | initManager();
53 | }, [state.healthManager, dispatch, navigate, state.centralClient]);
54 |
55 | if (!state.healthManager) {
56 | return (
57 |
58 |
59 |
62 | Loading provider data ...
63 |
64 |
65 | );
66 | }
67 |
68 | return null;
69 | }
70 |
--------------------------------------------------------------------------------
/ios/cpm/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | $(PRODUCT_NAME)
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(CURRENT_PROJECT_VERSION)
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSExceptionDomains
30 |
31 | localhost
32 |
33 | NSExceptionAllowsInsecureHTTPLoads
34 |
35 |
36 |
37 |
38 | NSBluetoothAlwaysUsageDescription
39 | CPM would like to use bluetooth to search for nearby devices
40 | NSCameraUsageDescription
41 | CPM would like to access your camera to scan QR codes.
42 | NSHealthShareUsageDescription
43 | Read and understand health data.
44 | NSHealthUpdateUsageDescription
45 | Share workout data with other apps.
46 | UIAppFonts
47 |
48 | Ionicons.ttf
49 | MaterialIcons.ttf
50 | MaterialCommunityIcons.ttf
51 |
52 | UILaunchStoryboardName
53 | LaunchScreen
54 | UIMainStoryboardFile
55 | LaunchScreen
56 | UIRequiredDeviceCapabilities
57 |
58 | armv7
59 |
60 | UISupportedInterfaceOrientations
61 |
62 | UIInterfaceOrientationPortrait
63 | UIInterfaceOrientationLandscapeLeft
64 | UIInterfaceOrientationLandscapeRight
65 |
66 | UIUserInterfaceStyle
67 | Light
68 | UIViewControllerBasedStatusBarAppearance
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/media/Apple_HealthKit.json:
--------------------------------------------------------------------------------
1 | {
2 | "@id": "urn:cpm:AppleHealthKit_5rt:1",
3 | "@type": "CapabilityModel",
4 | "implements": [
5 | {
6 | "@id": "urn:cpm:AppleHealthKit_5rt:480u2qoun:1",
7 | "@type": "InterfaceInstance",
8 | "displayName": {
9 | "en": "Interface"
10 | },
11 | "name": "health_telemetry",
12 | "schema": {
13 | "@id": "urn:cpm:HealthData:1",
14 | "@type": "Interface",
15 | "displayName": {
16 | "en": "Interface"
17 | },
18 | "contents": [
19 | {
20 | "@id": "urn:cpm:HealthData:BodyTemperature:1",
21 | "@type": [
22 | "Telemetry",
23 | "SemanticType/Temperature"
24 | ],
25 | "displayName": {
26 | "en": "Body Temperature"
27 | },
28 | "name": "BodyTemperature",
29 | "schema": "double"
30 | },
31 | {
32 | "@id": "urn:cpm:HealthData:HeartRate:1",
33 | "@type": "Telemetry",
34 | "displayName": {
35 | "en": "Heart Rate"
36 | },
37 | "name": "HeartRate",
38 | "schema": "integer"
39 | },
40 | {
41 | "@id": "urn:cpm:HealthData:BloodPressureDiastolic:1",
42 | "@type": [
43 | "Telemetry",
44 | "SemanticType/Pressure"
45 | ],
46 | "displayName": {
47 | "en": "Blood Pressure Diastolic"
48 | },
49 | "name": "BloodPressureDiastolic",
50 | "schema": "double"
51 | },
52 | {
53 | "@id": "urn:cpm:HealthData:BloodPressureSystolic:1",
54 | "@type": [
55 | "Telemetry",
56 | "SemanticType/Pressure"
57 | ],
58 | "displayName": {
59 | "en": "Blood Pressure Systolic"
60 | },
61 | "name": "BloodPressureSystolic",
62 | "schema": "double"
63 | },
64 | {
65 | "@id": "urn:cpm:HealthData:StepCount:1",
66 | "@type": "Telemetry",
67 | "displayName": {
68 | "en": "StepCount"
69 | },
70 | "name": "StepCount",
71 | "schema": "integer"
72 | }
73 | ]
74 | }
75 | }
76 | ],
77 | "displayName": {
78 | "en": "Apple HealthKit"
79 | },
80 | "@context": [
81 | "http://azureiot.com/v1/contexts/IoTModel.json"
82 | ]
83 | }
--------------------------------------------------------------------------------
/docs/google_fit.md:
--------------------------------------------------------------------------------
1 | # Google Fit
2 |
3 | ## 1. Add Item
4 |
5 | To enable telemetries, add an entry to the _GOOGLE_ITEMS_ enum in [_googleFit.ts_](../src/health/googleFit.ts#L27).
6 |
7 | ```ts
8 | enum GOOGLE_ITEMS {
9 | STEPS = 'steps',
10 | BLOOD_PRESSURE_SYSTOLIC = 'bloodPressureSystolic',
11 | BLOOD_PRESSURE_DIASTOLIC = 'bloodPressureDiastolic',
12 | ...
13 | }
14 | ```
15 |
16 | ## 2. Add types
17 |
18 | To leverage type definitions, add result types to [_types.ts_](../src/types.ts).
19 | Follow specs from the official documentation of the [_react-native-google-fit_](https://github.com/StasDoskalenko/react-native-google-fit#usage) library for available items and result types.
20 |
21 | ## 3. Add data handlers
22 |
23 | Each fit scope requires a different function to be called in order to fetch samples.
24 | Then add handling code for the specific item by adding a case in [_googleFit.ts_](../src/health/googleFit.ts#L183).
25 |
26 | ```ts
27 | case GOOGLE_ITEMS.STEPS:
28 | results = (await GoogleFit.getDailyStepCountSamples({
29 | startDate: startDate.toISOString(),
30 | endDate: new Date().toISOString(),
31 | })) as GoogleFitStepResult[];
32 | results.forEach(result => {
33 | ...
34 | ...
35 | this.eventEmitter.emit(DATA_AVAILABLE_EVENT, {
36 | itemId: item.id,
37 | value: item.value ?? 0,
38 | itemName: item.name,
39 | });
40 | break;
41 | ...
42 | ...
43 | ```
44 |
45 | ## 4. Add items to IoT Central model (optional)
46 |
47 | Every item added to the _GOOGLE_ITEMS_ enum will be send to IoT Central using the item Id as telemetry name.
48 |
49 | ```ts
50 | enum GOOGLE_ITEMS {
51 | STEPS = 'steps',
52 | BLOOD_PRESSURE_SYSTOLIC = 'bloodPressureSystolic',
53 | BLOOD_PRESSURE_DIASTOLIC = 'bloodPressureDiastolic',
54 | }
55 | ```
56 |
57 | ```json
58 | ...
59 | {
60 | "@id": "dtmi:cpm:GoogleFit_5r4:steps;1",
61 | "@type": "Telemetry",
62 | "displayName": {
63 | "en": "Steps"
64 | },
65 | "name": "steps",
66 | "schema": "double"
67 | },
68 | {
69 | "@id": "dtmi:cpm:GoogleFit_5r4:BloodPressureSystolic;1",
70 | "@type": "Telemetry",
71 | "displayName": {
72 | "en": "Blood Pressure Systolic"
73 | },
74 | "name": "BloodPressureSystolic",
75 | "schema": "double"
76 | },
77 | {
78 | "@id": "dtmi:cpm:GoogleFit_5r4:BloodPressureDiastolic;1",
79 | "@type": "Telemetry",
80 | "displayName": {
81 | "en": "Blood Pressure Diastolic"
82 | },
83 | "name": "BloodPressureDiastolic",
84 | "schema": "double"
85 | }
86 | ```
87 |
--------------------------------------------------------------------------------
/src/screens/welcome.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {View, StyleSheet} from 'react-native';
3 | import {Text} from 'react-native-paper';
4 | import LogoTitle from '../assets/logo_title.svg';
5 | import LinearGradient from 'react-native-linear-gradient';
6 | import ProgressCircleSnail from 'react-native-progress/CircleSnail';
7 | import {useScreenDimensions} from 'hooks/layout';
8 | import {useEffect} from 'react';
9 | import {useContext} from 'react';
10 | import {ConfigContext} from 'contexts/config';
11 |
12 | const title = 'Welcome to connected care.';
13 |
14 | const theme = {
15 | colors: {placeholder: 'white', text: 'white'},
16 | };
17 |
18 | export default React.memo(() => {
19 | const {screen} = useScreenDimensions();
20 | const {dispatch} = useContext(ConfigContext);
21 |
22 | useEffect(() => {
23 | setTimeout(() => {
24 | dispatch({
25 | type: 'INIT',
26 | payload: true,
27 | });
28 | }, 4000);
29 | }, [dispatch]);
30 |
31 | return (
32 |
33 |
34 |
35 |
36 | {title}
37 |
38 | {/*
39 | {subTitle}
40 | */}
41 |
42 |
51 |
52 | );
53 | });
54 |
55 | const style = StyleSheet.create({
56 | container: {
57 | alignItems: 'center',
58 | flex: 1,
59 | justifyContent: 'center',
60 | },
61 | logo: {
62 | alignItems: 'center',
63 | marginBottom: 50,
64 | },
65 | logoSub: {
66 | fontSize: 20,
67 | fontWeight: 'bold',
68 | color: 'white',
69 | },
70 | logoDetails: {
71 | fontSize: 15,
72 | color: 'white',
73 | },
74 | form: {
75 | width: '80%',
76 | flex: 2,
77 | alignItems: 'center',
78 | },
79 | forgot: {
80 | textAlign: 'right',
81 | marginTop: 6,
82 | },
83 | text: {
84 | color: 'white',
85 | width: '100%',
86 | backgroundColor: 'transparent',
87 | },
88 | button: {
89 | width: 120,
90 | marginVertical: 50,
91 | backgroundColor: 'white',
92 | },
93 | progress: {
94 | marginVertical: 5,
95 | },
96 | });
97 |
--------------------------------------------------------------------------------
/creds-generator/server/src/index.ts:
--------------------------------------------------------------------------------
1 | import Express from 'express';
2 | import * as path from 'path';
3 | import bodyParser from 'body-parser';
4 | import QRCode from 'qrcode';
5 | import CryptoJS from 'crypto-js'
6 | import * as fs from 'fs';
7 |
8 |
9 | export enum CredentialTypes {
10 | QRCODE = 1,
11 | NUMERIC = 2,
12 | ALL = 3
13 | }
14 | export type Credentials = {
15 | deviceId: string,
16 | modelId: string,
17 | patientId: string,
18 | deviceKey: string,
19 | scopeId: string,
20 | types: CredentialTypes
21 | }
22 |
23 |
24 | const app = Express();
25 | const port = process.env.PORT || 3700;
26 | const dbPath = path.join(__dirname, '../db.json');
27 | if (!fs.existsSync(dbPath)) {
28 | fs.writeFileSync(dbPath, '{}');
29 | }
30 | let db = JSON.parse(fs.readFileSync(dbPath).toString());
31 | // define a route handler for the default home page
32 |
33 | app.use(bodyParser.urlencoded({ extended: true }));
34 | app.use(bodyParser.json());
35 | app.use(Express.static(path.join(__dirname, 'public')));
36 |
37 | app.get('/', (req, res) => {
38 | res.sendFile(path.join(__dirname, './public/index.html'));
39 | });
40 | app.post('/creds', async (req, res) => {
41 | const creds: Credentials = req.body;
42 | if (!creds['scopeId']) {
43 | res.status(500).send('Invalid body');
44 | return;
45 | }
46 | let response: { qrCode?: string, numeric?: number } = {};
47 | let credType = +creds.types;
48 | const { types, ...credentials } = creds;
49 | let cr = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(credentials)));
50 | const codeStr = creds.patientId ? CryptoJS.AES.encrypt(cr, creds.patientId).toString() : cr;
51 | if (credType == CredentialTypes.ALL.valueOf() || credType == CredentialTypes.QRCODE.valueOf()) {
52 | response['qrCode'] = await QRCode.toDataURL(codeStr);
53 | }
54 | if (credType == CredentialTypes.ALL.valueOf() || credType == CredentialTypes.NUMERIC.valueOf()) {
55 | const numCode = Math.floor(Math.random() * 100000);
56 | db[numCode] = codeStr;
57 | fs.writeFileSync(dbPath, JSON.stringify(db));
58 | response['numeric'] = numCode;
59 | }
60 |
61 | res.send(response);
62 | });
63 | app.get('/numeric', (req, res) => {
64 | let numeric = req.query.numeric as string;
65 | if (db[numeric]) {
66 | res.send(db[numeric]);
67 | }
68 | else {
69 | res.send(-1);
70 | }
71 | });
72 |
73 | // start the Express server
74 | app.listen(port, () => {
75 | console.log(`server started at http://localhost:${port}`);
76 | });
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | import {NativeStackNavigationProp} from '@react-navigation/native-stack';
2 | import {DrawerNavigationProp} from '@react-navigation/drawer';
3 | import {
4 | LineData,
5 | LineValue,
6 | LineDatasetConfig,
7 | } from 'react-native-charts-wrapper';
8 | import {ItemData} from './models';
9 |
10 | export const Screens = {
11 | DEVICES_SCREEN: 'Devices',
12 | INSIGHT_SCREEN: 'Insight',
13 | HOME_SCREEN: 'Home',
14 | PROVIDERS_SCREEN: 'Health Provider',
15 | };
16 |
17 | export const DrawerScreens = {
18 | MAIN: 'Main',
19 | };
20 | // Type for getting the values of an object (lookup)
21 | export type valueof = T[keyof T];
22 |
23 | export type ReactDispatch = React.Dispatch>;
24 | export type ContextDispatch = React.Dispatch;
25 |
26 | /**
27 | * Parameters available for all routes
28 | */
29 | export type NavigationParams = {
30 | title?: string;
31 | backTitle?: string;
32 | titleColor?: string;
33 | headerLeft?: any;
34 | icon?: {
35 | name: string;
36 | type: string;
37 | };
38 | previousScreen?: string;
39 | };
40 |
41 | /**
42 | * Defines type of screens
43 | */
44 | export type NavigationScreens = {
45 | [k in valueof]: NavigationParams | undefined;
46 | };
47 |
48 | export type DrawerNavigationScreens = {
49 | [k in valueof]: NavigationParams | undefined;
50 | };
51 |
52 | export type ScreenNames = typeof Screens[keyof typeof Screens];
53 | export type DrawerScreenNames =
54 | typeof DrawerScreens[keyof typeof DrawerScreens];
55 | /**
56 | * Defines type of navigator properties
57 | */
58 | export type NavigationProperty = NativeStackNavigationProp<
59 | NavigationScreens,
60 | ScreenNames
61 | >;
62 |
63 | export type DrawerProperty = DrawerNavigationProp<
64 | DrawerNavigationScreens,
65 | DrawerScreenNames
66 | >;
67 |
68 | /**
69 | * Chart typings
70 | */
71 | export interface ExtendedLineData extends LineData {
72 | dataSets: {
73 | itemId: string;
74 | values?: Array;
75 | label?: string;
76 | config?: LineDatasetConfig;
77 | }[];
78 | }
79 |
80 | export type ChartUpdateCallback = (itemdata: ItemData) => void;
81 |
82 | /**
83 | * Health typings
84 | */
85 |
86 | export const HealthRealTimeData = {
87 | Walking: 'Walking',
88 | StairClimbing: 'StairClimbing',
89 | Running: 'Running',
90 | Cycling: 'Cycling',
91 | Workout: 'Workout',
92 | } as const;
93 |
94 | export type GoogleFitStepResult = {
95 | source: string;
96 | steps: {
97 | date: string;
98 | value: number;
99 | }[];
100 | };
101 |
102 | export type GoogleFitBloodPressureResult = {
103 | systolic: number;
104 | diastolic: number;
105 | endDate: string;
106 | startDate: string;
107 | day: string;
108 | };
109 |
--------------------------------------------------------------------------------
/src/assets/ios_icons/iOS/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "size": "20x20",
5 | "idiom": "iphone",
6 | "filename": "launcher-20@2x.png",
7 | "scale": "2x"
8 | },
9 | {
10 | "size": "20x20",
11 | "idiom": "iphone",
12 | "filename": "launcher-20@3x.png",
13 | "scale": "3x"
14 | },
15 | {
16 | "size": "20x20",
17 | "idiom": "ipad",
18 | "filename": "launcher-20.png",
19 | "scale": "1x"
20 | },
21 | {
22 | "size": "20x20",
23 | "idiom": "ipad",
24 | "filename": "launcher-20@2x.png",
25 | "scale": "2x"
26 | },
27 | {
28 | "size": "29x29",
29 | "idiom": "iphone",
30 | "filename": "launcher-29@2x.png",
31 | "scale": "2x"
32 | },
33 | {
34 | "size": "29x29",
35 | "idiom": "iphone",
36 | "filename": "launcher-29@3x.png",
37 | "scale": "3x"
38 | },
39 | {
40 | "size": "40x40",
41 | "idiom": "iphone",
42 | "filename": "launcher-40@2x.png",
43 | "scale": "2x"
44 | },
45 | {
46 | "size": "40x40",
47 | "idiom": "iphone",
48 | "filename": "launcher-40@3x.png",
49 | "scale": "3x"
50 | },
51 | {
52 | "size": "60x60",
53 | "idiom": "iphone",
54 | "filename": "launcher-60@2x.png",
55 | "scale": "2x"
56 | },
57 | {
58 | "size": "60x60",
59 | "idiom": "iphone",
60 | "filename": "launcher-60@3x.png",
61 | "scale": "3x"
62 | },
63 | {
64 | "size": "29x29",
65 | "idiom": "ipad",
66 | "filename": "launcher-29.png",
67 | "scale": "1x"
68 | },
69 | {
70 | "size": "29x29",
71 | "idiom": "ipad",
72 | "filename": "launcher-29@2x.png",
73 | "scale": "2x"
74 | },
75 | {
76 | "size": "40x40",
77 | "idiom": "ipad",
78 | "filename": "launcher-40.png",
79 | "scale": "1x"
80 | },
81 | {
82 | "size": "40x40",
83 | "idiom": "ipad",
84 | "filename": "launcher-40@2x.png",
85 | "scale": "2x"
86 | },
87 | {
88 | "size": "76x76",
89 | "idiom": "ipad",
90 | "filename": "launcher-76.png",
91 | "scale": "1x"
92 | },
93 | {
94 | "size": "76x76",
95 | "idiom": "ipad",
96 | "filename": "launcher-76@2x.png",
97 | "scale": "2x"
98 | },
99 | {
100 | "size": "83.5x83.5",
101 | "idiom": "ipad",
102 | "filename": "launcher-83.5@2x.png",
103 | "scale": "2x"
104 | },
105 | {
106 | "size": "1024x1024",
107 | "idiom": "ios-marketing",
108 | "filename": "launcher-1024.png",
109 | "scale": "1x"
110 | }
111 | ],
112 | "info": {
113 | "version": 1,
114 | "author": "xcode"
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem http://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34 |
35 | @rem Find java.exe
36 | if defined JAVA_HOME goto findJavaFromJavaHome
37 |
38 | set JAVA_EXE=java.exe
39 | %JAVA_EXE% -version >NUL 2>&1
40 | if "%ERRORLEVEL%" == "0" goto execute
41 |
42 | echo.
43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
44 | echo.
45 | echo Please set the JAVA_HOME variable in your environment to match the
46 | echo location of your Java installation.
47 |
48 | goto fail
49 |
50 | :findJavaFromJavaHome
51 | set JAVA_HOME=%JAVA_HOME:"=%
52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
53 |
54 | if exist "%JAVA_EXE%" goto execute
55 |
56 | echo.
57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
58 | echo.
59 | echo Please set the JAVA_HOME variable in your environment to match the
60 | echo location of your Java installation.
61 |
62 | goto fail
63 |
64 | :execute
65 | @rem Setup the command line
66 |
67 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
68 |
69 | @rem Execute Gradle
70 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
71 |
72 | :end
73 | @rem End local scope for the variables with windows NT shell
74 | if "%ERRORLEVEL%"=="0" goto mainEnd
75 |
76 | :fail
77 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
78 | rem the _cmd.exe /c_ return code!
79 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
80 | exit /b 1
81 |
82 | :mainEnd
83 | if "%OS%"=="Windows_NT" endlocal
84 |
85 | :omega
86 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (3.0.5)
5 | rexml
6 | activesupport (6.1.6.1)
7 | concurrent-ruby (~> 1.0, >= 1.0.2)
8 | i18n (>= 1.6, < 2)
9 | minitest (>= 5.1)
10 | tzinfo (~> 2.0)
11 | zeitwerk (~> 2.3)
12 | addressable (2.8.0)
13 | public_suffix (>= 2.0.2, < 5.0)
14 | algoliasearch (1.27.5)
15 | httpclient (~> 2.8, >= 2.8.3)
16 | json (>= 1.5.1)
17 | atomos (0.1.3)
18 | claide (1.1.0)
19 | cocoapods (1.11.3)
20 | addressable (~> 2.8)
21 | claide (>= 1.0.2, < 2.0)
22 | cocoapods-core (= 1.11.3)
23 | cocoapods-deintegrate (>= 1.0.3, < 2.0)
24 | cocoapods-downloader (>= 1.4.0, < 2.0)
25 | cocoapods-plugins (>= 1.0.0, < 2.0)
26 | cocoapods-search (>= 1.0.0, < 2.0)
27 | cocoapods-trunk (>= 1.4.0, < 2.0)
28 | cocoapods-try (>= 1.1.0, < 2.0)
29 | colored2 (~> 3.1)
30 | escape (~> 0.0.4)
31 | fourflusher (>= 2.3.0, < 3.0)
32 | gh_inspector (~> 1.0)
33 | molinillo (~> 0.8.0)
34 | nap (~> 1.0)
35 | ruby-macho (>= 1.0, < 3.0)
36 | xcodeproj (>= 1.21.0, < 2.0)
37 | cocoapods-core (1.11.3)
38 | activesupport (>= 5.0, < 7)
39 | addressable (~> 2.8)
40 | algoliasearch (~> 1.0)
41 | concurrent-ruby (~> 1.1)
42 | fuzzy_match (~> 2.0.4)
43 | nap (~> 1.0)
44 | netrc (~> 0.11)
45 | public_suffix (~> 4.0)
46 | typhoeus (~> 1.0)
47 | cocoapods-deintegrate (1.0.5)
48 | cocoapods-downloader (1.6.3)
49 | cocoapods-plugins (1.0.0)
50 | nap
51 | cocoapods-search (1.0.1)
52 | cocoapods-trunk (1.6.0)
53 | nap (>= 0.8, < 2.0)
54 | netrc (~> 0.11)
55 | cocoapods-try (1.2.0)
56 | colored2 (3.1.2)
57 | concurrent-ruby (1.1.10)
58 | escape (0.0.4)
59 | ethon (0.15.0)
60 | ffi (>= 1.15.0)
61 | ffi (1.15.5)
62 | fourflusher (2.3.1)
63 | fuzzy_match (2.0.4)
64 | gh_inspector (1.1.3)
65 | httpclient (2.8.3)
66 | i18n (1.12.0)
67 | concurrent-ruby (~> 1.0)
68 | json (2.6.2)
69 | minitest (5.16.2)
70 | molinillo (0.8.0)
71 | nanaimo (0.3.0)
72 | nap (1.1.0)
73 | netrc (0.11.0)
74 | public_suffix (4.0.7)
75 | rexml (3.2.5)
76 | ruby-macho (2.5.1)
77 | typhoeus (1.4.0)
78 | ethon (>= 0.9.0)
79 | tzinfo (2.0.5)
80 | concurrent-ruby (~> 1.0)
81 | xcodeproj (1.22.0)
82 | CFPropertyList (>= 2.3.3, < 4.0)
83 | atomos (~> 0.1.3)
84 | claide (>= 1.0.2, < 2.0)
85 | colored2 (~> 3.1)
86 | nanaimo (~> 0.3.0)
87 | rexml (~> 3.2.4)
88 | zeitwerk (2.6.0)
89 |
90 | PLATFORMS
91 | ruby
92 |
93 | DEPENDENCIES
94 | cocoapods (~> 1.11, >= 1.11.2)
95 |
96 | RUBY VERSION
97 | ruby 2.7.6p219
98 |
99 | BUNDLED WITH
100 | 2.1.4
101 |
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "launcher-20@2x.png",
5 | "idiom" : "iphone",
6 | "scale" : "2x",
7 | "size" : "20x20"
8 | },
9 | {
10 | "filename" : "launcher-20@3x.png",
11 | "idiom" : "iphone",
12 | "scale" : "3x",
13 | "size" : "20x20"
14 | },
15 | {
16 | "filename" : "launcher-29@2x.png",
17 | "idiom" : "iphone",
18 | "scale" : "2x",
19 | "size" : "29x29"
20 | },
21 | {
22 | "filename" : "launcher-29@3x.png",
23 | "idiom" : "iphone",
24 | "scale" : "3x",
25 | "size" : "29x29"
26 | },
27 | {
28 | "filename" : "launcher-40@2x.png",
29 | "idiom" : "iphone",
30 | "scale" : "2x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "filename" : "launcher-40@3x.png",
35 | "idiom" : "iphone",
36 | "scale" : "3x",
37 | "size" : "40x40"
38 | },
39 | {
40 | "filename" : "launcher-60@2x.png",
41 | "idiom" : "iphone",
42 | "scale" : "2x",
43 | "size" : "60x60"
44 | },
45 | {
46 | "filename" : "launcher-60@3x.png",
47 | "idiom" : "iphone",
48 | "scale" : "3x",
49 | "size" : "60x60"
50 | },
51 | {
52 | "filename" : "launcher-20.png",
53 | "idiom" : "ipad",
54 | "scale" : "1x",
55 | "size" : "20x20"
56 | },
57 | {
58 | "filename" : "launcher-20@2x.png",
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "20x20"
62 | },
63 | {
64 | "filename" : "launcher-29.png",
65 | "idiom" : "ipad",
66 | "scale" : "1x",
67 | "size" : "29x29"
68 | },
69 | {
70 | "filename" : "launcher-29@2x.png",
71 | "idiom" : "ipad",
72 | "scale" : "2x",
73 | "size" : "29x29"
74 | },
75 | {
76 | "filename" : "launcher-40.png",
77 | "idiom" : "ipad",
78 | "scale" : "1x",
79 | "size" : "40x40"
80 | },
81 | {
82 | "filename" : "launcher-40@2x.png",
83 | "idiom" : "ipad",
84 | "scale" : "2x",
85 | "size" : "40x40"
86 | },
87 | {
88 | "filename" : "launcher-76.png",
89 | "idiom" : "ipad",
90 | "scale" : "1x",
91 | "size" : "76x76"
92 | },
93 | {
94 | "filename" : "launcher-76@2x.png",
95 | "idiom" : "ipad",
96 | "scale" : "2x",
97 | "size" : "76x76"
98 | },
99 | {
100 | "filename" : "launcher-83.5@2x.png",
101 | "idiom" : "ipad",
102 | "scale" : "2x",
103 | "size" : "83.5x83.5"
104 | },
105 | {
106 | "filename" : "launcher-1024.png",
107 | "idiom" : "ios-marketing",
108 | "scale" : "1x",
109 | "size" : "1024x1024"
110 | }
111 | ],
112 | "info" : {
113 | "author" : "xcode",
114 | "version" : 1
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/docs/simulation.md:
--------------------------------------------------------------------------------
1 | # Simulation
2 | This application comes with a simulation feature that allows a complete experience without a physical BLE device or a real connection to IoT Central. Due to their limitations, this is a good option when testing on Android or iOS simulators.
3 |
4 | ## Simulate BLE device
5 | Two types of simulated devices are available in the application: "Smart Knee Brace" and "Smart Vitals Patch". This models reflect default models in the Azure IoT Central CPM application template (read more on Continuous Patient Monitoring [here](https://docs.microsoft.com/en-gb/azure/iot-central/healthcare/overview-iot-central-healthcare#what-is-continuous-patient-monitoring-template)).
6 |
7 | Both Knee Brace and Vitals Patch simulated devices send out all available telemetry items, however the CPM application template only shows some of them by default (Device Temperature and Battery Level).
8 | You can enable/disable items to be shown in IoT Central from the "Device templates" tab.
9 |
10 | 
11 | 
12 |
13 | Either add/remove items from the available tile as shown above or create new tiles.
14 | More details available in [official documentation.](https://docs.microsoft.com/en-gb/azure/iot-central/core/howto-set-up-template).
15 |
16 |
17 | ### Limitations
18 | The current version of the application doesn't support device re-mapping after switching between different simulated device models.
19 | This means that if a simulated device has been associated through credentials with a device in IoT Central and the user goes back selecting another simulated device of different type, a new device will not be created in IoT Central and data will not be available.
20 | We suggest you restart the application and generate new credentials to create/associate a different device in IoT Central.
21 |
22 | Possible scenarios:
23 | - Different templates (not working):
24 | 1. User generates credentials for a "Smart Knee Brace" device in Central.
25 | 2. User selects a "Smart Knee Brace" device in the mobile application.
26 | 3. Data starts flowing.
27 | 4. User goes back and selects a simulated "Smart Vitals Patch" device in the mobile application.
28 | 5. Data does not show in IoT Central (besides Device Temperature and Battery Level)
29 | - Same template (working):
30 | 1. User generates credentials for a "Smart Knee Brace" device in Central.
31 | 2. User selects a "Smart Knee Brace" device in the mobile application.
32 | 3. Data starts flowing.
33 | 4. User goes back and selects another simulated "Smart Knee Brace" device in the mobile application.
34 | 5. Data shows in IoT Central in the same device
35 |
36 |
37 |
38 | ## Simulate IoT Central connection
39 | If you don't have an IoT Central application, network is not available or simply want to see data in mobile application but not sending any telemetry out, you can skip connection to IoT Central by selecting "Use simulated code" in either QR code or numeric code screens.
40 |
41 | 
42 | 
43 |
44 | Since mobile application is not connected to any device in IoT Central, you can change device at any time during application run.
45 |
46 |
47 |
--------------------------------------------------------------------------------
/ios/cpm/AppDelegate.mm:
--------------------------------------------------------------------------------
1 | #import "AppDelegate.h"
2 | #import
3 | #import
4 | #import
5 | #import
6 | #if RCT_NEW_ARCH_ENABLED
7 | #import
8 | #import
9 | #import
10 | #import
11 | #import
12 | #import
13 | #import
14 | static NSString *const kRNConcurrentRoot = @"concurrentRoot";
15 | @interface AppDelegate () {
16 | RCTTurboModuleManager *_turboModuleManager;
17 | RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
18 | std::shared_ptr _reactNativeConfig;
19 | facebook::react::ContextContainer::Shared _contextContainer;
20 | }
21 | @end
22 | #endif
23 | @implementation AppDelegate
24 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
25 | {
26 | RCTAppSetupPrepareApp(application);
27 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
28 | #if RCT_NEW_ARCH_ENABLED
29 | _contextContainer = std::make_shared();
30 | _reactNativeConfig = std::make_shared();
31 | _contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
32 | _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
33 | bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
34 | #endif
35 | NSDictionary *initProps = [self prepareInitialProps];
36 | UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"cpm", initProps);
37 | if (@available(iOS 13.0, *)) {
38 | rootView.backgroundColor = [UIColor systemBackgroundColor];
39 | } else {
40 | rootView.backgroundColor = [UIColor whiteColor];
41 | }
42 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
43 | UIViewController *rootViewController = [UIViewController new];
44 | rootViewController.view = rootView;
45 | self.window.rootViewController = rootViewController;
46 | [self.window makeKeyAndVisible];
47 | return YES;
48 | }
49 | /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
50 | ///
51 | /// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
52 | /// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
53 | /// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
54 | - (BOOL)concurrentRootEnabled
55 | {
56 | // Switch this bool to turn on and off the concurrent root
57 | return true;
58 | }
59 | - (NSDictionary *)prepareInitialProps
60 | {
61 | NSMutableDictionary *initProps = [NSMutableDictionary new];
62 |
63 | return initProps;
64 | }
65 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
66 | {
67 | #if DEBUG
68 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
69 | #else
70 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
71 | #endif
72 | }
73 |
74 | @end
--------------------------------------------------------------------------------
/android/app/src/main/java/com/cpm/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.cpm;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import com.facebook.react.PackageList;
6 | import com.facebook.react.ReactApplication;
7 | import com.facebook.react.ReactInstanceManager;
8 | import com.facebook.react.ReactNativeHost;
9 | import com.facebook.react.ReactPackage;
10 | import com.facebook.react.config.ReactFeatureFlags;
11 | import com.facebook.soloader.SoLoader;
12 | import java.lang.reflect.InvocationTargetException;
13 | import java.util.List;
14 | import com.facebook.react.bridge.JSIModulePackage; // https://github.com/facebook/react-native/issues/32111
15 | import com.swmansion.reanimated.ReanimatedJSIModulePackage; // https://github.com/facebook/react-native/issues/32111
16 |
17 | public class MainApplication extends Application implements ReactApplication {
18 |
19 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
20 | @Override
21 | public boolean getUseDeveloperSupport() {
22 | return BuildConfig.DEBUG;
23 | }
24 |
25 | @Override
26 | protected List getPackages() {
27 | @SuppressWarnings("UnnecessaryLocalVariable")
28 | List packages = new PackageList(this).getPackages();
29 | // Packages that cannot be autolinked yet can be added manually here, for
30 | // example:
31 | // packages.add(new MyReactNativePackage());
32 | return packages;
33 | }
34 |
35 | @Override
36 | protected String getJSMainModuleName() {
37 | return "index";
38 | }
39 |
40 | @Override
41 | protected JSIModulePackage getJSIModulePackage() {
42 | return new ReanimatedJSIModulePackage();
43 | }
44 |
45 | };
46 |
47 | @Override
48 | public ReactNativeHost getReactNativeHost() {
49 | return mReactNativeHost;
50 | }
51 |
52 | @Override
53 | public void onCreate() {
54 | super.onCreate();
55 | SoLoader.init(this, /* native exopackage */ false);
56 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
57 | }
58 |
59 | /**
60 | * Loads Flipper in React Native templates. Call this in the onCreate method
61 | * with something like initializeFlipper(this,
62 | * getReactNativeHost().getReactInstanceManager());
63 | *
64 | * @param context
65 | * @param reactInstanceManager
66 | */
67 | private static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
68 | if (BuildConfig.DEBUG) {
69 | try {
70 | /*
71 | * We use reflection here to pick up the class that initializes Flipper, since
72 | * Flipper library is not available in release mode
73 | */
74 | Class> aClass = Class.forName("com.cpm.ReactNativeFlipper");
75 | aClass.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class).invoke(null, context,
76 | reactInstanceManager);
77 | } catch (ClassNotFoundException e) {
78 | e.printStackTrace();
79 | } catch (NoSuchMethodException e) {
80 | e.printStackTrace();
81 | } catch (IllegalAccessException e) {
82 | e.printStackTrace();
83 | } catch (InvocationTargetException e) {
84 | e.printStackTrace();
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cpm",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "android": "react-native run-android",
7 | "ios": "react-native run-ios",
8 | "start": "react-native start",
9 | "test": "jest",
10 | "lint": "tsc --noEmit && eslint --ext .js,.jsx,.ts,.tsx ./src",
11 | "format": "prettier --write src/",
12 | "build": "npm run format && npm run lint && tsc",
13 | "podinstall": "node podinstall.js",
14 | "postinstall": "npm run prepackage && patch-package",
15 | "prepackage": "node pre-packager.js"
16 | },
17 | "dependencies": {
18 | "@react-native-community/masked-view": "^0.1.10",
19 | "@react-navigation/drawer": "^6.1.4",
20 | "@react-navigation/material-bottom-tabs": "^6.0.5",
21 | "@react-navigation/native": "^6.0.10",
22 | "@react-navigation/native-stack": "^6.6.2",
23 | "buffer": "^5.6.0",
24 | "deprecated-react-native-prop-types": "^2.3.0",
25 | "events": "^3.2.0",
26 | "patch-package": "^6.4.7",
27 | "react": "^18.0.0",
28 | "react-native": "^0.69.1",
29 | "react-native-azure-iotcentral-client": "1.1.7",
30 | "react-native-ble-plx": "^2.0.3",
31 | "react-native-camera": "^4.1.1",
32 | "react-native-charts-wrapper": "^0.5.7",
33 | "react-native-gesture-handler": "^2.3.0",
34 | "react-native-get-random-values": "^1.4.0",
35 | "react-native-google-fit": "^0.18.2",
36 | "react-native-health": "^1.12.0",
37 | "react-native-linear-gradient": "^2.5.6",
38 | "react-native-paper": "^4.9.2",
39 | "react-native-permissions": "^3.3.0",
40 | "react-native-progress": "^5.0.0",
41 | "react-native-qrcode-scanner": "^1.3.1",
42 | "react-native-reanimated": "^2.9.1",
43 | "react-native-safe-area-context": "^4.2.5",
44 | "react-native-screens": "^3.13.1",
45 | "react-native-svg": "^12.1.1",
46 | "react-native-vector-icons": "^9.0.0"
47 | },
48 | "devDependencies": {
49 | "@babel/core": "^7.12.9",
50 | "@babel/runtime": "^7.12.5",
51 | "@react-native-community/eslint-config": "^3.0.0",
52 | "@types/react": "^17.0.19",
53 | "@types/react-native": "^0.64.13",
54 | "@types/react-native-charts-wrapper": "^0.5.0",
55 | "@types/react-native-linear-gradient": "^2.4.0",
56 | "@types/react-native-vector-icons": "^6.4.5",
57 | "@typescript-eslint/eslint-plugin": "^4.30.0",
58 | "@typescript-eslint/parser": "^4.30.0",
59 | "@welldone-software/why-did-you-render": "^4.2.5",
60 | "babel-jest": "^26.6.3",
61 | "babel-plugin-module-resolver": "^4.1.0",
62 | "eslint": "^7.32.0",
63 | "eslint-plugin-react": "^7.25.1",
64 | "eslint-plugin-react-hooks": "^4.2.0",
65 | "fs": "^0.0.1-security",
66 | "jest": "^26.6.3",
67 | "metro-react-native-babel-preset": "^0.70.3",
68 | "prettier": "^2.3.2",
69 | "react-native-codegen": "0.0.7",
70 | "react-native-svg-transformer": "^1.0.0",
71 | "react-test-renderer": "^18.0.0",
72 | "typescript": "^4.4.2"
73 | },
74 | "jest": {
75 | "preset": "react-native",
76 | "transform": {
77 | "^.+\\.js$": "/node_modules/react-native/jest/preprocessor.js",
78 | "\\.(ts|tsx)$": "ts-jest"
79 | },
80 | "globals": {
81 | "ts-jest": {
82 | "tsConfig": "tsconfig.jest.json"
83 | }
84 | },
85 | "moduleFileExtensions": [
86 | "ts",
87 | "tsx",
88 | "js"
89 | ],
90 | "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$"
91 | },
92 | "overrides": {
93 | "react-native-google-fit": {
94 | "moment": "2.29.4"
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/ios/cpm.xcodeproj/xcshareddata/xcschemes/cpm.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/ios/cpm/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "extent" : "full-screen",
5 | "filename" : "LaunchImage-1242x2688.png",
6 | "idiom" : "iphone",
7 | "minimum-system-version" : "12.0",
8 | "orientation" : "portrait",
9 | "scale" : "3x",
10 | "subtype" : "2688h"
11 | },
12 | {
13 | "extent" : "full-screen",
14 | "filename" : "LaunchImage-2688x1242.png",
15 | "idiom" : "iphone",
16 | "minimum-system-version" : "12.0",
17 | "orientation" : "landscape",
18 | "scale" : "3x",
19 | "subtype" : "2688h"
20 | },
21 | {
22 | "extent" : "full-screen",
23 | "filename" : "LaunchImage-828x1792.png",
24 | "idiom" : "iphone",
25 | "minimum-system-version" : "12.0",
26 | "orientation" : "portrait",
27 | "scale" : "2x",
28 | "subtype" : "1792h"
29 | },
30 | {
31 | "extent" : "full-screen",
32 | "filename" : "LaunchImage-1792x828.png",
33 | "idiom" : "iphone",
34 | "minimum-system-version" : "12.0",
35 | "orientation" : "landscape",
36 | "scale" : "2x",
37 | "subtype" : "1792h"
38 | },
39 | {
40 | "extent" : "full-screen",
41 | "filename" : "LaunchImage-1125x2436.png",
42 | "idiom" : "iphone",
43 | "minimum-system-version" : "11.0",
44 | "orientation" : "portrait",
45 | "scale" : "3x",
46 | "subtype" : "2436h"
47 | },
48 | {
49 | "extent" : "full-screen",
50 | "filename" : "LaunchImage-2436x1125.png",
51 | "idiom" : "iphone",
52 | "minimum-system-version" : "11.0",
53 | "orientation" : "landscape",
54 | "scale" : "3x",
55 | "subtype" : "2436h"
56 | },
57 | {
58 | "extent" : "full-screen",
59 | "filename" : "LaunchImage-1242x2208.png",
60 | "idiom" : "iphone",
61 | "minimum-system-version" : "8.0",
62 | "orientation" : "portrait",
63 | "scale" : "3x",
64 | "subtype" : "736h"
65 | },
66 | {
67 | "extent" : "full-screen",
68 | "filename" : "LaunchImage-2208x1242.png",
69 | "idiom" : "iphone",
70 | "minimum-system-version" : "8.0",
71 | "orientation" : "landscape",
72 | "scale" : "3x",
73 | "subtype" : "736h"
74 | },
75 | {
76 | "extent" : "full-screen",
77 | "filename" : "LaunchImage-750x1334.png",
78 | "idiom" : "iphone",
79 | "minimum-system-version" : "8.0",
80 | "orientation" : "portrait",
81 | "scale" : "2x",
82 | "subtype" : "667h"
83 | },
84 | {
85 | "extent" : "full-screen",
86 | "filename" : "LaunchImage-640x960.png",
87 | "idiom" : "iphone",
88 | "minimum-system-version" : "7.0",
89 | "orientation" : "portrait",
90 | "scale" : "2x"
91 | },
92 | {
93 | "extent" : "full-screen",
94 | "filename" : "LaunchImage-640x1136.png",
95 | "idiom" : "iphone",
96 | "minimum-system-version" : "7.0",
97 | "orientation" : "portrait",
98 | "scale" : "2x",
99 | "subtype" : "retina4"
100 | },
101 | {
102 | "extent" : "full-screen",
103 | "filename" : "LaunchImage-320x480.png",
104 | "idiom" : "iphone",
105 | "orientation" : "portrait",
106 | "scale" : "1x"
107 | },
108 | {
109 | "extent" : "full-screen",
110 | "filename" : "LaunchImage-640x960-1.png",
111 | "idiom" : "iphone",
112 | "orientation" : "portrait",
113 | "scale" : "2x"
114 | },
115 | {
116 | "extent" : "full-screen",
117 | "filename" : "LaunchImage-640x1136-1.png",
118 | "idiom" : "iphone",
119 | "orientation" : "portrait",
120 | "scale" : "2x",
121 | "subtype" : "retina4"
122 | }
123 | ],
124 | "info" : {
125 | "author" : "xcode",
126 | "version" : 1
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/components/insightDrawer.tsx:
--------------------------------------------------------------------------------
1 | import React, {useContext} from 'react';
2 | import {SafeAreaView, View, StyleSheet, Image} from 'react-native';
3 | import {Name, Headline, Detail, Item} from './typography';
4 | import {Switch, IconButton, Divider} from 'react-native-paper';
5 | import {ConfigContext} from '../contexts/config';
6 | import {ScrollView} from 'react-native-gesture-handler';
7 | import {AppleHealthManager} from '../health/appleHealth';
8 | import {GoogleFitManager} from '../health/googleFit';
9 | import {Screens} from 'types';
10 | interface DrawerProps {
11 | sourceSide: 'left' | 'right';
12 | currentScreen: string;
13 | close(): void;
14 | }
15 |
16 | /**
17 | * This navigator doesn't actually navigate to any screen.
18 | * It is used to have a drawer for chart management by levereging on what react-navigation already offers (gestures, styles...).
19 | * @param props
20 | */
21 | export default function InsightDrawer(props: DrawerProps) {
22 | const {state, dispatch} = useContext(ConfigContext);
23 | const {currentScreen} = props;
24 | let icon: any = 'bluetooth';
25 |
26 | if (state.healthManager) {
27 | if (state.healthManager instanceof AppleHealthManager) {
28 | icon = ({size}: {size: number}) => (
29 |
33 | );
34 | } else if (state.healthManager instanceof GoogleFitManager) {
35 | icon = ({size}: {size: number}) => (
36 |
40 | );
41 | }
42 | }
43 |
44 | if (
45 | !state.device ||
46 | !state.device.items ||
47 | currentScreen !== Screens.INSIGHT_SCREEN
48 | ) {
49 | return null;
50 | }
51 | return (
52 |
53 |
54 |
59 |
60 |
61 | Sync options
62 | {
64 | props.close();
65 | }}
66 | icon="chevron-left"
67 | style={{marginLeft: 40, marginTop: -5}}
68 | />
69 |
70 | Which kind of device data would you like to show?
71 |
72 |
73 | {state.device.name}
74 |
75 |
76 | {state.device.items.map((item, index) => (
77 |
78 | - {item.name}
79 | {/* pass extra parameter to the ref in order to process and enable only valid ids */}
80 | {
84 | await item.enable(current);
85 | // dispatch is needed to update state of device items
86 | dispatch({
87 | type: 'HEALTH_CONNECT',
88 | payload: state.device,
89 | });
90 | }}
91 | />
92 |
93 | ))}
94 |
95 |
96 | );
97 | }
98 |
99 | const style = StyleSheet.create({
100 | container: {
101 | flex: 1,
102 | marginLeft: 20,
103 | },
104 | header: {
105 | marginTop: 30,
106 | flexDirection: 'row',
107 | },
108 | itemContainer: {
109 | flexDirection: 'row',
110 | alignItems: 'center',
111 | justifyContent: 'space-between',
112 | padding: 20,
113 | },
114 | });
115 |
--------------------------------------------------------------------------------
/ios/cpm/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/.azuredevops/resign.yml:
--------------------------------------------------------------------------------
1 | pool:
2 | vmImage: 'macOS-12'
3 |
4 | name: $(Date:yyyyMMdd)$(Rev:.r)
5 | jobs:
6 | - job: iOS_Release
7 | timeoutInMinutes: 120
8 | variables:
9 | rootPath: '$(System.DefaultWorkingDirectory)'
10 | agentName: $[ dependencies.Setup.outputs['passOutput.AgentName'] ]
11 | outputPath: '$(rootPath)/output'
12 | exportPath: '$(rootPath)/output/ios_unsigned'
13 | zipToSign: '$(exportPath)/cpm.zip'
14 | signedExtractedPath: '$(exportPath)/signed'
15 | steps:
16 | - task: DownloadBuildArtifacts@0
17 | inputs:
18 | buildType: 'specific' # Options: current, specific
19 | project: 'One' # Required when buildType == Specific
20 | pipeline: '216276' # Required when buildType == Specific
21 | #specificBuildWithTriggering: false # Optional
22 | buildVersionToDownload: 'specific' # Required when buildType == Specific. Options: latest, latestFromBranch, specific
23 | allowPartiallySucceededBuilds: true # Optional
24 | #branchName: 'refs/heads/master' # Required when buildType == Specific && BuildVersionToDownload == LatestFromBranch
25 | buildId: '55245310' # Required when buildType == Specific && BuildVersionToDownload == Specific
26 | #tags: # Optional
27 | downloadType: 'single' # Choose whether to download a single artifact or all artifacts of a specific build. Options: single, specific
28 | artifactName: 'ios_unsigned' # Required when downloadType == Single
29 | #itemPattern: '**' # Optional
30 | downloadPath: '$(outputPath)'
31 | #cleanDestinationFolder: false # Optional
32 | #parallelizationLimit: '8' # Optional
33 | #extractTars: false # Optional
34 |
35 | # - task: DeleteFiles@1
36 | # inputs:
37 | # SourceFolder: '$(archivePath)'
38 | # Contents: 'ExportOptions.plist'
39 | #RemoveSourceFolder: # Optional
40 | - task: DownloadSecureFile@1
41 | displayName: 'Download distribution profile from Azure secure files storage'
42 | inputs:
43 | secureFile: '$(Distribution_Provisioning_Profile)'
44 | retryCount: 5
45 |
46 | - task: CopyFiles@2
47 | displayName: 'Copy distribution provisioning profile'
48 | inputs:
49 | SourceFolder: '$(Agent.TempDirectory)'
50 | Contents: '$(Distribution_Provisioning_Profile)'
51 | TargetFolder: '$(exportPath)'
52 | flattenFolders: true
53 |
54 | - task: CopyFiles@2
55 | displayName: 'Copy ExportOptions'
56 | inputs:
57 | SourceFolder: '$(rootPath)'
58 | Contents: 'ExportOptions.plist'
59 | TargetFolder: '$(exportPath)'
60 | flattenFolders: true
61 |
62 | - task: ArchiveFiles@2
63 | displayName: 'Create zip for signing'
64 | inputs:
65 | rootFolderOrFile: '$(exportPath)'
66 | includeRootFolder: false
67 | archiveFile: '$(zipToSign)'
68 |
69 | - task: UseDotNet@2
70 | displayName: 'Use .NET Core sdk(temporary)'
71 | inputs:
72 | packageType: sdk
73 | version: 2.1.x
74 | installationPath: $(Agent.ToolsDirectory)/dotnet
75 |
76 | - task: EsrpCodeSigning@1
77 | displayName: 'Sign build'
78 | inputs:
79 | ConnectedServiceName: 'IoT PnP PaaD'
80 | FolderPath: '$(exportPath)'
81 | Pattern: '*.zip'
82 | signConfigType: 'inlineSignParams'
83 | inlineOperation: |
84 | [
85 | {
86 | "KeyCode" : "CP-464234-Apple",
87 | "OperationCode" : "iOSAppSign",
88 | "Parameters" : {},
89 | "ToolName" : "sign",
90 | "ToolVersion" : "1.0"
91 | }
92 | ]
93 | SessionTimeout: '60'
94 | MaxConcurrency: '50'
95 | MaxRetryAttempts: '5'
96 |
97 | - task: ExtractFiles@1
98 | displayName: 'Extract signed build'
99 | inputs:
100 | archiveFilePatterns: '$(zipToSign)'
101 | destinationFolder: '$(signedExtractedPath)'
102 |
103 | - task: PublishBuildArtifacts@1
104 | displayName: 'Publish Signed Ipa'
105 | inputs:
106 | PathtoPublish: '$(signedExtractedPath)'
107 | ArtifactName: 'ios_signed'
108 | publishLocation: 'Container'
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/src/assets/logo_title.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------