Merge branch '14-encrypt-db' into 'master'
Resolve "encrypt DB" Closes #14 See merge request bloodyhealth/drip!76
This commit is contained in:
@@ -149,6 +149,8 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
compile project(':nodejs-mobile-react-native')
|
||||||
|
compile project(':react-native-restart')
|
||||||
compile project(':react-native-push-notification')
|
compile project(':react-native-push-notification')
|
||||||
compile project(':react-native-vector-icons')
|
compile project(':react-native-vector-icons')
|
||||||
compile project(':react-native-fs')
|
compile project(':react-native-fs')
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package com.drip;
|
|||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
|
||||||
import com.facebook.react.ReactApplication;
|
import com.facebook.react.ReactApplication;
|
||||||
|
import com.janeasystems.rn_nodejs_mobile.RNNodeJsMobilePackage;
|
||||||
|
import com.avishayil.rnrestart.ReactNativeRestartPackage;
|
||||||
import com.dieam.reactnativepushnotification.ReactNativePushNotificationPackage;
|
import com.dieam.reactnativepushnotification.ReactNativePushNotificationPackage;
|
||||||
import com.oblador.vectoricons.VectorIconsPackage;
|
import com.oblador.vectoricons.VectorIconsPackage;
|
||||||
import com.rnfs.RNFSPackage;
|
import com.rnfs.RNFSPackage;
|
||||||
@@ -30,6 +32,8 @@ public class MainApplication extends Application implements ReactApplication, Sh
|
|||||||
protected List<ReactPackage> getPackages() {
|
protected List<ReactPackage> getPackages() {
|
||||||
return Arrays.<ReactPackage>asList(
|
return Arrays.<ReactPackage>asList(
|
||||||
new MainReactPackage(),
|
new MainReactPackage(),
|
||||||
|
new RNNodeJsMobilePackage(),
|
||||||
|
new ReactNativeRestartPackage(),
|
||||||
new ReactNativePushNotificationPackage(),
|
new ReactNativePushNotificationPackage(),
|
||||||
new VectorIconsPackage(),
|
new VectorIconsPackage(),
|
||||||
new RNFSPackage(),
|
new RNFSPackage(),
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
rootProject.name = 'drip'
|
rootProject.name = 'drip'
|
||||||
|
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-push-notification'
|
include ':react-native-push-notification'
|
||||||
project(':react-native-push-notification').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-push-notification/android')
|
project(':react-native-push-notification').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-push-notification/android')
|
||||||
include ':react-native-vector-icons'
|
include ':react-native-vector-icons'
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,28 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import { View } from 'react-native'
|
||||||
|
import nodejs from 'nodejs-mobile-react-native'
|
||||||
|
import App from './app'
|
||||||
|
import PasswordPrompt from './password-prompt'
|
||||||
|
|
||||||
|
export default class AppWrapper extends Component {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.state = {}
|
||||||
|
nodejs.start('main.js')
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={{ flex: 1 }}>
|
||||||
|
{this.state.showApp ?
|
||||||
|
<App/>
|
||||||
|
:
|
||||||
|
<PasswordPrompt
|
||||||
|
showApp={() => {
|
||||||
|
this.setState({showApp: true})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-14
@@ -1,37 +1,37 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { CalendarList } from 'react-native-calendars'
|
import { CalendarList } from 'react-native-calendars'
|
||||||
import {LocalDate} from 'js-joda'
|
import {LocalDate} from 'js-joda'
|
||||||
import { getOrCreateCycleDay, bleedingDaysSortedByDate } from '../db'
|
import { getOrCreateCycleDay, getBleedingDaysSortedByDate } from '../db'
|
||||||
import cycleModule from '../lib/cycle'
|
import cycleModule from '../lib/cycle'
|
||||||
import {shadesOfRed} from '../styles/index'
|
import {shadesOfRed} from '../styles/index'
|
||||||
import styles from '../styles/index'
|
import styles from '../styles/index'
|
||||||
|
|
||||||
|
|
||||||
export default class CalendarView extends Component {
|
export default class CalendarView extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
this.bleedingDays = getBleedingDaysSortedByDate()
|
||||||
const predictedMenses = cycleModule().getPredictedMenses()
|
const predictedMenses = cycleModule().getPredictedMenses()
|
||||||
this.state = {
|
this.state = {
|
||||||
bleedingDaysInCalFormat: toCalFormat(bleedingDaysSortedByDate),
|
bleedingDaysInCalFormat: toCalFormat(this.bleedingDays),
|
||||||
predictedBleedingDaysInCalFormat: predictionToCalFormat(predictedMenses),
|
predictedBleedingDaysInCalFormat: predictionToCalFormat(predictedMenses),
|
||||||
todayInCalFormat: todayToCalFormat()
|
todayInCalFormat: todayToCalFormat()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setStateWithCalFormattedDays = (function (CalendarComponent) {
|
this.bleedingDays.addListener(this.setStateWithCalFormattedDays)
|
||||||
return function() {
|
}
|
||||||
const predictedMenses = cycleModule().getPredictedMenses()
|
|
||||||
CalendarComponent.setState({
|
|
||||||
bleedingDaysInCalFormat: toCalFormat(bleedingDaysSortedByDate),
|
|
||||||
predictedBleedingDaysInCalFormat: predictionToCalFormat(predictedMenses),
|
|
||||||
todayInCalFormat: todayToCalFormat()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})(this)
|
|
||||||
|
|
||||||
bleedingDaysSortedByDate.addListener(this.setStateWithCalFormattedDays)
|
setStateWithCalFormattedDays = () => {
|
||||||
|
const predictedMenses = cycleModule().getPredictedMenses()
|
||||||
|
this.setState({
|
||||||
|
bleedingDaysInCalFormat: toCalFormat(this.bleedingDays),
|
||||||
|
predictedBleedingDaysInCalFormat: predictionToCalFormat(predictedMenses),
|
||||||
|
todayInCalFormat: todayToCalFormat()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
bleedingDaysSortedByDate.removeListener(this.setStateWithCalFormattedDays)
|
this.bleedingDays.removeListener(this.setStateWithCalFormattedDays)
|
||||||
}
|
}
|
||||||
|
|
||||||
passDateToDayView = (result) => {
|
passDateToDayView = (result) => {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { LocalDate } from 'js-joda'
|
|||||||
import { makeYAxisLabels, normalizeToScale, makeHorizontalGrid } from './y-axis'
|
import { makeYAxisLabels, normalizeToScale, makeHorizontalGrid } from './y-axis'
|
||||||
import nfpLines from './nfp-lines'
|
import nfpLines from './nfp-lines'
|
||||||
import DayColumn from './day-column'
|
import DayColumn from './day-column'
|
||||||
import { getCycleDay, cycleDaysSortedByDate, getAmountOfCycleDays } from '../../db'
|
import { getCycleDay, getCycleDaysSortedByDate, getAmountOfCycleDays } from '../../db'
|
||||||
import styles from './styles'
|
import styles from './styles'
|
||||||
import { scaleObservable } from '../../local-storage'
|
import { scaleObservable } from '../../local-storage'
|
||||||
import config from '../../config'
|
import config from '../../config'
|
||||||
@@ -25,6 +25,7 @@ export default class CycleChart extends Component {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
this.cycleDaysSortedByDate = getCycleDaysSortedByDate()
|
||||||
}
|
}
|
||||||
|
|
||||||
onLayout = ({ nativeEvent }) => {
|
onLayout = ({ nativeEvent }) => {
|
||||||
@@ -35,12 +36,12 @@ export default class CycleChart extends Component {
|
|||||||
this.setState({ columns: this.makeColumnInfo(nfpLines(height)) })
|
this.setState({ columns: this.makeColumnInfo(nfpLines(height)) })
|
||||||
}
|
}
|
||||||
|
|
||||||
cycleDaysSortedByDate.addListener(this.reCalculateChartInfo)
|
this.cycleDaysSortedByDate.addListener(this.reCalculateChartInfo)
|
||||||
this.removeObvListener = scaleObservable(this.reCalculateChartInfo, false)
|
this.removeObvListener = scaleObservable(this.reCalculateChartInfo, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
cycleDaysSortedByDate.removeListener(this.reCalculateChartInfo)
|
this.cycleDaysSortedByDate.removeListener(this.reCalculateChartInfo)
|
||||||
this.removeObvListener()
|
this.removeObvListener()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +72,7 @@ export default class CycleChart extends Component {
|
|||||||
'pain',
|
'pain',
|
||||||
'note'
|
'note'
|
||||||
].filter((symptomName) => {
|
].filter((symptomName) => {
|
||||||
return cycleDaysSortedByDate.some(cycleDay => cycleDay[symptomName])
|
return this.cycleDaysSortedByDate.some(cycleDay => cycleDay[symptomName])
|
||||||
})
|
})
|
||||||
|
|
||||||
const columns = xAxisDates.map(dateString => {
|
const columns = xAxisDates.map(dateString => {
|
||||||
|
|||||||
@@ -9,10 +9,13 @@ import { getOrCreateCycleDay } from '../../db'
|
|||||||
import cycleModule from '../../lib/cycle'
|
import cycleModule from '../../lib/cycle'
|
||||||
import DotAndLine from './dot-and-line'
|
import DotAndLine from './dot-and-line'
|
||||||
|
|
||||||
const getCycleDayNumber = cycleModule().getCycleDayNumber
|
|
||||||
const label = styles.column.label
|
const label = styles.column.label
|
||||||
|
|
||||||
export default class DayColumn extends Component {
|
export default class DayColumn extends Component {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.getCycleDayNumber = cycleModule().getCycleDayNumber
|
||||||
|
}
|
||||||
passDateToDayView(dateString) {
|
passDateToDayView(dateString) {
|
||||||
const cycleDay = getOrCreateCycleDay(dateString)
|
const cycleDay = getOrCreateCycleDay(dateString)
|
||||||
this.props.navigate('CycleDay', { cycleDay })
|
this.props.navigate('CycleDay', { cycleDay })
|
||||||
@@ -68,7 +71,7 @@ export default class DayColumn extends Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const cycleDayNumber = getCycleDayNumber(dateString)
|
const cycleDayNumber = this.getCycleDayNumber(dateString)
|
||||||
const shortDate = dateString.split('-').slice(1).join('-')
|
const shortDate = dateString.split('-').slice(1).join('-')
|
||||||
const cycleDayLabel = (
|
const cycleDayLabel = (
|
||||||
<Text style = {label.number}>
|
<Text style = {label.number}>
|
||||||
|
|||||||
+13
-21
@@ -8,37 +8,35 @@ import {
|
|||||||
import { LocalDate, ChronoUnit } from 'js-joda'
|
import { LocalDate, ChronoUnit } from 'js-joda'
|
||||||
import styles from '../styles/index'
|
import styles from '../styles/index'
|
||||||
import cycleModule from '../lib/cycle'
|
import cycleModule from '../lib/cycle'
|
||||||
import { getOrCreateCycleDay, bleedingDaysSortedByDate, fillWithMucusDummyData, fillWithCervixDummyData, deleteAll } from '../db'
|
import { getOrCreateCycleDay, getBleedingDaysSortedByDate, fillWithMucusDummyData, fillWithCervixDummyData } from '../db'
|
||||||
import {bleedingPrediction as labels} from './labels'
|
import {bleedingPrediction as labels} from './labels'
|
||||||
|
|
||||||
const getCycleDayNumber = cycleModule().getCycleDayNumber
|
|
||||||
|
|
||||||
export default class Home extends Component {
|
export default class Home extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
this.getCycleDayNumber = cycleModule().getCycleDayNumber
|
||||||
this.todayDateString = LocalDate.now().toString()
|
this.todayDateString = LocalDate.now().toString()
|
||||||
const cycleDayNumber = getCycleDayNumber(this.todayDateString)
|
const cycleDayNumber = this.getCycleDayNumber(this.todayDateString)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
welcomeText: determineWelcomeText(cycleDayNumber),
|
welcomeText: determineWelcomeText(cycleDayNumber),
|
||||||
predictionText: determinePredictionText()
|
predictionText: determinePredictionText()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setStateWithCurrentText = (function (HomeComponent) {
|
this.bleedingDays = getBleedingDaysSortedByDate()
|
||||||
return function () {
|
this.bleedingDays.addListener(this.setStateWithCurrentText)
|
||||||
const cycleDayNumber = getCycleDayNumber(HomeComponent.todayDateString)
|
}
|
||||||
HomeComponent.setState({
|
|
||||||
welcomeText: determineWelcomeText(cycleDayNumber),
|
|
||||||
predictionText: determinePredictionText()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})(this)
|
|
||||||
|
|
||||||
bleedingDaysSortedByDate.addListener(this.setStateWithCurrentText)
|
setStateWithCurrentText = () => {
|
||||||
|
const cycleDayNumber = this.getCycleDayNumber(this.todayDateString)
|
||||||
|
this.setState({
|
||||||
|
welcomeText: determineWelcomeText(cycleDayNumber),
|
||||||
|
predictionText: determinePredictionText()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
bleedingDaysSortedByDate.removeListener(this.setStateWithCurrentText)
|
this.bleedingDays.removeListener(this.setStateWithCurrentText)
|
||||||
}
|
}
|
||||||
|
|
||||||
passTodayToDayView() {
|
passTodayToDayView() {
|
||||||
@@ -72,12 +70,6 @@ export default class Home extends Component {
|
|||||||
title="fill with example data for cervix&temp">
|
title="fill with example data for cervix&temp">
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.homeButton}>
|
|
||||||
<Button
|
|
||||||
onPress={() => deleteAll()}
|
|
||||||
title="delete everything">
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
)
|
)
|
||||||
|
|||||||
+32
-1
@@ -3,7 +3,12 @@ export const shared = {
|
|||||||
save: 'Save',
|
save: 'Save',
|
||||||
errorTitle: 'Error',
|
errorTitle: 'Error',
|
||||||
successTitle: 'Success',
|
successTitle: 'Success',
|
||||||
warning: 'Warning'
|
warning: 'Warning',
|
||||||
|
incorrectPassword: 'Password incorrect',
|
||||||
|
incorrectPasswordMessage: 'That password is incorrect.',
|
||||||
|
tryAgain: 'Try again',
|
||||||
|
ok: 'OK',
|
||||||
|
unlock: 'Unlock'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const settings = {
|
export const settings = {
|
||||||
@@ -48,6 +53,20 @@ export const settings = {
|
|||||||
noTimeSet: 'Set a time for a daily reminder to take your temperature',
|
noTimeSet: 'Set a time for a daily reminder to take your temperature',
|
||||||
timeSet: time => `Daily reminder set for ${time}`,
|
timeSet: time => `Daily reminder set for ${time}`,
|
||||||
notification: 'Record your morning temperature'
|
notification: 'Record your morning temperature'
|
||||||
|
},
|
||||||
|
passwordSettings: {
|
||||||
|
title: 'App password',
|
||||||
|
explainerDisabled: "Encrypt the app's database with a password. You need to enter the password every time the app is started.",
|
||||||
|
explainerEnabled: "Password protection and database encryption is currently enabled",
|
||||||
|
setPassword: 'Set password',
|
||||||
|
changePassword: 'Change password',
|
||||||
|
deletePassword: 'Delete password',
|
||||||
|
enterCurrent: "Please enter your current password",
|
||||||
|
enterNew: "Please enter a new password",
|
||||||
|
backupReminderTitle: 'Read this before making changes to your password',
|
||||||
|
backupReminder: 'Just to be safe, please backup your data using the export function before making changes to your password.\n\nLonger passwords are better! Consider using a passphrase.\n\nPlease also make sure you do not lose your password. There is no way to recover your data if you do.\n\nMaking any changes to your password setting will keep your data as it was before and restart the app.',
|
||||||
|
deleteBackupReminderTitle: 'Read this before deleting your password',
|
||||||
|
deleteBackupReminder: 'Deleting your password means your data will no longer be encrypted.\n\nJust to be safe, please backup your data using the export function before deleting your password.\n\nMaking any changes to your password setting will keep your data as it was before and restart the app.',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,3 +110,15 @@ export const bleedingPrediction = {
|
|||||||
predictionStartedNoDaysLeft: 'Your period is likely to start today.',
|
predictionStartedNoDaysLeft: 'Your period is likely to start today.',
|
||||||
predictionInPast: (startDate, endDate) => `Based on your documented data, your period was likely to start between ${startDate} and ${endDate}.`
|
predictionInPast: (startDate, endDate) => `Based on your documented data, your period was likely to start between ${startDate} and ${endDate}.`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const passwordPrompt = {
|
||||||
|
title: 'Unlock app',
|
||||||
|
enterPassword: 'Enter password here',
|
||||||
|
deleteDatabaseExplainer: "If you've forgotten your password, unfortunately, there is nothing we can do to recover your data, because it is encrypted with the password only you know. You can, however, delete all your encrypted data and start fresh. Once all data has been erased, you can set a new password in the settings, if you like.",
|
||||||
|
forgotPassword: 'Forgot your password?',
|
||||||
|
deleteDatabaseTitle: 'Forgot your password?',
|
||||||
|
deleteData: 'Yes, delete all my data',
|
||||||
|
areYouSureTitle: 'Are you sure?',
|
||||||
|
areYouSure: 'Are you absolutely sure you want to permanently delete all your data?',
|
||||||
|
reallyDeleteData: 'Yes, I am sure'
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import { View, TextInput, TouchableOpacity, Alert, Image } from 'react-native'
|
||||||
|
import nodejs from 'nodejs-mobile-react-native'
|
||||||
|
import { saveEncryptionFlag } from '../local-storage'
|
||||||
|
import { AppText } from './app-text'
|
||||||
|
import styles from '../styles'
|
||||||
|
import { passwordPrompt as labels, shared } from './labels'
|
||||||
|
import { requestHash, deleteDbAndOpenNew, openDb } from '../db'
|
||||||
|
|
||||||
|
export default class PasswordPrompt extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
password: null
|
||||||
|
}
|
||||||
|
|
||||||
|
nodejs.channel.addListener(
|
||||||
|
'check-pw',
|
||||||
|
this.passHashToDb,
|
||||||
|
this
|
||||||
|
)
|
||||||
|
|
||||||
|
this.tryToOpenDb()
|
||||||
|
}
|
||||||
|
|
||||||
|
async tryToOpenDb() {
|
||||||
|
try {
|
||||||
|
await openDb({ persistConnection: true })
|
||||||
|
} catch (err) {
|
||||||
|
this.setState({ showPasswordPrompt: true })
|
||||||
|
await saveEncryptionFlag(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await saveEncryptionFlag(false)
|
||||||
|
this.props.showApp()
|
||||||
|
}
|
||||||
|
|
||||||
|
passHashToDb = async hash => {
|
||||||
|
try {
|
||||||
|
await openDb({ hash, persistConnection: true })
|
||||||
|
} catch (err) {
|
||||||
|
Alert.alert(
|
||||||
|
shared.incorrectPassword,
|
||||||
|
shared.incorrectPasswordMessage,
|
||||||
|
[{
|
||||||
|
text: shared.tryAgain,
|
||||||
|
onPress: () => this.setState({ password: null })
|
||||||
|
}]
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.props.showApp()
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmDeletion = async () => {
|
||||||
|
Alert.alert(
|
||||||
|
labels.deleteDatabaseTitle,
|
||||||
|
labels.deleteDatabaseExplainer,
|
||||||
|
[{
|
||||||
|
text: shared.cancel,
|
||||||
|
style: 'cancel'
|
||||||
|
}, {
|
||||||
|
text: labels.deleteData,
|
||||||
|
onPress: () => {
|
||||||
|
Alert.alert(
|
||||||
|
labels.areYouSureTitle,
|
||||||
|
labels.areYouSure,
|
||||||
|
[{
|
||||||
|
text: shared.cancel,
|
||||||
|
style: 'cancel'
|
||||||
|
}, {
|
||||||
|
text: labels.reallyDeleteData,
|
||||||
|
onPress: async () => {
|
||||||
|
await deleteDbAndOpenNew()
|
||||||
|
await saveEncryptionFlag(false)
|
||||||
|
this.props.showApp()
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
nodejs.channel.removeListener('check-pw', this.passHashToDb)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View flex={1}>
|
||||||
|
{this.state.showPasswordPrompt &&
|
||||||
|
<View style={styles.passwordPromptPage}>
|
||||||
|
<Image
|
||||||
|
source={require('../assets/drip_small.png')}
|
||||||
|
style={styles.passwordPromptImage}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
onChangeText={val => this.setState({ password: val })}
|
||||||
|
style={styles.passwordPromptField}
|
||||||
|
secureTextEntry={true}
|
||||||
|
placeholder={labels.enterPassword}
|
||||||
|
/>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.passwordPromptButton}
|
||||||
|
onPress={() => {
|
||||||
|
requestHash('check-pw', this.state.password)
|
||||||
|
}}
|
||||||
|
disabled={!this.state.password}
|
||||||
|
>
|
||||||
|
<AppText style={styles.passwordPromptButtonText}>
|
||||||
|
{labels.title}
|
||||||
|
</AppText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={this.confirmDeletion}
|
||||||
|
>
|
||||||
|
<AppText style={styles.passwordPromptForgotPasswordText}>
|
||||||
|
{labels.forgotPassword}
|
||||||
|
</AppText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
import React, { Component } from 'react'
|
|
||||||
import {
|
|
||||||
View,
|
|
||||||
TouchableOpacity,
|
|
||||||
ScrollView,
|
|
||||||
Alert,
|
|
||||||
Switch
|
|
||||||
} from 'react-native'
|
|
||||||
import DateTimePicker from 'react-native-modal-datetime-picker-nevo'
|
|
||||||
import Slider from '@ptomasroos/react-native-multi-slider'
|
|
||||||
import Share from 'react-native-share'
|
|
||||||
import { DocumentPicker, DocumentPickerUtil } from 'react-native-document-picker'
|
|
||||||
import rnfs from 'react-native-fs'
|
|
||||||
import styles, { secondaryColor } from '../styles/index'
|
|
||||||
import config from '../config'
|
|
||||||
import { settings as labels, shared as sharedLabels } from './labels'
|
|
||||||
import getDataAsCsvDataUri from '../lib/import-export/export-to-csv'
|
|
||||||
import importCsv from '../lib/import-export/import-from-csv'
|
|
||||||
import {
|
|
||||||
scaleObservable,
|
|
||||||
saveTempScale,
|
|
||||||
tempReminderObservable,
|
|
||||||
saveTempReminder
|
|
||||||
} from '../local-storage'
|
|
||||||
import { AppText } from './app-text'
|
|
||||||
|
|
||||||
export default class Settings extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props)
|
|
||||||
this.state = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<ScrollView>
|
|
||||||
<TempReminderPicker/>
|
|
||||||
<View style={styles.settingsSegment}>
|
|
||||||
<AppText style={styles.settingsSegmentTitle}>
|
|
||||||
{labels.tempScale.segmentTitle}
|
|
||||||
</AppText>
|
|
||||||
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
|
||||||
<TempSlider/>
|
|
||||||
</View>
|
|
||||||
<View style={styles.settingsSegment}>
|
|
||||||
<AppText style={styles.settingsSegmentTitle}>
|
|
||||||
{labels.export.button}
|
|
||||||
</AppText>
|
|
||||||
<AppText>{labels.export.segmentExplainer}</AppText>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={openShareDialogAndExport}
|
|
||||||
style={styles.settingsButton}>
|
|
||||||
<AppText style={styles.settingsButtonText}>
|
|
||||||
{labels.export.button}
|
|
||||||
</AppText>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
<View style={styles.settingsSegment}>
|
|
||||||
<AppText style={styles.settingsSegmentTitle}>
|
|
||||||
{labels.import.button}
|
|
||||||
</AppText>
|
|
||||||
<AppText>{labels.import.segmentExplainer}</AppText>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={openImportDialogAndImport}
|
|
||||||
style={styles.settingsButton}>
|
|
||||||
<AppText style={styles.settingsButtonText}>
|
|
||||||
{labels.import.button}
|
|
||||||
</AppText>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TempReminderPicker extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props)
|
|
||||||
this.state = Object.assign({}, tempReminderObservable.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
style={styles.settingsSegment}
|
|
||||||
onPress={() => this.setState({ isTimePickerVisible: true })}
|
|
||||||
>
|
|
||||||
<AppText style={styles.settingsSegmentTitle}>
|
|
||||||
{labels.tempReminder.title}
|
|
||||||
</AppText>
|
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
||||||
<View style={{ flex: 1 }}>
|
|
||||||
{this.state.time && this.state.enabled ?
|
|
||||||
<AppText>{labels.tempReminder.timeSet(this.state.time)}</AppText>
|
|
||||||
:
|
|
||||||
<AppText>{labels.tempReminder.noTimeSet}</AppText>
|
|
||||||
}
|
|
||||||
</View>
|
|
||||||
<Switch
|
|
||||||
value={this.state.enabled}
|
|
||||||
onValueChange={switchOn => {
|
|
||||||
this.setState({ enabled: switchOn })
|
|
||||||
if (switchOn && !this.state.time) {
|
|
||||||
this.setState({ isTimePickerVisible: true })
|
|
||||||
}
|
|
||||||
if (!switchOn) saveTempReminder({ enabled: false })
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<DateTimePicker
|
|
||||||
mode="time"
|
|
||||||
isVisible={this.state.isTimePickerVisible}
|
|
||||||
onConfirm={jsDate => {
|
|
||||||
const time = padWithZeros(`${jsDate.getHours()}:${jsDate.getMinutes()}`)
|
|
||||||
this.setState({
|
|
||||||
time,
|
|
||||||
isTimePickerVisible: false,
|
|
||||||
enabled: true
|
|
||||||
})
|
|
||||||
saveTempReminder({
|
|
||||||
time,
|
|
||||||
enabled: true
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
onCancel={() => {
|
|
||||||
this.setState({ isTimePickerVisible: false })
|
|
||||||
if (!this.state.time) this.setState({enabled: false})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TempSlider extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props)
|
|
||||||
this.state = Object.assign({}, scaleObservable.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
onValuesChange = (values) => {
|
|
||||||
this.setState({
|
|
||||||
min: values[0],
|
|
||||||
max: values[1]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onValuesChangeFinish = (values) => {
|
|
||||||
this.setState({
|
|
||||||
min: values[0],
|
|
||||||
max: values[1]
|
|
||||||
})
|
|
||||||
try {
|
|
||||||
saveTempScale(this.state)
|
|
||||||
} catch(err) {
|
|
||||||
alertError(labels.tempScale.saveError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<View style={{ alignItems: 'center' }}>
|
|
||||||
<AppText>{`${labels.tempScale.min} ${this.state.min}`}</AppText>
|
|
||||||
<AppText>{`${labels.tempScale.max} ${this.state.max}`}</AppText>
|
|
||||||
<Slider
|
|
||||||
values={[this.state.min, this.state.max]}
|
|
||||||
min={config.temperatureScale.min}
|
|
||||||
max={config.temperatureScale.max}
|
|
||||||
step={0.5}
|
|
||||||
onValuesChange={this.onValuesChange}
|
|
||||||
onValuesChangeFinish={this.onValuesChangeFinish}
|
|
||||||
selectedStyle={{
|
|
||||||
backgroundColor: 'darkgrey',
|
|
||||||
}}
|
|
||||||
unselectedStyle={{
|
|
||||||
backgroundColor: 'silver',
|
|
||||||
}}
|
|
||||||
trackStyle={{
|
|
||||||
height: 10,
|
|
||||||
}}
|
|
||||||
markerStyle={{
|
|
||||||
backgroundColor: secondaryColor,
|
|
||||||
height: 20,
|
|
||||||
width: 20,
|
|
||||||
borderRadius: 100,
|
|
||||||
marginTop: 10
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function openShareDialogAndExport() {
|
|
||||||
let data
|
|
||||||
try {
|
|
||||||
data = getDataAsCsvDataUri()
|
|
||||||
if (!data) {
|
|
||||||
return alertError(labels.errors.noData)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err)
|
|
||||||
return alertError(labels.errors.couldNotConvert)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await Share.open({
|
|
||||||
title: labels.export.title,
|
|
||||||
url: data,
|
|
||||||
subject: labels.export.subject,
|
|
||||||
type: 'text/csv',
|
|
||||||
showAppsToView: true
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err)
|
|
||||||
return alertError(labels.export.errors.problemSharing)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function openImportDialogAndImport() {
|
|
||||||
Alert.alert(
|
|
||||||
labels.import.title,
|
|
||||||
labels.import.message,
|
|
||||||
[{
|
|
||||||
text: labels.import.replaceOption,
|
|
||||||
onPress: () => getFileContentAndImport({ deleteExisting: false })
|
|
||||||
}, {
|
|
||||||
text: labels.import.deleteOption,
|
|
||||||
onPress: () => getFileContentAndImport({ deleteExisting: true })
|
|
||||||
}, {
|
|
||||||
text: sharedLabels.cancel, style: 'cancel', onPress: () => { }
|
|
||||||
}]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getFileContentAndImport({ deleteExisting }) {
|
|
||||||
let fileInfo
|
|
||||||
try {
|
|
||||||
fileInfo = await new Promise((resolve, reject) => {
|
|
||||||
DocumentPicker.show({
|
|
||||||
filetype: [DocumentPickerUtil.allFiles()],
|
|
||||||
}, (err, res) => {
|
|
||||||
if (err) return reject(err)
|
|
||||||
resolve(res)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
// because cancelling also triggers an error, we do nothing here
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let fileContent
|
|
||||||
try {
|
|
||||||
fileContent = await rnfs.readFile(fileInfo.uri, 'utf8')
|
|
||||||
} catch (err) {
|
|
||||||
return importError(labels.import.errors.couldNotOpenFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await importCsv(fileContent, deleteExisting)
|
|
||||||
Alert.alert(sharedLabels.successTitle, labels.import.success.message)
|
|
||||||
} catch(err) {
|
|
||||||
importError(err.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function alertError(msg) {
|
|
||||||
Alert.alert(sharedLabels.errorTitle, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
function importError(msg) {
|
|
||||||
const postFixed = `${msg}\n\n${labels.import.errors.postFix}`
|
|
||||||
alertError(postFixed)
|
|
||||||
}
|
|
||||||
|
|
||||||
function padWithZeros(time) {
|
|
||||||
const vals = time.split(':')
|
|
||||||
return vals.map(val => {
|
|
||||||
if (parseInt(val) < 10) {
|
|
||||||
val = `0${val}`
|
|
||||||
}
|
|
||||||
return val
|
|
||||||
}).join(':')
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { Alert } from 'react-native'
|
||||||
|
import { shared as sharedLabels } from '../labels'
|
||||||
|
|
||||||
|
export default function alertError(msg) {
|
||||||
|
Alert.alert(sharedLabels.errorTitle, msg)
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import Share from 'react-native-share'
|
||||||
|
import getDataAsCsvDataUri from '../../lib/import-export/export-to-csv'
|
||||||
|
import alertError from './alert-error'
|
||||||
|
import { settings as labels } from '../labels'
|
||||||
|
|
||||||
|
export default async function openShareDialogAndExport() {
|
||||||
|
let data
|
||||||
|
try {
|
||||||
|
data = getDataAsCsvDataUri()
|
||||||
|
if (!data) {
|
||||||
|
return alertError(labels.errors.noData)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
return alertError(labels.errors.couldNotConvert)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Share.open({
|
||||||
|
title: labels.export.title,
|
||||||
|
url: data,
|
||||||
|
subject: labels.export.subject,
|
||||||
|
type: 'text/csv',
|
||||||
|
showAppsToView: true
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
return alertError(labels.export.errors.problemSharing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { Alert } from 'react-native'
|
||||||
|
import { DocumentPicker, DocumentPickerUtil } from 'react-native-document-picker'
|
||||||
|
import rnfs from 'react-native-fs'
|
||||||
|
import importCsv from '../../lib/import-export/import-from-csv'
|
||||||
|
import { settings as labels, shared as sharedLabels } from '../labels'
|
||||||
|
import alertError from './alert-error'
|
||||||
|
|
||||||
|
export default function openImportDialogAndImport() {
|
||||||
|
Alert.alert(
|
||||||
|
labels.import.title,
|
||||||
|
labels.import.message,
|
||||||
|
[{
|
||||||
|
text: labels.import.replaceOption,
|
||||||
|
onPress: () => getFileContentAndImport({ deleteExisting: false })
|
||||||
|
}, {
|
||||||
|
text: labels.import.deleteOption,
|
||||||
|
onPress: () => getFileContentAndImport({ deleteExisting: true })
|
||||||
|
}, {
|
||||||
|
text: sharedLabels.cancel, style: 'cancel', onPress: () => { }
|
||||||
|
}]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFileContentAndImport({ deleteExisting }) {
|
||||||
|
let fileInfo
|
||||||
|
try {
|
||||||
|
fileInfo = await new Promise((resolve, reject) => {
|
||||||
|
DocumentPicker.show({
|
||||||
|
filetype: [DocumentPickerUtil.allFiles()],
|
||||||
|
}, (err, res) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
// because cancelling also triggers an error, we do nothing here
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileContent
|
||||||
|
try {
|
||||||
|
fileContent = await rnfs.readFile(fileInfo.uri, 'utf8')
|
||||||
|
} catch (err) {
|
||||||
|
return importError(labels.import.errors.couldNotOpenFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await importCsv(fileContent, deleteExisting)
|
||||||
|
Alert.alert(sharedLabels.successTitle, labels.import.success.message)
|
||||||
|
} catch(err) {
|
||||||
|
importError(err.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function importError(msg) {
|
||||||
|
const postFixed = `${msg}\n\n${labels.import.errors.postFix}`
|
||||||
|
alertError(postFixed)
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
TouchableOpacity,
|
||||||
|
ScrollView,
|
||||||
|
} from 'react-native'
|
||||||
|
import styles from '../../styles/index'
|
||||||
|
import { settings as labels } from '../labels'
|
||||||
|
import { AppText } from '../app-text'
|
||||||
|
import TempReminderPicker from './temp-reminder-picker'
|
||||||
|
import TempSlider from './temp-slider'
|
||||||
|
import openImportDialogAndImport from './import-dialog'
|
||||||
|
import openShareDialogAndExport from './export-dialog'
|
||||||
|
import PasswordSetting from './password'
|
||||||
|
|
||||||
|
export default class Settings extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<ScrollView>
|
||||||
|
<TempReminderPicker/>
|
||||||
|
<View style={styles.settingsSegment}>
|
||||||
|
<AppText style={styles.settingsSegmentTitle}>
|
||||||
|
{labels.tempScale.segmentTitle}
|
||||||
|
</AppText>
|
||||||
|
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
||||||
|
<TempSlider/>
|
||||||
|
</View>
|
||||||
|
<PasswordSetting />
|
||||||
|
<View style={styles.settingsSegment}>
|
||||||
|
<AppText style={styles.settingsSegmentTitle}>
|
||||||
|
{labels.export.button}
|
||||||
|
</AppText>
|
||||||
|
<AppText>{labels.export.segmentExplainer}</AppText>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={openShareDialogAndExport}
|
||||||
|
style={styles.settingsButton}>
|
||||||
|
<AppText style={styles.settingsButtonText}>
|
||||||
|
{labels.export.button}
|
||||||
|
</AppText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
<View style={styles.settingsSegment}>
|
||||||
|
<AppText style={styles.settingsSegmentTitle}>
|
||||||
|
{labels.import.button}
|
||||||
|
</AppText>
|
||||||
|
<AppText>{labels.import.segmentExplainer}</AppText>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={openImportDialogAndImport}
|
||||||
|
style={styles.settingsButton}>
|
||||||
|
<AppText style={styles.settingsButtonText}>
|
||||||
|
{labels.import.button}
|
||||||
|
</AppText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { Alert } from 'react-native'
|
||||||
|
import { openDb } from '../../../db'
|
||||||
|
import { shared } from '../../labels'
|
||||||
|
|
||||||
|
export default async function checkPassword({hash, onCancel, onTryAgain }) {
|
||||||
|
try {
|
||||||
|
await openDb({ hash, persistConnection: false })
|
||||||
|
return true
|
||||||
|
} catch (err) {
|
||||||
|
Alert.alert(
|
||||||
|
shared.incorrectPassword,
|
||||||
|
shared.incorrectPasswordMessage,
|
||||||
|
[{
|
||||||
|
text: shared.cancel,
|
||||||
|
onPress: onCancel
|
||||||
|
}, {
|
||||||
|
text: shared.tryAgain,
|
||||||
|
onPress: onTryAgain
|
||||||
|
}]
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
TouchableOpacity,
|
||||||
|
} from 'react-native'
|
||||||
|
import nodejs from 'nodejs-mobile-react-native'
|
||||||
|
import { AppText } from '../../app-text'
|
||||||
|
import styles from '../../../styles'
|
||||||
|
import { settings as labels } from '../../labels'
|
||||||
|
import { requestHash, changeEncryptionAndRestartApp } from '../../../db'
|
||||||
|
import PasswordField from './password-field'
|
||||||
|
import showBackUpReminder from './show-backup-reminder'
|
||||||
|
|
||||||
|
export default class CreatePassword extends Component {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.state = {
|
||||||
|
enteringNewPassword: false,
|
||||||
|
newPassword: null
|
||||||
|
}
|
||||||
|
nodejs.channel.addListener(
|
||||||
|
'create-pw-hash',
|
||||||
|
changeEncryptionAndRestartApp,
|
||||||
|
this
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
nodejs.channel.removeListener('create-pw-hash', changeEncryptionAndRestartApp)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
{this.state.enteringNewPassword &&
|
||||||
|
<PasswordField
|
||||||
|
placeholder={labels.passwordSettings.enterNew}
|
||||||
|
value={this.state.newPassword}
|
||||||
|
onChangeText={val => this.setState({newPassword: val})}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => {
|
||||||
|
if (!this.state.enteringNewPassword) {
|
||||||
|
showBackUpReminder(() => {
|
||||||
|
this.setState({ enteringNewPassword: true })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
requestHash('create-pw-hash', this.state.newPassword)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={this.state.enteringNewPassword && !this.state.newPassword}
|
||||||
|
style={styles.settingsButton}>
|
||||||
|
<AppText style={styles.settingsButtonText}>
|
||||||
|
{labels.passwordSettings.setPassword}
|
||||||
|
</AppText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
TouchableOpacity
|
||||||
|
} from 'react-native'
|
||||||
|
import nodejs from 'nodejs-mobile-react-native'
|
||||||
|
import { AppText } from '../../app-text'
|
||||||
|
import styles from '../../../styles'
|
||||||
|
import { settings as labels } from '../../labels'
|
||||||
|
import { requestHash, changeEncryptionAndRestartApp } from '../../../db'
|
||||||
|
import PasswordField from './password-field'
|
||||||
|
import showBackUpReminder from './show-backup-reminder'
|
||||||
|
import checkCurrentPassword from './check-current-password'
|
||||||
|
|
||||||
|
export default class DeletePassword extends Component {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.state = {
|
||||||
|
enteringCurrentPassword: false,
|
||||||
|
currentPassword: null
|
||||||
|
}
|
||||||
|
|
||||||
|
nodejs.channel.addListener(
|
||||||
|
'pre-delete-pw-check',
|
||||||
|
this.removeEncryption,
|
||||||
|
this
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
nodejs.channel.removeListener('pre-delete-pw-check', this.removeEncryption)
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEncryption = async hash => {
|
||||||
|
const passwordIsCorrect = await checkCurrentPassword({
|
||||||
|
hash,
|
||||||
|
onTryAgain: () => this.setState({currentPassword: null}),
|
||||||
|
onCancel: () => this.setState({
|
||||||
|
enteringCurrentPassword: false,
|
||||||
|
currentPassword: null
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (passwordIsCorrect) await changeEncryptionAndRestartApp()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
{this.state.enteringCurrentPassword &&
|
||||||
|
<PasswordField
|
||||||
|
onChangeText={val => this.setState({ currentPassword: val })}
|
||||||
|
value={this.state.currentPassword}
|
||||||
|
placeholder={labels.passwordSettings.enterCurrent}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => {
|
||||||
|
if (!this.state.enteringCurrentPassword) {
|
||||||
|
showBackUpReminder(() => {
|
||||||
|
this.setState({ enteringCurrentPassword: true })
|
||||||
|
}, true)
|
||||||
|
} else {
|
||||||
|
requestHash('pre-delete-pw-check', this.state.currentPassword)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={
|
||||||
|
this.state.enteringCurrentPassword &&
|
||||||
|
!this.state.currentPassword
|
||||||
|
}
|
||||||
|
style={styles.settingsButton}
|
||||||
|
>
|
||||||
|
<AppText style={styles.settingsButtonText}>
|
||||||
|
{labels.passwordSettings.deletePassword}
|
||||||
|
</AppText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import { View } from 'react-native'
|
||||||
|
import CreatePassword from './create'
|
||||||
|
import ChangePassword from './update'
|
||||||
|
import DeletePassword from './delete'
|
||||||
|
import { AppText } from '../../app-text'
|
||||||
|
import {
|
||||||
|
hasEncryptionObservable
|
||||||
|
} from '../../../local-storage'
|
||||||
|
import styles from '../../../styles/index'
|
||||||
|
import { settings as labels } from '../../labels'
|
||||||
|
|
||||||
|
export default class PasswordSetting extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
showUpdateAndDelete: hasEncryptionObservable.value,
|
||||||
|
showCreate: !hasEncryptionObservable.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={styles.settingsSegment}>
|
||||||
|
|
||||||
|
<AppText style={styles.settingsSegmentTitle}>
|
||||||
|
{labels.passwordSettings.title}
|
||||||
|
</AppText>
|
||||||
|
|
||||||
|
{this.state.showUpdateAndDelete ?
|
||||||
|
<AppText>{labels.passwordSettings.explainerEnabled}</AppText>
|
||||||
|
:
|
||||||
|
<AppText>{labels.passwordSettings.explainerDisabled}</AppText>
|
||||||
|
}
|
||||||
|
|
||||||
|
{this.state.showUpdateAndDelete &&
|
||||||
|
<View>
|
||||||
|
<ChangePassword/>
|
||||||
|
<DeletePassword/>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
|
||||||
|
{this.state.showCreate &&
|
||||||
|
<CreatePassword/>
|
||||||
|
}
|
||||||
|
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { TextInput } from 'react-native'
|
||||||
|
import styles from '../../../styles'
|
||||||
|
|
||||||
|
export default function PasswordField(props) {
|
||||||
|
return (
|
||||||
|
<TextInput
|
||||||
|
style={styles.passwordField}
|
||||||
|
autoFocus={true}
|
||||||
|
secureTextEntry={true}
|
||||||
|
onChangeText={props.onChangeText}
|
||||||
|
value={props.value}
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Alert } from 'react-native'
|
||||||
|
import { settings as labels, shared } from '../../labels'
|
||||||
|
|
||||||
|
export default function showBackUpReminder(okHandler, isDelete) {
|
||||||
|
let title, message
|
||||||
|
if (isDelete) {
|
||||||
|
title = labels.passwordSettings.deleteBackupReminderTitle
|
||||||
|
message = labels.passwordSettings.deleteBackupReminder
|
||||||
|
} else {
|
||||||
|
title = labels.passwordSettings.backupReminderTitle
|
||||||
|
message = labels.passwordSettings.backupReminder
|
||||||
|
}
|
||||||
|
|
||||||
|
Alert.alert(
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
[{
|
||||||
|
text: shared.cancel,
|
||||||
|
style: 'cancel'
|
||||||
|
}, {
|
||||||
|
text: shared.ok,
|
||||||
|
onPress: okHandler
|
||||||
|
}]
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
TouchableOpacity} from 'react-native'
|
||||||
|
import nodejs from 'nodejs-mobile-react-native'
|
||||||
|
import { AppText } from '../../app-text'
|
||||||
|
import styles from '../../../styles'
|
||||||
|
import { settings as labels, shared } from '../../labels'
|
||||||
|
import { requestHash, changeEncryptionAndRestartApp } from '../../../db'
|
||||||
|
import PasswordField from './password-field'
|
||||||
|
import showBackUpReminder from './show-backup-reminder'
|
||||||
|
import checkCurrentPassword from './check-current-password'
|
||||||
|
|
||||||
|
export default class ChangePassword extends Component {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.state = {
|
||||||
|
enteringCurrentPassword: false,
|
||||||
|
currentPassword: null,
|
||||||
|
enteringNewPassword: false,
|
||||||
|
newPassword: null
|
||||||
|
}
|
||||||
|
|
||||||
|
nodejs.channel.addListener(
|
||||||
|
'pre-change-pw-check',
|
||||||
|
this.openNewPasswordField,
|
||||||
|
this
|
||||||
|
)
|
||||||
|
|
||||||
|
nodejs.channel.addListener(
|
||||||
|
'change-pw',
|
||||||
|
changeEncryptionAndRestartApp,
|
||||||
|
this
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
nodejs.channel.removeListener('pre-change-pw-check', this.openNewPasswordField)
|
||||||
|
nodejs.channel.removeListener('change-pw', changeEncryptionAndRestartApp)
|
||||||
|
}
|
||||||
|
|
||||||
|
openNewPasswordField = async hash => {
|
||||||
|
const passwordCorrect = await checkCurrentPassword({
|
||||||
|
hash,
|
||||||
|
onTryAgain: () => this.setState({ currentPassword: null }),
|
||||||
|
onCancel: () => this.setState({
|
||||||
|
enteringCurrentPassword: false,
|
||||||
|
currentPassword: null
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (passwordCorrect) {
|
||||||
|
this.setState({
|
||||||
|
enteringCurrentPassword: false,
|
||||||
|
currentPassword: null,
|
||||||
|
enteringNewPassword: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
{!this.state.enteringCurrentPassword &&
|
||||||
|
!this.state.enteringNewPassword &&
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => showBackUpReminder(() => {
|
||||||
|
this.setState({ enteringCurrentPassword: true })
|
||||||
|
})}
|
||||||
|
disabled={this.state.currentPassword}
|
||||||
|
style={styles.settingsButton}>
|
||||||
|
<AppText style={styles.settingsButtonText}>
|
||||||
|
{labels.passwordSettings.changePassword}
|
||||||
|
</AppText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
}
|
||||||
|
|
||||||
|
{this.state.enteringCurrentPassword &&
|
||||||
|
<View>
|
||||||
|
<PasswordField
|
||||||
|
onChangeText={val => {
|
||||||
|
this.setState({
|
||||||
|
currentPassword: val,
|
||||||
|
wrongPassword: false
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
value={this.state.currentPassword}
|
||||||
|
placeholder={labels.passwordSettings.enterCurrent}
|
||||||
|
/>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => requestHash('pre-change-pw-check', this.state.currentPassword)}
|
||||||
|
disabled={!this.state.currentPassword}
|
||||||
|
style={styles.settingsButton}>
|
||||||
|
<AppText style={styles.settingsButtonText}>
|
||||||
|
{shared.unlock}
|
||||||
|
</AppText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
|
||||||
|
{this.state.enteringNewPassword &&
|
||||||
|
<View>
|
||||||
|
<PasswordField
|
||||||
|
style={styles.passwordField}
|
||||||
|
onChangeText={val => {
|
||||||
|
this.setState({
|
||||||
|
newPassword: val
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
value={this.state.changedPassword}
|
||||||
|
placeholder={labels.passwordSettings.enterNew}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => requestHash('change-pw', this.state.newPassword)}
|
||||||
|
disabled={ !this.state.newPassword }
|
||||||
|
style={styles.settingsButton}>
|
||||||
|
<AppText style={styles.settingsButtonText}>
|
||||||
|
{labels.passwordSettings.changePassword}
|
||||||
|
</AppText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
TouchableOpacity,
|
||||||
|
Switch
|
||||||
|
} from 'react-native'
|
||||||
|
import DateTimePicker from 'react-native-modal-datetime-picker-nevo'
|
||||||
|
import { AppText } from '../app-text'
|
||||||
|
import {
|
||||||
|
tempReminderObservable,
|
||||||
|
saveTempReminder
|
||||||
|
} from '../../local-storage'
|
||||||
|
import styles from '../../styles/index'
|
||||||
|
import { settings as labels } from '../labels'
|
||||||
|
|
||||||
|
export default class TempReminderPicker extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = Object.assign({}, tempReminderObservable.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.settingsSegment}
|
||||||
|
onPress={() => this.setState({ isTimePickerVisible: true })}
|
||||||
|
>
|
||||||
|
<AppText style={styles.settingsSegmentTitle}>
|
||||||
|
{labels.tempReminder.title}
|
||||||
|
</AppText>
|
||||||
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
|
<View style={{ flex: 1 }}>
|
||||||
|
{this.state.time && this.state.enabled ?
|
||||||
|
<AppText>{labels.tempReminder.timeSet(this.state.time)}</AppText>
|
||||||
|
:
|
||||||
|
<AppText>{labels.tempReminder.noTimeSet}</AppText>
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
<Switch
|
||||||
|
value={this.state.enabled}
|
||||||
|
onValueChange={switchOn => {
|
||||||
|
this.setState({ enabled: switchOn })
|
||||||
|
if (switchOn && !this.state.time) {
|
||||||
|
this.setState({ isTimePickerVisible: true })
|
||||||
|
}
|
||||||
|
if (!switchOn) saveTempReminder({ enabled: false })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<DateTimePicker
|
||||||
|
mode="time"
|
||||||
|
isVisible={this.state.isTimePickerVisible}
|
||||||
|
onConfirm={jsDate => {
|
||||||
|
const time = padWithZeros(`${jsDate.getHours()}:${jsDate.getMinutes()}`)
|
||||||
|
this.setState({
|
||||||
|
time,
|
||||||
|
isTimePickerVisible: false,
|
||||||
|
enabled: true
|
||||||
|
})
|
||||||
|
saveTempReminder({
|
||||||
|
time,
|
||||||
|
enabled: true
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
onCancel={() => {
|
||||||
|
this.setState({ isTimePickerVisible: false })
|
||||||
|
if (!this.state.time) this.setState({enabled: false})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function padWithZeros(time) {
|
||||||
|
const vals = time.split(':')
|
||||||
|
return vals.map(val => {
|
||||||
|
if (parseInt(val) < 10) {
|
||||||
|
val = `0${val}`
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}).join(':')
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import { View } from 'react-native'
|
||||||
|
import Slider from '@ptomasroos/react-native-multi-slider'
|
||||||
|
import { AppText } from '../app-text'
|
||||||
|
import {
|
||||||
|
scaleObservable,
|
||||||
|
saveTempScale,
|
||||||
|
} from '../../local-storage'
|
||||||
|
import { secondaryColor } from '../../styles/index'
|
||||||
|
import { settings as labels } from '../labels'
|
||||||
|
import config from '../../config'
|
||||||
|
import alertError from './alert-error'
|
||||||
|
|
||||||
|
export default class TempSlider extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = Object.assign({}, scaleObservable.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
onValuesChange = (values) => {
|
||||||
|
this.setState({
|
||||||
|
min: values[0],
|
||||||
|
max: values[1]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onValuesChangeFinish = (values) => {
|
||||||
|
this.setState({
|
||||||
|
min: values[0],
|
||||||
|
max: values[1]
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
saveTempScale(this.state)
|
||||||
|
} catch(err) {
|
||||||
|
alertError(labels.tempScale.saveError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={{ alignItems: 'center' }}>
|
||||||
|
<AppText>{`${labels.tempScale.min} ${this.state.min}`}</AppText>
|
||||||
|
<AppText>{`${labels.tempScale.max} ${this.state.max}`}</AppText>
|
||||||
|
<Slider
|
||||||
|
values={[this.state.min, this.state.max]}
|
||||||
|
min={config.temperatureScale.min}
|
||||||
|
max={config.temperatureScale.max}
|
||||||
|
step={0.5}
|
||||||
|
onValuesChange={this.onValuesChange}
|
||||||
|
onValuesChangeFinish={this.onValuesChangeFinish}
|
||||||
|
selectedStyle={{
|
||||||
|
backgroundColor: 'darkgrey',
|
||||||
|
}}
|
||||||
|
unselectedStyle={{
|
||||||
|
backgroundColor: 'silver',
|
||||||
|
}}
|
||||||
|
trackStyle={{
|
||||||
|
height: 10,
|
||||||
|
}}
|
||||||
|
markerStyle={{
|
||||||
|
backgroundColor: secondaryColor,
|
||||||
|
height: 20,
|
||||||
|
width: 20,
|
||||||
|
borderRadius: 100,
|
||||||
|
marginTop: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+86
-185
@@ -1,5 +1,8 @@
|
|||||||
import Realm from 'realm'
|
import Realm from 'realm'
|
||||||
import { LocalDate, ChronoUnit } from 'js-joda'
|
import { LocalDate, ChronoUnit } from 'js-joda'
|
||||||
|
import nodejs from 'nodejs-mobile-react-native'
|
||||||
|
import fs from 'react-native-fs'
|
||||||
|
import restart from 'react-native-restart'
|
||||||
import {
|
import {
|
||||||
cycleWithFhmMucus,
|
cycleWithFhmMucus,
|
||||||
longAndComplicatedCycleWithMucus,
|
longAndComplicatedCycleWithMucus,
|
||||||
@@ -8,165 +11,30 @@ import {
|
|||||||
longAndComplicatedCycleWithCervix,
|
longAndComplicatedCycleWithCervix,
|
||||||
cycleWithTempAndNoCervixShift
|
cycleWithTempAndNoCervixShift
|
||||||
} from './fixtures'
|
} from './fixtures'
|
||||||
|
import dbSchema from './schema'
|
||||||
|
|
||||||
const TemperatureSchema = {
|
let db
|
||||||
name: 'Temperature',
|
|
||||||
properties: {
|
|
||||||
value: 'double',
|
|
||||||
exclude: 'bool',
|
|
||||||
time: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true
|
|
||||||
},
|
|
||||||
note: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const BleedingSchema = {
|
|
||||||
name: 'Bleeding',
|
|
||||||
properties: {
|
|
||||||
value: 'int',
|
|
||||||
exclude: 'bool'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MucusSchema = {
|
|
||||||
name: 'Mucus',
|
|
||||||
properties: {
|
|
||||||
feeling: 'int',
|
|
||||||
texture: 'int',
|
|
||||||
value: 'int',
|
|
||||||
exclude: 'bool'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const CervixSchema = {
|
|
||||||
name: 'Cervix',
|
|
||||||
properties: {
|
|
||||||
opening: 'int',
|
|
||||||
firmness: 'int',
|
|
||||||
position: {type: 'int', optional: true },
|
|
||||||
exclude: 'bool'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const NoteSchema = {
|
|
||||||
name: 'Note',
|
|
||||||
properties: {
|
|
||||||
value: 'string'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const DesireSchema = {
|
|
||||||
name: 'Desire',
|
|
||||||
properties: {
|
|
||||||
value: 'int'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const SexSchema = {
|
|
||||||
name: 'Sex',
|
|
||||||
properties: {
|
|
||||||
solo: { type: 'bool', optional: true },
|
|
||||||
partner: { type: 'bool', optional: true },
|
|
||||||
condom: { type: 'bool', optional: true },
|
|
||||||
pill: { type: 'bool', optional: true },
|
|
||||||
iud: { type: 'bool', optional: true },
|
|
||||||
patch: { type: 'bool', optional: true },
|
|
||||||
ring: { type: 'bool', optional: true },
|
|
||||||
implant: { type: 'bool', optional: true },
|
|
||||||
other: { type: 'bool', optional: true },
|
|
||||||
note: { type: 'string', optional: true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const PainSchema = {
|
|
||||||
name: 'Pain',
|
|
||||||
properties: {
|
|
||||||
cramps: { type: 'bool', optional: true },
|
|
||||||
ovulationPain: { type: 'bool', optional: true },
|
|
||||||
headache: { type: 'bool', optional: true },
|
|
||||||
backache: { type: 'bool', optional: true },
|
|
||||||
nausea: { type: 'bool', optional: true },
|
|
||||||
tenderBreasts: { type: 'bool', optional: true },
|
|
||||||
migraine: { type: 'bool', optional: true },
|
|
||||||
other: { type: 'bool', optional: true },
|
|
||||||
note: { type: 'string', optional: true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const CycleDaySchema = {
|
|
||||||
name: 'CycleDay',
|
|
||||||
primaryKey: 'date',
|
|
||||||
properties: {
|
|
||||||
date: 'string',
|
|
||||||
temperature: {
|
|
||||||
type: 'Temperature',
|
|
||||||
optional: true
|
|
||||||
},
|
|
||||||
bleeding: {
|
|
||||||
type: 'Bleeding',
|
|
||||||
optional: true
|
|
||||||
},
|
|
||||||
mucus: {
|
|
||||||
type: 'Mucus',
|
|
||||||
optional: true
|
|
||||||
},
|
|
||||||
cervix: {
|
|
||||||
type: 'Cervix',
|
|
||||||
optional: true
|
|
||||||
},
|
|
||||||
note: {
|
|
||||||
type: 'Note',
|
|
||||||
optional: true
|
|
||||||
},
|
|
||||||
desire: {
|
|
||||||
type: 'Desire',
|
|
||||||
optional: true
|
|
||||||
},
|
|
||||||
sex: {
|
|
||||||
type: 'Sex',
|
|
||||||
optional: true
|
|
||||||
},
|
|
||||||
pain: {
|
|
||||||
type: 'Pain',
|
|
||||||
optional: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const realmConfig = {
|
const realmConfig = {
|
||||||
schema: [
|
schema: dbSchema
|
||||||
CycleDaySchema,
|
|
||||||
TemperatureSchema,
|
|
||||||
BleedingSchema,
|
|
||||||
MucusSchema,
|
|
||||||
CervixSchema,
|
|
||||||
NoteSchema,
|
|
||||||
DesireSchema,
|
|
||||||
SexSchema,
|
|
||||||
PainSchema
|
|
||||||
],
|
|
||||||
// we only want this in dev mode
|
|
||||||
deleteRealmIfMigrationNeeded: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = new Realm(realmConfig)
|
export function getBleedingDaysSortedByDate() {
|
||||||
|
return db.objects('CycleDay').filtered('bleeding != null').sorted('date', true)
|
||||||
|
}
|
||||||
|
export function getTemperatureDaysSortedByDate() {
|
||||||
|
return db.objects('CycleDay').filtered('temperature != null').sorted('date', true)
|
||||||
|
}
|
||||||
|
export function getCycleDaysSortedByDate() {
|
||||||
|
return db.objects('CycleDay').sorted('date', true)
|
||||||
|
}
|
||||||
|
|
||||||
const bleedingDaysSortedByDate = db.objects('CycleDay').filtered('bleeding != null').sorted('date', true)
|
export function saveSymptom(symptom, cycleDay, val) {
|
||||||
const temperatureDaysSortedByDate = db.objects('CycleDay').filtered('temperature != null').sorted('date', true)
|
|
||||||
const cycleDaysSortedByDate = db.objects('CycleDay').sorted('date', true)
|
|
||||||
|
|
||||||
function saveSymptom(symptom, cycleDay, val) {
|
|
||||||
db.write(() => {
|
db.write(() => {
|
||||||
cycleDay[symptom] = val
|
cycleDay[symptom] = val
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrCreateCycleDay(localDate) {
|
export function getOrCreateCycleDay(localDate) {
|
||||||
let result = db.objectForPrimaryKey('CycleDay', localDate)
|
let result = db.objectForPrimaryKey('CycleDay', localDate)
|
||||||
if (!result) {
|
if (!result) {
|
||||||
db.write(() => {
|
db.write(() => {
|
||||||
@@ -178,11 +46,11 @@ function getOrCreateCycleDay(localDate) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCycleDay(localDate) {
|
export function getCycleDay(localDate) {
|
||||||
return db.objectForPrimaryKey('CycleDay', localDate)
|
return db.objectForPrimaryKey('CycleDay', localDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillWithMucusDummyData() {
|
export function fillWithMucusDummyData() {
|
||||||
const dummyCycles = [
|
const dummyCycles = [
|
||||||
cycleWithFhmMucus,
|
cycleWithFhmMucus,
|
||||||
longAndComplicatedCycleWithMucus,
|
longAndComplicatedCycleWithMucus,
|
||||||
@@ -207,7 +75,7 @@ function fillWithMucusDummyData() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillWithCervixDummyData() {
|
export function fillWithCervixDummyData() {
|
||||||
const dummyCycles = [
|
const dummyCycles = [
|
||||||
cycleWithFhmCervix,
|
cycleWithFhmCervix,
|
||||||
longAndComplicatedCycleWithCervix,
|
longAndComplicatedCycleWithCervix,
|
||||||
@@ -232,16 +100,9 @@ function fillWithCervixDummyData() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPreviousTemperature(cycleDay) {
|
||||||
function deleteAll() {
|
|
||||||
db.write(() => {
|
|
||||||
db.deleteAll()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPreviousTemperature(cycleDay) {
|
|
||||||
cycleDay.wrappedDate = LocalDate.parse(cycleDay.date)
|
cycleDay.wrappedDate = LocalDate.parse(cycleDay.date)
|
||||||
const winner = temperatureDaysSortedByDate.find(day => {
|
const winner = getTemperatureDaysSortedByDate().find(day => {
|
||||||
const wrappedDate = LocalDate.parse(day.date)
|
const wrappedDate = LocalDate.parse(day.date)
|
||||||
return wrappedDate.isBefore(cycleDay.wrappedDate)
|
return wrappedDate.isBefore(cycleDay.wrappedDate)
|
||||||
})
|
})
|
||||||
@@ -249,12 +110,7 @@ function getPreviousTemperature(cycleDay) {
|
|||||||
return winner.temperature.value
|
return winner.temperature.value
|
||||||
}
|
}
|
||||||
|
|
||||||
const schema = db.schema.reduce((acc, curr) => {
|
export function tryToCreateCycleDay(day, i) {
|
||||||
acc[curr.name] = curr.properties
|
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
|
|
||||||
function tryToCreateCycleDay(day, i) {
|
|
||||||
try {
|
try {
|
||||||
db.create('CycleDay', day)
|
db.create('CycleDay', day)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -263,7 +119,8 @@ function tryToCreateCycleDay(day, i) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAmountOfCycleDays() {
|
export function getAmountOfCycleDays() {
|
||||||
|
const cycleDaysSortedByDate = getCycleDaysSortedByDate()
|
||||||
const amountOfCycleDays = cycleDaysSortedByDate.length
|
const amountOfCycleDays = cycleDaysSortedByDate.length
|
||||||
if (!amountOfCycleDays) return 0
|
if (!amountOfCycleDays) return 0
|
||||||
const earliest = cycleDaysSortedByDate[amountOfCycleDays - 1]
|
const earliest = cycleDaysSortedByDate[amountOfCycleDays - 1]
|
||||||
@@ -272,14 +129,21 @@ function getAmountOfCycleDays() {
|
|||||||
return earliestAsLocalDate.until(today, ChronoUnit.DAYS)
|
return earliestAsLocalDate.until(today, ChronoUnit.DAYS)
|
||||||
}
|
}
|
||||||
|
|
||||||
function tryToImportWithDelete(cycleDays) {
|
export function getSchema() {
|
||||||
|
return db.schema.reduce((acc, curr) => {
|
||||||
|
acc[curr.name] = curr.properties
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tryToImportWithDelete(cycleDays) {
|
||||||
db.write(() => {
|
db.write(() => {
|
||||||
db.delete(db.objects('CycleDay'))
|
db.delete(db.objects('CycleDay'))
|
||||||
cycleDays.forEach(tryToCreateCycleDay)
|
cycleDays.forEach(tryToCreateCycleDay)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function tryToImportWithoutDelete(cycleDays) {
|
export function tryToImportWithoutDelete(cycleDays) {
|
||||||
db.write(() => {
|
db.write(() => {
|
||||||
cycleDays.forEach((day, i) => {
|
cycleDays.forEach((day, i) => {
|
||||||
const existing = getCycleDay(day.date)
|
const existing = getCycleDay(day.date)
|
||||||
@@ -289,19 +153,56 @@ function tryToImportWithoutDelete(cycleDays) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export function requestHash(type, pw) {
|
||||||
saveSymptom,
|
nodejs.channel.post('request-SHA512', JSON.stringify({
|
||||||
getOrCreateCycleDay,
|
type: type,
|
||||||
bleedingDaysSortedByDate,
|
message: pw
|
||||||
temperatureDaysSortedByDate,
|
}))
|
||||||
cycleDaysSortedByDate,
|
}
|
||||||
fillWithMucusDummyData,
|
|
||||||
fillWithCervixDummyData,
|
export async function openDb ({ hash, persistConnection }) {
|
||||||
deleteAll,
|
if (hash) {
|
||||||
getPreviousTemperature,
|
realmConfig.encryptionKey = hashToInt8Array(hash)
|
||||||
getCycleDay,
|
}
|
||||||
getAmountOfCycleDays,
|
|
||||||
schema,
|
const connection = await Realm.open(realmConfig)
|
||||||
tryToImportWithDelete,
|
|
||||||
tryToImportWithoutDelete
|
if (persistConnection) db = connection
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function changeEncryptionAndRestartApp(hash) {
|
||||||
|
let key
|
||||||
|
if (hash) key = hashToInt8Array(hash)
|
||||||
|
const defaultPath = db.path
|
||||||
|
const dir = db.path.split('/')
|
||||||
|
dir.pop()
|
||||||
|
dir.push('copied.realm')
|
||||||
|
const copyPath = dir.join('/')
|
||||||
|
const exists = await fs.exists(copyPath)
|
||||||
|
if (exists) await fs.unlink(copyPath)
|
||||||
|
// for some reason, realm complains if we give it a key with value undefined
|
||||||
|
if (key) {
|
||||||
|
db.writeCopyTo(copyPath, key)
|
||||||
|
} else {
|
||||||
|
db.writeCopyTo(copyPath)
|
||||||
|
}
|
||||||
|
db.close()
|
||||||
|
await fs.unlink(defaultPath)
|
||||||
|
await fs.moveFile(copyPath, defaultPath)
|
||||||
|
restart.Restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteDbAndOpenNew() {
|
||||||
|
const exists = await fs.exists(Realm.defaultPath)
|
||||||
|
if (exists) await fs.unlink(Realm.defaultPath)
|
||||||
|
await openDb({ persistConnection: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
function hashToInt8Array(hash) {
|
||||||
|
const key = new Uint8Array(64)
|
||||||
|
for (let i = 0; i < key.length; i++) {
|
||||||
|
const twoDigitHex = hash.slice(i * 2, i * 2 + 2)
|
||||||
|
key[i] = parseInt(twoDigitHex, 16)
|
||||||
|
}
|
||||||
|
return key
|
||||||
}
|
}
|
||||||
|
|||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
const TemperatureSchema = {
|
||||||
|
name: 'Temperature',
|
||||||
|
properties: {
|
||||||
|
value: 'double',
|
||||||
|
exclude: 'bool',
|
||||||
|
time: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
note: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BleedingSchema = {
|
||||||
|
name: 'Bleeding',
|
||||||
|
properties: {
|
||||||
|
value: 'int',
|
||||||
|
exclude: 'bool'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MucusSchema = {
|
||||||
|
name: 'Mucus',
|
||||||
|
properties: {
|
||||||
|
feeling: 'int',
|
||||||
|
texture: 'int',
|
||||||
|
value: 'int',
|
||||||
|
exclude: 'bool'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CervixSchema = {
|
||||||
|
name: 'Cervix',
|
||||||
|
properties: {
|
||||||
|
opening: 'int',
|
||||||
|
firmness: 'int',
|
||||||
|
position: {type: 'int', optional: true },
|
||||||
|
exclude: 'bool'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoteSchema = {
|
||||||
|
name: 'Note',
|
||||||
|
properties: {
|
||||||
|
value: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const DesireSchema = {
|
||||||
|
name: 'Desire',
|
||||||
|
properties: {
|
||||||
|
value: 'int'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SexSchema = {
|
||||||
|
name: 'Sex',
|
||||||
|
properties: {
|
||||||
|
solo: { type: 'bool', optional: true },
|
||||||
|
partner: { type: 'bool', optional: true },
|
||||||
|
condom: { type: 'bool', optional: true },
|
||||||
|
pill: { type: 'bool', optional: true },
|
||||||
|
iud: { type: 'bool', optional: true },
|
||||||
|
patch: { type: 'bool', optional: true },
|
||||||
|
ring: { type: 'bool', optional: true },
|
||||||
|
implant: { type: 'bool', optional: true },
|
||||||
|
other: { type: 'bool', optional: true },
|
||||||
|
note: { type: 'string', optional: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PainSchema = {
|
||||||
|
name: 'Pain',
|
||||||
|
properties: {
|
||||||
|
cramps: { type: 'bool', optional: true },
|
||||||
|
ovulationPain: { type: 'bool', optional: true },
|
||||||
|
headache: { type: 'bool', optional: true },
|
||||||
|
backache: { type: 'bool', optional: true },
|
||||||
|
nausea: { type: 'bool', optional: true },
|
||||||
|
tenderBreasts: { type: 'bool', optional: true },
|
||||||
|
migraine: { type: 'bool', optional: true },
|
||||||
|
other: { type: 'bool', optional: true },
|
||||||
|
note: { type: 'string', optional: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CycleDaySchema = {
|
||||||
|
name: 'CycleDay',
|
||||||
|
primaryKey: 'date',
|
||||||
|
properties: {
|
||||||
|
date: 'string',
|
||||||
|
temperature: {
|
||||||
|
type: 'Temperature',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
bleeding: {
|
||||||
|
type: 'Bleeding',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
mucus: {
|
||||||
|
type: 'Mucus',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
cervix: {
|
||||||
|
type: 'Cervix',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
note: {
|
||||||
|
type: 'Note',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
desire: {
|
||||||
|
type: 'Desire',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
sex: {
|
||||||
|
type: 'Sex',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
pain: {
|
||||||
|
type: 'Pain',
|
||||||
|
optional: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default [
|
||||||
|
CycleDaySchema,
|
||||||
|
TemperatureSchema,
|
||||||
|
BleedingSchema,
|
||||||
|
MucusSchema,
|
||||||
|
CervixSchema,
|
||||||
|
NoteSchema,
|
||||||
|
DesireSchema,
|
||||||
|
SexSchema,
|
||||||
|
PainSchema
|
||||||
|
]
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AppRegistry } from 'react-native'
|
import { AppRegistry } from 'react-native'
|
||||||
import App from './components/app'
|
import AppWrapper from './components/app-wrapper'
|
||||||
|
|
||||||
AppRegistry.registerComponent('home', () => App)
|
AppRegistry.registerComponent('home', () => AppWrapper)
|
||||||
@@ -58,6 +58,12 @@
|
|||||||
A1410AC4C98A49B2820D9E45 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B6F5078F7DEC470782757471 /* Zocial.ttf */; };
|
A1410AC4C98A49B2820D9E45 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B6F5078F7DEC470782757471 /* Zocial.ttf */; };
|
||||||
29DF0CCC1AEA4C92BCA0BCCD /* libRNDocumentPicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D211D71BE5A8436A978770A9 /* libRNDocumentPicker.a */; };
|
29DF0CCC1AEA4C92BCA0BCCD /* libRNDocumentPicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D211D71BE5A8436A978770A9 /* libRNDocumentPicker.a */; };
|
||||||
17AD822C42A44BADA96BD860 /* libRNFS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84CCEBD3B2C44758853BC941 /* libRNFS.a */; };
|
17AD822C42A44BADA96BD860 /* libRNFS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84CCEBD3B2C44758853BC941 /* libRNFS.a */; };
|
||||||
|
72DA6B4241504DB096AFAD40 /* libRCTRestart.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AB636AA0286D45CE9B23B2C3 /* libRCTRestart.a */; };
|
||||||
|
E09F3B05A4F84E9883101CC7 /* libRNNodeJsMobile.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F992F2D99E614DD79FAD6565 /* libRNNodeJsMobile.a */; };
|
||||||
|
E43EF009AC8C4698AB322190 /* NodeMobile.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C225FC4966694B9FBD32E946 /* NodeMobile.framework */; };
|
||||||
|
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 */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -389,6 +395,13 @@
|
|||||||
D211D71BE5A8436A978770A9 /* libRNDocumentPicker.a */ = {isa = PBXFileReference; name = "libRNDocumentPicker.a"; path = "libRNDocumentPicker.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
|
D211D71BE5A8436A978770A9 /* libRNDocumentPicker.a */ = {isa = PBXFileReference; name = "libRNDocumentPicker.a"; path = "libRNDocumentPicker.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
|
||||||
49089E09BFCF4F3DB209B6E9 /* RNFS.xcodeproj */ = {isa = PBXFileReference; name = "RNFS.xcodeproj"; path = "../node_modules/react-native-fs/RNFS.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
|
49089E09BFCF4F3DB209B6E9 /* RNFS.xcodeproj */ = {isa = PBXFileReference; name = "RNFS.xcodeproj"; path = "../node_modules/react-native-fs/RNFS.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
|
||||||
84CCEBD3B2C44758853BC941 /* libRNFS.a */ = {isa = PBXFileReference; name = "libRNFS.a"; path = "libRNFS.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
|
84CCEBD3B2C44758853BC941 /* libRNFS.a */ = {isa = PBXFileReference; name = "libRNFS.a"; path = "libRNFS.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
|
||||||
|
50DBC4BCDDF74A10AEDC99D5 /* RCTRestart.xcodeproj */ = {isa = PBXFileReference; name = "RCTRestart.xcodeproj"; path = "../node_modules/react-native-restart/ios/RCTRestart.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
|
||||||
|
AB636AA0286D45CE9B23B2C3 /* libRCTRestart.a */ = {isa = PBXFileReference; name = "libRCTRestart.a"; path = "libRCTRestart.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
|
||||||
|
65F706FAFA1444AE9937D472 /* RNNodeJsMobile.xcodeproj */ = {isa = PBXFileReference; name = "RNNodeJsMobile.xcodeproj"; path = "../node_modules/nodejs-mobile-react-native/ios/RNNodeJsMobile.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
|
||||||
|
F992F2D99E614DD79FAD6565 /* libRNNodeJsMobile.a */ = {isa = PBXFileReference; name = "libRNNodeJsMobile.a"; path = "libRNNodeJsMobile.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
|
||||||
|
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; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -424,6 +437,9 @@
|
|||||||
AED64B7892744F21B3A156BB /* libRNVectorIcons.a in Frameworks */,
|
AED64B7892744F21B3A156BB /* libRNVectorIcons.a in Frameworks */,
|
||||||
29DF0CCC1AEA4C92BCA0BCCD /* libRNDocumentPicker.a in Frameworks */,
|
29DF0CCC1AEA4C92BCA0BCCD /* libRNDocumentPicker.a in Frameworks */,
|
||||||
17AD822C42A44BADA96BD860 /* libRNFS.a in Frameworks */,
|
17AD822C42A44BADA96BD860 /* libRNFS.a in Frameworks */,
|
||||||
|
72DA6B4241504DB096AFAD40 /* libRCTRestart.a in Frameworks */,
|
||||||
|
E09F3B05A4F84E9883101CC7 /* libRNNodeJsMobile.a in Frameworks */,
|
||||||
|
E43EF009AC8C4698AB322190 /* NodeMobile.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -576,6 +592,7 @@
|
|||||||
2D16E6891FA4F8E400B85C8A /* libReact.a */,
|
2D16E6891FA4F8E400B85C8A /* libReact.a */,
|
||||||
9AEBF0735214455AAEDF56D5 /* libc++.tbd */,
|
9AEBF0735214455AAEDF56D5 /* libc++.tbd */,
|
||||||
CD8C8B91E0A747B3883A0D56 /* libz.tbd */,
|
CD8C8B91E0A747B3883A0D56 /* libz.tbd */,
|
||||||
|
C225FC4966694B9FBD32E946 /* NodeMobile.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -618,6 +635,8 @@
|
|||||||
D1E5ACC4B66345868F556374 /* RNVectorIcons.xcodeproj */,
|
D1E5ACC4B66345868F556374 /* RNVectorIcons.xcodeproj */,
|
||||||
1F05FE29622E4F21AF70C2B7 /* RNDocumentPicker.xcodeproj */,
|
1F05FE29622E4F21AF70C2B7 /* RNDocumentPicker.xcodeproj */,
|
||||||
49089E09BFCF4F3DB209B6E9 /* RNFS.xcodeproj */,
|
49089E09BFCF4F3DB209B6E9 /* RNFS.xcodeproj */,
|
||||||
|
50DBC4BCDDF74A10AEDC99D5 /* RCTRestart.xcodeproj */,
|
||||||
|
65F706FAFA1444AE9937D472 /* RNNodeJsMobile.xcodeproj */,
|
||||||
);
|
);
|
||||||
name = Libraries;
|
name = Libraries;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -640,6 +659,8 @@
|
|||||||
83CBBA001A601CBA00E9B192 /* Products */,
|
83CBBA001A601CBA00E9B192 /* Products */,
|
||||||
2D16E6871FA4F8E400B85C8A /* Frameworks */,
|
2D16E6871FA4F8E400B85C8A /* Frameworks */,
|
||||||
006C39A0B9774387BC5ACA43 /* Resources */,
|
006C39A0B9774387BC5ACA43 /* Resources */,
|
||||||
|
6466AE2461BE4FA88B8372F0 /* nodejs-project */,
|
||||||
|
36F1B55D0DEE47AA9AF4BBDD /* builtin_modules */,
|
||||||
);
|
);
|
||||||
indentWidth = 2;
|
indentWidth = 2;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -717,6 +738,10 @@
|
|||||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||||
|
2B572382D4504B8FB4B9D251 /* Embed Frameworks */,
|
||||||
|
7DDFD19623084447885928A6 /* Build NodeJS Mobile Native Modules */,
|
||||||
|
554E2494DF2646B083F4BD1D /* Sign NodeJS Mobile Native Modules */,
|
||||||
|
8F5D6E75B7D344BD80BC6EC0 /* Remove NodeJS Mobile Framework Simulator Strips */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -1148,6 +1173,8 @@
|
|||||||
DB91E6CCC3EB4A549D947797 /* Octicons.ttf in Resources */,
|
DB91E6CCC3EB4A549D947797 /* Octicons.ttf in Resources */,
|
||||||
3DF2498A20844F298CD84CC3 /* SimpleLineIcons.ttf in Resources */,
|
3DF2498A20844F298CD84CC3 /* SimpleLineIcons.ttf in Resources */,
|
||||||
A1410AC4C98A49B2820D9E45 /* Zocial.ttf in Resources */,
|
A1410AC4C98A49B2820D9E45 /* Zocial.ttf in Resources */,
|
||||||
|
E4584E55EEC24302A3E84A23 /* nodejs-project in Resources */,
|
||||||
|
A16B351C3F3644CF95F104D2 /* builtin_modules in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -1197,6 +1224,160 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
|
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
|
||||||
};
|
};
|
||||||
|
7DDFD19623084447885928A6 /* Build NodeJS Mobile Native Modules */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
name = "Build NodeJS Mobile Native Modules";
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "
|
||||||
|
set -e
|
||||||
|
if [ -z \"$NODEJS_MOBILE_BUILD_NATIVE_MODULES\" ]; then
|
||||||
|
# If build native modules preference is not set, look for it in the project's
|
||||||
|
#nodejs-assets/BUILD_NATIVE_MODULES.txt file.
|
||||||
|
NODEJS_ASSETS_DIR=\"$( cd \"$PROJECT_DIR\" && cd ../nodejs-assets/ && pwd )\"
|
||||||
|
PREFERENCE_FILE_PATH=\"$NODEJS_ASSETS_DIR/BUILD_NATIVE_MODULES.txt\"
|
||||||
|
if [ -f \"$PREFERENCE_FILE_PATH\" ]; then
|
||||||
|
NODEJS_MOBILE_BUILD_NATIVE_MODULES=\"$(cat $PREFERENCE_FILE_PATH | xargs)\"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -z \"$NODEJS_MOBILE_BUILD_NATIVE_MODULES\" ]; then
|
||||||
|
# If build native modules preference is not set, try to find .gyp files
|
||||||
|
#to turn it on.
|
||||||
|
gypfiles=($(find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -type f -name \"*.gyp\"))
|
||||||
|
if [ ${#gypfiles[@]} -gt 0 ]; then
|
||||||
|
NODEJS_MOBILE_BUILD_NATIVE_MODULES=1
|
||||||
|
else
|
||||||
|
NODEJS_MOBILE_BUILD_NATIVE_MODULES=0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ \"1\" != \"$NODEJS_MOBILE_BUILD_NATIVE_MODULES\" ]; then exit 0; fi
|
||||||
|
# Delete object files that may already come from within the npm package.
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -name \"*.o\" -type f -delete
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -name \"*.a\" -type f -delete
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -name \"*.node\" -type f -delete
|
||||||
|
# Delete bundle contents that may be there from previous builds.
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -path \"*/*.node/*\" -delete
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -name \"*.node\" -type d -delete
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -path \"*/*.framework/*\" -delete
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -name \"*.framework\" -type d -delete
|
||||||
|
# Apply patches to the modules package.json
|
||||||
|
if [ -d \"$CODESIGNING_FOLDER_PATH\"/nodejs-project/node_modules/ ]; then
|
||||||
|
PATCH_SCRIPT_DIR=\"$( cd \"$PROJECT_DIR\" && cd ../node_modules/nodejs-mobile-react-native/scripts/ && pwd )\"
|
||||||
|
NODEJS_PROJECT_MODULES_DIR=\"$( cd \"$CODESIGNING_FOLDER_PATH\" && cd nodejs-project/node_modules/ && pwd )\"
|
||||||
|
node \"$PATCH_SCRIPT_DIR\"/patch-package.js $NODEJS_PROJECT_MODULES_DIR
|
||||||
|
fi
|
||||||
|
# Get the nodejs-mobile-gyp location
|
||||||
|
if [ -d \"$PROJECT_DIR/../node_modules/nodejs-mobile-gyp/\" ]; then
|
||||||
|
NODEJS_MOBILE_GYP_DIR=\"$( cd \"$PROJECT_DIR\" && cd ../node_modules/nodejs-mobile-gyp/ && pwd )\"
|
||||||
|
else
|
||||||
|
NODEJS_MOBILE_GYP_DIR=\"$( cd \"$PROJECT_DIR\" && cd ../node_modules/nodejs-mobile-react-native/node_modules/nodejs-mobile-gyp/ && pwd )\"
|
||||||
|
fi
|
||||||
|
NODEJS_MOBILE_GYP_BIN_FILE=\"$NODEJS_MOBILE_GYP_DIR\"/bin/node-gyp.js
|
||||||
|
# Rebuild modules with right environment
|
||||||
|
NODEJS_HEADERS_DIR=\"$( cd \"$PROJECT_DIR\" && cd ../node_modules/nodejs-mobile-react-native/ios/libnode/ && pwd )\"
|
||||||
|
pushd $CODESIGNING_FOLDER_PATH/nodejs-project/
|
||||||
|
if [ \"$PLATFORM_NAME\" == \"iphoneos\" ]
|
||||||
|
then
|
||||||
|
GYP_DEFINES=\"OS=ios\" npm_config_nodedir=\"$NODEJS_HEADERS_DIR\" npm_config_node_gyp=\"$NODEJS_MOBILE_GYP_BIN_FILE\" npm_config_platform=\"ios\" npm_config_format=\"make-ios\" npm_config_node_engine=\"chakracore\" npm_config_arch=\"arm64\" npm --verbose rebuild --build-from-source
|
||||||
|
else
|
||||||
|
GYP_DEFINES=\"OS=ios\" npm_config_nodedir=\"$NODEJS_HEADERS_DIR\" npm_config_node_gyp=\"$NODEJS_MOBILE_GYP_BIN_FILE\" npm_config_platform=\"ios\" npm_config_format=\"make-ios\" npm_config_node_engine=\"chakracore\" npm_config_arch=\"x64\" npm --verbose rebuild --build-from-source
|
||||||
|
fi
|
||||||
|
popd
|
||||||
|
";
|
||||||
|
};
|
||||||
|
554E2494DF2646B083F4BD1D /* Sign NodeJS Mobile Native Modules */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
name = "Sign NodeJS Mobile Native Modules";
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "
|
||||||
|
set -e
|
||||||
|
if [ -z \"$NODEJS_MOBILE_BUILD_NATIVE_MODULES\" ]; then
|
||||||
|
# If build native modules preference is not set, look for it in the project's
|
||||||
|
#nodejs-assets/BUILD_NATIVE_MODULES.txt file.
|
||||||
|
NODEJS_ASSETS_DIR=\"$( cd \"$PROJECT_DIR\" && cd ../nodejs-assets/ && pwd )\"
|
||||||
|
PREFERENCE_FILE_PATH=\"$NODEJS_ASSETS_DIR/BUILD_NATIVE_MODULES.txt\"
|
||||||
|
if [ -f \"$PREFERENCE_FILE_PATH\" ]; then
|
||||||
|
NODEJS_MOBILE_BUILD_NATIVE_MODULES=\"$(cat $PREFERENCE_FILE_PATH | xargs)\"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -z \"$NODEJS_MOBILE_BUILD_NATIVE_MODULES\" ]; then
|
||||||
|
# If build native modules preference is not set, try to find .gyp files
|
||||||
|
#to turn it on.
|
||||||
|
gypfiles=($(find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -type f -name \"*.gyp\"))
|
||||||
|
if [ ${#gypfiles[@]} -gt 0 ]; then
|
||||||
|
NODEJS_MOBILE_BUILD_NATIVE_MODULES=1
|
||||||
|
else
|
||||||
|
NODEJS_MOBILE_BUILD_NATIVE_MODULES=0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ \"1\" != \"$NODEJS_MOBILE_BUILD_NATIVE_MODULES\" ]; then exit 0; fi
|
||||||
|
# Delete object files
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -name \"*.o\" -type f -delete
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -name \"*.a\" -type f -delete
|
||||||
|
# Create Info.plist for each framework built and loader override.
|
||||||
|
PATCH_SCRIPT_DIR=\"$( cd \"$PROJECT_DIR\" && cd ../node_modules/nodejs-mobile-react-native/scripts/ && pwd )\"
|
||||||
|
NODEJS_PROJECT_DIR=\"$( cd \"$CODESIGNING_FOLDER_PATH\" && cd nodejs-project/ && pwd )\"
|
||||||
|
node \"$PATCH_SCRIPT_DIR\"/ios-create-plists-and-dlopen-override.js $NODEJS_PROJECT_DIR
|
||||||
|
# Embed every resulting .framework in the application and delete them afterwards.
|
||||||
|
embed_framework()
|
||||||
|
{
|
||||||
|
FRAMEWORK_NAME=\"$(basename \"$1\")\"
|
||||||
|
cp -r \"$1\" \"$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/\"
|
||||||
|
|
||||||
|
/usr/bin/codesign --force --sign $EXPANDED_CODE_SIGN_IDENTITY --preserve-metadata=identifier,entitlements,flags --timestamp=none \"$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/$FRAMEWORK_NAME\"
|
||||||
|
}
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -name \"*.framework\" -type d | while read frmwrk_path; do embed_framework \"$frmwrk_path\"; done
|
||||||
|
|
||||||
|
#Delete gyp temporary .deps dependency folders from the project structure.
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -path \"*/.deps/*\" -delete
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -name \".deps\" -type d -delete
|
||||||
|
|
||||||
|
#Delete frameworks from their build paths
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -path \"*/*.framework/*\" -delete
|
||||||
|
find \"$CODESIGNING_FOLDER_PATH/nodejs-project/\" -name \"*.framework\" -type d -delete
|
||||||
|
";
|
||||||
|
};
|
||||||
|
8F5D6E75B7D344BD80BC6EC0 /* Remove NodeJS Mobile Framework Simulator Strips */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
name = "Remove NodeJS Mobile Framework Simulator Strips";
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "
|
||||||
|
set -e
|
||||||
|
FRAMEWORK_BINARY_PATH=\"$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/NodeMobile.framework/NodeMobile\"
|
||||||
|
FRAMEWORK_STRIPPED_PATH=\"$FRAMEWORK_BINARY_PATH-strip\"
|
||||||
|
if [ \"$PLATFORM_NAME\" != \"iphonesimulator\" ]; then
|
||||||
|
if $(lipo \"$FRAMEWORK_BINARY_PATH\" -verify_arch \"x86_64\") ; then
|
||||||
|
lipo -output \"$FRAMEWORK_STRIPPED_PATH\" -remove \"x86_64\" \"$FRAMEWORK_BINARY_PATH\"
|
||||||
|
rm \"$FRAMEWORK_BINARY_PATH\"
|
||||||
|
mv \"$FRAMEWORK_STRIPPED_PATH\" \"$FRAMEWORK_BINARY_PATH\"
|
||||||
|
echo \"Removed simulator strip from NodeMobile.framework\"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
";
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
@@ -1284,6 +1465,8 @@
|
|||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
);
|
);
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1292,7 +1475,15 @@
|
|||||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||||
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
||||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||||
|
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
|
||||||
|
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
|
||||||
);
|
);
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
);
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -1315,6 +1506,8 @@
|
|||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
);
|
);
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1323,7 +1516,15 @@
|
|||||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||||
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
||||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||||
|
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
|
||||||
|
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
|
||||||
);
|
);
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
);
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -1349,7 +1550,14 @@
|
|||||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||||
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
||||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||||
|
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
|
||||||
|
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
|
||||||
);
|
);
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
);
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -1374,7 +1582,14 @@
|
|||||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||||
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
||||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||||
|
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
|
||||||
|
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
|
||||||
);
|
);
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
);
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -1406,6 +1621,8 @@
|
|||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
);
|
);
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1414,7 +1631,15 @@
|
|||||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||||
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
||||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||||
|
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
|
||||||
|
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
|
||||||
);
|
);
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
);
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -1446,6 +1671,8 @@
|
|||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
);
|
);
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1454,7 +1681,15 @@
|
|||||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||||
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
||||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||||
|
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
|
||||||
|
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
|
||||||
);
|
);
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
);
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -1485,6 +1720,8 @@
|
|||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
);
|
);
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1493,7 +1730,15 @@
|
|||||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||||
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
||||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||||
|
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
|
||||||
|
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
|
||||||
);
|
);
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
);
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -1524,6 +1769,8 @@
|
|||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
|
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||||
);
|
);
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1532,7 +1779,15 @@
|
|||||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||||
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
|
||||||
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
"$(SRCROOT)/../node_modules/react-native-fs/**",
|
||||||
|
"$(SRCROOT)/../node_modules/react-native-restart/ios/RCTRestart/**",
|
||||||
|
"$(SRCROOT)/../node_modules/nodejs-mobile-react-native/ios/**",
|
||||||
);
|
);
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
"\"../node_modules/nodejs-mobile-react-native/ios\"",
|
||||||
|
);
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -1574,6 +1829,7 @@
|
|||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -1609,6 +1865,7 @@
|
|||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -1661,6 +1918,20 @@
|
|||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
2B572382D4504B8FB4B9D251 /* Embed Frameworks */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
8EA186B6112C41D1B206762D /* NodeMobile.framework in Embed Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
name = "Embed Frameworks";
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 10;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
};
|
};
|
||||||
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -13,8 +13,8 @@ export default function config(opts) {
|
|||||||
if (!opts) {
|
if (!opts) {
|
||||||
// we only want to require (and run) the db module
|
// we only want to require (and run) the db module
|
||||||
// when not running the tests
|
// when not running the tests
|
||||||
bleedingDaysSortedByDate = require('../db').bleedingDaysSortedByDate
|
bleedingDaysSortedByDate = require('../db').getBleedingDaysSortedByDate()
|
||||||
cycleDaysSortedByDate = require('../db').cycleDaysSortedByDate
|
cycleDaysSortedByDate = require('../db').getCycleDaysSortedByDate()
|
||||||
maxBreakInBleeding = 1
|
maxBreakInBleeding = 1
|
||||||
maxCycleLength = 99
|
maxCycleLength = 99
|
||||||
minCyclesForPrediction = 3
|
minCyclesForPrediction = 3
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import objectPath from 'object-path'
|
import objectPath from 'object-path'
|
||||||
import { Base64 } from 'js-base64'
|
import { Base64 } from 'js-base64'
|
||||||
import { cycleDaysSortedByDate } from '../../db'
|
import { getCycleDaysSortedByDate } from '../../db'
|
||||||
import getColumnNamesForCsv from './get-csv-column-names'
|
import getColumnNamesForCsv from './get-csv-column-names'
|
||||||
|
|
||||||
export default function makeDataURI() {
|
export default function makeDataURI() {
|
||||||
|
const cycleDaysSortedByDate = getCycleDaysSortedByDate()
|
||||||
if (!cycleDaysSortedByDate.length) return null
|
if (!cycleDaysSortedByDate.length) return null
|
||||||
|
|
||||||
const csv = transformToCsv(cycleDaysSortedByDate)
|
const csv = transformToCsv(cycleDaysSortedByDate)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { schema } from '../../db'
|
import { getSchema } from '../../db'
|
||||||
|
|
||||||
export default function getColumnNamesForCsv() {
|
export default function getColumnNamesForCsv() {
|
||||||
return getPrefixedKeys('CycleDay')
|
return getPrefixedKeys('CycleDay')
|
||||||
|
|
||||||
function getPrefixedKeys(schemaName, prefix) {
|
function getPrefixedKeys(schemaName, prefix) {
|
||||||
|
const schema = getSchema()
|
||||||
const model = schema[schemaName]
|
const model = schema[schemaName]
|
||||||
return Object.keys(model).reduce((acc, key) => {
|
return Object.keys(model).reduce((acc, key) => {
|
||||||
const prefixedKey = prefix ? [prefix, key].join('.') : key
|
const prefixedKey = prefix ? [prefix, key].join('.') : key
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import csvParser from 'csvtojson'
|
import csvParser from 'csvtojson'
|
||||||
import isObject from 'isobject'
|
import isObject from 'isobject'
|
||||||
import { schema, tryToImportWithDelete, tryToImportWithoutDelete } from '../../db'
|
import { getSchema, tryToImportWithDelete, tryToImportWithoutDelete } from '../../db'
|
||||||
import getColumnNamesForCsv from './get-csv-column-names'
|
import getColumnNamesForCsv from './get-csv-column-names'
|
||||||
|
|
||||||
export default async function importCsv(csv, deleteFirst) {
|
export default async function importCsv(csv, deleteFirst) {
|
||||||
@@ -23,6 +23,7 @@ export default async function importCsv(csv, deleteFirst) {
|
|||||||
return Number(val)
|
return Number(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const schema = getSchema()
|
||||||
const config = {
|
const config = {
|
||||||
ignoreEmpty: true,
|
ignoreEmpty: true,
|
||||||
colParser: getColumnNamesForCsv().reduce((acc, colName) => {
|
colParser: getColumnNamesForCsv().reduce((acc, colName) => {
|
||||||
@@ -76,6 +77,7 @@ function putNullForEmptySymptoms(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDbType(modelProperties, path) {
|
function getDbType(modelProperties, path) {
|
||||||
|
const schema = getSchema()
|
||||||
if (path.length === 1) return modelProperties[path[0]].type
|
if (path.length === 1) return modelProperties[path[0]].type
|
||||||
const modelName = modelProperties[path[0]].objectType
|
const modelName = modelProperties[path[0]].objectType
|
||||||
return getDbType(schema[modelName], path.slice(1))
|
return getDbType(schema[modelName], path.slice(1))
|
||||||
|
|||||||
@@ -2,12 +2,6 @@ import getFertilityStatus from './sympto'
|
|||||||
import cycleModule from './cycle'
|
import cycleModule from './cycle'
|
||||||
import { fertilityStatus } from '../components/cycle-day/labels/labels'
|
import { fertilityStatus } from '../components/cycle-day/labels/labels'
|
||||||
|
|
||||||
const {
|
|
||||||
getCycleForDay,
|
|
||||||
getCyclesBefore,
|
|
||||||
getPreviousCycle
|
|
||||||
} = cycleModule()
|
|
||||||
|
|
||||||
export function getFertilityStatusStringForDay(dateString) {
|
export function getFertilityStatusStringForDay(dateString) {
|
||||||
const status = getCycleStatusForDay(dateString)
|
const status = getCycleStatusForDay(dateString)
|
||||||
if (!status) return fertilityStatus.unknown
|
if (!status) return fertilityStatus.unknown
|
||||||
@@ -28,6 +22,12 @@ export function getFertilityStatusStringForDay(dateString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getCycleStatusForDay(dateString) {
|
export function getCycleStatusForDay(dateString) {
|
||||||
|
const {
|
||||||
|
getCycleForDay,
|
||||||
|
getCyclesBefore,
|
||||||
|
getPreviousCycle
|
||||||
|
} = cycleModule()
|
||||||
|
|
||||||
const cycle = getCycleForDay(dateString)
|
const cycle = getCycleForDay(dateString)
|
||||||
if (!cycle) return null
|
if (!cycle) return null
|
||||||
|
|
||||||
|
|||||||
+17
-10
@@ -19,12 +19,29 @@ scaleObservable((scale) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export async function saveTempScale(scale) {
|
||||||
|
await AsyncStorage.setItem('tempScale', JSON.stringify(scale))
|
||||||
|
scaleObservable.set(scale)
|
||||||
|
}
|
||||||
|
|
||||||
export const tempReminderObservable = Observable()
|
export const tempReminderObservable = Observable()
|
||||||
setObvWithInitValue('tempReminder', tempReminderObservable, {
|
setObvWithInitValue('tempReminder', tempReminderObservable, {
|
||||||
enabled: false
|
enabled: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export async function saveTempReminder(reminder) {
|
||||||
|
await AsyncStorage.setItem('tempReminder', JSON.stringify(reminder))
|
||||||
|
tempReminderObservable.set(reminder)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hasEncryptionObservable = Observable()
|
||||||
|
setObvWithInitValue('hasEncryption', hasEncryptionObservable, false)
|
||||||
|
|
||||||
|
export async function saveEncryptionFlag(bool) {
|
||||||
|
await AsyncStorage.setItem('hasEncryption', JSON.stringify(bool))
|
||||||
|
hasEncryptionObservable.set(bool)
|
||||||
|
}
|
||||||
|
|
||||||
async function setObvWithInitValue(key, obv, defaultValue) {
|
async function setObvWithInitValue(key, obv, defaultValue) {
|
||||||
const result = await AsyncStorage.getItem(key)
|
const result = await AsyncStorage.getItem(key)
|
||||||
let value
|
let value
|
||||||
@@ -35,13 +52,3 @@ async function setObvWithInitValue(key, obv, defaultValue) {
|
|||||||
}
|
}
|
||||||
obv.set(value)
|
obv.set(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveTempScale(scale) {
|
|
||||||
await AsyncStorage.setItem('tempScale', JSON.stringify(scale))
|
|
||||||
scaleObservable.set(scale)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function saveTempReminder(reminder) {
|
|
||||||
await AsyncStorage.setItem('tempReminder', JSON.stringify(reminder))
|
|
||||||
tempReminderObservable.set(reminder)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// too see stdout / stderr from this process, run
|
||||||
|
// adb logcat | grep "NODEJS-MOBILE"
|
||||||
|
const rnBridge = require('rn-bridge')
|
||||||
|
const crypto = require('crypto')
|
||||||
|
|
||||||
|
rnBridge.channel.on('request-SHA512', (msg) => {
|
||||||
|
msg = JSON.parse(msg)
|
||||||
|
const hash = crypto.createHash('sha512')
|
||||||
|
hash.update(msg.message)
|
||||||
|
const result = hash.digest('hex')
|
||||||
|
rnBridge.channel.post(msg.type, result)
|
||||||
|
})
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {},
|
||||||
|
"main": "main.js"
|
||||||
|
}
|
||||||
Generated
+144
-124
@@ -1088,11 +1088,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
},
|
|
||||||
"kind-of": {
|
"kind-of": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||||
@@ -1287,9 +1282,9 @@
|
|||||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||||
},
|
},
|
||||||
"atob": {
|
"atob": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||||
"integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio="
|
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
|
||||||
},
|
},
|
||||||
"aws-sign2": {
|
"aws-sign2": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
@@ -1992,9 +1987,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"babel-preset-fbjs": {
|
"babel-preset-fbjs": {
|
||||||
"version": "2.2.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-2.3.0.tgz",
|
||||||
"integrity": "sha512-jj0KFJDioYZMtPtZf77dQuU+Ad/1BtN0UnAYlHDa8J8f4tGXr3YrPoJImD5MdueaOPeN/jUdrCgu330EfXr0XQ==",
|
"integrity": "sha512-ZOpAI1/bN0Y3J1ZAK9gRsFkHy9gGgJoDRUjtUCla/129LC7uViq9nIK22YdHfey8szohYoZY3f9L2lGOv0Edqw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"babel-plugin-check-es2015-constants": "^6.8.0",
|
"babel-plugin-check-es2015-constants": "^6.8.0",
|
||||||
"babel-plugin-syntax-class-properties": "^6.8.0",
|
"babel-plugin-syntax-class-properties": "^6.8.0",
|
||||||
@@ -2205,11 +2200,6 @@
|
|||||||
"kind-of": "^6.0.2"
|
"kind-of": "^6.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
},
|
|
||||||
"kind-of": {
|
"kind-of": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||||
@@ -2252,9 +2242,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"big-integer": {
|
"big-integer": {
|
||||||
"version": "1.6.34",
|
"version": "1.6.36",
|
||||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.34.tgz",
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz",
|
||||||
"integrity": "sha512-+w6B0Uo0ZvTSzDkXjoBCTNK0oe+aVL+yPi7kwGZm8hd8+Nj1AFPoxoq1Bl/mEu/G/ivOkUc1LRqVR0XeWFUzuA=="
|
"integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg=="
|
||||||
},
|
},
|
||||||
"bl": {
|
"bl": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
@@ -2405,13 +2395,6 @@
|
|||||||
"to-object-path": "^0.3.0",
|
"to-object-path": "^0.3.0",
|
||||||
"union-value": "^1.0.0",
|
"union-value": "^1.0.0",
|
||||||
"unset-value": "^1.0.0"
|
"unset-value": "^1.0.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"caller-path": {
|
"caller-path": {
|
||||||
@@ -2484,6 +2467,11 @@
|
|||||||
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
|
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"chownr": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE="
|
||||||
|
},
|
||||||
"circular-json": {
|
"circular-json": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
|
||||||
@@ -2513,11 +2501,6 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"is-descriptor": "^0.1.0"
|
"is-descriptor": "^0.1.0"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2620,9 +2603,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "2.16.0",
|
"version": "2.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz",
|
||||||
"integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew=="
|
"integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ=="
|
||||||
},
|
},
|
||||||
"commondir": {
|
"commondir": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@@ -2696,9 +2679,12 @@
|
|||||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
||||||
},
|
},
|
||||||
"convert-source-map": {
|
"convert-source-map": {
|
||||||
"version": "1.5.1",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
|
||||||
"integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU="
|
"integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.1.1"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"copy-descriptor": {
|
"copy-descriptor": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
@@ -2964,11 +2950,6 @@
|
|||||||
"kind-of": "^6.0.2"
|
"kind-of": "^6.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
},
|
|
||||||
"kind-of": {
|
"kind-of": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||||
@@ -3736,13 +3717,11 @@
|
|||||||
},
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@@ -3755,18 +3734,15 @@
|
|||||||
},
|
},
|
||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@@ -3869,8 +3845,7 @@
|
|||||||
},
|
},
|
||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@@ -3880,7 +3855,6 @@
|
|||||||
"is-fullwidth-code-point": {
|
"is-fullwidth-code-point": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -3893,20 +3867,17 @@
|
|||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.1.1",
|
"safe-buffer": "^5.1.1",
|
||||||
"yallist": "^3.0.0"
|
"yallist": "^3.0.0"
|
||||||
@@ -3923,7 +3894,6 @@
|
|||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
}
|
}
|
||||||
@@ -3996,8 +3966,7 @@
|
|||||||
},
|
},
|
||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@@ -4007,7 +3976,6 @@
|
|||||||
"once": {
|
"once": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
@@ -4113,7 +4081,6 @@
|
|||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
@@ -4394,13 +4361,6 @@
|
|||||||
"get-value": "^2.0.6",
|
"get-value": "^2.0.6",
|
||||||
"has-values": "^1.0.0",
|
"has-values": "^1.0.0",
|
||||||
"isobject": "^3.0.0"
|
"isobject": "^3.0.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"has-values": {
|
"has-values": {
|
||||||
@@ -4834,13 +4794,6 @@
|
|||||||
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
|
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"isobject": "^3.0.1"
|
"isobject": "^3.0.1"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"is-posix-bracket": {
|
"is-posix-bracket": {
|
||||||
@@ -5567,6 +5520,30 @@
|
|||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||||
},
|
},
|
||||||
|
"minipass": {
|
||||||
|
"version": "2.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.4.tgz",
|
||||||
|
"integrity": "sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "^5.1.2",
|
||||||
|
"yallist": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
|
||||||
|
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minizlib": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
|
||||||
|
"requires": {
|
||||||
|
"minipass": "^2.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"mixin-deep": {
|
"mixin-deep": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
|
||||||
@@ -5674,9 +5651,9 @@
|
|||||||
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
|
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
|
||||||
},
|
},
|
||||||
"nan": {
|
"nan": {
|
||||||
"version": "2.10.0",
|
"version": "2.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.11.0.tgz",
|
||||||
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
|
"integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"nanomatch": {
|
"nanomatch": {
|
||||||
@@ -5737,6 +5714,11 @@
|
|||||||
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ncp": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M="
|
||||||
|
},
|
||||||
"negotiator": {
|
"negotiator": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
|
||||||
@@ -5865,6 +5847,68 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nodejs-mobile-gyp": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nodejs-mobile-gyp/-/nodejs-mobile-gyp-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-zdeI4UhZUaDbwfOSS7ZgtKzagNb7nUiqV/Es67LKixiSIMSE1+9fwoVu9TVpCPFgizsoxRSxaxtSmZlL0yRmYA==",
|
||||||
|
"requires": {
|
||||||
|
"glob": "^7.0.3",
|
||||||
|
"graceful-fs": "^4.1.2",
|
||||||
|
"minimatch": "^3.0.2",
|
||||||
|
"mkdirp": "^0.5.0",
|
||||||
|
"nopt": "2 || 3",
|
||||||
|
"npmlog": "0 || 1 || 2 || 3 || 4",
|
||||||
|
"osenv": "0",
|
||||||
|
"request": "2",
|
||||||
|
"rimraf": "2",
|
||||||
|
"semver": "~5.3.0",
|
||||||
|
"tar": "^3.1.3",
|
||||||
|
"which": "1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"nopt": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
|
||||||
|
"integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
|
||||||
|
"requires": {
|
||||||
|
"abbrev": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
||||||
|
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8="
|
||||||
|
},
|
||||||
|
"tar": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar/-/tar-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-ZSzds1E0IqutvMU8HxjMaU8eB7urw2fGwTq88ukDOVuUIh0656l7/P7LiVPxhO5kS4flcRJQk8USG+cghQbTUQ==",
|
||||||
|
"requires": {
|
||||||
|
"chownr": "^1.0.1",
|
||||||
|
"minipass": "^2.0.2",
|
||||||
|
"minizlib": "^1.0.3",
|
||||||
|
"mkdirp": "^0.5.0",
|
||||||
|
"yallist": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
|
||||||
|
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nodejs-mobile-react-native": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nodejs-mobile-react-native/-/nodejs-mobile-react-native-0.3.0.tgz",
|
||||||
|
"integrity": "sha512-cY0tF27Mf3VbIGA8xz/c6j7WlP1b8sapYfb+SZUbjYxztYH1YFGdjymAQ/s4vtvK0rXf2h1WXMRjRw6nu4jjKA==",
|
||||||
|
"requires": {
|
||||||
|
"mkdirp": "^0.5.1",
|
||||||
|
"ncp": "^2.0.0",
|
||||||
|
"nodejs-mobile-gyp": "^0.2.0",
|
||||||
|
"xcode": "^0.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nopt": {
|
"nopt": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
|
||||||
@@ -5971,13 +6015,6 @@
|
|||||||
"integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
|
"integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"isobject": "^3.0.0"
|
"isobject": "^3.0.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"object.omit": {
|
"object.omit": {
|
||||||
@@ -5995,13 +6032,6 @@
|
|||||||
"integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
|
"integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"isobject": "^3.0.1"
|
"isobject": "^3.0.1"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"obv": {
|
"obv": {
|
||||||
@@ -6192,9 +6222,9 @@
|
|||||||
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
|
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
|
||||||
},
|
},
|
||||||
"path-parse": {
|
"path-parse": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
||||||
"integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
|
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
|
||||||
},
|
},
|
||||||
"path-type": {
|
"path-type": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -6373,9 +6403,9 @@
|
|||||||
"integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw=="
|
"integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw=="
|
||||||
},
|
},
|
||||||
"randomatic": {
|
"randomatic": {
|
||||||
"version": "3.0.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz",
|
||||||
"integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==",
|
"integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-number": "^4.0.0",
|
"is-number": "^4.0.0",
|
||||||
"kind-of": "^6.0.0",
|
"kind-of": "^6.0.0",
|
||||||
@@ -6427,14 +6457,14 @@
|
|||||||
"integrity": "sha1-K7qMaUBMXkqUQ5hgC8xMlB+GBoI="
|
"integrity": "sha1-K7qMaUBMXkqUQ5hgC8xMlB+GBoI="
|
||||||
},
|
},
|
||||||
"react-deep-force-update": {
|
"react-deep-force-update": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-deep-force-update/-/react-deep-force-update-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-deep-force-update/-/react-deep-force-update-1.1.2.tgz",
|
||||||
"integrity": "sha1-vNMUeAJ7ZLMznxCJIatSC0MT3Cw="
|
"integrity": "sha512-WUSQJ4P/wWcusaH+zZmbECOk7H5N2pOIl0vzheeornkIMhu+qrNdGFm0bDZLCb0hSF0jf/kH1SgkNGfBdTc4wA=="
|
||||||
},
|
},
|
||||||
"react-devtools-core": {
|
"react-devtools-core": {
|
||||||
"version": "3.2.3",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-3.3.3.tgz",
|
||||||
"integrity": "sha1-o34ZnZSGXiy7YWuXvo9YIGdOar0=",
|
"integrity": "sha512-RftDnDpmIjNz39JQA04EmUD6wxpDW1J+zKSh25g/JOdtoe9BeoreIXbeQJcdnHBPZ4x3Dpy64nrXYzHnpO684A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"shell-quote": "^1.6.1",
|
"shell-quote": "^1.6.1",
|
||||||
"ws": "^3.3.1"
|
"ws": "^3.3.1"
|
||||||
@@ -6610,6 +6640,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-push-notification/-/react-native-push-notification-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-push-notification/-/react-native-push-notification-3.1.1.tgz",
|
||||||
"integrity": "sha512-4+4yQXNPqh5IVvpSBmR4Cy/UeMjTcfE8KIJgEuT7pME97WK+aGPn6W3ybhOoXC1n+ZWKfrAlsHydLE4xfBZDJg=="
|
"integrity": "sha512-4+4yQXNPqh5IVvpSBmR4Cy/UeMjTcfE8KIJgEuT7pME97WK+aGPn6W3ybhOoXC1n+ZWKfrAlsHydLE4xfBZDJg=="
|
||||||
},
|
},
|
||||||
|
"react-native-restart": {
|
||||||
|
"version": "0.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-restart/-/react-native-restart-0.0.7.tgz",
|
||||||
|
"integrity": "sha512-/7TdL3pHM7H0Cut6U6SK1jd6fVYvLlQq0O4inJ7j4YD0w9BtAAFqLkLnBDOA0jL4oLw/89yR8HhLOzNFGvVsfw=="
|
||||||
|
},
|
||||||
"react-native-share": {
|
"react-native-share": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-1.1.0.tgz",
|
||||||
@@ -6863,9 +6898,9 @@
|
|||||||
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
|
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
|
||||||
},
|
},
|
||||||
"repeat-element": {
|
"repeat-element": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
|
||||||
"integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo="
|
"integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g=="
|
||||||
},
|
},
|
||||||
"repeat-string": {
|
"repeat-string": {
|
||||||
"version": "1.6.1",
|
"version": "1.6.1",
|
||||||
@@ -7337,11 +7372,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
},
|
|
||||||
"kind-of": {
|
"kind-of": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||||
@@ -7643,11 +7673,6 @@
|
|||||||
"kind-of": "^6.0.2"
|
"kind-of": "^6.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
},
|
|
||||||
"kind-of": {
|
"kind-of": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||||
@@ -8397,11 +8422,6 @@
|
|||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
|
||||||
"integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
|
"integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
|
||||||
},
|
|
||||||
"isobject": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"js-base64": "^2.4.8",
|
"js-base64": "^2.4.8",
|
||||||
"js-joda": "^1.8.2",
|
"js-joda": "^1.8.2",
|
||||||
"moment": "^2.22.2",
|
"moment": "^2.22.2",
|
||||||
|
"nodejs-mobile-react-native": "^0.3.0",
|
||||||
"object-path": "^0.11.4",
|
"object-path": "^0.11.4",
|
||||||
"obv": "0.0.1",
|
"obv": "0.0.1",
|
||||||
"react": "16.4.1",
|
"react": "16.4.1",
|
||||||
@@ -32,6 +33,7 @@
|
|||||||
"react-native-fs": "^2.10.14",
|
"react-native-fs": "^2.10.14",
|
||||||
"react-native-modal-datetime-picker-nevo": "^4.11.0",
|
"react-native-modal-datetime-picker-nevo": "^4.11.0",
|
||||||
"react-native-push-notification": "^3.1.1",
|
"react-native-push-notification": "^3.1.1",
|
||||||
|
"react-native-restart": "0.0.7",
|
||||||
"react-native-share": "^1.1.0",
|
"react-native-share": "^1.1.0",
|
||||||
"react-native-vector-icons": "^5.0.0",
|
"react-native-vector-icons": "^5.0.0",
|
||||||
"realm": "^2.7.1"
|
"realm": "^2.7.1"
|
||||||
|
|||||||
+38
-2
@@ -170,7 +170,7 @@ export default StyleSheet.create({
|
|||||||
backgroundColor: secondaryColor,
|
backgroundColor: secondaryColor,
|
||||||
padding: 10,
|
padding: 10,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
margin: 10
|
margin: 10,
|
||||||
},
|
},
|
||||||
settingsButtonText: {
|
settingsButtonText: {
|
||||||
color: fontOnPrimaryColor
|
color: fontOnPrimaryColor
|
||||||
@@ -249,6 +249,42 @@ export default StyleSheet.create({
|
|||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: secondaryColor,
|
color: secondaryColor,
|
||||||
marginTop: 1
|
marginTop: 1
|
||||||
|
},
|
||||||
|
passwordField: {
|
||||||
|
padding: 10,
|
||||||
|
marginTop: 10,
|
||||||
|
marginHorizontal: 10,
|
||||||
|
backgroundColor: 'white'
|
||||||
|
},
|
||||||
|
passwordPromptPage: {
|
||||||
|
padding: 30,
|
||||||
|
alignItems: 'center'
|
||||||
|
},
|
||||||
|
passwordPromptField: {
|
||||||
|
padding: 10,
|
||||||
|
marginTop: 10,
|
||||||
|
marginHorizontal: 10,
|
||||||
|
borderBottomWidth: 3,
|
||||||
|
borderBottomColor: primaryColor,
|
||||||
|
width: '100%',
|
||||||
|
fontSize: 20,
|
||||||
|
marginVertical: 20
|
||||||
|
},
|
||||||
|
passwordPromptButton: {
|
||||||
|
backgroundColor: secondaryColor,
|
||||||
|
padding: 10,
|
||||||
|
alignItems: 'center',
|
||||||
|
margin: 10,
|
||||||
|
width: '100%',
|
||||||
|
borderRadius: 10
|
||||||
|
},
|
||||||
|
passwordPromptButtonText: {
|
||||||
|
color: fontOnPrimaryColor,
|
||||||
|
fontSize: 20
|
||||||
|
},
|
||||||
|
passwordPromptForgotPasswordText: {
|
||||||
|
marginTop: 20,
|
||||||
|
color: 'grey'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -268,6 +304,6 @@ export const iconStyles = {
|
|||||||
color: fontOnPrimaryColor
|
color: fontOnPrimaryColor
|
||||||
},
|
},
|
||||||
menuIconInactive: {
|
menuIconInactive: {
|
||||||
color: 'lightgrey'
|
color: 'lightgrey',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user