Merge branch '197-re-make-chart-with-svg-again' into 'master'

Resolve "re-make chart with svg (again)"

Closes #197 and #168

See merge request bloodyhealth/drip!77
This commit is contained in:
Julia Friesel
2018-09-19 13:00:04 +00:00
11 changed files with 156 additions and 103 deletions
+1
View File
@@ -151,6 +151,7 @@ android {
dependencies {
compile project(':nodejs-mobile-react-native')
compile project(':react-native-restart')
compile project(':react-native-svg')
compile project(':react-native-push-notification')
compile project(':react-native-vector-icons')
compile project(':react-native-fs')
@@ -5,6 +5,7 @@ import android.app.Application;
import com.facebook.react.ReactApplication;
import com.janeasystems.rn_nodejs_mobile.RNNodeJsMobilePackage;
import com.avishayil.rnrestart.ReactNativeRestartPackage;
import com.horcrux.svg.SvgPackage;
import com.dieam.reactnativepushnotification.ReactNativePushNotificationPackage;
import com.oblador.vectoricons.VectorIconsPackage;
import com.rnfs.RNFSPackage;
@@ -34,6 +35,7 @@ public class MainApplication extends Application implements ReactApplication, Sh
new MainReactPackage(),
new RNNodeJsMobilePackage(),
new ReactNativeRestartPackage(),
new SvgPackage(),
new ReactNativePushNotificationPackage(),
new VectorIconsPackage(),
new RNFSPackage(),
+2
View File
@@ -3,6 +3,8 @@ include ':nodejs-mobile-react-native'
project(':nodejs-mobile-react-native').projectDir = new File(rootProject.projectDir, '../node_modules/nodejs-mobile-react-native/android')
include ':react-native-restart'
project(':react-native-restart').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-restart/android')
include ':react-native-svg'
project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android')
include ':react-native-push-notification'
project(':react-native-push-notification').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-push-notification/android')
include ':react-native-vector-icons'
+4 -3
View File
@@ -33,7 +33,7 @@ export default class CycleChart extends Component {
const height = nativeEvent.layout.height
this.setState({ chartHeight: height })
this.reCalculateChartInfo = () => {
this.setState({ columns: this.makeColumnInfo(nfpLines(height)) })
this.setState({ columns: this.makeColumnInfo(nfpLines()) })
}
this.cycleDaysSortedByDate.addListener(this.reCalculateChartInfo)
@@ -62,6 +62,7 @@ export default class CycleChart extends Component {
jsDate.getDate()
).toString()
})
const chartSymptoms = [
'bleeding',
'temperature',
@@ -103,8 +104,8 @@ export default class CycleChart extends Component {
return {
dateString,
y: temp ? normalizeToScale(temp, columnHeight) : null,
symptoms,
...getFhmAndLtlInfo(dateString, temp)
...symptoms,
...getFhmAndLtlInfo(dateString, temp, columnHeight)
}
})
+47 -40
View File
@@ -2,6 +2,7 @@ import React, { Component } from 'react'
import {
Text, View, TouchableOpacity
} from 'react-native'
import Svg,{ G, Rect, Line } from 'react-native-svg'
import Icon from 'react-native-vector-icons/Entypo'
import styles from './styles'
import config from '../../config'
@@ -30,7 +31,6 @@ export default class DayColumn extends Component {
dateString,
y,
temperatureExclude,
symptoms,
drawFhmLine,
drawLtlAt,
rightY,
@@ -47,16 +47,31 @@ export default class DayColumn extends Component {
const columnElements = []
if(drawLtlAt) {
const ltlLine = (<View
position = 'absolute'
width={'100%'}
top={drawLtlAt}
const ltlLine = (<Line
x1={0}
y1={drawLtlAt}
x2={config.columnWidth}
y2={drawLtlAt}
{...styles.nfpLine}
key='ltl'
/>)
columnElements.push(ltlLine)
}
if (drawFhmLine) {
const x = styles.nfpLine.strokeWidth / 2
const fhmLine = (<Line
x1={x}
y1={x}
x2={x}
y2={columnHeight}
{...styles.nfpLine}
key='fhm'
/>)
columnElements.push(fhmLine)
}
if (y) {
columnElements.push(
<DotAndLine
@@ -83,64 +98,53 @@ export default class DayColumn extends Component {
</Text>
)
// we merge the colors here instead of from the stylesheet because of a RN
// bug that doesn't apply borderLeftColor otherwise
const potentialCustomStyle = {
height: columnHeight,
borderLeftColor: 'grey',
}
if (drawFhmLine) {
potentialCustomStyle.borderLeftColor = styles.nfpLine.borderColor
potentialCustomStyle.borderLeftWidth = 3
}
const column = React.createElement(
TouchableOpacity,
{
style: [styles.column.rect, potentialCustomStyle],
key: this.props.index.toString(),
onPress: () => {
this.passDateToDayView(dateString)
},
activeOpacity: 1
},
columnElements
const column = (
<G>
<Rect
height={chartHeight}
{...styles.column.rect}
/>
{ columnElements }
</G>
)
return (
<View>
<TouchableOpacity
onPress={() => this.passDateToDayView(dateString)}
activeOpacity={1}
>
<View height={symptomHeight}>
<View style={styles.symptomRow}>
{typeof symptoms.bleeding === 'number' &&
{typeof this.props.bleeding === 'number' &&
<Icon
name='drop'
size={12}
color={styles.bleedingIconShades[symptoms.bleeding]}
color={styles.bleedingIconShades[this.props.bleeding]}
key='bleeding'
/>
}
</View>
<View style={styles.symptomRow}>
{typeof symptoms.mucus === 'number' &&
{typeof this.props.mucus === 'number' &&
<View
{...styles.mucusIcon}
backgroundColor={styles.mucusIconShades[symptoms.mucus]}
backgroundColor={styles.mucusIconShades[this.props.mucus]}
key='mucus'
/>
}
</View>
<View style={styles.symptomRow}>
{typeof symptoms.cervix === 'number' &&
{typeof this.props.cervix === 'number' &&
<View
{...styles.mucusIcon}
// cervix is sum of openess and firmness - fertile only when closed and hard (=0)
backgroundColor={symptoms.cervix > 0 ? 'blue' : 'green'}
backgroundColor={this.props.cervix > 0 ? 'blue' : 'green'}
key='cervix'
/>
}
</View>
<View style={styles.symptomRow}>
{typeof symptoms.sex === 'number' &&
{typeof this.props.sex === 'number' &&
<View
{...styles.mucusIcon}
backgroundColor='orange'
@@ -149,7 +153,7 @@ export default class DayColumn extends Component {
}
</View>
<View style={styles.symptomRow}>
{typeof symptoms.desire === 'number' &&
{typeof this.props.desire === 'number' &&
<View
{...styles.mucusIcon}
backgroundColor='red'
@@ -158,7 +162,7 @@ export default class DayColumn extends Component {
}
</View>
<View style={styles.symptomRow}>
{symptoms.pain &&
{this.props.pain &&
<View
{...styles.mucusIcon}
backgroundColor='blue'
@@ -167,7 +171,7 @@ export default class DayColumn extends Component {
}
</View>
<View style={styles.symptomRow}>
{symptoms.note &&
{this.props.note &&
<View
{...styles.mucusIcon}
backgroundColor='green'
@@ -176,13 +180,16 @@ export default class DayColumn extends Component {
}
</View>
</View>
{column}
<Svg width={config.columnWidth} height={columnHeight}>
{column}
</Svg>
<View style={{height: xAxisHeight}}>
{cycleDayLabel}
{dateLabel}
</View>
</View>
</TouchableOpacity>
)
}
}
+16 -34
View File
@@ -1,5 +1,6 @@
import React, { Component } from 'react'
import { View } from 'react-native'
import { Circle, Line } from 'react-native-svg'
import styles from './styles'
import config from '../../config'
@@ -17,21 +18,20 @@ export default class DotAndLine extends Component {
if (this.props.leftY) {
const middleY = ((this.props.leftY - y) / 2) + y
const excludedLine = this.props.leftTemperatureExclude || exclude
lineToLeft = makeLine(middleY, y, 'left', excludedLine)
lineToLeft = makeLine(y, middleY, 0, excludedLine)
}
if (this.props.rightY) {
const middleY = ((y - this.props.rightY) / 2) + this.props.rightY
const excludedLine = this.props.rightTemperatureExclude || exclude
lineToRight = makeLine(y, middleY, 'right', excludedLine)
lineToRight = makeLine(y, middleY, config.columnWidth, excludedLine)
}
const dotStyle = exclude ? styles.curveDotsExcluded : styles.curveDots
const dot = (
<View
position='absolute'
top={y - (dotStyle.height / 2)}
left={config.columnMiddle - (dotStyle.width / 2)}
style={dotStyle}
<Circle
cx={config.columnMiddle}
cy={y}
{...dotStyle}
key='dot'
/>
)
@@ -39,33 +39,15 @@ export default class DotAndLine extends Component {
}
}
function makeLine(leftY, rightY, direction, excludeLine) {
const colWidth = config.columnWidth
const heightDiff = -(leftY - rightY)
const angle = Math.atan2(heightDiff, colWidth / 2)
function makeLine(currY, middleY, x, excludeLine) {
const lineStyle = excludeLine ? styles.curveExcluded : styles.curve
// hypotenuse, we add 3px for good measure, because otherwise the lines
// don't quite touch at the day border
const h = (colWidth / 2) / Math.cos(angle) + 10
// the rotation by default rotates from the middle of the line,
// but we want the transform origin to be at its beginning
// react native doesn't have transformOrigin, so we do this manually
// if it's the right line, we put the pivot at 3/4 of the column
// if it's to the left, at 1/4
const pivot = direction === 'right' ? colWidth / 4 : -(colWidth / 4)
const projectedX = -(h - colWidth) / 2 + pivot
return (<View
width={h}
position='absolute'
top={((leftY + rightY) / 2) - lineStyle.borderWidth / 2}
left={projectedX}
style={{
transform: [
{ rotateZ: `${angle}rad` }
],
}}
return <Line
x1={config.columnMiddle}
y1={currY}
x2={x}
y2={middleY}
{...lineStyle}
key ={direction}
/>)
key={x.toString()}
/>
}
+3 -3
View File
@@ -1,7 +1,7 @@
import { getCycleStatusForDay } from '../../lib/sympto-adapter'
import { normalizeToScale } from './y-axis'
export default function (chartHeight) {
export default function () {
const cycle = {
status: null
}
@@ -49,7 +49,7 @@ export default function (chartHeight) {
)
}
return function(dateString, temperature) {
return function(dateString, temperature, columnHeight) {
const ret = {
drawLtlAt: null,
drawFhmLine: false
@@ -71,7 +71,7 @@ export default function (chartHeight) {
dateIsInPeriOrPostPhase(dateString) &&
isInTempMeasuringPhase(temperature, dateString)
) {
ret.drawLtlAt = normalizeToScale(tempShift.ltl, chartHeight)
ret.drawLtlAt = normalizeToScale(tempShift.ltl, columnHeight)
}
}
+21 -23
View File
@@ -3,32 +3,28 @@ import {primaryColor, shadesOfRed} from '../../styles/index'
const colorTemperature = '#765285'
const colorTemperatureLight = '#a67fb5'
const dotWidth = 10
const lineWidth = 2
const dotRadius = 5
const lineWidth = 1.5
const colorLtl = '#feb47b'
const gridColor = 'lightgrey'
const gridLineWidth = 0.5
const styles = {
curve: {
borderStyle: 'solid',
borderColor: colorTemperature,
borderWidth: lineWidth,
stroke: colorTemperature,
strokeWidth: lineWidth,
},
curveExcluded: {
borderColor: colorTemperatureLight,
borderWidth: lineWidth,
borderStyle: 'dotted'
stroke: colorTemperatureLight,
strokeWidth: lineWidth
},
curveDots: {
backgroundColor: colorTemperature,
width: dotWidth,
height: dotWidth,
borderRadius: 50
fill: colorTemperature,
r: dotRadius
},
curveDotsExcluded: {
backgroundColor: colorTemperatureLight,
width: dotWidth,
height: dotWidth,
borderRadius: 50
fill: colorTemperatureLight,
r: dotRadius
},
column: {
label: {
@@ -44,9 +40,12 @@ const styles = {
}
},
rect: {
x:'0',
y:'0',
width: config.columnWidth,
borderStyle: 'solid',
borderLeftWidth: 0.5,
stroke: gridColor,
strokeWidth: gridLineWidth,
fill: 'transparent'
}
},
bleedingIcon: {
@@ -83,16 +82,15 @@ const styles = {
},
horizontalGrid: {
position:'absolute',
borderColor: 'lightgrey',
borderWidth: 0.5,
borderColor: gridColor,
borderWidth: gridLineWidth,
width: '100%',
borderStyle: 'solid',
left: config.columnWidth
},
nfpLine: {
borderColor: colorLtl,
borderWidth: lineWidth,
borderStyle: 'solid'
stroke: colorLtl,
strokeWidth: lineWidth,
},
symptomRow: {
alignItems: 'center',
+16
View File
@@ -64,6 +64,8 @@
8EA186B6112C41D1B206762D /* NodeMobile.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C225FC4966694B9FBD32E946 /* NodeMobile.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
E4584E55EEC24302A3E84A23 /* nodejs-project in Resources */ = {isa = PBXBuildFile; fileRef = 6466AE2461BE4FA88B8372F0 /* nodejs-project */; };
A16B351C3F3644CF95F104D2 /* builtin_modules in Resources */ = {isa = PBXBuildFile; fileRef = 36F1B55D0DEE47AA9AF4BBDD /* builtin_modules */; };
45794BEC42E34672A759220F /* libRNSVG.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 93C745A8EE95400C96FD5CF7 /* libRNSVG.a */; };
3E63FB3C405F4AF39969C7E3 /* libRNSVG-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AD4FC2FD95A84EFCBB59195F /* libRNSVG-tvOS.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -402,6 +404,9 @@
C225FC4966694B9FBD32E946 /* NodeMobile.framework */ = {isa = PBXFileReference; name = "NodeMobile.framework"; path = "../node_modules/nodejs-mobile-react-native/ios/NodeMobile.framework"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.framework; explicitFileType = undefined; includeInIndex = 0; };
6466AE2461BE4FA88B8372F0 /* nodejs-project */ = {isa = PBXFileReference; name = "nodejs-project"; path = "../nodejs-assets/nodejs-project"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
36F1B55D0DEE47AA9AF4BBDD /* builtin_modules */ = {isa = PBXFileReference; name = "builtin_modules"; path = "../node_modules/nodejs-mobile-react-native/install/resources/nodejs-modules/builtin_modules"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
DEB488BF9A9642508320FB42 /* 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; };
93C745A8EE95400C96FD5CF7 /* libRNSVG.a */ = {isa = PBXFileReference; name = "libRNSVG.a"; path = "libRNSVG.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
AD4FC2FD95A84EFCBB59195F /* 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 */
@@ -440,6 +445,7 @@
72DA6B4241504DB096AFAD40 /* libRCTRestart.a in Frameworks */,
E09F3B05A4F84E9883101CC7 /* libRNNodeJsMobile.a in Frameworks */,
E43EF009AC8C4698AB322190 /* NodeMobile.framework in Frameworks */,
45794BEC42E34672A759220F /* libRNSVG.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -456,6 +462,7 @@
2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */,
2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */,
934282049FA3497D9062CEC1 /* libRNSVG-tvOS.a in Frameworks */,
3E63FB3C405F4AF39969C7E3 /* libRNSVG-tvOS.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -637,6 +644,7 @@
49089E09BFCF4F3DB209B6E9 /* RNFS.xcodeproj */,
50DBC4BCDDF74A10AEDC99D5 /* RCTRestart.xcodeproj */,
65F706FAFA1444AE9937D472 /* RNNodeJsMobile.xcodeproj */,
DEB488BF9A9642508320FB42 /* RNSVG.xcodeproj */,
);
name = Libraries;
sourceTree = "<group>";
@@ -1482,6 +1490,7 @@ fi
"$(inherited)",
"\"../node_modules/nodejs-mobile-react-native/ios\"",
"\"../node_modules/nodejs-mobile-react-native/ios\"",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
ENABLE_BITCODE = NO;
};
@@ -1523,6 +1532,7 @@ fi
"$(inherited)",
"\"../node_modules/nodejs-mobile-react-native/ios\"",
"\"../node_modules/nodejs-mobile-react-native/ios\"",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
ENABLE_BITCODE = NO;
};
@@ -1552,6 +1562,7 @@ fi
"$(SRCROOT)/../node_modules/react-native-fs/**",
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -1584,6 +1595,7 @@ fi
"$(SRCROOT)/../node_modules/react-native-fs/**",
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -1638,6 +1650,7 @@ fi
"$(inherited)",
"\"../node_modules/nodejs-mobile-react-native/ios\"",
"\"../node_modules/nodejs-mobile-react-native/ios\"",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
ENABLE_BITCODE = NO;
};
@@ -1688,6 +1701,7 @@ fi
"$(inherited)",
"\"../node_modules/nodejs-mobile-react-native/ios\"",
"\"../node_modules/nodejs-mobile-react-native/ios\"",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
ENABLE_BITCODE = NO;
};
@@ -1732,6 +1746,7 @@ fi
"$(SRCROOT)/../node_modules/react-native-fs/**",
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -1781,6 +1796,7 @@ fi
"$(SRCROOT)/../node_modules/react-native-fs/**",
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
"$(SRCROOT)/../node_modules/react-native-svg/ios/**",
);
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
+43
View File
@@ -2566,6 +2566,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.2",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
@@ -2579,6 +2588,15 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok="
},
"color-string": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz",
"integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==",
"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",
@@ -6650,6 +6668,16 @@
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-1.1.0.tgz",
"integrity": "sha512-uQXo+HzZGUo9VlfgfWwGa9vLrY9OBQOFAsxhH/e3GWAlCxrGGjXNu/La+aJzMJdhoHzzn1+NRWDp1LWvlxJHew=="
},
"react-native-svg": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-7.0.2.tgz",
"integrity": "sha512-vDHePF9sSPp3s+AmAkk4HBvgWHdlaH5ns1mCAcrPqTiyF1QsApAtp3/3AHh8G8o57F2eJjEQ7LrRFNYyQPUBEw==",
"requires": {
"color": "^2.0.1",
"lodash": "^4.16.6",
"pegjs": "^0.10.0"
}
},
"react-native-vector-icons": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-5.0.0.tgz",
@@ -7577,6 +7605,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.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
}
}
},
"slash": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+1
View File
@@ -35,6 +35,7 @@
"react-native-push-notification": "^3.1.1",
"react-native-restart": "0.0.7",
"react-native-share": "^1.1.0",
"react-native-svg": "^7.0.2",
"react-native-vector-icons": "^5.0.0",
"realm": "^2.7.1"
},