Merge branch 'diy-svg' into 'master'

Temperature chart

See merge request bloodyhealth/drip!18
This commit is contained in:
Julia Friesel
2018-06-27 11:05:10 +00:00
12 changed files with 447 additions and 6 deletions
+1
View File
@@ -137,6 +137,7 @@ android {
}
dependencies {
compile project(':react-native-svg')
compile project(':realm')
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
@@ -3,6 +3,7 @@ package com.drip;
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.horcrux.svg.SvgPackage;
import io.realm.react.RealmReactPackage;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
@@ -24,6 +25,7 @@ public class MainApplication extends Application implements ReactApplication {
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new SvgPackage(),
new RealmReactPackage()
);
}
+2
View File
@@ -1,4 +1,6 @@
rootProject.name = 'drip'
include ':react-native-svg'
project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android')
include ':realm'
project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android')
+3 -1
View File
@@ -3,6 +3,7 @@ import Home from './home'
import Calendar from './calendar'
import CycleDay from './cycle-day'
import Chart from './components/chart'
// this is until react native fixes this bug, see https://github.com/facebook/react-native/issues/18868#issuecomment-382671739
import { YellowBox } from 'react-native'
@@ -11,5 +12,6 @@ YellowBox.ignoreWarnings(['Warning: isMounted(...) is deprecated'])
export default createStackNavigator({
home: { screen: Home },
calendar: { screen: Calendar },
cycleDay: { screen: CycleDay }
cycleDay: { screen: CycleDay },
chart: { screen: Chart }
})
+219
View File
@@ -0,0 +1,219 @@
import React, { Component } from 'react'
import { Text as ReactNativeText, View, FlatList } from 'react-native'
import range from 'date-range'
import Svg,{
G,
Rect,
Text,
Circle,
Line,
Path
} from 'react-native-svg'
import { LocalDate } from 'js-joda'
import { getCycleDay, getOrCreateCycleDay, cycleDaysSortedByDate } from '../db'
import getCycleDayNumberModule from '../get-cycle-day-number'
import styles from './styles'
import config from './config'
const getCycleDayNumber = getCycleDayNumberModule()
const yAxis = makeYAxis(config)
export default class CycleChart extends Component {
constructor(props) {
super(props)
this.state = {
columns: makeColumnInfo(config.xAxisRangeInDays)
}
this.reCalculateChartInfo = (function(Chart) {
return function() {
Chart.setState({columns: makeColumnInfo(config.xAxisRangeInDays)})
}
})(this)
cycleDaysSortedByDate.addListener(this.reCalculateChartInfo)
}
componentWillUnmount() {
cycleDaysSortedByDate.removeListener(this.reCalculateChartInfo)
}
passDateToDayView(dateString) {
const cycleDay = getOrCreateCycleDay(dateString)
this.props.navigation.navigate('cycleDay', { cycleDay })
}
placeHorizontalGrid() {
return yAxis.tickPositions.map(tick => {
return (
<Line
x1={0}
y1={tick}
x2={config.columnWidth}
y2={tick}
{...styles.horizontalGrid}
key={tick}
/>
)
})
}
makeDayColumn({ dateString, cycleDay, y }, index) {
const cycleDayNumber = getCycleDayNumber(dateString)
const label = styles.column.label
const dateLabel = dateString.split('-').slice(1).join('-')
return (
<G onPress={() => this.passDateToDayView(dateString)}>
<Rect {...styles.column.rect} />
{this.placeHorizontalGrid()}
<Text {...label.number} y={config.cycleDayNumberRowY}>{cycleDayNumber}</Text>
<Text {...label.date} y={config.dateRowY}>{dateLabel}</Text>
{cycleDay && cycleDay.bleeding ?
<Path {...styles.bleedingIcon}
d="M15 3
Q16.5 6.8 25 18
A12.8 12.8 0 1 1 5 18
Q13.5 6.8 15 3z" />
: null}
{y ? this.drawDotAndLines(y, cycleDay.temperature.exclude, index) : null}
</G>
)
}
drawDotAndLines(currY, exclude, index) {
let lineToRight
let lineToLeft
const cols = this.state.columns
function makeLine(otherColY, x, excludeLine) {
const middleY = ((otherColY - currY) / 2) + currY
const target = [x, middleY]
const lineStyle = excludeLine ? styles.curveExcluded : styles.curve
return <Line
x1={config.columnMiddle}
y1={currY}
x2={target[0]}
y2={target[1]}
{...lineStyle}
/>
}
const thereIsADotToTheRight = index > 0 && cols[index - 1].y
const thereIsADotToTheLeft = index < cols.length - 1 && cols[index + 1].y
if (thereIsADotToTheRight) {
const otherDot = cols[index - 1]
const excludedLine = otherDot.cycleDay.temperature.exclude || exclude
lineToRight = makeLine(otherDot.y, config.columnWidth, excludedLine)
}
if (thereIsADotToTheLeft) {
const otherDot = cols[index + 1]
const excludedLine = otherDot.cycleDay.temperature.exclude || exclude
lineToLeft = makeLine(otherDot.y, 0, excludedLine)
}
const dotStyle = exclude ? styles.curveDotsExcluded : styles.curveDots
return (<G>
{lineToRight}
{lineToLeft}
<Circle
cx={config.columnMiddle}
cy={currY}
{...dotStyle}
/>
</G>)
}
render() {
return (
<View style={{flex: 1, flexDirection: 'row'}}>
<View {...styles.yAxis}>{yAxis.labels}</View>
<FlatList
horizontal={true}
inverted={true}
showsHorizontalScrollIndicator={false}
data={this.state.columns}
renderItem={({ item, index }) => {
return (
<Svg width={config.columnWidth} height={config.chartHeight}>
{this.makeDayColumn(item, index)}
</Svg>
)
}}
keyExtractor={item => item.dateString}
>
</FlatList>
</View>
)
}
}
function makeColumnInfo(n) {
const xAxisDates = getPreviousDays(n).map(jsDate => {
return LocalDate.of(
jsDate.getFullYear(),
jsDate.getMonth() + 1,
jsDate.getDate()
).toString()
})
return xAxisDates.map(dateString => {
const cycleDay = getCycleDay(dateString)
const temp = cycleDay && cycleDay.temperature && cycleDay.temperature.value
return {
dateString,
cycleDay,
y: temp ? normalizeToScale(temp) : null
}
})
}
function getPreviousDays(n) {
const today = new Date()
today.setHours(0); today.setMinutes(0); today.setSeconds(0); today.setMilliseconds(0)
const earlierDate = new Date(today - (range.DAY * n))
return range(earlierDate, today).reverse()
}
function normalizeToScale(temp) {
const temperatureScale = config.temperatureScale
const valueRelativeToScale = (temperatureScale.high - temp) / (temperatureScale.high - temperatureScale.low)
const scaleHeight = config.chartHeight
return scaleHeight * valueRelativeToScale
}
function makeYAxis() {
const scaleMin = config.temperatureScale.low
const scaleMax = config.temperatureScale.high
const numberOfTicks = (scaleMax - scaleMin) * 2
const tickDistance = config.chartHeight / numberOfTicks
const tickPositions = []
const labels = []
// for style reasons, we don't want the first and last tick
for (let i = 1; i < numberOfTicks - 1; i++) {
const y = tickDistance * i
const style = styles.yAxisLabel
// this eyeballing is sadly necessary because RN does not
// support percentage values for transforms, which we'd need
// to reliably place the label vertically centered to the grid
style.top = y - 8
labels.push(
<ReactNativeText
style={{...style}}
key={i}>
{scaleMax - i * 0.5}
</ReactNativeText>
)
tickPositions.push(y)
}
return {labels, tickPositions}
}
+16
View File
@@ -0,0 +1,16 @@
const config = {
chartHeight: 350,
columnWidth: 30,
temperatureScale: {
low: 33,
high: 40
},
xAxisRangeInDays: 40
}
const margin = 3
config.columnMiddle = config.columnWidth / 2,
config.dateRowY = config.chartHeight - 15 - margin
config.cycleDayNumberRowY = config.chartHeight - margin
export default config
+68
View File
@@ -0,0 +1,68 @@
import config from './config'
const styles = {
curve: {
stroke: '#ffc425',
strokeWidth: 2
},
curveExcluded: {
stroke: 'lightgrey',
strokeWidth: 2,
strokeDashArray: [4]
},
curveDots: {
fill: '#00aedb',
r: 6
},
curveDotsExcluded: {
fill: 'lightgrey',
r: 6
},
column: {
label: {
date: {
stroke: 'grey',
fontSize: 10,
x: 2,
fontWeight: '100'
},
number: {
stroke: '#00b159',
fontSize: 13,
x: config.columnMiddle - 1
}
},
rect: {
fill: '#f9f9f9',
strokeWidth: 1,
stroke: 'grey',
x: 0,
y: 0,
width: config.columnWidth,
height: config.chartHeight
}
},
bleedingIcon: {
fill: '#fb2e01',
scale: 0.6,
x: 7,
y: 3
},
yAxis: {
height: config.chartHeight,
width: config.columnWidth,
},
yAxisLabel: {
position: 'absolute',
right: 3,
color: 'grey',
fontSize: 12,
fontWeight: 'bold'
},
horizontalGrid: {
stroke: 'lightgrey',
strokeWidth: 1
}
}
export default styles
+9 -3
View File
@@ -53,7 +53,7 @@ function saveTemperature(cycleDay, temperature) {
})
}
const getCycleDaysSortedByDateView = () => db.objects('CycleDay').sorted('date', true)
const cycleDaysSortedByDate = db.objects('CycleDay').sorted('date', true)
function saveBleeding(cycleDay, bleeding) {
db.write(() => {
@@ -73,6 +73,10 @@ function getOrCreateCycleDay(localDate) {
return result
}
function getCycleDay(localDate) {
return db.objectForPrimaryKey('CycleDay', localDate)
}
function deleteAll() {
db.write(() => {
db.deleteAll()
@@ -94,7 +98,9 @@ export {
saveBleeding,
getOrCreateCycleDay,
bleedingDaysSortedByDate,
getCycleDaysSortedByDateView,
temperatureDaysSortedByDate,
cycleDaysSortedByDate,
deleteAll,
getPreviousTemperature
getPreviousTemperature,
getCycleDay
}
+6
View File
@@ -65,6 +65,12 @@ export default class Home extends Component {
title="Go to calendar">
</Button>
</View>
<View>
<Button
onPress={() => navigate('chart')}
title="Go to chart">
</Button>
</View>
<View>
<Button
onPress={() => deleteAll()}
+71 -2
View File
@@ -5,7 +5,6 @@
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
@@ -38,6 +37,8 @@
5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; };
4DD9342A0EA14FF399CBC625 /* libRNSVG.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 154304354E2E4612B01C5232 /* libRNSVG.a */; };
2F7162338C9C4298AAF05308 /* libRNSVG-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F597327061840D088EE7B05 /* libRNSVG-tvOS.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -343,6 +344,9 @@
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = "<group>"; };
E20F46E373F5493594D234EB /* RNSVG.xcodeproj */ = {isa = PBXFileReference; name = "RNSVG.xcodeproj"; path = "../node_modules/react-native-svg/ios/RNSVG.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
154304354E2E4612B01C5232 /* libRNSVG.a */ = {isa = PBXFileReference; name = "libRNSVG.a"; path = "libRNSVG.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
0F597327061840D088EE7B05 /* libRNSVG-tvOS.a */ = {isa = PBXFileReference; name = "libRNSVG-tvOS.a"; path = "libRNSVG-tvOS.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -371,6 +375,7 @@
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
4DD9342A0EA14FF399CBC625 /* libRNSVG.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -386,6 +391,7 @@
2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */,
2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */,
2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */,
2F7162338C9C4298AAF05308 /* libRNSVG-tvOS.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -557,6 +563,7 @@
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
E20F46E373F5493594D234EB /* RNSVG.xcodeproj */,
);
name = Libraries;
sourceTree = "<group>";
@@ -685,7 +692,7 @@
83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
LastUpgradeCheck = 610;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
00E356ED1AD99517003FC87E = {
@@ -1181,6 +1188,15 @@
);
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/drip.app/drip";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
};
name = Debug;
};
@@ -1198,6 +1214,15 @@
);
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/drip.app/drip";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
};
name = Release;
};
@@ -1216,6 +1241,10 @@
);
PRODUCT_NAME = drip;
VERSIONING_SYSTEM = "apple-generic";
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
};
name = Debug;
};
@@ -1233,6 +1262,10 @@
);
PRODUCT_NAME = drip;
VERSIONING_SYSTEM = "apple-generic";
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
};
name = Release;
};
@@ -1259,6 +1292,15 @@
SDKROOT = appletvos;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.2;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
};
name = Debug;
};
@@ -1285,6 +1327,15 @@
SDKROOT = appletvos;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.2;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
};
name = Release;
};
@@ -1310,6 +1361,15 @@
SDKROOT = appletvos;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/drip-tvOS.app/drip-tvOS";
TVOS_DEPLOYMENT_TARGET = 10.1;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
};
name = Debug;
};
@@ -1335,6 +1395,15 @@
SDKROOT = appletvos;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/drip-tvOS.app/drip-tvOS";
TVOS_DEPLOYMENT_TARGET = 10.1;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
};
name = Release;
};
+48
View File
@@ -2329,6 +2329,15 @@
"object-visit": "^1.0.0"
}
},
"color": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color/-/color-2.0.1.tgz",
"integrity": "sha512-ubUCVVKfT7r2w2D3qtHakj8mbmKms+tThR8gI8zEYCbUBl8/voqFGt3kgBqGwXAopgXybnkuOq+qMYCRrp4cXw==",
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.2"
}
},
"color-convert": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
@@ -2342,6 +2351,15 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"color-string": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.2.tgz",
"integrity": "sha1-JuRYFLw8mny9Z1FkikFDRRSnc6k=",
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"color-support": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
@@ -2506,6 +2524,11 @@
}
}
},
"date-range": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/date-range/-/date-range-0.0.2.tgz",
"integrity": "sha1-OVHZ5SWZgu3VMewx5APYImPvbjk="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -6272,6 +6295,16 @@
"resolved": "https://registry.npmjs.org/react-native-simple-radio-button/-/react-native-simple-radio-button-2.7.1.tgz",
"integrity": "sha512-O3RIKBl1GgSAITAEhf4BscrEa3jWdW82xP6yCC40+h7rliQpHEL/3lYTyO9V4wYi3RV8kwvDbxiF4v1+fR0k3w=="
},
"react-native-svg": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-6.3.1.tgz",
"integrity": "sha512-0kmfUwKUBWnPuJpy+bdGIYKkXHg/M/X57ji8b3d3ZFB2rRTWMRkwI1D+AJ6FQRX109+FJn6L6hsIokDj1lckzA==",
"requires": {
"color": "^2.0.1",
"lodash": "^4.16.6",
"pegjs": "^0.10.0"
}
},
"react-native-tab-view": {
"version": "0.0.77",
"resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-0.0.77.tgz",
@@ -7222,6 +7255,21 @@
}
}
},
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"requires": {
"is-arrayish": "^0.3.1"
},
"dependencies": {
"is-arrayish": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.1.tgz",
"integrity": "sha1-wt/DhquqDD4zxI2z/ocFnmkGXv0="
}
}
},
"slash": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+2
View File
@@ -14,12 +14,14 @@
"lint": "eslint app test"
},
"dependencies": {
"date-range": "0.0.2",
"js-joda": "^1.8.2",
"moment": "^2.22.1",
"react": "16.3.1",
"react-native": "0.55.4",
"react-native-calendars": "^1.19.3",
"react-native-simple-radio-button": "^2.7.1",
"react-native-svg": "^6.3.1",
"react-navigation": "^2.0.4",
"realm": "^2.7.1",
"uuid": "^3.2.1"