├── .watchmanconfig
├── .gitattributes
├── .babelrc
├── app.json
├── assets
├── back.png
├── logo.png
├── back@2x.png
├── back@3x.png
├── close.png
├── loginID.png
├── loginPW.png
├── logo@2x.png
├── logo@3x.png
├── splash.jpg
├── vitalON.png
├── calendar.png
├── close@2x.png
├── close@3x.png
├── profileON.png
├── symptomON.png
├── vitalOFF.png
├── calendar@2x.png
├── calendar@3x.png
├── loginID@2x.png
├── loginID@3x.png
├── loginPW@2x.png
├── loginPW@3x.png
├── profileOFF.png
├── profileON@2x.png
├── profileON@3x.png
├── symptomOFF.png
├── symptomON@2x.png
├── symptomON@3x.png
├── vitalOFF@2x.png
├── vitalOFF@3x.png
├── vitalON@2x.png
├── vitalON@3x.png
├── bluetoothSync.png
├── calendarScroll.png
├── profileOFF@2x.png
├── profileOFF@3x.png
├── symptomOFF@2x.png
├── symptomOFF@3x.png
├── bluetoothSync@2x.png
├── bluetoothSync@3x.png
├── calendarScroll@2x.png
└── calendarScroll@3x.png
├── README
├── Landing.jpg
└── Pages.jpg
├── android
├── app
│ ├── 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
│ │ │ ├── assets
│ │ │ └── fonts
│ │ │ │ ├── Entypo.ttf
│ │ │ │ ├── Feather.ttf
│ │ │ │ ├── Zocial.ttf
│ │ │ │ ├── EvilIcons.ttf
│ │ │ │ ├── Foundation.ttf
│ │ │ │ ├── Ionicons.ttf
│ │ │ │ ├── Octicons.ttf
│ │ │ │ ├── FontAwesome.ttf
│ │ │ │ ├── MaterialIcons.ttf
│ │ │ │ ├── SimpleLineIcons.ttf
│ │ │ │ ├── FontAwesome5_Brands.ttf
│ │ │ │ ├── FontAwesome5_Regular.ttf
│ │ │ │ ├── FontAwesome5_Solid.ttf
│ │ │ │ └── MaterialCommunityIcons.ttf
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── signalus
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── MainApplication.java
│ │ │ └── AndroidManifest.xml
│ ├── proguard-rules.pro
│ ├── BUCK
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── keystores
│ ├── debug.keystore.properties
│ └── BUCK
├── gradle.properties
├── build.gradle
├── settings.gradle
├── gradlew.bat
└── gradlew
├── ios
├── Signalus
│ ├── Images.xcassets
│ │ ├── Contents.json
│ │ ├── Image.imageset
│ │ │ ├── logo.png
│ │ │ ├── logo@2x.png
│ │ │ ├── logo@3x.png
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── 앱 아이콘 배수 40.png
│ │ │ ├── 앱 아이콘 배수 58.png
│ │ │ ├── 앱 아이콘 배수 60.png
│ │ │ ├── 앱 아이콘 배수 80.png
│ │ │ ├── 앱 아이콘 배수 87.png
│ │ │ ├── 앱 아이콘 배수 1024.png
│ │ │ ├── 앱 아이콘 배수 120.png
│ │ │ ├── 앱 아이콘 배수 180.png
│ │ │ ├── 앱 아이콘 배수 120-1.png
│ │ │ └── Contents.json
│ ├── AppDelegate.h
│ ├── main.m
│ ├── Info.plist
│ ├── Base.lproj
│ │ └── LaunchScreen.xib
│ └── AppDelegate.m
├── Signalus-Bridging-Header.h
├── ReactNativeBle.swift
├── SignalusTests
│ ├── Info.plist
│ └── SignalusTests.m
├── Signalus-tvOSTests
│ └── Info.plist
├── View.xib
├── Signalus-tvOS
│ └── Info.plist
└── Signalus.xcodeproj
│ └── xcshareddata
│ └── xcschemes
│ ├── Signalus-tvOS.xcscheme
│ └── Signalus.xcscheme
├── .buckconfig
├── index.js
├── src
├── reducers
│ ├── bluetooth
│ │ ├── actionTypes.js
│ │ ├── actions.js
│ │ └── reducer.js
│ ├── index.js
│ ├── auth
│ │ ├── actionTypes.js
│ │ ├── API.js
│ │ ├── reducer.js
│ │ └── actions.js
│ ├── contact
│ │ ├── actionTypes.js
│ │ ├── API.js
│ │ ├── reducer.js
│ │ └── actions.js
│ ├── nav
│ │ ├── actionTypes.js
│ │ └── reducer.js
│ └── symptom
│ │ ├── actionTypes.js
│ │ ├── API.js
│ │ ├── reducer.js
│ │ └── actions.js
├── styles
│ ├── CalendarStyle.js
│ ├── SplashStyle.js
│ ├── SettingStyle.js
│ ├── PickerModal.js
│ ├── SymptomLogStyle.js
│ ├── SymptomDetailPatchStyle.js
│ ├── VitalStyle.js
│ ├── SymptomDetailUserStyle.js
│ ├── SymptomStyle.js
│ ├── ConsentStyle.js
│ ├── RegisterStyle.js
│ ├── SignInStyle.js
│ ├── ProfileStyle.js
│ └── BluetoothStyle.js
├── constants
│ ├── dimens.js
│ ├── model.js
│ ├── color.js
│ ├── utils.js
│ └── string.js
├── components
│ ├── CustomHeaderButton.js
│ ├── CustomFAB.js
│ ├── CustomSimpleTouchableText.js
│ ├── CustomDevicesItem.js
│ ├── CustomFilledButton.js
│ ├── CustomBorderedButton.js
│ ├── CustomChart.js
│ ├── CustomContactItem.js
│ ├── CustomSymptomCheckBox.js
│ ├── CustomSymptomItem.js
│ ├── CustomCheckBox.js
│ ├── CustomFormPicker.js
│ ├── CustomHealthStatusBar.js
│ ├── CustomPicker.js
│ └── CustomFormInput.js
├── navigators
│ ├── AppNavigator.js
│ ├── RootNavigator.js
│ └── MainTabNavigator.js
└── screens
│ ├── SymptomDetailUserScreen.js
│ ├── ConsentHTMLScreen.js
│ ├── CalendarScreen.js
│ ├── SplashScreen.js
│ ├── SymptomDetailPatchScreen.js
│ ├── ConsentScreen.js
│ ├── SymptomScreen.js
│ ├── SignInScreen.js
│ ├── SettingScreen.js
│ ├── BluetoothScreen.js
│ └── SymptomLogScreen.js
├── App.js
├── .gitignore
├── package.json
├── README.md
└── .flowconfig
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-native"]
3 | }
4 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Signalus",
3 | "displayName": "Signalus"
4 | }
--------------------------------------------------------------------------------
/assets/back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/back.png
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/logo.png
--------------------------------------------------------------------------------
/README/Landing.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/README/Landing.jpg
--------------------------------------------------------------------------------
/README/Pages.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/README/Pages.jpg
--------------------------------------------------------------------------------
/assets/back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/back@2x.png
--------------------------------------------------------------------------------
/assets/back@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/back@3x.png
--------------------------------------------------------------------------------
/assets/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/close.png
--------------------------------------------------------------------------------
/assets/loginID.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/loginID.png
--------------------------------------------------------------------------------
/assets/loginPW.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/loginPW.png
--------------------------------------------------------------------------------
/assets/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/logo@2x.png
--------------------------------------------------------------------------------
/assets/logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/logo@3x.png
--------------------------------------------------------------------------------
/assets/splash.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/splash.jpg
--------------------------------------------------------------------------------
/assets/vitalON.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/vitalON.png
--------------------------------------------------------------------------------
/assets/calendar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/calendar.png
--------------------------------------------------------------------------------
/assets/close@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/close@2x.png
--------------------------------------------------------------------------------
/assets/close@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/close@3x.png
--------------------------------------------------------------------------------
/assets/profileON.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/profileON.png
--------------------------------------------------------------------------------
/assets/symptomON.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/symptomON.png
--------------------------------------------------------------------------------
/assets/vitalOFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/vitalOFF.png
--------------------------------------------------------------------------------
/assets/calendar@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/calendar@2x.png
--------------------------------------------------------------------------------
/assets/calendar@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/calendar@3x.png
--------------------------------------------------------------------------------
/assets/loginID@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/loginID@2x.png
--------------------------------------------------------------------------------
/assets/loginID@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/loginID@3x.png
--------------------------------------------------------------------------------
/assets/loginPW@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/loginPW@2x.png
--------------------------------------------------------------------------------
/assets/loginPW@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/loginPW@3x.png
--------------------------------------------------------------------------------
/assets/profileOFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/profileOFF.png
--------------------------------------------------------------------------------
/assets/profileON@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/profileON@2x.png
--------------------------------------------------------------------------------
/assets/profileON@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/profileON@3x.png
--------------------------------------------------------------------------------
/assets/symptomOFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/symptomOFF.png
--------------------------------------------------------------------------------
/assets/symptomON@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/symptomON@2x.png
--------------------------------------------------------------------------------
/assets/symptomON@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/symptomON@3x.png
--------------------------------------------------------------------------------
/assets/vitalOFF@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/vitalOFF@2x.png
--------------------------------------------------------------------------------
/assets/vitalOFF@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/vitalOFF@3x.png
--------------------------------------------------------------------------------
/assets/vitalON@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/vitalON@2x.png
--------------------------------------------------------------------------------
/assets/vitalON@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/vitalON@3x.png
--------------------------------------------------------------------------------
/assets/bluetoothSync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/bluetoothSync.png
--------------------------------------------------------------------------------
/assets/calendarScroll.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/calendarScroll.png
--------------------------------------------------------------------------------
/assets/profileOFF@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/profileOFF@2x.png
--------------------------------------------------------------------------------
/assets/profileOFF@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/profileOFF@3x.png
--------------------------------------------------------------------------------
/assets/symptomOFF@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/symptomOFF@2x.png
--------------------------------------------------------------------------------
/assets/symptomOFF@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/symptomOFF@3x.png
--------------------------------------------------------------------------------
/assets/bluetoothSync@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/bluetoothSync@2x.png
--------------------------------------------------------------------------------
/assets/bluetoothSync@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/bluetoothSync@3x.png
--------------------------------------------------------------------------------
/assets/calendarScroll@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/calendarScroll@2x.png
--------------------------------------------------------------------------------
/assets/calendarScroll@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/assets/calendarScroll@3x.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Signalus
3 |
4 |
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Entypo.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/Entypo.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Feather.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/Feather.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Zocial.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/Zocial.ttf
--------------------------------------------------------------------------------
/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/EvilIcons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/EvilIcons.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Foundation.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/Foundation.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Ionicons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/Ionicons.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Octicons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/Octicons.ttf
--------------------------------------------------------------------------------
/ios/Signalus-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 |
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/FontAwesome.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/FontAwesome.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/MaterialIcons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/MaterialIcons.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/SimpleLineIcons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/SimpleLineIcons.ttf
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/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/TaeJoongYoon/Signalus/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/TaeJoongYoon/Signalus/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/Image.imageset/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/Image.imageset/logo.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/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/TaeJoongYoon/Signalus/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/keystores/debug.keystore.properties:
--------------------------------------------------------------------------------
1 | key.store=debug.keystore
2 | key.alias=androiddebugkey
3 | key.store.password=android
4 | key.alias.password=android
5 |
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/Image.imageset/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/Image.imageset/logo@2x.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/Image.imageset/logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/Image.imageset/logo@3x.png
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/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/TaeJoongYoon/Signalus/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/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/TaeJoongYoon/Signalus/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 40.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 58.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 60.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 80.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 87.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 1024.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 120.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 180.png
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 120-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaeJoongYoon/Signalus/HEAD/ios/Signalus/Images.xcassets/AppIcon.appiconset/앱 아이콘 배수 120-1.png
--------------------------------------------------------------------------------
/android/keystores/BUCK:
--------------------------------------------------------------------------------
1 | keystore(
2 | name = "debug",
3 | properties = "debug.keystore.properties",
4 | store = "debug.keystore",
5 | visibility = [
6 | "PUBLIC",
7 | ],
8 | )
9 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /** @format */
2 |
3 | import {AppRegistry} from 'react-native';
4 | import App from './App';
5 | import {name as appName} from './app.json';
6 | AppRegistry.registerComponent(appName, () => App);
7 |
--------------------------------------------------------------------------------
/ios/ReactNativeBle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReactNativeBle.swift
3 | // Signalus
4 | //
5 | // Created by Tae joong Yoon on 25/08/2018.
6 | // Copyright © 2018 Facebook. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-all.zip
6 |
--------------------------------------------------------------------------------
/src/reducers/bluetooth/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const CONNECT_PENDING = 'CONNECT_PENDING';
2 | export const CONNECT_SUCCESS = 'CONNECT_SUCCESS';
3 | export const CONNECT_FAILURE = 'CONNECT_FAILURE';
4 |
5 | export const DISCONNECT_PENDING = 'DISCONNECT_PENDING';
6 | export const DISCONNECT_SUCCESS = 'DISCONNECT_SUCCESS';
7 | export const DISCONNECT_FAILURE = 'DISCONNECT_FAILURE';
8 |
--------------------------------------------------------------------------------
/src/styles/CalendarStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { WIDTH, HEIGHT } from '../constants/dimens';
3 | import { backgroundColor } from '../constants/color';
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | flex: 1,
8 | backgroundColor: backgroundColor,
9 | },
10 | calendar: {
11 | },
12 | });
13 |
14 | export default styles;
--------------------------------------------------------------------------------
/ios/Signalus/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
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 |
10 | @interface AppDelegate : UIResponder
11 |
12 | @property (nonatomic, strong) UIWindow *window;
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/src/styles/SplashStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { WIDTH, HEIGHT } from '../constants/dimens';
3 |
4 | const styles = StyleSheet.create({
5 | container: {
6 | flex: 1,
7 | justifyContent: 'center',
8 | alignItems: 'center',
9 | },
10 | image: {
11 | flex:1 ,
12 | width: WIDTH,
13 | height: HEIGHT,
14 | }
15 | });
16 |
17 | export default styles;
--------------------------------------------------------------------------------
/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import auth from './auth/reducer';
3 | import nav from './nav/reducer';
4 | import bluetooth from './bluetooth/reducer';
5 | import contact from './contact/reducer';
6 | import symptom from './symptom/reducer';
7 |
8 | const reducer = combineReducers({
9 | auth,
10 | nav,
11 | bluetooth,
12 | contact,
13 | symptom,
14 | });
15 |
16 | export default reducer;
--------------------------------------------------------------------------------
/ios/Signalus/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
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 |
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/constants/dimens.js:
--------------------------------------------------------------------------------
1 | import { Dimensions } from 'react-native';
2 |
3 | export const WIDTH = Dimensions.get('window').width;
4 | export const HEIGHT = Dimensions.get('window').height;
5 |
6 | export const defaultMinLength = 8;
7 | export const defaultMaxLength = 20;
8 |
9 | export const checkboxSize = 30;
10 |
11 | export const modalOffset = 0;
12 | export const modalDuration = 300;
13 |
14 | export const borderRadius = 10;
15 | export const dividerViewHeight = 10;
--------------------------------------------------------------------------------
/android/app/src/main/java/com/signalus/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.signalus;
2 |
3 | import com.facebook.react.ReactActivity;
4 |
5 | public class MainActivity extends ReactActivity {
6 |
7 | /**
8 | * Returns the name of the main component registered from JavaScript.
9 | * This is used to schedule rendering of the component.
10 | */
11 | @Override
12 | protected String getMainComponentName() {
13 | return "Signalus";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/Image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "filename" : "logo.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "filename" : "logo@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "filename" : "logo@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/src/reducers/auth/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const REGISTER_PENDING = 'REGISTER_PENDING';
2 | export const REGISTER_SUCCESS = 'REGISTER_SUCCESS';
3 | export const REGISTER_FAILURE = 'REGISTER_FAILURE';
4 |
5 | export const SIGNIN_PENDING = 'SIGNIN_PENDING';
6 | export const SIGNIN_SUCCESS = 'SIGNIN_SUCCESS';
7 | export const SIGNIN_FAILURE = 'SIGNIN_FAILURE';
8 |
9 | export const WITHDRAWAL_PENDING = 'WITHDRAWAL_PENDING';
10 | export const WITHDRAWAL_SUCCESS = 'WITHDRAWAL_SUCCESS';
11 | export const WITHDRAWAL_FAILURE = 'WITHDRAWAL_FAILURE';
--------------------------------------------------------------------------------
/src/constants/model.js:
--------------------------------------------------------------------------------
1 | import { ModeAge, ModeSex, ModeHeight, ModeWeight } from './string';
2 |
3 | export const ages = [{value: ModeAge},{value:'10'},{value:'20'},{value:'30'},{value:'40'},{value:'50'},{value:'60'},{value:'70'}];
4 | export const sex = [{value: ModeSex},{value:'F'},{value:'M'}];
5 | export const heights = [{value: ModeHeight},{value:'160'},{value:'165'},{value:'170'},{value:'175'},{value:'180'},{value:'185'},{value:'190'}];
6 | export const weights = [{value: ModeWeight},{value:'45'},{value:'50'},{value:'55'},{value:'60'},{value:'65'},{value:'70'}];
--------------------------------------------------------------------------------
/src/constants/color.js:
--------------------------------------------------------------------------------
1 | export const mainColor = '#1c9bff';
2 | export const highlightColor = '#e9f0f4';
3 | export const placeholderText = '#899ba3';
4 | export const disable = '#dde3e8';
5 | export const divider = '#4b565e';
6 | export const patch = '#72e9ff';
7 |
8 | export const activeTintColor = 'blue';
9 | export const inactiveTintColor = 'gray';
10 | export const backgroundColor = 'white';
11 | export const headerTintColor = 'white';
12 |
13 | export const pickerBackgroundColor = 'white';
14 | export const closeButtonColor = '#027afe';
15 | export const closeButtonBorderColor = '#e2e2e2';
--------------------------------------------------------------------------------
/src/components/CustomHeaderButton.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { TouchableOpacity, Image } from 'react-native';
3 |
4 | class CustomHeaderButton extends Component {
5 | constructor(props){
6 | super(props)
7 | }
8 |
9 | render(){
10 | const { onPress, style, source } = this.props;
11 |
12 | return(
13 |
15 |
19 |
20 | );
21 | }
22 | }
23 |
24 | export default CustomHeaderButton;
--------------------------------------------------------------------------------
/src/reducers/contact/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const CONTACT_REGISTER_PENDING = 'CONTACT_REGISTER_PENDING';
2 | export const CONTACT_REGISTER_SUCCESS = 'CONTACT_REGISTER_SUCCESS';
3 | export const CONTACT_REGISTER_FAILURE = 'CONTACT_REGISTER_FAILURE';
4 |
5 | export const CONTACT_DELETE_PENDING = 'CONTACT_DELETE_PENDING';
6 | export const CONTACT_DELETE_SUCCESS = 'CONTACT_DELETE_SUCCESS';
7 | export const CONTACT_DELETE_FAILURE = 'CONTACT_DELETE_FAILURE';
8 |
9 | export const CONTACT_GET_PENDING = 'CONTACT_GET_PENDING';
10 | export const CONTACT_GET_SUCCESS = 'CONTACT_GET_SUCCESS';
11 | export const CONTACT_GET_FAILURE = 'CONTACT_GET_FAILURE';
--------------------------------------------------------------------------------
/src/navigators/AppNavigator.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import { reduxifyNavigator, createReactNavigationReduxMiddleware } from 'react-navigation-redux-helpers';
3 |
4 | import RootNavigator from './RootNavigator';
5 |
6 | const middleware = createReactNavigationReduxMiddleware(
7 | 'root',
8 | state => state.nav
9 | );
10 |
11 | const AppWithNavigationState = reduxifyNavigator(RootNavigator, 'root');
12 |
13 | const mapStateToProps = state => ({
14 | state: state.nav,
15 | });
16 |
17 | const AppNavigator = connect(mapStateToProps)(AppWithNavigationState);
18 |
19 | export { RootNavigator, AppNavigator, middleware };
--------------------------------------------------------------------------------
/src/reducers/nav/actionTypes.js:
--------------------------------------------------------------------------------
1 | // SIGNED
2 | export const NOT_SIGNED = 'NOT_SIGNED';
3 | export const ON_CONSENT = 'ON_CONSENT';
4 | export const ON_REGISTER = 'ON_REGISTER';
5 | export const SIGNED = 'SIGNED';
6 | export const SIGNOUT = 'SIGNOUT';
7 |
8 | // BLUETOOTH CONNECTED
9 | export const NOT_CONNECTED = 'NOT_CONNECTED';
10 | export const CONNECTED = 'CONNECTED';
11 |
12 | // MAIN PAGE
13 | export const ON_CALENDAR = 'ON_CALENDAR';
14 | export const ON_LOG = 'ON_LOG';
15 | export const LOGGED = 'LOGGED';
16 | export const ON_DETAIL_PATCH = 'ON_DETAIL_PATCH';
17 | export const ON_DETAIL_USER = 'ON_DETAIL_USER';
18 | export const ON_SETTING = 'ON_SETTING';
--------------------------------------------------------------------------------
/src/components/CustomFAB.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import FAB from 'react-native-fab';
3 |
4 | class CustomFAB extends Component {
5 | constructor(props){
6 | super(props)
7 | }
8 |
9 | render(){
10 | const {buttonColor, iconTextColor, onClickAction, visible, iconTextComponent } = this.props;
11 | return(
12 |
20 | );
21 | }
22 | }
23 |
24 | export default CustomFAB;
--------------------------------------------------------------------------------
/src/components/CustomSimpleTouchableText.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, TouchableOpacity, Text } from 'react-native';
3 |
4 | class CustomSimpleTouchableText extends Component {
5 | constructor(props){
6 | super(props)
7 | }
8 |
9 | render(){
10 | const { style, text, title, onPress } = this.props;
11 |
12 | return(
13 |
14 |
15 |
17 | {title}
18 |
19 |
20 |
21 | );
22 | }
23 | }
24 |
25 | export default CustomSimpleTouchableText;
--------------------------------------------------------------------------------
/src/styles/SettingStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { normalize } from '../constants/utils';
3 | import { WIDTH, HEIGHT } from '../constants/dimens';
4 | import { backgroundColor, divider, mainColor } from '../constants/color';
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | flex: 1,
9 | flexDirection: 'column',
10 | backgroundColor: backgroundColor,
11 | padding: 30,
12 | },
13 | textView: {
14 | marginBottom: 20,
15 | },
16 | text: {
17 | color: divider,
18 | fontSize: normalize(18),
19 | },
20 | highlightText: {
21 | color: mainColor,
22 | fontSize: normalize(18),
23 | fontWeight: 'bold',
24 | },
25 | });
26 |
27 | export default styles;
--------------------------------------------------------------------------------
/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 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/src/styles/PickerModal.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { pickerBackgroundColor, closeButtonColor, closeButtonBorderColor } from '../constants/color';
3 |
4 | var styles = StyleSheet.create({
5 | background: {
6 | backgroundColor: pickerBackgroundColor
7 | },
8 | closeButtonContainer: {
9 | flexDirection: 'row',
10 | justifyContent: 'flex-end',
11 | borderTopColor: closeButtonBorderColor,
12 | borderTopWidth: 1,
13 | borderBottomColor: closeButtonBorderColor,
14 | borderBottomWidth:1
15 | },
16 | closeButton: {
17 | paddingRight:10,
18 | paddingTop:10,
19 | paddingBottom:10
20 | },
21 | closeButtonText: {
22 | color: closeButtonColor
23 | },
24 | });
25 |
26 | export default styles;
--------------------------------------------------------------------------------
/src/reducers/symptom/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const SYMPTOM_ADD_PENDING = 'SYMPTOM_ADD_PENDING';
2 | export const SYMPTOM_ADD_SUCCESS = 'SYMPTOM_ADD_SUCCESS';
3 | export const SYMPTOM_ADD_FAILURE = 'SYMPTOM_ADD_FAILURE';
4 |
5 | export const SYMPTOM_GET_PENDING = 'SYMPTOM_GET_PENDING';
6 | export const SYMPTOM_GET_SUCCESS = 'SYMPTOM_GET_SUCCESS';
7 | export const SYMPTOM_GET_FAILURE = 'SYMPTOM_GET_FAILURE';
8 |
9 | export const SIGNAL_ADD_PENDING = 'SIGNAL_ADD_PENDING';
10 | export const SIGNAL_ADD_SUCCESS = 'SIGNAL_ADD_SUCCESS';
11 | export const SIGNAL_ADD_FAILURE = 'SIGNAL_ADD_FAILURE';
12 |
13 | export const SIGNAL_GET_PENDING = 'SIGNAL_GET_PENDING';
14 | export const SIGNAL_GET_SUCCESS = 'SIGNAL_GET_SUCCESS';
15 | export const SIGNAL_GET_FAILURE = 'SIGNAL_GET_FAILURE';
16 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Provider } from 'react-redux';
3 | import { createStore, applyMiddleware } from 'redux';
4 | import ReduxThunk from 'redux-thunk';
5 | import promiseMiddleware from 'redux-promise-middleware';
6 |
7 | import reducers from './src/reducers';
8 | import { AppNavigator, middleware } from './src/navigators/AppNavigator';
9 |
10 | const customizedPromiseMiddleware = promiseMiddleware({
11 | promiseTypeSuffixes: ['LOADING', 'SUCCESS', 'FAILURE']
12 | });
13 | const store = createStore(reducers, applyMiddleware(middleware,ReduxThunk));
14 |
15 | export default class App extends Component {
16 | render() {
17 | return (
18 |
19 |
20 |
21 | );
22 | }
23 | }
--------------------------------------------------------------------------------
/src/components/CustomDevicesItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, TouchableOpacity, Text } from 'react-native';
3 | import { Divider } from 'react-native-elements';
4 |
5 | class CustomDevicesItem extends Component {
6 | constructor(props){
7 | super(props)
8 | }
9 |
10 | render(){
11 | const { style, text, divider, title, onPress } = this.props;
12 |
13 | return(
14 |
15 |
16 |
18 | {title}
19 |
20 |
21 |
22 |
23 | );
24 | }
25 | }
26 |
27 | export default CustomDevicesItem;
--------------------------------------------------------------------------------
/src/components/CustomFilledButton.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, TouchableOpacity, Text } from 'react-native';
3 |
4 | class CustomFilledButton extends Component {
5 | constructor(props){
6 | super(props)
7 | }
8 |
9 | render(){
10 | const { style, title, disabled, onPress } = this.props;
11 |
12 | return(
13 |
14 |
17 |
20 | {title}
21 |
22 |
23 |
24 | );
25 | }
26 | }
27 |
28 | export default CustomFilledButton;
--------------------------------------------------------------------------------
/src/reducers/bluetooth/actions.js:
--------------------------------------------------------------------------------
1 | import { AsyncStorage } from 'react-native';
2 | import {
3 | CONNECT_PENDING, CONNECT_SUCCESS, CONNECT_FAILURE,
4 | DISCONNECT_PENDING, DISCONNECT_SUCCESS, DISCONNECT_FAILURE,
5 | } from './actionTypes';
6 |
7 | export const connect = (device) => dispatch => {
8 | const pending = () => { return {type: CONNECT_PENDING}};
9 | const success = (device) => { return {type: CONNECT_SUCCESS, payload: device}};
10 | const failure = (error) => { return {type: CONNECT_FAILURE, payload: error}};
11 |
12 | dispatch(pending()); // Dispatch Action Starting
13 |
14 | dispatch(success(device)) // return ConnectedDevice
15 | saveData(device)
16 | }
17 |
18 |
19 | const saveData = (device) => {
20 | AsyncStorage.multiSet([
21 | ["device", device],
22 | ])
23 | }
--------------------------------------------------------------------------------
/src/components/CustomBorderedButton.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, TouchableOpacity, Text } from 'react-native';
3 | import { mainColor } from '../constants/color';
4 |
5 | class CustomBorderedButton extends Component {
6 | constructor(props){
7 | super(props)
8 | }
9 |
10 | render(){
11 | const { style, title, onPress } = this.props;
12 |
13 | return(
14 |
15 |
17 |
20 | {title}
21 |
22 |
23 |
24 | );
25 | }
26 | }
27 |
28 | export default CustomBorderedButton;
--------------------------------------------------------------------------------
/src/styles/SymptomLogStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { WIDTH, HEIGHT } from '../constants/dimens';
3 | import { backgroundColor, device, divider } from '../constants/color';
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | flex: 1,
8 | flexDirection: 'column',
9 | backgroundColor: backgroundColor,
10 | },
11 | header:{
12 | flexDirection: 'column',
13 | backgroundColor: backgroundColor,
14 | paddingTop: 20,
15 | paddingLeft: 20,
16 | paddingRight: 20,
17 | },
18 | date:{
19 | color: divider,
20 | fontSize: 16,
21 | fontWeight: 'bold',
22 | marginBottom: 5,
23 | },
24 | title:{
25 | color: divider,
26 | fontSize: 16,
27 | marginBottom: 20,
28 | },
29 | });
30 |
31 | export default styles;
--------------------------------------------------------------------------------
/src/styles/SymptomDetailPatchStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { normalize } from '../constants/utils';
3 | import { WIDTH, HEIGHT } from '../constants/dimens';
4 | import { backgroundColor, divider } from '../constants/color';
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | flex: 1,
9 | flexDirection: 'column',
10 | backgroundColor: backgroundColor,
11 | padding: 30,
12 | },
13 | date: {
14 | fontSize: normalize(20),
15 | color: divider,
16 | marginBottom: 15,
17 | },
18 | time: {
19 | fontSize: normalize(15),
20 | color: divider,
21 | },
22 | ChartTitle:{
23 | fontSize: normalize(15),
24 | fontWeight: 'bold',
25 | color: divider,
26 | paddingBottom: 10,
27 | },
28 | chart: {
29 | height: HEIGHT*0.3 + 60
30 | },
31 | });
32 |
33 | export default styles;
--------------------------------------------------------------------------------
/ios/SignalusTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
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 |
--------------------------------------------------------------------------------
/ios/Signalus-tvOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
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 |
--------------------------------------------------------------------------------
/src/styles/VitalStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { WIDTH, HEIGHT, borderRadius } from '../constants/dimens';
3 | import { backgroundColor, mainColor, highlightColor } from '../constants/color';
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | flex: 1,
8 | flexDirection: 'column',
9 | backgroundColor: backgroundColor,
10 | paddingBottom: 15,
11 | },
12 | card: {
13 | flex: 1,
14 | },
15 | cardView:{
16 | flex: 1,
17 | justifyContent: 'center',
18 | borderColor: 'white',
19 | borderRadius: borderRadius,
20 | shadowColor: '#000',
21 | shadowOffset: {
22 | width: 0,
23 | height: 2,
24 | },
25 | shadowOpacity: 0.25,
26 | shadowRadius: 3.84,
27 | elevation: 5,
28 | },
29 | bpmStatus:{
30 | flexDirection: 'row',
31 | alignItems:'center',
32 | height:HEIGHT * 0.14
33 | },
34 | });
35 |
36 | export default styles;
--------------------------------------------------------------------------------
/src/styles/SymptomDetailUserStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { normalize } from '../constants/utils';
3 | import { WIDTH, HEIGHT } from '../constants/dimens';
4 | import { backgroundColor, divider } from '../constants/color';
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | flex: 1,
9 | flexDirection: 'column',
10 | backgroundColor: backgroundColor,
11 | padding: 30,
12 | },
13 | date: {
14 | fontSize: normalize(20),
15 | color: divider,
16 | marginBottom: 15,
17 | },
18 | time: {
19 | fontSize: normalize(15),
20 | color: divider,
21 | },
22 | symptomListTitle:{
23 | fontSize: normalize(15),
24 | fontWeight: 'bold',
25 | color: divider,
26 | paddingBottom: 10,
27 | },
28 | symptomList:{
29 | fontSize: normalize(12),
30 | color: divider,
31 | paddingLeft: 10,
32 | paddingTop: 5,
33 | },
34 | });
35 |
36 | export default styles;
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | android.useDeprecatedNdk=true
21 |
--------------------------------------------------------------------------------
/src/reducers/bluetooth/reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | CONNECT_PENDING, CONNECT_SUCCESS, CONNECT_FAILURE,
3 | DISCONNECT_PENDING, DISCONNECT_SUCCESS, DISCONNECT_FAILURE,
4 | } from './actionTypes';
5 |
6 | const initialState = {
7 | pending: false,
8 | error: false,
9 | isConnected: false,
10 | device: {},
11 | }
12 |
13 | export default bluetooth = (state=initialState, action) => {
14 | switch(action.type){
15 |
16 | case CONNECT_PENDING:
17 | return {
18 | ...state,
19 | pending: true,
20 | error: false
21 | };
22 |
23 | case CONNECT_SUCCESS:
24 | return {
25 | ...state,
26 | pending: false,
27 | isConnected: true,
28 | device: action.payload
29 | };
30 |
31 | case DISCONNECT_PENDING:
32 | return {
33 | ...state,
34 | pending: true,
35 | error: false,
36 | };
37 |
38 | case DISCONNECT_SUCCESS:
39 | return {
40 | ...state,
41 | pending: false,
42 | isConnected: false,
43 | };
44 |
45 | default:
46 | return state;
47 | }
48 | }
--------------------------------------------------------------------------------
/src/components/CustomChart.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import LinearGradient from 'react-native-linear-gradient'
3 | import { LineChart } from 'react-native-svg-charts'
4 | import * as shape from 'd3-shape'
5 | import { HEIGHT } from '../constants/dimens';
6 | import { mainColor, highlightColor } from '../constants/color'
7 |
8 | class CustomChart extends React.PureComponent {
9 | constructor(props){
10 | super(props)
11 | }
12 |
13 | render() {
14 | const { data } = this.props;
15 |
16 | return (
17 |
22 |
32 |
33 |
34 | )
35 | }
36 | }
37 |
38 | export default CustomChart
--------------------------------------------------------------------------------
/.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 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 | yarn-error.log
38 |
39 | # BUCK
40 | buck-out/
41 | \.buckd/
42 | *.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://docs.fastlane.tools/best-practices/source-control/
50 |
51 | */fastlane/report.xml
52 | */fastlane/Preview.html
53 | */fastlane/screenshots
54 |
55 | # Bundle artifact
56 | *.jsbundle
57 |
58 | # private
59 | /src/constants/URL.js
60 | /src/constants/html.js
61 | *.html
62 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | maven {
7 | url 'https://maven.google.com/'
8 | name 'Google'
9 | }
10 | }
11 | dependencies {
12 | classpath 'com.android.tools.build:gradle:2.3.3'
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | mavenLocal()
22 | jcenter()
23 | maven {
24 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
25 | url "$rootDir/../node_modules/react-native/android"
26 | }
27 | maven {
28 | url 'https://maven.google.com/'
29 | name 'Google'
30 | }
31 | }
32 | }
33 |
34 | ext {
35 | buildToolsVersion = "26.0.3"
36 | minSdkVersion = 18
37 | compileSdkVersion = 26
38 | targetSdkVersion = 26
39 | supportLibVersion = "26.1.0"
40 | }
41 |
--------------------------------------------------------------------------------
/src/components/CustomContactItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, TouchableOpacity, Text } from 'react-native';
3 | import { Icon } from 'react-native-elements';
4 | import { normalize } from '../constants/utils';
5 |
6 |
7 | class CustomContactItem extends Component {
8 | constructor(props){
9 | super(props)
10 | }
11 |
12 | render(){
13 | const { style, name, phoneNumber, onPress } = this.props;
14 |
15 | return(
16 |
17 |
18 | {name}
19 | {phoneNumber}
20 |
21 |
22 |
26 |
27 |
28 | );
29 | }
30 | }
31 |
32 | export default CustomContactItem;
--------------------------------------------------------------------------------
/ios/View.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/components/CustomSymptomCheckBox.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, Text, TouchableOpacity } from 'react-native';
3 | import { CheckBox } from 'react-native-elements'
4 | import { checkboxSize } from '../constants/dimens'
5 | import { mainColor, divider } from '../constants/color';
6 |
7 | class CustomSymptomCheckBox extends Component {
8 | constructor(props){
9 | super(props)
10 | }
11 |
12 | render(){
13 | const { checked, onPress, onTouch, title } = this.props;
14 | return(
15 |
16 |
27 |
29 |
30 | {title}
31 |
32 |
33 |
34 | );
35 | }
36 | }
37 |
38 | export default CustomSymptomCheckBox;
--------------------------------------------------------------------------------
/src/reducers/contact/API.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { CONTACT_URL } from '../../constants/URL';
3 |
4 | export const registerAPI = (id, name, phoneNumber, token) => { // Register
5 | let data = JSON.stringify({
6 | id: id,
7 | name: name,
8 | phoneNumber: phoneNumber,
9 | });
10 |
11 | let headerConfig = {
12 | headers: {
13 | 'Content-Type': 'application/json;charset=UTF-8',
14 | 'x-access-token': token,
15 | }
16 | };
17 |
18 | return axios.put(`${CONTACT_URL}/add`,data, headerConfig);
19 | }
20 |
21 | export const deleteAPI = (id, phoneNumber, token) => { // Delete
22 | let data = {
23 | 'data': {
24 | id: id,
25 | phoneNumber: phoneNumber,
26 | }
27 | }
28 |
29 | let headerConfig = {
30 | headers: {
31 | 'Content-Type': 'application/json;charset=UTF-8',
32 | 'x-access-token': token,
33 | }
34 | };
35 |
36 | let config = Object.assign({}, data, headerConfig);
37 |
38 | return axios.delete(`${CONTACT_URL}/delete`, config);
39 | }
40 |
41 | export const getContactsAPI = (id, token) => { // Get Contacts
42 |
43 | let headerConfig = {
44 | headers: {
45 | 'Content-Type': 'application/json;charset=UTF-8',
46 | 'x-access-token': token,
47 | }
48 | };
49 |
50 | return axios.get(`${CONTACT_URL}/list/${id}`, headerConfig);
51 | }
--------------------------------------------------------------------------------
/src/styles/SymptomStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { normalize } from '../constants/utils';
3 | import { WIDTH, HEIGHT, borderRadius } from '../constants/dimens';
4 | import { backgroundColor, divider, mainColor, disable, highlightColor, placeholderText, patch } from '../constants/color';
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | flex: 1,
9 | flexDirection: 'column',
10 | backgroundColor: backgroundColor,
11 | paddingLeft: 10,
12 | paddingRight: 10,
13 | },
14 | itemView: {
15 | flexDirection: 'row',
16 | justifyContent: 'space-between',
17 | height: HEIGHT * 0.08,
18 | alignItems: 'center',
19 | paddingLeft: 20,
20 | paddingRight: 20,
21 | marginTop: 15,
22 | marginBottom: 15,
23 | },
24 | fromPatch:{
25 | color: patch,
26 | fontSize: normalize(13),
27 | marginBottom: 10,
28 | },
29 | fromUser:{
30 | color: placeholderText,
31 | fontSize: normalize(13),
32 | marginBottom: 10,
33 | },
34 | titleStyle:{
35 | color: divider,
36 | fontSize: normalize(16),
37 | fontWeight: 'bold',
38 | marginBottom: 10,
39 | },
40 | dateStyle:{
41 | color: divider,
42 | fontSize: normalize(16),
43 | },
44 | divider:{
45 | backgroundColor: disable,
46 | },
47 | });
48 |
49 | export default styles;
--------------------------------------------------------------------------------
/src/components/CustomSymptomItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, TouchableOpacity, Text } from 'react-native';
3 | import { Divider } from 'react-native-elements';
4 | import { LabelSymptomFromPatch, LabelSymptomFromUser } from '../constants/string';
5 |
6 | class CustomSymptomItem extends Component {
7 | constructor(props){
8 | super(props)
9 | }
10 |
11 | render(){
12 | const { style, type, typeStyle, titleStyle, dateStyle, divider, title, date, onPress } = this.props;
13 |
14 | return(
15 |
16 |
17 |
18 |
19 |
20 | {type == "patch" ? LabelSymptomFromPatch : LabelSymptomFromUser}
21 |
22 |
23 | {title}
24 |
25 |
26 |
27 |
28 |
29 | {date}
30 |
31 |
32 |
33 |
34 |
35 |
36 | );
37 | }
38 | }
39 |
40 | export default CustomSymptomItem;
--------------------------------------------------------------------------------
/src/navigators/RootNavigator.js:
--------------------------------------------------------------------------------
1 | import { createStackNavigator } from 'react-navigation';
2 |
3 | import SplashScreen from '../screens/SplashScreen'; // Splash
4 | import SignInScreen from '../screens/SignInScreen'; // Sign
5 | import ConsentScreen from '../screens/ConsentScreen'; // Consent
6 | import ConsentHTMLScreen from '../screens/ConsentHTMLScreen'; // Consent HTML
7 | import RegisterScreen from '../screens/RegisterScreen'; // Register
8 | import BluetoothScreen from '../screens/BluetoothScreen'; // Bluetooth
9 | import MainScreen from './MainTabNavigator'; // Main
10 |
11 | import { headerTintColor, mainColor } from '../constants/color';
12 |
13 | const RootNavigator = createStackNavigator({
14 | Splash: { screen: SplashScreen },
15 | SignIn: { screen: SignInScreen},
16 | Consent: { screen: ConsentScreen},
17 | ConsentHTML: { screen: ConsentHTMLScreen},
18 | Register: { screen: RegisterScreen },
19 | Bluetooth: { screen: BluetoothScreen },
20 | Main: { screen: MainScreen },
21 | },{
22 | initialRouteName: 'Splash',
23 | headerMode: 'screen',
24 | navigationOptions: {
25 | title: 'Signalus',
26 | headerStyle: {
27 | backgroundColor: mainColor,
28 | borderBottomWidth: 0,
29 | },
30 | headerTintColor: headerTintColor,
31 | headerTitleStyle: {
32 | fontWeight: 'bold',
33 | },
34 | },
35 | });
36 |
37 | export default RootNavigator;
--------------------------------------------------------------------------------
/src/reducers/auth/API.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { AUTH_URL } from '../../constants/URL';
3 |
4 | export const registerAPI = (id, password, age, gender, height, weight) => { // Register
5 | let data = JSON.stringify({
6 | id: id,
7 | password: password,
8 | age: age,
9 | gender: gender,
10 | height: height,
11 | weight: weight
12 | });
13 |
14 | let headerConfig = {
15 | headers: {
16 | 'Content-Type': 'application/json;charset=UTF-8',
17 | }
18 | };
19 |
20 | return axios.post(`${AUTH_URL}/signup`,data, headerConfig);
21 | }
22 |
23 | export const loginAPI = (id, password) => { // Login
24 | let data = JSON.stringify({
25 | id: id,
26 | password: password
27 | });
28 |
29 | let headerConfig = {
30 | headers: {
31 | 'Content-Type': 'application/json;charset=UTF-8',
32 | }
33 | };
34 |
35 | return axios.post(`${AUTH_URL}/signin`,data, headerConfig);
36 | }
37 |
38 | export const withdrawAPI = (id, token) => { // Withdraw
39 | let data = {
40 | 'data': {
41 | id: id
42 | }
43 | }
44 |
45 | let headerConfig = {
46 | headers: {
47 | 'Content-Type': 'application/json;charset=UTF-8',
48 | 'x-access-token': token,
49 | }
50 | };
51 |
52 | let config = Object.assign({}, data, headerConfig);
53 |
54 | return axios.delete(`${AUTH_URL}/withdrawal`, config);
55 | }
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'Signalus'
2 | include ':react-native-fs'
3 | project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fs/android')
4 | include ':react-native-notifications'
5 | project(':react-native-notifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android')
6 | include ':react-native-sms'
7 | project(':react-native-sms').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sms/android')
8 | include ':react-native-contacts'
9 | project(':react-native-contacts').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-contacts/android')
10 | include ':react-native-linear-gradient'
11 | project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
12 | include ':react-native-ble-plx'
13 | project(':react-native-ble-plx').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-ble-plx/android')
14 | include ':react-native-svg'
15 | project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android')
16 | include ':react-native-vector-icons'
17 | project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
18 |
19 | include ':app'
20 |
--------------------------------------------------------------------------------
/src/styles/ConsentStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { WIDTH, HEIGHT, borderRadius, dividerViewHeight } from '../constants/dimens';
3 | import { backgroundColor, divider, mainColor, disable } from '../constants/color';
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | flex: 1,
8 | flexDirection: 'column',
9 | backgroundColor: backgroundColor,
10 | paddingTop: 20,
11 | },
12 | dividerView: {
13 | flexDirection: 'column',
14 | alignItems: 'center',
15 | justifyContent: 'center',
16 | height: dividerViewHeight,
17 | },
18 | divider: {
19 | width: WIDTH * 0.9,
20 | backgroundColor: divider,
21 | },
22 | agreeButtonView: {
23 | marginTop: HEIGHT * 0.05,
24 | flexDirection: 'column',
25 | alignItems: 'center',
26 | justifyContent: 'center',
27 | }
28 | ,
29 | agreeEnable: {
30 | flexDirection: 'column',
31 | alignItems: 'center',
32 | justifyContent: 'center',
33 | backgroundColor: mainColor,
34 | width: WIDTH * 0.85,
35 | height: HEIGHT * 0.08,
36 | borderRadius:borderRadius,
37 | },
38 | agreeDisable: {
39 | flexDirection: 'column',
40 | alignItems: 'center',
41 | justifyContent: 'center',
42 | backgroundColor: disable,
43 | width: WIDTH * 0.85,
44 | height: HEIGHT * 0.08,
45 | borderRadius:borderRadius,
46 | },
47 | });
48 |
49 | export default styles;
--------------------------------------------------------------------------------
/src/styles/RegisterStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { normalize } from '../constants/utils';
3 | import { WIDTH, HEIGHT, borderRadius } from '../constants/dimens';
4 | import { backgroundColor, mainColor, disable } from '../constants/color';
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | flex: 1,
9 | flexDirection: 'column',
10 | backgroundColor: backgroundColor,
11 | },
12 | title:{
13 | paddingTop: 35,
14 | paddingLeft: 20,
15 | paddingBottom: 20,
16 | fontSize: normalize(16),
17 | fontWeight: 'bold',
18 | },
19 | contents: {
20 | flex: 1,
21 | flexDirection: 'column',
22 | alignItems: 'center',
23 | },
24 | input: {
25 | alignItems: 'center',
26 | width: WIDTH * 0.85,
27 | height: HEIGHT * 0.09,
28 | },
29 | registerEnable: {
30 | flexDirection: 'column',
31 | alignItems: 'center',
32 | justifyContent: 'center',
33 | backgroundColor: mainColor,
34 | width: WIDTH * 0.85,
35 | height: HEIGHT * 0.08,
36 | borderRadius: borderRadius,
37 | },
38 | registerDisable: {
39 | flexDirection: 'column',
40 | alignItems: 'center',
41 | justifyContent: 'center',
42 | backgroundColor: disable,
43 | width: WIDTH * 0.85,
44 | height: HEIGHT * 0.08,
45 | borderRadius: borderRadius,
46 | },
47 | error: {
48 | color: 'red',
49 | },
50 | });
51 |
52 | export default styles;
--------------------------------------------------------------------------------
/src/reducers/auth/reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | REGISTER_PENDING, REGISTER_SUCCESS, REGISTER_FAILURE,
3 | SIGNIN_PENDING, SIGNIN_SUCCESS, SIGNIN_FAILURE,
4 | WITHDRAWAL_PENDING, WITHDRAWAL_SUCCESS, WITHDRAWAL_FAILURE
5 | } from './actionTypes';
6 | import { SIGNOUT, ON_CONSENT } from '../nav/actionTypes';
7 |
8 | const initialState = {
9 | pending: false,
10 | error: false,
11 | isLoggedIn: false,
12 | }
13 |
14 | export default auth = (state=initialState, action) => {
15 | switch(action.type){
16 |
17 | case REGISTER_PENDING:
18 | case SIGNIN_PENDING:
19 | case WITHDRAWAL_PENDING:
20 | return {
21 | ...state,
22 | pending: true,
23 | error: false
24 | };
25 |
26 | case SIGNIN_SUCCESS:
27 | case REGISTER_SUCCESS:
28 | const {msg, token} = action.payload.data;
29 | return {
30 | ...state,
31 | pending: false,
32 | isLoggedIn: true
33 | };
34 |
35 | case SIGNIN_FAILURE:
36 | case REGISTER_FAILURE:
37 | case WITHDRAWAL_FAILURE:
38 | return {
39 | ...state,
40 | pending: false,
41 | error: true
42 | };
43 |
44 | case WITHDRAWAL_SUCCESS:
45 | case SIGNOUT:
46 | return {
47 | ...state,
48 | isLoggedIn: false
49 | };
50 |
51 | case ON_CONSENT:
52 | state = initialState;
53 | return state;
54 |
55 | default:
56 | return state;
57 | }
58 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Signalus",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node node_modules/react-native/local-cli/cli.js start",
7 | "test": "jest"
8 | },
9 | "dependencies": {
10 | "axios": "^0.18.1",
11 | "buffer": "^5.2.1",
12 | "lodash": ">=4.17.11",
13 | "react": "16.4.1",
14 | "react-addons-update": "^15.6.2",
15 | "react-native": "^0.56.0",
16 | "react-native-ble-plx": "^0.10.0",
17 | "react-native-calendars": "^1.21.0",
18 | "react-native-contacts": "^2.2.4",
19 | "react-native-elements": "^1.0.0-beta5",
20 | "react-native-fab": "^1.0.8",
21 | "react-native-fs": "^2.12.1",
22 | "react-native-linear-gradient": "^2.4.2",
23 | "react-native-notifications": "^1.1.21",
24 | "react-native-progress": "^3.5.0",
25 | "react-native-sms": "^1.8.0",
26 | "react-native-svg": "^6.5.2",
27 | "react-native-svg-charts": "^5.2.0",
28 | "react-native-vector-icons": "^5.0.0",
29 | "react-navigation": "^2.8.0",
30 | "react-navigation-redux-helpers": "^2.0.3",
31 | "react-redux": "^5.0.7",
32 | "redux": "^4.0.0",
33 | "redux-promise-middleware": "^5.1.1",
34 | "redux-thunk": "^2.3.0"
35 | },
36 | "devDependencies": {
37 | "babel-jest": "23.4.0",
38 | "babel-preset-react-native": "^5",
39 | "jest": "23.4.1",
40 | "react-test-renderer": "16.4.1"
41 | },
42 | "jest": {
43 | "preset": "react-native"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/components/CustomCheckBox.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, Text, TouchableOpacity } from 'react-native';
3 | import { CheckBox } from 'react-native-elements'
4 | import { checkboxSize } from '../constants/dimens'
5 | import { placeholderText, mainColor } from '../constants/color';
6 |
7 | class CustomCheckBox extends Component {
8 | constructor(props){
9 | super(props)
10 | }
11 |
12 | render(){
13 | const { checked, onPress, onTouch, title, underline } = this.props;
14 | return(
15 |
16 |
27 |
29 |
33 | {title}
34 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
41 | export default CustomCheckBox;
--------------------------------------------------------------------------------
/src/components/CustomFormPicker.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, TouchableOpacity } from 'react-native';
3 | import { Input } from 'react-native-elements'
4 |
5 | import { mainColor, placeholderText } from '../constants/color'
6 |
7 | class CustomFormPicker extends Component {
8 | constructor(props){
9 | super(props)
10 | this.state= {
11 | focus: false,
12 | changed: false,
13 | }
14 | }
15 |
16 | _onFocus = () => {
17 | this.setState({focus: true})
18 | }
19 |
20 | _onBlur = () => {
21 | this.setState({focus: false})
22 | }
23 |
24 | render(){
25 | const { style, onPress, placeholder,value } = this.props;
26 | customValue = value ? String(value) : ''
27 |
28 | return(
29 |
30 |
31 | this._onFocus()}
34 | onBlur={ () => this._onBlur() }
35 | inputContainerStyle={{borderBottomColor: this.state.focus ? mainColor : placeholderText}}
36 | inputStyle={{color: placeholderText}}
37 | pointerEvents='none'
38 | placeholder={placeholder}
39 | editable={false}
40 | autoCorrect={false}
41 | errorStyle={{ color: 'red' }}
42 | value={customValue}
43 | />
44 |
45 |
46 | );
47 | }
48 | }
49 |
50 | export default CustomFormPicker;
--------------------------------------------------------------------------------
/ios/Signalus/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "앱 아이콘 배수 40.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "앱 아이콘 배수 60.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "앱 아이콘 배수 58.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "앱 아이콘 배수 87.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "앱 아이콘 배수 80.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "앱 아이콘 배수 120-1.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "앱 아이콘 배수 120.png",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "앱 아이콘 배수 180.png",
49 | "scale" : "3x"
50 | },
51 | {
52 | "size" : "1024x1024",
53 | "idiom" : "ios-marketing",
54 | "filename" : "앱 아이콘 배수 1024.png",
55 | "scale" : "1x"
56 | }
57 | ],
58 | "info" : {
59 | "version" : 1,
60 | "author" : "xcode"
61 | }
62 | }
--------------------------------------------------------------------------------
/src/reducers/contact/reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | CONTACT_REGISTER_PENDING, CONTACT_REGISTER_SUCCESS, CONTACT_REGISTER_FAILURE,
3 | CONTACT_DELETE_PENDING, CONTACT_DELETE_SUCCESS, CONTACT_DELETE_FAILURE,
4 | CONTACT_GET_PENDING, CONTACT_GET_SUCCESS, CONTACT_GET_FAILURE
5 | } from './actionTypes';
6 |
7 | const initialState = {
8 | pending: false,
9 | error: false,
10 | isRegisterd: false,
11 | isDeleted: false,
12 | contacts: [],
13 | }
14 |
15 | export default contact = (state=initialState, action) => {
16 | switch(action.type){
17 |
18 | case CONTACT_REGISTER_PENDING:
19 | case CONTACT_DELETE_PENDING:
20 | case CONTACT_GET_PENDING:
21 | return {
22 | ...state,
23 | pending: true,
24 | error: false
25 | };
26 |
27 | case CONTACT_REGISTER_SUCCESS:
28 | return {
29 | ...state,
30 | pending: false,
31 | isRegisterd: true
32 | };
33 |
34 | case CONTACT_DELETE_SUCCESS:
35 | return {
36 | ...state,
37 | pending: false,
38 | isDeleted: true
39 | };
40 |
41 | case CONTACT_GET_SUCCESS:
42 | const {contacts} = action.payload.data;
43 | return{
44 | ...state,
45 | pending: false,
46 | isRegisterd: false,
47 | isDeleted: false,
48 | contacts: contacts
49 | };
50 |
51 | case CONTACT_REGISTER_FAILURE:
52 | case CONTACT_DELETE_FAILURE:
53 | case CONTACT_GET_FAILURE:
54 | return {
55 | ...state,
56 | pending: false,
57 | error: true
58 | };
59 |
60 | default:
61 | return state;
62 | }
63 | }
--------------------------------------------------------------------------------
/src/reducers/symptom/API.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { SYMPTOM_URL, SIGNAL_URL } from '../../constants/URL';
3 |
4 | export const addSymptomAPI = (id, symptoms, time, type, token) => { // Register
5 | let data = JSON.stringify({
6 | id: id,
7 | symptoms: symptoms,
8 | time: time,
9 | type: type,
10 | });
11 |
12 | let headerConfig = {
13 | headers: {
14 | 'Content-Type': 'application/json;charset=UTF-8',
15 | 'x-access-token': token,
16 | }
17 | };
18 |
19 | return axios.put(`${SYMPTOM_URL}/add`,data, headerConfig);
20 | }
21 |
22 | export const getSymptomAPI = (id, token) => { // Get Contacts
23 |
24 | let headerConfig = {
25 | headers: {
26 | 'Content-Type': 'application/json;charset=UTF-8',
27 | 'x-access-token': token,
28 | }
29 | };
30 |
31 | return axios.get(`${SYMPTOM_URL}/list/${id}`, headerConfig);
32 | }
33 |
34 | export const addSignalAPI = (id, signalFile, time, token) => { // Register
35 | let data = new FormData();
36 | data.append("id", id);
37 | data.append("signalFile", { uri: signalFile, name: `${time}.txt`, type: 'text/plain' });
38 | data.append("time", time);
39 |
40 | let headerConfig = {
41 | headers: {
42 | 'Content-Type': 'multipart/form-data',
43 | 'x-access-token': token,
44 | }
45 | };
46 |
47 | return axios.post(`${SIGNAL_URL}`,data, headerConfig);
48 | }
49 |
50 | export const getSignalAPI = (id, time, token) => { // Get Contacts
51 |
52 | let headerConfig = {
53 | headers: {
54 | 'Content-Type': 'application/json;charset=UTF-8',
55 | 'x-access-token': token,
56 | }
57 | };
58 |
59 | return axios.get(`${SIGNAL_URL}/${id}/${time}`, headerConfig);
60 | }
--------------------------------------------------------------------------------
/src/styles/SignInStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { WIDTH, HEIGHT, borderRadius } from '../constants/dimens';
3 | import { backgroundColor, mainColor, disable } from '../constants/color';
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | flex: 1,
8 | flexDirection: 'column',
9 | alignItems: 'center',
10 | backgroundColor: backgroundColor,
11 | },
12 | image: {
13 | marginTop: '8%',
14 | width: WIDTH * 0.3,
15 | },
16 | input: {
17 | alignItems: 'center',
18 | width: WIDTH * 0.85,
19 | height: HEIGHT * 0.1,
20 | },
21 | icon: {
22 | width: 20,
23 | },
24 | loginEnable: {
25 | flexDirection: 'column',
26 | alignItems: 'center',
27 | justifyContent: 'center',
28 | backgroundColor: mainColor,
29 | width: WIDTH * 0.85,
30 | height: HEIGHT * 0.08,
31 | borderRadius: borderRadius,
32 | },
33 | loginDisable: {
34 | flexDirection: 'column',
35 | alignItems: 'center',
36 | justifyContent: 'center',
37 | backgroundColor: disable,
38 | width: WIDTH * 0.85,
39 | height: HEIGHT * 0.08,
40 | borderRadius: borderRadius,
41 | },
42 | find:{
43 | flexDirection: 'column',
44 | alignItems: 'center',
45 | justifyContent: 'center',
46 | height: HEIGHT * 0.08,
47 | },
48 | register: {
49 | marginTop: HEIGHT * 0.04,
50 | flexDirection: 'column',
51 | alignItems: 'center',
52 | justifyContent: 'center',
53 | width: WIDTH * 0.85,
54 | height: HEIGHT * 0.08,
55 | borderRadius: borderRadius,
56 | borderWidth: 1,
57 | borderColor: mainColor
58 | },
59 | error: {
60 | color: 'red',
61 | }
62 | });
63 |
64 | export default styles;
--------------------------------------------------------------------------------
/ios/Signalus-tvOS/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 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSExceptionDomains
28 |
29 | localhost
30 |
31 | NSExceptionAllowsInsecureHTTPLoads
32 |
33 |
34 |
35 |
36 | NSLocationWhenInUseUsageDescription
37 |
38 | UILaunchStoryboardName
39 | LaunchScreen
40 | UIRequiredDeviceCapabilities
41 |
42 | armv7
43 |
44 | UISupportedInterfaceOrientations
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationLandscapeLeft
48 | UIInterfaceOrientationLandscapeRight
49 |
50 | UIViewControllerBasedStatusBarAppearance
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
17 |
18 |
19 |
20 |
26 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/reducers/symptom/reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | SYMPTOM_ADD_PENDING, SYMPTOM_ADD_SUCCESS, SYMPTOM_ADD_FAILURE,
3 | SYMPTOM_GET_PENDING, SYMPTOM_GET_SUCCESS, SYMPTOM_GET_FAILURE,
4 | SIGNAL_ADD_PENDING, SIGNAL_ADD_SUCCESS, SIGNAL_ADD_FAILURE,
5 | SIGNAL_GET_PENDING, SIGNAL_GET_SUCCESS, SIGNAL_GET_FAILURE,
6 | } from './actionTypes';
7 |
8 | const initialState = {
9 | pending: false,
10 | error: false,
11 | isRegisterd: false,
12 | symptoms: [],
13 | signal: "",
14 | }
15 |
16 | export default symptom = (state=initialState, action) => {
17 | switch(action.type){
18 |
19 | case SIGNAL_ADD_PENDING:
20 | case SIGNAL_GET_PENDING:
21 | case SYMPTOM_ADD_PENDING:
22 | case SYMPTOM_GET_PENDING:
23 | return {
24 | ...state,
25 | pending: true,
26 | error: false
27 | };
28 |
29 | case SIGNAL_ADD_SUCCESS:
30 | case SYMPTOM_ADD_SUCCESS:
31 | return {
32 | ...state,
33 | pending: false,
34 | isRegisterd: true
35 | };
36 |
37 | case SYMPTOM_GET_SUCCESS:
38 | const { symptom_list } = action.payload.data;
39 | return{
40 | ...state,
41 | pending: false,
42 | isRegisterd: false,
43 | symptoms: symptom_list,
44 | };
45 |
46 | case SIGNAL_GET_SUCCESS:
47 | return{
48 | ...state,
49 | pending: false,
50 | isRegisterd: false,
51 | signal: action.payload.data,
52 | };
53 |
54 | case SIGNAL_ADD_FAILURE:
55 | case SIGNAL_GET_FAILURE:
56 | case SYMPTOM_ADD_FAILURE:
57 | case SYMPTOM_GET_FAILURE:
58 | return {
59 | ...state,
60 | pending: false,
61 | error: true
62 | };
63 |
64 | default:
65 | return state;
66 | }
67 | }
--------------------------------------------------------------------------------
/src/styles/ProfileStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { normalize } from '../constants/utils';
3 | import { WIDTH, HEIGHT, borderRadius } from '../constants/dimens';
4 | import { backgroundColor, divider, mainColor, disable, highlightColor } from '../constants/color';
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | flex: 1,
9 | flexDirection: 'column',
10 | backgroundColor: backgroundColor,
11 | paddingLeft: 10,
12 | paddingRight: 10,
13 | },
14 | upper: {
15 | flex: 2,
16 | flexDirection: 'row',
17 | justifyContent: 'space-between',
18 | alignItems: 'center',
19 | paddingLeft: 20,
20 | paddingRight: 20,
21 | },
22 | sectionTitle:{
23 | color: divider,
24 | fontSize: normalize(18),
25 | fontWeight: 'bold',
26 | marginBottom: 10,
27 | },
28 | alertStatusOn:{
29 | color: mainColor,
30 | fontSize: normalize(15),
31 | fontWeight: 'bold'
32 | },
33 | alertStatusOff:{
34 | color: disable,
35 | fontSize: normalize(15),
36 | fontWeight: 'bold'
37 | },
38 | registerContact:{
39 | flex: 2.3,
40 | justifyContent: 'center',
41 | paddingLeft: 20,
42 | paddingRight: 20,
43 | },
44 | registerView:{
45 | flexDirection: 'row',
46 | height: HEIGHT * 0.06,
47 | },
48 | registerInput:{
49 | flex:2,
50 | backgroundColor: highlightColor,
51 | padding: 5,
52 | marginRight: 5,
53 | borderRadius: borderRadius,
54 | },
55 | registerButton:{
56 | flexDirection: 'column',
57 | alignItems: 'center',
58 | justifyContent: 'center',
59 | backgroundColor: mainColor,
60 | flex:1,
61 | borderRadius: borderRadius,
62 | },
63 | phoneList:{
64 | flex: 5,
65 | padding: 20,
66 | }
67 | });
68 |
69 | export default styles;
--------------------------------------------------------------------------------
/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 | lib_deps = []
12 |
13 | for jarfile in glob(['libs/*.jar']):
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 |
21 | for aarfile in glob(['libs/*.aar']):
22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
23 | lib_deps.append(':' + name)
24 | android_prebuilt_aar(
25 | name = name,
26 | aar = aarfile,
27 | )
28 |
29 | android_library(
30 | name = "all-libs",
31 | exported_deps = lib_deps,
32 | )
33 |
34 | android_library(
35 | name = "app-code",
36 | srcs = glob([
37 | "src/main/java/**/*.java",
38 | ]),
39 | deps = [
40 | ":all-libs",
41 | ":build_config",
42 | ":res",
43 | ],
44 | )
45 |
46 | android_build_config(
47 | name = "build_config",
48 | package = "com.signalus",
49 | )
50 |
51 | android_resource(
52 | name = "res",
53 | package = "com.signalus",
54 | res = "src/main/res",
55 | )
56 |
57 | android_binary(
58 | name = "app",
59 | keystore = "//android/keystores:debug",
60 | manifest = "src/main/AndroidManifest.xml",
61 | package_type = "debug",
62 | deps = [
63 | ":app-code",
64 | ],
65 | )
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Signalus
2 |
3 | This application is "Arrhythmia Monitoring" with 24Patch.
4 |
5 | Once you wear our patch, That's all!
6 |
7 | Our patch monitor your heart signal 24hours.
8 |
9 | If you have arrhythmia, the patch sends the signal to your smartphone.
10 |
11 | Automatically, app report to the 119(911 in America) if you are in emergency situation.
12 |
13 | Also, you can check your heart status easily.
14 |
15 |
16 |
17 | ## View
18 |
19 | *All views*
20 |
21 | 
22 |
23 |
24 |
25 | *Pages*
26 |
27 | 
28 |
29 |
30 |
31 | ## Libraries
32 |
33 | | Name | Version |
34 | | ------------------------------ | :---------- |
35 | | axios | 0.18.0 |
36 | | buffer | 5.2.1 |
37 | | lodash | 4.17.10 |
38 | | react | 16.4.1 |
39 | | react-addons-update | 15.6.2 |
40 | | react-native | 0.56.0 |
41 | | react-native-ble-plx | 0.10.0 |
42 | | react-native-calendars | 1.21.0 |
43 | | react-native-contacts | 2.2.4 |
44 | | react-native-elements | 1.0.0-beta5 |
45 | | react-native-fab | 1.0.7 |
46 | | react-native-linear-gradient | 2.4.2 |
47 | | react-native-progress | 3.5.0 |
48 | | react-native-sms | 1.8.0 |
49 | | react-native-svg | 6.5.2 |
50 | | react-native-svg-charts | 5.2.0 |
51 | | react-native-vector-icons | 5.0.0 |
52 | | react-navigation | 2.8.0 |
53 | | react-navigation-redux-helpers | 2.0.3 |
54 | | react-redux | 5.0.7 |
55 | | redux | 4.0.0 |
56 | | redux-promise-middleware | 5.1.1 |
57 | | redux-thunk | 2.3.0 |
58 |
59 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/signalus/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.signalus;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.react.ReactApplication;
6 | import com.rnfs.RNFSPackage;
7 | import com.wix.reactnativenotifications.RNNotificationsPackage;
8 | import com.tkporter.sendsms.SendSMSPackage;
9 | import com.rt2zz.reactnativecontacts.ReactNativeContacts;
10 | import com.BV.LinearGradient.LinearGradientPackage;
11 | import com.polidea.reactnativeble.BlePackage;
12 | import com.horcrux.svg.SvgPackage;
13 | import com.oblador.vectoricons.VectorIconsPackage;
14 | import com.facebook.react.ReactNativeHost;
15 | import com.facebook.react.ReactPackage;
16 | import com.facebook.react.shell.MainReactPackage;
17 | import com.facebook.soloader.SoLoader;
18 |
19 | import java.util.Arrays;
20 | import java.util.List;
21 |
22 | public class MainApplication extends Application implements ReactApplication {
23 |
24 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
25 | @Override
26 | public boolean getUseDeveloperSupport() {
27 | return BuildConfig.DEBUG;
28 | }
29 |
30 | @Override
31 | protected List getPackages() {
32 | return Arrays.asList(
33 | new MainReactPackage(),
34 | new RNFSPackage(),
35 | new RNNotificationsPackage(),
36 | SendSMSPackage.getInstance(),
37 | new ReactNativeContacts(),
38 | new LinearGradientPackage(),
39 | new BlePackage(),
40 | new SvgPackage(),
41 | new VectorIconsPackage()
42 | );
43 | }
44 |
45 | @Override
46 | protected String getJSMainModuleName() {
47 | return "index";
48 | }
49 | };
50 |
51 | @Override
52 | public ReactNativeHost getReactNativeHost() {
53 | return mReactNativeHost;
54 | }
55 |
56 | @Override
57 | public void onCreate() {
58 | super.onCreate();
59 | SoLoader.init(this, /* native exopackage */ false);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/styles/BluetoothStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, } from 'react-native';
2 | import { WIDTH, HEIGHT } from '../constants/dimens';
3 | import { normalize } from '../constants/utils';
4 | import { backgroundColor, mainColor, disable, divider, placeholderText } from '../constants/color';
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | flex: 1,
9 | flexDirection: 'column',
10 | backgroundColor: backgroundColor,
11 | },
12 | headerBox: {
13 | flexDirection: 'row',
14 | justifyContent: 'space-between',
15 | alignItems: 'center',
16 | width: WIDTH,
17 | height: HEIGHT * 0.1,
18 | padding: 25,
19 | backgroundColor: backgroundColor,
20 | shadowColor: '#000',
21 | shadowOffset: {
22 | width: 0,
23 | height: 2,
24 | },
25 | shadowOpacity: 0.25,
26 | shadowRadius: 3.84,
27 | elevation: 5,
28 | },
29 | textToggleOn:{
30 | fontSize: normalize(13),
31 | color: mainColor,
32 | fontWeight: 'bold',
33 | },
34 | textToggleOff:{
35 | fontSize: normalize(13),
36 | color: divider,
37 | fontWeight: 'bold',
38 | },
39 | toggleView:{
40 | flexDirection: 'row',
41 | alignItems: 'center',
42 | },
43 | listTitle:{
44 | padding: 25,
45 | fontSize: normalize(15),
46 | color: divider,
47 | fontWeight: 'bold',
48 | },
49 | listTitleError:{
50 | padding: 25,
51 | fontSize: normalize(15),
52 | color: divider,
53 | fontWeight: 'bold',
54 | color: 'red',
55 | },
56 | deviceContainer:{
57 | flex: 1,
58 | flexDirection: 'column',
59 | alignItems: 'center',
60 | },
61 | deviceList:{
62 | flexDirection: 'column',
63 | width: WIDTH * 0.8,
64 | },
65 | device:{
66 | height: HEIGHT * 0.1,
67 | },
68 | deviceTitle:{
69 | margin: 20,
70 | fontSize: normalize(15),
71 | color: placeholderText,
72 | },
73 | divider:{
74 | backgroundColor: divider,
75 | },
76 | next: {
77 | flex: 1,
78 | flexDirection: 'row',
79 | alignItems: 'flex-end',
80 | justifyContent: 'center',
81 | padding: 50,
82 | },
83 | });
84 |
85 | export default styles;
--------------------------------------------------------------------------------
/src/reducers/contact/actions.js:
--------------------------------------------------------------------------------
1 | import { registerAPI, deleteAPI, getContactsAPI, } from './API';
2 | import {
3 | CONTACT_REGISTER_PENDING, CONTACT_REGISTER_SUCCESS, CONTACT_REGISTER_FAILURE,
4 | CONTACT_DELETE_PENDING, CONTACT_DELETE_SUCCESS, CONTACT_DELETE_FAILURE,
5 | CONTACT_GET_PENDING, CONTACT_GET_SUCCESS, CONTACT_GET_FAILURE,
6 | } from './actionTypes';
7 |
8 | export const register = (id, name, phoneNumber, token) => dispatch => {
9 | const pending = () => { return {type: CONTACT_REGISTER_PENDING}};
10 | const success = (response) => { return {type: CONTACT_REGISTER_SUCCESS, payload: response}};
11 | const failure = (error) => { return {type: CONTACT_REGISTER_FAILURE, payload: error}};
12 |
13 | dispatch(pending()); // Dispatch Action Starting
14 |
15 | return registerAPI(id, name, phoneNumber, token).then(
16 | (response) => { // Success
17 | dispatch(success(response));
18 | }).catch((error) => { // Failure
19 | dispatch(failure(error))
20 | })
21 | }
22 |
23 | export const deleteContact = (id, phoneNumber, token) => dispatch => {
24 | const pending = () => { return {type: CONTACT_DELETE_PENDING}};
25 | const success = (response) => { return {type: CONTACT_DELETE_SUCCESS, payload: response}};
26 | const failure = (error) => { return {type: CONTACT_DELETE_FAILURE, payload: error}};
27 |
28 | dispatch(pending()); // Dispatch Action Starting
29 |
30 | return deleteAPI(id, phoneNumber, token).then(
31 | (response) => { // Success
32 | dispatch(success(response));
33 | }).catch((error) => { // Failure
34 | dispatch(failure(error))
35 | })
36 | }
37 |
38 | export const getContacts = (id, token) => dispatch => {
39 | const pending = () => { return {type: CONTACT_GET_PENDING}};
40 | const success = (response) => { return {type: CONTACT_GET_SUCCESS, payload: response}};
41 | const failure = (error) => { return {type: CONTACT_GET_FAILURE, payload: error}};
42 |
43 | dispatch(pending()); // Dispatch Action Starting
44 |
45 | return getContactsAPI(id, token).then(
46 | (response) => { // Success
47 | dispatch(success(response));
48 | }).catch((error) => { // Failure
49 | dispatch(failure(error))
50 | })
51 | }
52 |
--------------------------------------------------------------------------------
/src/components/CustomHealthStatusBar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, Text } from 'react-native';
3 | import * as Progress from 'react-native-progress';
4 | import { HEIGHT } from '../constants/dimens';
5 | import { LabelNormal, LabelWarning, LabelEmergency } from '../constants/string';
6 | import { mainColor, divider } from '../constants/color';
7 | import { normalize } from '../constants/utils';
8 |
9 | class CustomHealthStatusBar extends Component {
10 | constructor(props){
11 | super(props)
12 | this.state={
13 | status:LabelNormal,
14 | color:mainColor,
15 | }
16 | }
17 |
18 | componentDidMount(){
19 | const { percent } = this.props;
20 |
21 | if(percent > 95){
22 | this.setState({status: LabelNormal, color: mainColor})
23 | } else if(percent > 85 && percent <= 95){
24 | this.setState({status: LabelWarning, color: '#e9e063'})
25 | } else{
26 | this.setState({status: LabelEmergency, color: 'red'})
27 | }
28 | }
29 |
30 | render(){
31 | const { title, percent } = this.props;
32 |
33 | return(
34 |
35 |
36 | {`${title}\t`} {this.state.status}
37 |
38 |
39 |
40 | {percent}%
41 |
42 |
43 | );
44 | }
45 |
46 | componentWillReceiveProps(nextProps){
47 | const { percent } = nextProps;
48 |
49 | if(percent > 95){
50 | this.setState({status: LabelNormal, color: mainColor})
51 | } else if(percent > 85 && percent <= 95){
52 | this.setState({status: LabelWarning, color: '#e9e063'})
53 | } else{
54 | this.setState({status: LabelEmergency, color: 'red'})
55 | }
56 | }
57 | }
58 |
59 | export default CustomHealthStatusBar;
--------------------------------------------------------------------------------
/src/screens/SymptomDetailUserScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { connect } from 'react-redux';
3 | import _ from 'lodash';
4 | // Elements
5 | import {
6 | View, Text
7 | } from 'react-native';
8 | import { Divider } from 'react-native-elements'
9 | import styles from '../styles/SymptomDetailUserStyle';
10 | // Actions
11 |
12 | // Strings
13 | import { HeaderSymptomDetailFromUser, } from '../constants/string';
14 | // Colors
15 | import { disable } from '../constants/color';
16 |
17 | class SymptomDetailUserScreen extends Component{
18 | static navigationOptions = {
19 | title: HeaderSymptomDetailFromUser,
20 | };
21 |
22 | constructor(props){
23 | super(props)
24 | }
25 |
26 | _date = (time) =>{
27 | const year = time.substring(0,4)
28 | const month = time.substring(5,7)
29 | const day = time.substring(8,10)
30 |
31 | return `${year}년 ${month}월 ${day}일`
32 | }
33 |
34 | _time = (time) => {
35 | const hour = time.substring(0,2)
36 | const minute = time.substring(3,5)
37 | const second = time.substring(6,8)
38 |
39 | return `${hour}시 ${minute}분 ${second}초`
40 | }
41 |
42 | // Functions
43 |
44 | // LifeCycle
45 | render(){
46 | const { navigation } = this.props;
47 | const time = navigation.getParam('time', '2000.01.01 00:00:00');
48 | const symptoms = navigation.getParam('symptoms', 'Invalid');
49 |
50 | return(
51 |
52 |
53 | {/* HEADER */}
54 | {this._date(time)}
55 | 추가된 시간 : {this._time(time.substring(11))}
56 |
57 |
58 |
59 | {/* Symptom List */}
60 | 느낀 증상 목록
61 | {_.map(symptoms, symptom => {
62 | return (
63 | ■ {symptom}
64 | );
65 | })}
66 |
67 |
68 | );
69 | }
70 | }
71 |
72 | export default connect(
73 | (state) => ({
74 |
75 | }),
76 | (dispatch) => ({
77 |
78 | })
79 | )(SymptomDetailUserScreen);
--------------------------------------------------------------------------------
/ios/SignalusTests/SignalusTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
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 | #import
12 | #import
13 |
14 | #define TIMEOUT_SECONDS 600
15 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
16 |
17 | @interface SignalusTests : XCTestCase
18 |
19 | @end
20 |
21 | @implementation SignalusTests
22 |
23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
24 | {
25 | if (test(view)) {
26 | return YES;
27 | }
28 | for (UIView *subview in [view subviews]) {
29 | if ([self findSubviewInView:subview matching:test]) {
30 | return YES;
31 | }
32 | }
33 | return NO;
34 | }
35 |
36 | - (void)testRendersWelcomeScreen
37 | {
38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
40 | BOOL foundElement = NO;
41 |
42 | __block NSString *redboxError = nil;
43 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
44 | if (level >= RCTLogLevelError) {
45 | redboxError = message;
46 | }
47 | });
48 |
49 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
50 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
51 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
52 |
53 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
54 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
55 | return YES;
56 | }
57 | return NO;
58 | }];
59 | }
60 |
61 | RCTSetLogFunction(RCTDefaultLogFunction);
62 |
63 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
64 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
65 | }
66 |
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/src/screens/ConsentHTMLScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | // Elements
3 | import {
4 | View, WebView
5 | } from 'react-native';
6 | // Strings
7 | import {
8 | HeaderConsentTerms, HeaderConsentPrivate, HeaderConsentTermsofGeo, HeaderConsentMarketing
9 | } from '../constants/string';
10 | import { Terms, Private, TermsofGeo, Marketing } from '../constants/html'
11 |
12 |
13 | class ConsentHTMLScreen extends Component{
14 | static navigationOptions = ({ navigation }) => {
15 | let header;
16 | switch(navigation.getParam('item')){
17 | case "Terms":
18 | header = HeaderConsentTerms
19 | break;
20 | case "Private":
21 | header = HeaderConsentPrivate
22 | break;
23 | case "TermsofGeo":
24 | header = HeaderConsentTermsofGeo
25 | break;
26 | case "Marketing":
27 | header = HeaderConsentMarketing
28 | break;
29 | }
30 | return{
31 | title: header
32 | }};
33 |
34 | constructor(props){
35 | super(props)
36 | this.state= {
37 | }
38 | }
39 |
40 | // LifeCyle
41 | render(){
42 | const { navigation } = this.props;
43 | switch(navigation.getParam('item')){
44 | case "Terms":
45 | return(
46 |
52 | );
53 |
54 | case "Private":
55 | return(
56 |
62 | );
63 |
64 | case "TermsofGeo":
65 | return(
66 |
72 | );
73 |
74 | case "Marketing":
75 | return(
76 |
82 | );
83 | }
84 | }
85 | }
86 |
87 | export default ConsentHTMLScreen;
--------------------------------------------------------------------------------
/src/screens/CalendarScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { connect } from 'react-redux';
3 | import _ from 'lodash';
4 | // Elements
5 | import {
6 | View, Text, ScrollView,
7 | } from 'react-native';
8 | import { Calendar, CalendarList, Agenda } from 'react-native-calendars';
9 | import styles from '../styles/CalendarStyle';
10 | import { getToday } from '../constants/utils';
11 | // Actions
12 | import { HISTORY } from '../reducers/nav/actionTypes'
13 | // Strings
14 | import { HeaderCalendar } from '../constants/string';
15 |
16 | class CalendarScreen extends Component{
17 | static navigationOptions = {
18 | title: HeaderCalendar,
19 | headerBackTitle: null,
20 | };
21 |
22 | constructor(props) {
23 | super(props);
24 | this.state = {
25 | today: getToday(),
26 | eventDay: ['2018-10-25', '2018-10-26', '2018-11-01', '2018-10-31'],
27 | selected: getToday(),
28 | };
29 | }
30 |
31 | // Functions
32 | _onDayPress = (day) => {
33 | this.setState({
34 | selected: day.dateString
35 | });
36 |
37 | console.log(day)
38 | }
39 |
40 | _mark = () => {
41 |
42 | // today
43 | let marked = {[this.state.selected]: {selected: true, selectedDotColor: 'orange'}}
44 |
45 | // event days
46 | _.map(this.state.eventDay, day => {
47 | marked[day] = {marked: true, dotColor: 'red'}
48 | })
49 |
50 | return marked
51 | }
52 |
53 | // LifeCycle
54 | render(){
55 | const { history } = this.props;
56 | return(
57 |
58 | {console.log('month changed', month)}}
69 | />
70 |
71 |
72 |
73 |
74 | );
75 | }
76 | }
77 |
78 | export default connect(
79 | (state) => ({
80 |
81 | }),
82 | (dispatch) => ({
83 | history: () => dispatch({ type: HISTORY}),
84 | })
85 | )(CalendarScreen);
--------------------------------------------------------------------------------
/src/screens/SplashScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { bindActionCreators } from "redux";
3 | import { connect } from 'react-redux';
4 | // Elements
5 | import {
6 | View, AsyncStorage, Image
7 | } from 'react-native';
8 | import styles from '../styles/SplashStyle';
9 | // Actions
10 | import * as loginActions from '../reducers/auth/actions';
11 | import {
12 | SIGNED, NOT_SIGNED, NOT_CONNECTED
13 | } from '../reducers/nav/actionTypes'
14 |
15 |
16 | class SplashScreen extends Component{
17 | static navigationOptions = {
18 | header: null,
19 | headerBackTitle: null
20 | };
21 |
22 | // Functions
23 | _login = async (id, password) => {
24 | const { LoginActions } = this.props;
25 |
26 | return await LoginActions.login(id, password);
27 | }
28 |
29 | // LifeCycle
30 | componentDidMount(){
31 | const { goToSignIn } = this.props;
32 |
33 | let id;
34 | let password;
35 | let device;
36 |
37 | setTimeout(()=>{
38 | AsyncStorage.multiGet(['id', 'pw', 'device']).then((value) => { // Check LocalStorage
39 | id = value[0][1];
40 | password = value[1][1];
41 | device = value[2][1];
42 |
43 | if(id != null && password != null) { // Login
44 | this._login(id,password)
45 | .catch((e) =>{})
46 | } else {
47 | goToSignIn();
48 | }
49 | })
50 | },2000)
51 | }
52 |
53 | componentWillReceiveProps(nextProps) {
54 | const { isLoggedIn, goToSignIn, goToBluetooth } = nextProps;
55 |
56 | isLoggedIn ? goToBluetooth() : goToSignIn()
57 |
58 | }
59 |
60 | render(){
61 | return(
62 |
63 |
64 | {/* Splash */}
65 |
69 |
70 | );
71 | }
72 | }
73 |
74 | // Redux Connect
75 | export default connect(
76 | (state) => ({
77 | isLoggedIn : state.auth.isLoggedIn,
78 | }),
79 | (dispatch) => ({
80 | LoginActions: bindActionCreators(loginActions, dispatch),
81 | goToMain: () => dispatch({ type: SIGNED}),
82 | goToBluetooth: () => dispatch({ type: NOT_CONNECTED }),
83 | goToSignIn: () => dispatch({ type: NOT_SIGNED}),
84 | })
85 | )(SplashScreen);
86 |
--------------------------------------------------------------------------------
/src/reducers/auth/actions.js:
--------------------------------------------------------------------------------
1 | import { AsyncStorage } from 'react-native';
2 | import { registerAPI, loginAPI, withdrawAPI } from './API';
3 | import {
4 | REGISTER_PENDING, REGISTER_SUCCESS, REGISTER_FAILURE,
5 | SIGNIN_PENDING, SIGNIN_SUCCESS, SIGNIN_FAILURE,
6 | WITHDRAWAL_PENDING, WITHDRAWAL_SUCCESS, WITHDRAWAL_FAILURE
7 | } from './actionTypes';
8 |
9 | export const register = (id, password, age, gender, height, weight) => dispatch => {
10 | const pending = () => { return {type: REGISTER_PENDING}};
11 | const success = (response) => { return {type: REGISTER_SUCCESS, payload: response}};
12 | const failure = (error) => { return {type: REGISTER_FAILURE, payload: error}};
13 |
14 | dispatch(pending()); // Dispatch Action Starting
15 |
16 | return registerAPI(id,password,age,gender,height,weight).then(
17 | (response) => { // Success
18 | dispatch(success(response));
19 | saveData(id, password, response);
20 | }).catch((error) => { // Failure
21 | dispatch(failure(error))
22 | })
23 | }
24 |
25 | export const login = (id, password) => dispatch => {
26 | const pending = () => { return {type: SIGNIN_PENDING}};
27 | const success = (response) => { return {type: SIGNIN_SUCCESS, payload: response}};
28 | const failure = (error) => { return {type: SIGNIN_FAILURE, payload: error}};
29 |
30 | dispatch(pending()); // Dispatch Action Starting
31 |
32 | return loginAPI(id,password).then(
33 | (response) => { // Success
34 | dispatch(success(response));
35 | saveData(id, password, response);
36 | }).catch((error) => {// Failure
37 | dispatch(failure(error))
38 | })
39 | }
40 |
41 | export const withdraw = (id, token) => dispatch => {
42 | const pending = () => { return {type: WITHDRAWAL_PENDING}};
43 | const success = (response) => { return {type: WITHDRAWAL_SUCCESS, payload: response}};
44 | const failure = (error) => { return {type: WITHDRAWAL_FAILURE, payload: error}};
45 |
46 | dispatch(pending()); // Dispatch Action Starting
47 |
48 | return withdrawAPI(id, token).then(
49 | (response) => { // Success
50 | dispatch(success(response));
51 | }).catch((error) => {// Failure
52 | dispatch(failure(error))
53 | })
54 | }
55 |
56 | const saveData = (id, password, response) => {
57 | AsyncStorage.multiSet([
58 | ["id", id],
59 | ["pw", password],
60 | ["token", response.data.token],
61 | ])
62 | }
63 |
--------------------------------------------------------------------------------
/src/components/CustomPicker.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, Animated, TouchableHighlight, Text, Picker } from 'react-native';
3 | import { LabelChoose, ModeAge, ModeSex, ModeHeight, ModeWeight } from '../constants/string';
4 | import { HEIGHT, modalOffset, modalDuration } from '../constants/dimens'
5 | import styles from '../styles/PickerModal';
6 | import { ages, sex, heights, weights } from '../constants/model';
7 |
8 | let values = [];
9 |
10 | class CustomPicker extends Component {
11 | constructor(props){
12 | super(props)
13 | }
14 |
15 | componentDidMount(){
16 | const { offSet } = this.props;
17 | Animated.timing(offSet, {
18 | duration: modalDuration,
19 | toValue: modalOffset
20 | }).start()
21 | }
22 |
23 | closeModal = () => {
24 | const { offSet, closeModal } = this.props;
25 |
26 | Animated.timing(offSet, {
27 | duration: modalDuration,
28 | toValue: HEIGHT
29 | }).start(closeModal);
30 | }
31 |
32 |
33 | render() {
34 | const { offSet, showModal, changeValue, mode } = this.props;
35 | switch(mode){
36 | case ModeAge:
37 | values = ages
38 | break;
39 | case ModeSex:
40 | values = sex
41 | break;
42 | case ModeHeight:
43 | values = heights
44 | break;
45 | case ModeWeight:
46 | values = weights;
47 | break;
48 | default:
49 | values = ages
50 | break;
51 | }
52 | return (
53 |
54 |
55 |
56 |
57 | {LabelChoose}
58 |
59 |
60 | changeValue(value)}>
63 | {Object.keys(values).map((index) => (
64 |
69 | ))}
70 |
71 |
72 |
73 | )
74 | }
75 | }
76 |
77 | export default CustomPicker;
78 |
--------------------------------------------------------------------------------
/ios/Signalus/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | Signalus
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 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSExceptionDomains
30 |
31 | localhost
32 |
33 | NSExceptionAllowsInsecureHTTPLoads
34 |
35 |
36 |
37 |
38 | NSContactsUsageDescription
39 |
40 | NSLocationWhenInUseUsageDescription
41 |
42 | UIAppFonts
43 |
44 | Entypo.ttf
45 | EvilIcons.ttf
46 | Feather.ttf
47 | FontAwesome.ttf
48 | FontAwesome5_Brands.ttf
49 | FontAwesome5_Regular.ttf
50 | FontAwesome5_Solid.ttf
51 | Foundation.ttf
52 | Ionicons.ttf
53 | MaterialCommunityIcons.ttf
54 | MaterialIcons.ttf
55 | Octicons.ttf
56 | SimpleLineIcons.ttf
57 | Zocial.ttf
58 |
59 | UIBackgroundModes
60 |
61 | bluetooth-central
62 |
63 | UILaunchStoryboardName
64 | LaunchScreen
65 | UIRequiredDeviceCapabilities
66 |
67 | armv7
68 |
69 | UISupportedInterfaceOrientations
70 |
71 | UIInterfaceOrientationPortrait
72 |
73 | UIViewControllerBasedStatusBarAppearance
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | ; We fork some components by platform
3 | .*/*[.]android.js
4 |
5 | ; Ignore "BUCK" generated dirs
6 | /\.buckd/
7 |
8 | ; Ignore unexpected extra "@providesModule"
9 | .*/node_modules/.*/node_modules/fbjs/.*
10 |
11 | ; Ignore duplicate module providers
12 | ; For RN Apps installed via npm, "Libraries" folder is inside
13 | ; "node_modules/react-native" but in the source repo it is in the root
14 | .*/Libraries/react-native/React.js
15 |
16 | ; Ignore polyfills
17 | .*/Libraries/polyfills/.*
18 |
19 | ; Ignore metro
20 | .*/node_modules/metro/.*
21 |
22 | [include]
23 |
24 | [libs]
25 | node_modules/react-native/Libraries/react-native/react-native-interface.js
26 | node_modules/react-native/flow/
27 | node_modules/react-native/flow-github/
28 |
29 | [options]
30 | emoji=true
31 |
32 | module.system=haste
33 | module.system.haste.use_name_reducers=true
34 | # get basename
35 | module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
36 | # strip .js or .js.flow suffix
37 | module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
38 | # strip .ios suffix
39 | module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
40 | module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
41 | module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
42 | module.system.haste.paths.blacklist=.*/__tests__/.*
43 | module.system.haste.paths.blacklist=.*/__mocks__/.*
44 | module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.*
45 | module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.*
46 |
47 | munge_underscores=true
48 |
49 | 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\)$' -> 'RelativeImageStub'
50 |
51 | module.file_ext=.js
52 | module.file_ext=.jsx
53 | module.file_ext=.json
54 | module.file_ext=.native.js
55 |
56 | suppress_type=$FlowIssue
57 | suppress_type=$FlowFixMe
58 | suppress_type=$FlowFixMeProps
59 | suppress_type=$FlowFixMeState
60 |
61 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
62 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
63 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
64 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
65 |
66 | [version]
67 | ^0.75.0
68 |
--------------------------------------------------------------------------------
/src/components/CustomFormInput.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, Image } from 'react-native';
3 | import { Input } from 'react-native-elements'
4 |
5 | import { defaultMaxLength } from '../constants/dimens'
6 | import { mainColor, placeholderText } from '../constants/color'
7 |
8 | class CustomFormInput extends Component {
9 | constructor(props){
10 | super(props)
11 | this.state= {
12 | focus: false,
13 | changed: false,
14 | }
15 | }
16 |
17 | _focus = () => {
18 |
19 | }
20 |
21 | _onFocus = () => {
22 | this.setState({focus: true})
23 | }
24 |
25 | _onBlur = () => {
26 | this.setState({focus: false})
27 | }
28 |
29 | _onChange = () => {
30 | this.setState({changed: true})
31 | }
32 |
33 | render(){
34 | const { childRef, onSubmitEditing, blurOnSubmit, style, iconStyle, placeholder, isIcon, type, onChangeText, maxLength, returnKeyType, clearButtonMode, secureTextEntry, error, errorMsg } = this.props;
35 | let iconSRC
36 |
37 | if(isIcon){
38 | switch(type){
39 | case "ID": iconSRC = require("../../assets/loginID.png")
40 | break
41 | case "PW": iconSRC = require("../../assets/loginPW.png")
42 | break
43 | default :
44 | break
45 | }
46 | }
47 |
48 | return(
49 |
50 | this._onFocus()}
57 | onBlur={ () => this._onBlur() }
58 | inputContainerStyle={{borderBottomColor: this.state.focus ? mainColor : placeholderText}}
59 | inputStyle={{color: placeholderText}}
60 | placeholder={placeholder}
61 | onChangeText={onChangeText}
62 | maxLength={maxLength ? maxLength : defaultMaxLength}
63 | secureTextEntry={secureTextEntry}
64 | returnKeyType={returnKeyType}
65 | clearButtonMode={clearButtonMode}
66 | shake={error}
67 | autoCorrect={false}
68 | errorStyle={{ color: 'red' }}
69 | errorMessage={error ? errorMsg : " "}
70 | onChange={() => this._onChange()}
71 | rightIcon={
72 | isIcon &&
73 | this.state.changed &&
74 |
79 | }
80 | />
81 |
82 | );
83 | }
84 | }
85 |
86 | export default CustomFormInput;
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/ios/Signalus/Base.lproj/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 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/ios/Signalus/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
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 "AppDelegate.h"
9 |
10 | #import
11 | #import
12 | #import
13 |
14 |
15 | @implementation AppDelegate
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
18 | {
19 | NSURL *jsCodeLocation;
20 |
21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
22 |
23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
24 | moduleName:@"Signalus"
25 | initialProperties:nil
26 | launchOptions:launchOptions];
27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
28 |
29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
30 | UIViewController *rootViewController = [UIViewController new];
31 | rootViewController.view = rootView;
32 | self.window.rootViewController = rootViewController;
33 | [self.window makeKeyAndVisible];
34 | return YES;
35 | }
36 |
37 | // Required to register for notifications
38 | - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
39 | {
40 | [RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings];
41 | }
42 | // Required for the register event.
43 | - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
44 | {
45 | [RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
46 | }
47 | // Required for the notification event. You must call the completion handler after handling the remote notification.
48 | - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
49 | fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
50 | {
51 | [RCTPushNotificationManager didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
52 | }
53 | // Required for the registrationError event.
54 | - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
55 | {
56 | [RCTPushNotificationManager didFailToRegisterForRemoteNotificationsWithError:error];
57 | }
58 | // Required for the localNotification event.
59 | - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
60 | {
61 | [RCTPushNotificationManager didReceiveLocalNotification:notification];
62 | }
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/src/reducers/symptom/actions.js:
--------------------------------------------------------------------------------
1 | import { addSymptomAPI, getSymptomAPI, addSignalAPI, getSignalAPI } from './API';
2 | import {
3 | SYMPTOM_ADD_PENDING, SYMPTOM_ADD_SUCCESS, SYMPTOM_ADD_FAILURE,
4 | SYMPTOM_GET_PENDING, SYMPTOM_GET_SUCCESS, SYMPTOM_GET_FAILURE,
5 | SIGNAL_ADD_PENDING, SIGNAL_ADD_SUCCESS, SIGNAL_ADD_FAILURE,
6 | SIGNAL_GET_PENDING, SIGNAL_GET_SUCCESS, SIGNAL_GET_FAILURE,
7 | } from './actionTypes';
8 |
9 | export const addSymptom = (id, symptoms, time, type, token) => dispatch => {
10 | const pending = () => { return {type: SYMPTOM_ADD_PENDING}};
11 | const success = (response) => { return {type: SYMPTOM_ADD_SUCCESS, payload: response}};
12 | const failure = (error) => { return {type: SYMPTOM_ADD_FAILURE, payload: error}};
13 |
14 | dispatch(pending()); // Dispatch Action Starting
15 |
16 | return addSymptomAPI(id, symptoms, time, type, token).then(
17 | (response) => { // Success
18 | console.log(response)
19 | dispatch(success(response));
20 | }).catch((error) => { // Failure
21 | console.log(error)
22 | dispatch(failure(error))
23 | })
24 | }
25 |
26 | export const getSymptoms = (id, token) => dispatch => {
27 | const pending = () => { return {type: SYMPTOM_GET_PENDING}};
28 | const success = (response) => { return {type: SYMPTOM_GET_SUCCESS, payload: response}};
29 | const failure = (error) => { return {type: SYMPTOM_GET_FAILURE, payload: error}};
30 |
31 | dispatch(pending()); // Dispatch Action Starting
32 |
33 | return getSymptomAPI(id, token).then(
34 | (response) => { // Success
35 | console.log(response)
36 | dispatch(success(response));
37 | }).catch((error) => { // Failure
38 | console.log(error)
39 | dispatch(failure(error))
40 | })
41 | }
42 |
43 | export const addSignal = (id, signalFile, time, token) => dispatch => {
44 | const pending = () => { return {type: SIGNAL_ADD_PENDING}};
45 | const success = (response) => { return {type: SIGNAL_ADD_SUCCESS, payload: response}};
46 | const failure = (error) => { return {type: SIGNAL_ADD_FAILURE, payload: error}};
47 |
48 | dispatch(pending()); // Dispatch Action Starting
49 |
50 | return addSignalAPI(id, signalFile, time, token).then(
51 | (response) => { // Success
52 | console.log(response)
53 | dispatch(success(response));
54 | }).catch((error) => { // Failure
55 | console.log(error)
56 | dispatch(failure(error))
57 | })
58 | }
59 |
60 | export const getSignal = (id, time, token) => dispatch => {
61 | const pending = () => { return {type: SIGNAL_GET_PENDING}};
62 | const success = (response) => { return {type: SIGNAL_GET_SUCCESS, payload: response}};
63 | const failure = (error) => { return {type: SIGNAL_GET_FAILURE, payload: error}};
64 |
65 | dispatch(pending()); // Dispatch Action Starting
66 |
67 | return getSignalAPI(id, time, token).then(
68 | (response) => { // Success
69 | console.log(response)
70 | dispatch(success(response));
71 | }).catch((error) => { // Failure
72 | console.log(error)
73 | dispatch(failure(error))
74 | })
75 | }
--------------------------------------------------------------------------------
/src/screens/SymptomDetailPatchScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { connect } from 'react-redux';
3 | import { bindActionCreators } from "redux";
4 | // Elements
5 | import {
6 | View, Text, AsyncStorage
7 | } from 'react-native';
8 | import { Divider } from 'react-native-elements'
9 | import styles from '../styles/SymptomDetailPatchStyle';
10 | import { stringToSignal, getTimeForNowPath } from '../constants/utils';
11 | import CustomChart from '../components/CustomChart';
12 | // Actions
13 | import * as symptomActions from '../reducers/symptom/actions';
14 | // Strings
15 | import { HeaderSymptomDetailFromDevice, } from '../constants/string';
16 | // Colors
17 | import { disable } from '../constants/color';
18 |
19 | class SymptomDetailDeviceScreen extends Component{
20 | static navigationOptions = {
21 | title: HeaderSymptomDetailFromDevice,
22 | };
23 |
24 | constructor(props){
25 | super(props)
26 | this.state= {
27 | data: [0],
28 | }
29 | }
30 |
31 | // Functions
32 | _date = (time) =>{
33 | const year = time.substring(0,4)
34 | const month = time.substring(5,7)
35 | const day = time.substring(8,10)
36 |
37 | return `${year}년 ${month}월 ${day}일`
38 | }
39 |
40 | _time = (time) => {
41 | const hour = time.substring(0,2)
42 | const minute = time.substring(3,5)
43 | const second = time.substring(6,8)
44 |
45 | return `${hour}시 ${minute}분 ${second}초`
46 | }
47 |
48 | _getsignal = async (id, time, token) => {
49 | const { SymptomActions } = this.props;
50 |
51 | return await SymptomActions.getSignal(id, time, token);
52 | }
53 |
54 | // LifeCycle
55 | componentDidMount(){
56 | const { navigation } = this.props;
57 | const time = navigation.getParam('time', '2000.01.01 00:00:00');
58 |
59 | AsyncStorage.multiGet(['id', 'token']).then((value) => { // Get Data From LocalStorage
60 | id = value[0][1];
61 | token = value[1][1];
62 |
63 | this._getsignal(id, getTimeForNowPath(time), token)
64 | .catch((e) =>{})
65 | })
66 | }
67 |
68 | componentWillReceiveProps(nextProps){
69 | const { signal } = nextProps;
70 |
71 | this.setState({data: stringToSignal(signal)});
72 | }
73 |
74 | render(){
75 | const { navigation } = this.props;
76 | const time = navigation.getParam('time', '2000.01.01 00:00:00');
77 |
78 | return(
79 |
80 |
81 | {/* HEADER */}
82 | {this._date(time)}
83 | 추가된 시간 : {this._time(time.substring(11))}
84 |
85 |
86 |
87 | {/* ECG Graph */}
88 | 수신된 신호
89 |
90 |
93 |
94 |
95 |
96 | );
97 | }
98 | }
99 |
100 | export default connect(
101 | (state) => ({
102 | signal: state.symptom.signal,
103 | }),
104 | (dispatch) => ({
105 | SymptomActions: bindActionCreators(symptomActions, dispatch),
106 | })
107 | )(SymptomDetailDeviceScreen);
--------------------------------------------------------------------------------
/src/constants/utils.js:
--------------------------------------------------------------------------------
1 | import { Buffer } from 'buffer';
2 | import { Dimensions, Platform, PixelRatio, PushNotificationIOS } from 'react-native';
3 | import SendSMS from 'react-native-sms'
4 |
5 | const {
6 | width: SCREEN_WIDTH,
7 | height: SCREEN_HEIGHT,
8 | } = Dimensions.get('window');
9 |
10 | // based on iphone 5s's scale
11 | const scale = SCREEN_WIDTH / 320;
12 |
13 | export const normalize = (size) => {
14 | const newSize = size * scale
15 | if (Platform.OS === 'ios') {
16 | return Math.round(PixelRatio.roundToNearestPixel(newSize))
17 | } else {
18 | return Math.round(PixelRatio.roundToNearestPixel(newSize)) - 2
19 | }
20 | }
21 |
22 |
23 | export const base64ToHex = (value) => new Buffer(value, 'base64').toString('hex')
24 | export const getDecValue = (c) => {
25 | const originHex = base64ToHex(c.value);
26 | let value = parseInt(originHex, 16)
27 | if((value & 0x8000) >> 15 == 1){
28 | value = value & 0xffff;
29 | value = value - 0x10000;
30 | }
31 |
32 | return value
33 | }
34 |
35 | export const getToday = () => {
36 | var date = new Date();
37 | var year = date.getFullYear();
38 | var month = new String(date.getMonth()+1);
39 | var day = new String(date.getDate());
40 |
41 | // 한자리수일 경우 0을 채워준다.
42 | if(month.length == 1){
43 | month = "0" + month;
44 | }
45 | if(day.length == 1){
46 | day = "0" + day;
47 | }
48 |
49 | return year + "-" + month + "-" + day;
50 | }
51 |
52 | export const getTimeForNow = () => {
53 | let date = new Date();
54 | var year = date.getFullYear();
55 | var month = new String(date.getMonth()+1);
56 | var day = new String(date.getDate());
57 | let h = date.getHours();
58 | let m = date.getMinutes();
59 | let s = date.getSeconds();
60 |
61 | // 한자리수일 경우 0을 채워준다.
62 | if(month.length == 1){
63 | month = "0" + month;
64 | }
65 | if(day.length == 1){
66 | day = "0" + day;
67 | }
68 |
69 | m = this._checkTime(m);
70 | s = this._checkTime(s);
71 |
72 | const now = `${year}.${month}.${day} ${h}:${m}:${s}`
73 |
74 | return now
75 | }
76 |
77 | export const getTimeForNowPath = (t) => {
78 | let time = t
79 |
80 | const year = time.substring(0,4)
81 | const month = time.substring(5,7)
82 | const day = time.substring(8,10)
83 |
84 | time = time.substring(11)
85 |
86 | const hour = time.substring(0,2)
87 | const minute = time.substring(3,5)
88 | const second = time.substring(6,8)
89 |
90 | const now = `${year}.${month}.${day}_${hour}:${minute}:${second}`
91 | return now
92 | }
93 |
94 | _checkTime = (i) => {
95 | if (i < 10) {i = "0" + i};
96 | return i;
97 | }
98 |
99 | export const send = (message, contacts) => {
100 |
101 | SendSMS.send({
102 | body: message,
103 | recipients: contacts,
104 | }, (completed, cancelled, error) => {
105 |
106 | console.log('SMS Callback: completed: ' + completed + ' cancelled: ' + cancelled + 'error: ' + error);
107 | });
108 | }
109 |
110 | export const notification = () => {
111 | PushNotificationIOS.scheduleLocalNotification({
112 | fireDate: new Date(Date.now() + 60 * 1000).getTime(),
113 | alertTitle: '위험상황 감지!',
114 | alertBody: '부정맥으로 의심되는 신호가 감지되었습니다!'
115 | });
116 | }
117 |
118 | export const signalToString = (data) => {
119 | let signalString = ''
120 | for(i in data){
121 | signalString += `${data[i]}\n`
122 | }
123 |
124 | return signalString
125 | }
126 |
127 | export const stringToSignal = (data) => {
128 | var signal = data.split('\n').map((item) => {
129 | return parseInt(item, 10);
130 | });
131 |
132 | return signal.slice(0,-1)
133 | }
--------------------------------------------------------------------------------
/src/reducers/nav/reducer.js:
--------------------------------------------------------------------------------
1 | import { NavigationActions, StackActions } from 'react-navigation';
2 | import { RootNavigator } from '../../navigators/AppNavigator';
3 |
4 | import {
5 | NOT_SIGNED, ON_CONSENT, ON_REGISTER, SIGNED, SIGNOUT,
6 | CONNECTED, NOT_CONNECTED,
7 | ON_CALENDAR, ON_LOG, LOGGED, ON_DETAIL_PATCH, ON_DETAIL_USER, ON_SETTING
8 | } from './actionTypes';
9 |
10 | // Start with two routes: The Main screen, with the Login screen on top.
11 | const router = RootNavigator.router;
12 | const firstAction =router.getActionForPathAndParams('Splash');
13 | const initialNavState = router.getStateForAction(firstAction);
14 |
15 |
16 | export default nav = (state = initialNavState, action) => {
17 | let nextState;
18 | switch (action.type) {
19 | case NOT_SIGNED:
20 | nextState = router.getStateForAction(
21 | StackActions.reset({
22 | index: 0,
23 | actions: [NavigationActions.navigate({ routeName: 'SignIn' })]
24 | }),
25 | state
26 | );
27 | break;
28 | case ON_CONSENT:
29 | nextState = router.getStateForAction(
30 | NavigationActions.navigate({ routeName: 'Consent' }),
31 | state
32 | );
33 | break;
34 | case ON_REGISTER:
35 | nextState = router.getStateForAction(
36 | NavigationActions.navigate({ routeName: 'Register' }),
37 | state
38 | );
39 | break;
40 | case SIGNED:
41 | nextState = router.getStateForAction(
42 | StackActions.reset({
43 | index: 0,
44 | actions: [NavigationActions.navigate({ routeName: 'Main' })]
45 | }),
46 | state
47 | );
48 | break;
49 | case CONNECTED:
50 | nextState = router.getStateForAction(
51 | StackActions.reset({
52 | index: 0,
53 | actions: [NavigationActions.navigate({ routeName: 'Main' })]
54 | }),
55 | state
56 | );
57 | break;
58 | case NOT_CONNECTED:
59 | nextState = router.getStateForAction(
60 | StackActions.reset({
61 | index: 0,
62 | key: null,
63 | actions: [NavigationActions.navigate({ routeName: 'Bluetooth' })]
64 | }),
65 | state
66 | );
67 | break;
68 |
69 | case ON_CALENDAR:
70 | nextState = router.getStateForAction(
71 | NavigationActions.navigate({ routeName: 'Calendar' }),
72 | state
73 | );
74 | break;
75 | case ON_LOG:
76 | nextState = router.getStateForAction(
77 | NavigationActions.navigate({ routeName: 'SymptomLog'}),
78 | state
79 | );
80 | break;
81 | case LOGGED:
82 | nextState = router.getStateForAction(
83 | NavigationActions.back(),
84 | state
85 | );
86 | break;
87 | case ON_DETAIL_PATCH:
88 | nextState = router.getStateForAction(
89 | NavigationActions.navigate({ routeName: 'SymptomDetailPatch'}),
90 | state
91 | );
92 | break;
93 | case ON_DETAIL_USER:
94 | nextState = router.getStateForAction(
95 | NavigationActions.navigate({ routeName: 'SymptomDetailUser'}),
96 | state
97 | );
98 | break;
99 | case ON_SETTING:
100 | nextState = router.getStateForAction(
101 | NavigationActions.navigate({ routeName: 'Setting'}),
102 | state
103 | );
104 | break;
105 |
106 | case SIGNOUT:
107 | nextState = router.getStateForAction(
108 | StackActions.reset({
109 | index: 0,
110 | key: null,
111 | actions: [NavigationActions.navigate({ routeName: 'SignIn' })]
112 | }),
113 | state
114 | );
115 | break;
116 | default:
117 | nextState = RootNavigator.router.getStateForAction(action, state);
118 | break;
119 | }
120 | return nextState || state;
121 | };
--------------------------------------------------------------------------------
/src/screens/ConsentScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { connect } from 'react-redux';
3 | // Elements
4 | import {
5 | View,
6 | } from 'react-native';
7 | import { Divider } from 'react-native-elements';
8 | import CustomCheckBox from '../components/CustomCheckBox';
9 | import CustomFilledButton from '../components/CustomFilledButton';
10 | import styles from '../styles/ConsentStyle';
11 | // Actions
12 | import {
13 | ON_REGISTER, ON_CONSENT_HTML
14 | } from '../reducers/nav/actionTypes'
15 | // Strings
16 | import {
17 | HeaderConsent, LabelConsentTerms, LabelConsentPrivate, LabelConsentTermsofGeo, LabelConsentMarketing,
18 | LabelAgreementAll, LabelAgreement
19 | } from '../constants/string';
20 |
21 | class ConsentScreen extends Component{
22 | static navigationOptions = {
23 | title: HeaderConsent,
24 | headerBackTitle: null,
25 | };
26 |
27 | constructor(props){
28 | super(props)
29 | this.state= {
30 | checked_1:false,
31 | checked_2:false,
32 | checked_3:false,
33 | checked_4:false,
34 | }
35 | }
36 |
37 | // Functions
38 | _viewHTML =(item) => {
39 | this.props.navigation.navigate('ConsentHTML', {
40 | item: item,
41 | })
42 | }
43 |
44 | // LifeCyle
45 | render(){
46 | const { goToRegister } = this.props;
47 | return(
48 |
49 |
50 | {/* Agreement All */}
51 | this.setState({checked_1: true, checked_2: true, checked_3: true, checked_4: true})}
54 | title={LabelAgreementAll}
55 | />
56 |
57 | {/* Divider */}
58 |
59 |
60 |
61 |
62 | {/* Agreement 1 */}
63 | this.setState({checked_1: !this.state.checked_1})}
66 | onTouch={() => this._viewHTML("Terms")}
67 | title={LabelConsentTerms}
68 | underline={true}
69 | />
70 |
71 | {/* Agreement 2 */}
72 | this.setState({checked_2: !this.state.checked_2})}
75 | onTouch={() => this._viewHTML("Private")}
76 | title={LabelConsentPrivate}
77 | underline={true}
78 | />
79 |
80 | {/* Agreement 3 */}
81 | this.setState({checked_3: !this.state.checked_3})}
84 | onTouch={() => this._viewHTML("TermsofGeo")}
85 | title={LabelConsentTermsofGeo}
86 | underline={true}
87 | />
88 |
89 | {/* Agreement 4 */}
90 | this.setState({checked_4: !this.state.checked_4})}
93 | onTouch={() => this._viewHTML("Marketing")}
94 | title={LabelConsentMarketing}
95 | underline={true}
96 | />
97 |
98 | {/* Next Button */}
99 |
100 |
106 |
107 |
108 | );
109 | }
110 | }
111 |
112 | // Redux Connect
113 | export default connect(
114 | (state) => ({
115 |
116 | }),
117 | (dispatch) => ({
118 | goToRegister: () => dispatch({ type: ON_REGISTER }),
119 | goToHTML: () => dispatch({ type: ON_CONSENT_HTML }),
120 | })
121 | )(ConsentScreen);
122 |
--------------------------------------------------------------------------------
/src/navigators/MainTabNavigator.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
3 | import { Image } from 'react-native';
4 |
5 | import VitalScreen from '../screens/VitalScreen'; // Main-Vital
6 | import CalendarScreen from '../screens/CalendarScreen'; // Vital-Calendar
7 | import SymptomScreen from '../screens/SymptomScreen'; // Main-Symptom
8 | import SymptomLogScreen from '../screens/SymptomLogScreen'; // Symptom-Log
9 | import SymptomDetailPatchScreen from '../screens/SymptomDetailPatchScreen'; //Symptom-DetailFromDevice
10 | import SymptomDetailUserScreen from '../screens/SymptomDetailUserScreen'; //Symptom-DetailFromUser
11 | import ProfileScreen from '../screens/ProfileScreen'; // Main-Profile
12 | import SettingScreen from '../screens/SettingScreen'; // Profile-Setting
13 |
14 | import { activeTintColor, inactiveTintColor, backgroundColor, mainColor, headerTintColor } from '../constants/color';
15 |
16 | const VitalStack = createStackNavigator({
17 | Vital: VitalScreen,
18 | Calendar: CalendarScreen
19 | },{
20 | navigationOptions: {
21 | title: 'Signalus',
22 | headerStyle: {
23 | backgroundColor: mainColor,
24 | borderBottomWidth: 0,
25 | },
26 | headerTintColor: headerTintColor,
27 | headerTitleStyle: {
28 | fontWeight: 'bold',
29 | },
30 | },
31 | });
32 |
33 | VitalStack.navigationOptions = ({ navigation }) => {
34 | let tabBarVisible = true;
35 | if (navigation.state.index > 0) {
36 | tabBarVisible = false;
37 | }
38 |
39 | return {
40 | tabBarVisible,
41 | };
42 | };
43 |
44 | const SymptomStack = createStackNavigator({
45 | Symptom: SymptomScreen,
46 | SymptomLog: SymptomLogScreen,
47 | SymptomDetailPatch: SymptomDetailPatchScreen,
48 | SymptomDetailUser: SymptomDetailUserScreen,
49 | },{
50 | navigationOptions: {
51 | title: 'Signalus',
52 | headerStyle: {
53 | backgroundColor: mainColor,
54 | borderBottomWidth: 0,
55 | },
56 | headerTintColor: headerTintColor,
57 | headerTitleStyle: {
58 | fontWeight: 'bold',
59 | },
60 | },
61 | });
62 |
63 | SymptomStack.navigationOptions = ({ navigation }) => {
64 | let tabBarVisible = true;
65 | if (navigation.state.index > 0) {
66 | tabBarVisible = false;
67 | }
68 |
69 | return {
70 | tabBarVisible,
71 | };
72 | };
73 |
74 | const ProfileStack = createStackNavigator({
75 | Profile: ProfileScreen,
76 | Setting: SettingScreen,
77 | },{
78 | navigationOptions: {
79 | title: 'Signalus',
80 | headerStyle: {
81 | backgroundColor: mainColor,
82 | borderBottomWidth: 0,
83 | },
84 | headerTintColor: headerTintColor,
85 | headerTitleStyle: {
86 | fontWeight: 'bold',
87 | },
88 | },
89 | });
90 |
91 | const MainScreen = createBottomTabNavigator({
92 | Vital: {
93 | screen: VitalStack,
94 | navigationOptions:{
95 | tabBarIcon: ({ focused }) => {
96 | let src = focused ? require('../../assets/vitalON.png') : require('../../assets/vitalOFF.png')
97 | return ;
101 | },
102 | }
103 | },
104 | Symptom: {
105 | screen: SymptomStack,
106 | navigationOptions:{
107 | tabBarIcon: ({ focused }) => {
108 | let src = focused ? require('../../assets/symptomON.png') : require('../../assets/symptomOFF.png')
109 | return ;
113 | },
114 | }
115 | },
116 | Profile: {
117 | screen: ProfileStack,
118 | navigationOptions:{
119 | tabBarIcon: ({ focused }) => {
120 | let src = focused ? require('../../assets/profileON.png') : require('../../assets/profileOFF.png')
121 | return ;
125 | },
126 | }
127 | },
128 | },{
129 | initialRouteName: 'Vital',
130 | tabBarOptions:{
131 | activeTintColor: activeTintColor,
132 | inactiveTintColor: inactiveTintColor,
133 | showLabel: false,
134 | style: {
135 | backgroundColor: backgroundColor,
136 | },
137 | },
138 | });
139 |
140 | MainScreen.navigationOptions = {
141 | header: null,
142 | };
143 |
144 |
145 | export default MainScreen;
--------------------------------------------------------------------------------
/src/constants/string.js:
--------------------------------------------------------------------------------
1 | // Bluetooth
2 | export const targetDeviceName = "24Patch";
3 | export const ecgRawUUID = "00002a06-0000-1000-8000-00805f9b34fb";
4 | export const emergencyUUID = "00002a3f-0000-1000-8000-00805f9b34fb";
5 | export const ppgHeartRateUUID = "00002a37-0000-1000-8000-00805f9b34fb";
6 | export const ppgSpO2UUID = "00002a39-0000-1000-8000-00805f9b34fb";
7 | // Header
8 | export const HeaderConsent = "회원가입 1/2";
9 | export const HeaderRegister = "회원가입 2/2";
10 | export const HeaderConsentTerms = "이용 약관";
11 | export const HeaderConsentPrivate = "개인정보 처리방침";
12 | export const HeaderConsentTermsofGeo = "위치기반 서비스 이용약관";
13 | export const HeaderConsentMarketing = "마케팅정보 수신동의";
14 | export const HeaderBluetooth = "블루투스";
15 | export const HeaderVital = "생체신호";
16 | export const HeaderSymptom = "증상 기록";
17 | export const HeaderProfile = "설정";
18 | export const HeaderCalendar = "달력";
19 | export const HeaderSymptomLog = "증상 목록";
20 | export const HeaderSymptomDetailFromDevice = "수신된 증상 기록";
21 | export const HeaderSymptomDetailFromUser = "추가한 증상 기록";
22 | export const HeaderSetting = "세부 정보";
23 |
24 | // Label
25 | export const LabelId = "ID";
26 | export const LabelPassword = "Password";
27 | export const LabelSignIn = "로그인";
28 | export const LabelRegister = "회원가입";
29 | export const LabelFind = "아이디 / 비밀번호 찾기";
30 | export const LabelConsentTerms = "이용약관 동의 (필수)";
31 | export const LabelConsentPrivate = "개인정보 처리방침 동의 (필수)";
32 | export const LabelConsentTermsofGeo = "위치기반 서비스 이용약관 동의 (필수)";
33 | export const LabelConsentMarketing = "마케팅정보 수신동의 (선택)";
34 | export const LabelAgreementAll = "전체동의";
35 | export const LabelAgreement = "다음";
36 | export const LabelRegisterTitle = "회원정보";
37 | export const LabelAge = "Age";
38 | export const LabelSex = "Sex";
39 | export const LabelHeight = "Height";
40 | export const LabelWeight = "Weight";
41 | export const LabelChoose = "선택";
42 | export const LabelBluetoothToggleOn = "사용 중";
43 | export const LabelBluetoothToggleOff = "사용 안 함";
44 | export const LabelBluetoothListTitle = "연결 가능한 디바이스 목록";
45 | export const LabelBluetoothNotConnect = "건너 뛰기";
46 | export const LabelNowBPM = "현재 심박수"
47 | export const LabelBPMHighLow = "오늘 최고, 최저 심박수";
48 | export const LabelSpO2 = "산소포화도";
49 | export const LabelStress = "스트레스 건강 지수";
50 | export const LabelNormal = "정상";
51 | export const LabelWarning = "주의";
52 | export const LabelEmergency = "위험";
53 | export const LabelSymptomFromPatch = "수신된 증상";
54 | export const LabelSymptomFromUser = "내가 추가한 증상";
55 | export const LabelAddSymptom= "추가";
56 | export const LabelSelectSymptom = "확인된 증상을 선택 해주세요";
57 | export const LabelAnxious = "불안함";
58 | export const LabelArmNeckPain = "팔, 목 통증";
59 | export const LabelChestPain = "흉통";
60 | export const LabelDizziness = "어지러움";
61 | export const LabelFainted = "기절";
62 | export const LabelFluttering = "두근거림";
63 | export const LabelLightHeaded = "현기증";
64 | export const LabelVomiting = "구토(메스꺼움)";
65 | export const LabelAlertTitle = "위험상황 시 소리 알림";
66 | export const LabelAlertStatusOn = "사용 중";
67 | export const LabelAlertStatusOff = "사용 안함";
68 | export const LabelRegisterContact = "긴급번호 등록하기";
69 |
70 | export const LabelRegisterButton = "등록";
71 | export const LabelPhoneListTitle = "등록된 전화번호";
72 | export const LabelAccountSetting = "계정 관리";
73 | export const LabelAppSetting = "환경 설정";
74 | export const LabelSupport = "고객 센터";
75 | export const LabelReport = "문제 신고";
76 | export const LabelPrivateInfo = "개인정보 처리방침";
77 | export const LabelTerms = "이용 약관";
78 | export const LabelLogout = "로그아웃";
79 | export const LabelWithdraw = "회원탈퇴";
80 |
81 | // Placeholder
82 | export const PlaceholderId = "아이디";
83 | export const PlaceholderPassword = "비밀번호";
84 | export const PlaceholderPasswordRegister = "비밀번호 : 영문+숫자 8~20자";
85 | export const PlaceholderPasswordCheck = "비밀번호 확인";
86 | export const PlaceholderAge = "연령대";
87 | export const PlaceholderSex = "성별";
88 | export const PlaceholderHeight = "키";
89 | export const PlaceholderWeight = "몸무게";
90 | export const PlaceholderContact = "이름을 입력해주세요";
91 |
92 | // Error
93 | export const ErrorMsgId = "아이디는 8자 이상이어야 합니다";
94 | export const ErrorMsgPassword = "비밀번호는 8자 이상이어야 합니다";
95 | export const ErrorMsgPasswordRegister = "공백을 제외한 8~20자, 영문+숫자 조합으로 설정해주세요";
96 | export const ErrorMsgPasswordCheck = "위와 동일하게 비밀번호를 입력해주세요";
97 | export const ErrorMsgLogin = "일치하는 정보가 없습니다. 다시 입력해주세요";
98 | export const ErrorMsgRegister = "존재하는 아이디입니다";
99 |
100 |
101 | // Mode
102 | export const ModeAge = "연령대";
103 | export const ModeSex = "성별";
104 | export const ModeHeight = "키";
105 | export const ModeWeight = "몸무게";
--------------------------------------------------------------------------------
/src/screens/SymptomScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { connect } from 'react-redux';
3 | import _ from 'lodash';
4 | import { bindActionCreators } from "redux";
5 | // Elements
6 | import {
7 | View, ScrollView, AsyncStorage, RefreshControl, PushNotificationIOS
8 | } from 'react-native';
9 | import { Icon } from 'react-native-elements'
10 | import CustomSymptomItem from '../components/CustomSymptomItem';
11 | import CustomFAB from '../components/CustomFAB';
12 | import styles from '../styles/SymptomStyle';
13 | // Actions
14 | import * as symptomActions from '../reducers/symptom/actions';
15 | import {
16 | ON_LOG, ON_DETAIL_PATCH, ON_DETAIL_USER
17 | } from '../reducers/nav/actionTypes'
18 | // Strings
19 | import {
20 | HeaderSymptom,
21 | } from '../constants/string';
22 | // Colors
23 | import { mainColor } from '../constants/color';
24 |
25 | class SymptomScreen extends Component{
26 | static navigationOptions = {
27 | title: HeaderSymptom,
28 | headerBackTitle: null,
29 | };
30 |
31 | constructor(props){
32 | super(props)
33 | this.state= {
34 | id:'',
35 | token:'',
36 | symptoms:[],
37 | refreshing: false,
38 | }
39 | }
40 |
41 | // Functions
42 | _onRefresh = () => {
43 | this.setState({refreshing: true});
44 | this._getSymptoms(this.state.id, this.state.token)
45 | .then(this.setState({refreshing: false}))
46 | .catch((e) => {});
47 | }
48 |
49 | _getSymptoms = async (id, token) => {
50 | const { SymptomActions } = this.props;
51 |
52 | return await SymptomActions.getSymptoms(id, token);
53 | }
54 |
55 | _goToLog = () => {
56 | this.props.goToLog();
57 | }
58 |
59 | _goToDetailPatch = (symptom) => {
60 | this.props.navigation.navigate('SymptomDetailPatch', {
61 | time: symptom.time,
62 | });
63 | }
64 |
65 | _goToDetailUser = (symptom) => {
66 | this.props.navigation.navigate('SymptomDetailUser', {
67 | time: symptom.time,
68 | symptoms: symptom.symptoms,
69 | });
70 | }
71 |
72 |
73 | // LifeCyle
74 | componentDidMount(){
75 | const { navigation } = this.props;
76 |
77 | AsyncStorage.multiGet(['id', 'token']).then((value) => { // Get Data From LocalStorage
78 | id = value[0][1];
79 | token = value[1][1];
80 |
81 | this.setState({id: id, token: token})
82 | this._getSymptoms(id,token)
83 | .catch((e) =>{})
84 | })
85 | }
86 |
87 | render(){
88 | const { isConnected, symptoms } = this.props;
89 | return(
90 |
91 |
92 | {/* Symptom List */}
93 |
99 | }
100 | >
101 | {_.map(symptoms, symptom => {
102 | _title = symptom.symptoms.length > 1 ? `${symptom.symptoms[0]} 외 ${symptom.symptoms.length-1}개` : `${symptom.symptoms[0]}`;
103 | return (
104 | symptom.type === "patch" ? this._goToDetailPatch(symptom) : this._goToDetailUser(symptom)}
115 | />
116 | );
117 | })}
118 |
119 |
120 |
121 | {/* Floating Action Button */}
122 | {isConnected ?
123 | this._goToLog()}
127 | visible={true}
128 | iconTextComponent={
129 |
133 | }
134 | /> : null}
135 |
136 | );
137 | }
138 | }
139 |
140 | export default connect(
141 | (state) => ({
142 | isConnected: state.bluetooth.isConnected,
143 | symptoms: state.symptom.symptoms,
144 | }),
145 | (dispatch) => ({
146 | SymptomActions: bindActionCreators(symptomActions, dispatch),
147 | goToLog: () => dispatch({ type: ON_LOG}),
148 | goToDetailPatch: () => dispatch({ type: ON_DETAIL_PATCH}),
149 | goToDetailUser: () => dispatch({ type: ON_DETAIL_USER}),
150 | })
151 | )(SymptomScreen);
--------------------------------------------------------------------------------
/ios/Signalus.xcodeproj/xcshareddata/xcschemes/Signalus-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
113 |
119 |
120 |
121 |
122 |
124 |
125 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/ios/Signalus.xcodeproj/xcshareddata/xcschemes/Signalus.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
107 |
108 |
109 |
110 |
111 |
112 |
118 |
120 |
126 |
127 |
128 |
129 |
131 |
132 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/src/screens/SignInScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { bindActionCreators } from "redux";
3 | import { connect } from 'react-redux';
4 | // Elements
5 | import {
6 | Image, View, Text, TouchableOpacity, TouchableWithoutFeedback, Keyboard
7 | } from 'react-native';
8 | import CustomFormInput from '../components/CustomFormInput';
9 | import CustomFilledButton from '../components/CustomFilledButton';
10 | import CustomBorderedButton from '../components/CustomBorderedButton';
11 | import styles from '../styles/SignInStyle';
12 | import { defaultMinLength } from '../constants/dimens';
13 | import { normalize } from '../constants/utils';
14 | // Actions
15 | import * as loginActions from '../reducers/auth/actions';
16 | import {
17 | NOT_CONNECTED, ON_CONSENT
18 | } from '../reducers/nav/actionTypes'
19 | // Strings
20 | import {
21 | LabelSignIn, LabelRegister, LabelFind, PlaceholderId, PlaceholderPassword, ErrorMsgId, ErrorMsgPassword, ErrorMsgLogin, HeaderBluetooth
22 | } from '../constants/string';
23 | // Colors
24 | import { mainColor } from '../constants/color';
25 |
26 | class SignInScreen extends Component{
27 | static navigationOptions = {
28 | header: null,
29 | headerBackTitle: null
30 | };
31 |
32 | constructor(props){
33 | super(props)
34 | this.state= {
35 | id:'',
36 | password:'',
37 | idError:false,
38 | pwError:false,
39 | }
40 | }
41 |
42 | // Functions
43 | _login = () => {
44 | const { LoginActions } = this.props;
45 | this.setState({idError:false, pwError:false})
46 |
47 | if(this.state.id.length >= 8 && this.state.password.length >= 8){ // Check Id and Password
48 | try{
49 | LoginActions.login(this.state.id, this.state.password);
50 | }catch(e){}
51 | } else if(this.state.id.length < defaultMinLength){
52 | this.setState({idError: true})
53 | } else if(this.state.password.length < defaultMinLength){
54 | this.setState({pwError: true})
55 | }
56 | }
57 |
58 | _find = () => {
59 |
60 | }
61 |
62 | // LifeCycle
63 | componentWillReceiveProps(nextProps) {
64 | const { goToBluetooth, isLoggedIn } = nextProps;
65 |
66 | if(isLoggedIn){
67 | goToBluetooth();
68 | }
69 | }
70 |
71 | render(){
72 | const { error, goToConsent } = this.props;
73 |
74 | return(
75 |
76 |
77 |
78 | {/* Logo */}
79 |
84 |
85 | {/* Error Message */}
86 |
87 | {error && {ErrorMsgLogin}}
88 |
89 |
90 | {/* ID Form */}
91 | this.refs.passwordForm.refs.passwordTextInput.focus()}
93 | blurOnSubmit={false}
94 | style={styles.input}
95 | iconStyle={styles.icon}
96 | isIcon={true}
97 | type="ID"
98 | placeholder={PlaceholderId}
99 | onChangeText={(id) => this.setState({id})}
100 | maxLength={20}
101 | returnKeyType="next"
102 | clearButtonMode="never"
103 | error={this.state.idError}
104 | errorMsg={ErrorMsgId}
105 | />
106 |
107 | {/* PW Form */}
108 | this._login()}
112 | blurOnSubmit={false}
113 | style={styles.input}
114 | iconStyle={styles.icon}
115 | isIcon={true}
116 | type="PW"
117 | placeholder={PlaceholderPassword}
118 | onChangeText={(password) => this.setState({password})}
119 | maxLength={20}
120 | returnKeyType="done"
121 | clearButtonMode="always"
122 | secureTextEntry={true}
123 | error={this.state.pwError}
124 | errorMsg={ErrorMsgPassword}
125 | />
126 |
127 | {/* SignIn Button */}
128 | this._login()}
133 | />
134 |
135 | {/* Find Button */}
136 |
137 | this._find()}>
139 |
142 | {LabelFind}
143 |
144 |
145 |
146 |
147 | {/* Register Button */}
148 |
153 |
154 |
155 |
156 | );
157 | }
158 | }
159 |
160 | // Redux Connect
161 | export default connect(
162 | (state) => ({
163 | loading: state.auth.pending,
164 | isLoggedIn : state.auth.isLoggedIn,
165 | error: state.auth.error
166 | }),
167 | (dispatch) => ({
168 | LoginActions: bindActionCreators(loginActions, dispatch),
169 | goToBluetooth: () => dispatch({ type: NOT_CONNECTED}),
170 | goToConsent: () => dispatch({ type: ON_CONSENT}),
171 | })
172 | )(SignInScreen);
173 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/src/screens/SettingScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { bindActionCreators } from "redux";
3 | import { connect } from 'react-redux';
4 | // Elements
5 | import {
6 | View, AsyncStorage, PushNotificationIOS
7 | } from 'react-native';
8 | import { Divider } from 'react-native-elements'
9 | import CustomSimpleTouchableText from '../components/CustomSimpleTouchableText';
10 | import styles from '../styles/SettingStyle';
11 | // Actions
12 | import * as withdrawActions from '../reducers/auth/actions';
13 | import { SIGNOUT } from '../reducers/nav/actionTypes'
14 | import { DISCONNECT_SUCCESS } from '../reducers/bluetooth/actionTypes';
15 | // Strings
16 | import {
17 | HeaderSetting,
18 | LabelAccountSetting, LabelAppSetting, LabelSupport, LabelReport,
19 | LabelPrivateInfo, LabelTerms, LabelLogout, LabelWithdraw,
20 | } from '../constants/string';
21 | // Colors
22 | import { disable } from '../constants/color';
23 |
24 | class Settingscreen extends Component{
25 | static navigationOptions = {
26 | title: HeaderSetting,
27 | };
28 |
29 | constructor(props){
30 | super(props)
31 | this.state= {
32 | id:'',
33 | password:'',
34 | token:'',
35 | }
36 | }
37 |
38 | // Functions
39 | _accountSetting = () => {
40 |
41 | }
42 |
43 | _appSetting = () => {
44 |
45 | }
46 |
47 | _support = () => {
48 |
49 | }
50 |
51 | _report = () => {
52 |
53 | }
54 |
55 | _privateInfo = () => {
56 |
57 | }
58 |
59 | _terms = () => {
60 |
61 | }
62 |
63 | _logout = () => {
64 | const { device, isConnected, disconnect, logout } = this.props;
65 |
66 | if(isConnected){
67 | device.cancelConnection()
68 | disconnect();
69 | }
70 |
71 | AsyncStorage.multiRemove(['id', 'pw', 'token', 'device']).then(() => { // Clear LocalStorage
72 | logout();
73 | })
74 | }
75 |
76 | _withdraw = () => {
77 | const { device, isConnected, disconnect, WithdrawActions } = this.props;
78 |
79 | if(isConnected){
80 | device.cancelConnection()
81 | disconnect();
82 | }
83 |
84 | AsyncStorage.multiRemove(['id', 'pw', 'token', 'device']).then(() => { // Clear LocalStorage
85 | try{
86 | WithdrawActions.withdraw(this.state.id, this.state.token); // Withdraw the Account
87 | }catch(e){}
88 | })
89 | }
90 |
91 | // LifeCycle
92 | componentDidMount(){
93 | AsyncStorage.multiGet(['id', 'pw', 'token']).then((value) => { // Get Data From LocalStorage
94 | id = value[0][1];
95 | password = value[1][1];
96 | token = value[2][1];
97 |
98 | this.setState({id: id, password: password, token: token})
99 | })
100 |
101 | PushNotificationIOS.checkPermissions((currentPermissions) => {
102 | console.log('Badges enabled: ' + !!currentPermissions.badge);
103 | console.log('Sounds enabled: ' + !!currentPermissions.sound);
104 | console.log('Alerts enabled: ' + !!currentPermissions.alert);
105 | });
106 | }
107 |
108 | componentWillReceiveProps(nextProps) {
109 | const { logout, isLoggedIn } = nextProps;
110 | if(!isLoggedIn){
111 | logout();
112 | }
113 | }
114 |
115 | render(){
116 | return(
117 |
118 |
119 | {/* Account Setting */}
120 | this._accountSetting()}
125 | />
126 |
127 | {/* App Setting */}
128 | this._appSetting()}
133 | />
134 |
135 |
136 |
137 | {/* Support */}
138 | this._support()}
143 | />
144 |
145 | {/* Report */}
146 | this._report()}
151 | />
152 |
153 | {/* Private Infomation */}
154 | this._privateInfo()}
159 | />
160 |
161 | {/* Terms */}
162 | this._terms()}
167 | />
168 |
169 |
170 |
171 | {/* Logout */}
172 | this._logout()}
177 | />
178 |
179 | {/* Withdraw */}
180 | this._withdraw()}
185 | />
186 |
187 | );
188 | }
189 | }
190 |
191 | export default connect(
192 | (state) => ({
193 | device: state.bluetooth.device,
194 | isConnected: state.bluetooth.isConnected,
195 | loading: state.auth.pending,
196 | isLoggedIn : state.auth.isLoggedIn,
197 | error: state.auth.error
198 | }),
199 | (dispatch) => ({
200 | WithdrawActions: bindActionCreators(withdrawActions, dispatch),
201 | logout: () => dispatch({ type: SIGNOUT}),
202 | disconnect: () => dispatch({ type: DISCONNECT_SUCCESS })
203 | })
204 | )(Settingscreen);
--------------------------------------------------------------------------------
/src/screens/BluetoothScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { bindActionCreators } from "redux";
3 | import { connect } from 'react-redux';
4 | import update from 'react-addons-update';
5 | import _ from 'lodash';
6 | import { BleManager } from 'react-native-ble-plx';
7 | // Elements
8 | import {
9 | View, Text, Switch, Image, TouchableOpacity
10 | } from 'react-native';
11 | import { Divider } from 'react-native-elements';
12 | import styles from '../styles/BluetoothStyle';
13 | import CustomDevicesItem from '../components/CustomDevicesItem';
14 | import { normalize } from '../constants/utils';
15 | // Actions
16 | import * as connectActions from '../reducers/bluetooth/actions';
17 | import { CONNECTED } from '../reducers/nav/actionTypes'
18 | // Strings
19 | import {
20 | HeaderBluetooth, targetDeviceName,
21 | LabelBluetoothToggleOn, LabelBluetoothToggleOff, LabelBluetoothListTitle, LabelBluetoothNotConnect
22 | } from '../constants/string';
23 | // Colors
24 | import { mainColor, placeholderText } from '../constants/color';
25 |
26 |
27 | class BluetoothScreen extends Component{
28 | static navigationOptions = {
29 | title: HeaderBluetooth,
30 | };
31 |
32 | constructor(props) {
33 | super(props)
34 | this.manager = new BleManager()
35 | this.timeOut
36 | this.state = {
37 | isON: false,
38 | isScanning: false,
39 | isScanned: false,
40 | deviceNames: [],
41 | deviceList: [],
42 | error: false,
43 | errorMsg: "",
44 | }
45 | }
46 |
47 | // Functions
48 | _toggleBluetooth = (value) => {
49 | this.setState({isON: value})
50 | value ? this._scan() : this._stop()
51 | }
52 |
53 | _scan = () => {
54 | this.setState({isScanning: true, isScanned: false, deviceNames: [], deviceList: []})
55 | this.timeOut = setTimeout(this._stop, 5000)
56 | this.manager.startDeviceScan(null,
57 | null, (error, device) => {
58 |
59 | if(device){
60 | console.log("scan : "+device.name)
61 | if(device.name && device.name.startsWith(targetDeviceName)){
62 | if(this.state.deviceNames.indexOf(device.name) == -1){
63 | this.setState({
64 | deviceNames: update(
65 | this.state.deviceNames,
66 | {
67 | $push: [device.name],
68 | }),
69 | deviceList: update(
70 | this.state.deviceList,
71 | {
72 | $push: [device],
73 | }),
74 | })
75 | }
76 | }
77 | }
78 |
79 | if (error) {
80 | this.manager.stopDeviceScan()
81 | clearTimeout(this.timeOut)
82 | this.setState({isON: false, isScanning:false, isScanned:false, error: true, errorMsg: error.message})
83 | return
84 | }
85 | });
86 | }
87 |
88 | _stop = () => {
89 | this.manager.stopDeviceScan()
90 | this.setState({isScanning: false, isScanned: true, error: false})
91 | clearTimeout(this.timeOut)
92 | console.log('scan stop')
93 | }
94 |
95 | _connect = (device) => {
96 | const { ConnectActions } = this.props;
97 |
98 | this._stop();
99 | try{
100 | ConnectActions.connect(device);
101 | }catch(e){}
102 | }
103 |
104 | // LifeCycle
105 | componentDidMount(){
106 |
107 | }
108 |
109 | componentWillReceiveProps(nextProps) {
110 | const { goToMain, isConnected, error } = nextProps;
111 |
112 | if(error) this.setState({isON: false, isScanning:false, isScanned:false, error: true, errorMsg: error.message})
113 | else if(isConnected) goToMain();
114 | }
115 |
116 | render(){
117 | const { goToMain } = this.props;
118 |
119 | return(
120 |
121 |
122 | {/* Header View */}
123 |
124 |
125 | {this.state.isON ? LabelBluetoothToggleOn : LabelBluetoothToggleOff}
126 |
127 |
128 | {this.state.isScanning ?
129 | : null
133 | }
134 |
139 |
140 |
141 |
142 | {/* ListTitle */}
143 |
144 | {this.state.error ? this.state.errorMsg : LabelBluetoothListTitle }
145 |
146 |
147 | {/* Device List */}
148 | {this.state.isON ?
149 |
150 |
151 | {_.map(this.state.deviceList, device => {
152 | return (
153 | this._connect(device)}
160 | />
161 | );
162 | })}
163 |
164 | : null
165 | }
166 |
167 | {/* Next */}
168 | {!this.state.isON ?
169 |
170 |
172 |
175 | {LabelBluetoothNotConnect}
176 |
177 |
178 |
179 | : null
180 | }
181 |
182 |
183 | );
184 | }
185 | }
186 |
187 | export default connect(
188 | (state) => ({
189 | isConnected: state.bluetooth.isConnected,
190 | loading: state.bluetooth.pending,
191 | error: state.bluetooth.error,
192 | }),
193 | (dispatch) => ({
194 | ConnectActions: bindActionCreators(connectActions, dispatch),
195 | goToMain: () => dispatch({ type: CONNECTED}),
196 | })
197 | )(BluetoothScreen);
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 |
3 | import com.android.build.OutputFile
4 |
5 | /**
6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7 | * and bundleReleaseJsAndAssets).
8 | * These basically call `react-native bundle` with the correct arguments during the Android build
9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10 | * bundle directly from the development server. Below you can see all the possible configurations
11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
12 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
13 | *
14 | * project.ext.react = [
15 | * // the name of the generated asset file containing your JS bundle
16 | * bundleAssetName: "index.android.bundle",
17 | *
18 | * // the entry file for bundle generation
19 | * entryFile: "index.android.js",
20 | *
21 | * // whether to bundle JS and assets in debug mode
22 | * bundleInDebug: false,
23 | *
24 | * // whether to bundle JS and assets in release mode
25 | * bundleInRelease: true,
26 | *
27 | * // whether to bundle JS and assets in another build variant (if configured).
28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
29 | * // The configuration property can be in the following formats
30 | * // 'bundleIn${productFlavor}${buildType}'
31 | * // 'bundleIn${buildType}'
32 | * // bundleInFreeDebug: true,
33 | * // bundleInPaidRelease: true,
34 | * // bundleInBeta: true,
35 | *
36 | * // whether to disable dev mode in custom build variants (by default only disabled in release)
37 | * // for example: to disable dev mode in the staging build type (if configured)
38 | * devDisabledInStaging: true,
39 | * // The configuration property can be in the following formats
40 | * // 'devDisabledIn${productFlavor}${buildType}'
41 | * // 'devDisabledIn${buildType}'
42 | *
43 | * // the root of your project, i.e. where "package.json" lives
44 | * root: "../../",
45 | *
46 | * // where to put the JS bundle asset in debug mode
47 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
48 | *
49 | * // where to put the JS bundle asset in release mode
50 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
51 | *
52 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
53 | * // require('./image.png')), in debug mode
54 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
55 | *
56 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
57 | * // require('./image.png')), in release mode
58 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
59 | *
60 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
61 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
62 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
63 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
64 | * // for example, you might want to remove it from here.
65 | * inputExcludes: ["android/**", "ios/**"],
66 | *
67 | * // override which node gets called and with what additional arguments
68 | * nodeExecutableAndArgs: ["node"],
69 | *
70 | * // supply additional arguments to the packager
71 | * extraPackagerArgs: []
72 | * ]
73 | */
74 |
75 | project.ext.react = [
76 | entryFile: "index.js"
77 | ]
78 |
79 | apply from: "../../node_modules/react-native/react.gradle"
80 |
81 | /**
82 | * Set this to true to create two separate APKs instead of one:
83 | * - An APK that only works on ARM devices
84 | * - An APK that only works on x86 devices
85 | * The advantage is the size of the APK is reduced by about 4MB.
86 | * Upload all the APKs to the Play Store and people will download
87 | * the correct one based on the CPU architecture of their device.
88 | */
89 | def enableSeparateBuildPerCPUArchitecture = false
90 |
91 | /**
92 | * Run Proguard to shrink the Java bytecode in release builds.
93 | */
94 | def enableProguardInReleaseBuilds = false
95 |
96 | android {
97 | compileSdkVersion rootProject.ext.compileSdkVersion
98 | buildToolsVersion rootProject.ext.buildToolsVersion
99 |
100 | defaultConfig {
101 | applicationId "com.signalus"
102 | minSdkVersion rootProject.ext.minSdkVersion
103 | targetSdkVersion rootProject.ext.targetSdkVersion
104 | versionCode 1
105 | versionName "1.0"
106 | ndk {
107 | abiFilters "armeabi-v7a", "x86"
108 | }
109 | }
110 | splits {
111 | abi {
112 | reset()
113 | enable enableSeparateBuildPerCPUArchitecture
114 | universalApk false // If true, also generate a universal APK
115 | include "armeabi-v7a", "x86"
116 | }
117 | }
118 | buildTypes {
119 | release {
120 | minifyEnabled enableProguardInReleaseBuilds
121 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
122 | }
123 | }
124 | // applicationVariants are e.g. debug, release
125 | applicationVariants.all { variant ->
126 | variant.outputs.each { output ->
127 | // For each separate APK per architecture, set a unique version code as described here:
128 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
129 | def versionCodes = ["armeabi-v7a":1, "x86":2]
130 | def abi = output.getFilter(OutputFile.ABI)
131 | if (abi != null) { // null for the universal-debug, universal-release variants
132 | output.versionCodeOverride =
133 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
134 | }
135 | }
136 | }
137 | }
138 |
139 | dependencies {
140 | compile project(':react-native-fs')
141 | compile project(':react-native-notifications')
142 | compile project(':react-native-sms')
143 | compile project(':react-native-contacts')
144 | compile project(':react-native-linear-gradient')
145 | compile project(':react-native-ble-plx')
146 | compile project(':react-native-svg')
147 | compile project(':react-native-vector-icons')
148 | compile fileTree(dir: "libs", include: ["*.jar"])
149 | compile "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
150 | compile "com.facebook.react:react-native:+" // From node_modules
151 | }
152 |
153 | // Run this once to be able to run the application with BUCK
154 | // puts all compile dependencies into folder libs for BUCK to use
155 | task copyDownloadableDepsToLibs(type: Copy) {
156 | from configurations.compile
157 | into 'libs'
158 | }
159 |
--------------------------------------------------------------------------------
/src/screens/SymptomLogScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import _ from "lodash";
3 | import { bindActionCreators } from "redux";
4 | import update from 'react-addons-update';
5 | import { connect } from 'react-redux';
6 | // Elements
7 | import {
8 | View, Text, TouchableOpacity, AsyncStorage,
9 | } from 'react-native';
10 | import { Divider } from 'react-native-elements'
11 | import CustomSymptomCheckBox from '../components/CustomSymptomCheckBox';
12 | import styles from '../styles/SymptomLogStyle';
13 | // Actions
14 | import * as symptomActions from '../reducers/symptom/actions';
15 | import { DISCONNECT_SUCCESS } from '../reducers/bluetooth/actionTypes';
16 | // Strings
17 | import {
18 | HeaderSymptomLog, LabelAddSymptom, LabelSelectSymptom,
19 | LabelAnxious, LabelArmNeckPain, LabelChestPain, LabelDizziness,
20 | LabelFainted, LabelFluttering, LabelLightHeaded, LabelVomiting,
21 | } from '../constants/string';
22 | // Colors
23 | import { disable } from '../constants/color';
24 | import { getToday, getTimeForNow } from '../constants/utils';
25 |
26 | class SymptomLogScreen extends Component{
27 | static navigationOptions = ({ navigation }) => {
28 | return{
29 | title: HeaderSymptomLog,
30 | headerBackTitle: null,
31 | headerRight: (
32 |
33 |
34 | {LabelAddSymptom}
35 |
36 |
37 | ),
38 | }};
39 |
40 | constructor(props){
41 | super(props)
42 | this.state= {
43 | id:'',
44 | token:'',
45 | anxious: false,
46 | armNeckPain: false,
47 | chestPain: false,
48 | dizziness: false,
49 | fainted: false,
50 | fluttering: false,
51 | lightHeaded: false,
52 | vomiting: false,
53 | }
54 | }
55 |
56 | // Functions
57 | _addSymptom = () => {
58 | const { SymptomActions } = this.props;
59 |
60 | let symptoms = []
61 |
62 | if(this.state.anxious){
63 | symptoms.push(LabelAnxious)
64 | }
65 |
66 | if(this.state.armNeckPain){
67 | symptoms.push(LabelArmNeckPain)
68 | }
69 |
70 | if(this.state.chestPain){
71 | symptoms.push(LabelChestPain)
72 | }
73 |
74 | if(this.state.dizziness){
75 | symptoms.push(LabelDizziness)
76 | }
77 |
78 | if(this.state.fainted){
79 | symptoms.push(LabelFainted)
80 | }
81 |
82 | if(this.state.fluttering){
83 | symptoms.push(LabelFluttering)
84 | }
85 |
86 | if(this.state.lightHeaded){
87 | symptoms.push(LabelLightHeaded)
88 | }
89 |
90 | if(this.state.vomiting){
91 | symptoms.push(LabelVomiting)
92 | }
93 |
94 | if(symptoms.length > 0){
95 | try{
96 | SymptomActions.addSymptom(this.state.id, symptoms, getTimeForNow(), "device", this.state.token)
97 | }catch(e){}
98 | }
99 | else{
100 | alert("증상을 최소 1개 이상 선택해주세요!")
101 | }
102 | };
103 |
104 | _getSymptoms = async (id, token) => {
105 | const { SymptomActions } = this.props;
106 |
107 | return await SymptomActions.getSymptoms(id, token);
108 | }
109 |
110 | // LifeCycle
111 | componentDidMount(){
112 | const { navigation } = this.props;
113 | console.log(this.props)
114 |
115 | AsyncStorage.multiGet(['id', 'token']).then((value) => { // Get Data From LocalStorage
116 | id = value[0][1];
117 | token = value[1][1];
118 |
119 | this.setState({id: id, token: token})
120 | })
121 |
122 | navigation.setParams({ addSymptom: this._addSymptom });
123 | }
124 |
125 | componentWillReceiveProps(nextProps) {
126 | const { navigation, device, isConnected, error, isRegisterd, } = nextProps;
127 | if(isRegisterd){
128 | this._getSymptoms(this.state.id,this.state.token)
129 | .catch((e) =>{})
130 | navigation.pop();
131 | alert("등록하였습니다!")
132 | }
133 | if(error){
134 | alert("등록에 실패하였습니다..")
135 | }
136 | }
137 |
138 | render(){
139 | return(
140 |
141 |
142 | {/* Header */}
143 |
144 | {getToday()}
145 | {LabelSelectSymptom}
146 |
147 |
148 |
149 |
150 | {/* Symptom CheckBox List */}
151 | this.setState({anxious: !this.state.anxious})}
154 | onTouch={() => console.log("CLICK")}
155 | title={LabelAnxious}
156 | />
157 |
158 | this.setState({armNeckPain: !this.state.armNeckPain})}
161 | onTouch={() => console.log("CLICK")}
162 | title={LabelArmNeckPain}
163 | />
164 |
165 | this.setState({chestPain: !this.state.chestPain})}
168 | onTouch={() => console.log("CLICK")}
169 | title={LabelChestPain}
170 | />
171 |
172 | this.setState({dizziness: !this.state.dizziness})}
175 | onTouch={() => console.log("CLICK")}
176 | title={LabelDizziness}
177 | />
178 |
179 | this.setState({fainted: !this.state.fainted})}
182 | onTouch={() => console.log("CLICK")}
183 | title={LabelFainted}
184 | />
185 |
186 | this.setState({fluttering: !this.state.fluttering})}
189 | onTouch={() => console.log("CLICK")}
190 | title={LabelFluttering}
191 | />
192 |
193 | this.setState({lightHeaded: !this.state.lightHeaded})}
196 | onTouch={() => console.log("CLICK")}
197 | title={LabelLightHeaded}
198 | />
199 |
200 | this.setState({vomiting: !this.state.vomiting})}
203 | onTouch={() => console.log("CLICK")}
204 | title={LabelVomiting}
205 | />
206 |
207 |
208 | );
209 | }
210 | }
211 |
212 | export default connect(
213 | (state) => ({
214 | device: state.bluetooth.device,
215 | isConnected: state.bluetooth.isConnected,
216 | error: state.symptom.error,
217 | isRegisterd: state.symptom.isRegisterd,
218 | }),
219 | (dispatch) => ({
220 | SymptomActions: bindActionCreators(symptomActions, dispatch),
221 | disconnect: () => dispatch({ type: DISCONNECT_SUCCESS })
222 | })
223 | )(SymptomLogScreen);
--------------------------------------------------------------------------------