merge master
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
|
||||
[android]
|
||||
target = Google Inc.:Google APIs:23
|
||||
|
||||
[maven_repositories]
|
||||
central = https://repo1.maven.org/maven2
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
[ignore]
|
||||
; We fork some components by platform
|
||||
.*/*[.]android.js
|
||||
|
||||
; Ignore "BUCK" generated dirs
|
||||
<PROJECT_ROOT>/\.buckd/
|
||||
|
||||
; Ignore unexpected extra "@providesModule"
|
||||
.*/node_modules/.*/node_modules/fbjs/.*
|
||||
|
||||
; Ignore duplicate module providers
|
||||
; For RN Apps installed via npm, "Libraries" folder is inside
|
||||
; "node_modules/react-native" but in the source repo it is in the root
|
||||
.*/Libraries/react-native/React.js
|
||||
|
||||
; Ignore polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
; Ignore metro
|
||||
.*/node_modules/metro/.*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
node_modules/react-native/Libraries/react-native/react-native-interface.js
|
||||
node_modules/react-native/flow/
|
||||
node_modules/react-native/flow-github/
|
||||
|
||||
[options]
|
||||
emoji=true
|
||||
|
||||
module.system=haste
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
|
||||
module.file_ext=.js
|
||||
module.file_ext=.jsx
|
||||
module.file_ext=.json
|
||||
module.file_ext=.native.js
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
[version]
|
||||
^0.67.0
|
||||
@@ -53,8 +53,7 @@ Unfortunately, the react native version we use doesn't work on Windows 10 it see
|
||||
You can run the tests with `npm test`.
|
||||
|
||||
## Debugging
|
||||
When running into an old version of the app try to run the following command first:
|
||||
`react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res`
|
||||
In order to see logging output from the app, run `npm run log` in a separate terminal.
|
||||
|
||||
## NFP rules
|
||||
More information about how the app calculates fertility status and bleeding predictions in the [wiki on Gitlab](https://gitlab.com/bloodyhealth/drip/wikis/home)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.drip">
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.drip"
|
||||
>
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
@@ -36,9 +39,11 @@
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
tools:replace="android:resource"
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/filepaths" />
|
||||
</provider>
|
||||
|
||||
<meta-data android:name="com.dieam.reactnativepushnotification.notification_channel_name"
|
||||
android:value="drip-notification"/>
|
||||
<meta-data android:name="com.dieam.reactnativepushnotification.notification_channel_description"
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<external-path name="Downloads" path="Download/" />
|
||||
<root-path name="root" path="" />
|
||||
<files-path
|
||||
name="files-path"
|
||||
path="." /> <!-- Used to access into application data files -->
|
||||
</paths>
|
||||
@@ -35,3 +35,11 @@ ext {
|
||||
targetSdkVersion = 26
|
||||
supportLibVersion = "26.1.0"
|
||||
}
|
||||
|
||||
subprojects {project ->
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url = 'https://dl.bintray.com/android/android-tools/' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-25
@@ -1,33 +1,30 @@
|
||||
import React, { Component } from 'react'
|
||||
import React from 'react'
|
||||
import { Text } from 'react-native'
|
||||
import styles from "../styles"
|
||||
|
||||
export default class AppText extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Text style={[styles.appText, this.props.style]}>
|
||||
{this.props.children}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
export default function AppText(props) {
|
||||
return (
|
||||
<Text
|
||||
style={[styles.appText, props.style]}
|
||||
onPress={props.onPress}
|
||||
>
|
||||
{props.children}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
export class AppTextLight extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Text style={[styles.appTextLight, this.props.style]}>
|
||||
{this.props.children}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
export function AppTextLight(props) {
|
||||
return (
|
||||
<Text style={[styles.appTextLight, props.style]}>
|
||||
{props.children}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
export class SymptomSectionHeader extends Component {
|
||||
render() {
|
||||
return (
|
||||
<AppText style={styles.symptomViewHeading}>
|
||||
{this.props.children}
|
||||
</AppText>
|
||||
)
|
||||
}
|
||||
export function SymptomSectionHeader(props) {
|
||||
return (
|
||||
<AppText style={styles.symptomViewHeading}>
|
||||
{props.children}
|
||||
</AppText>
|
||||
)
|
||||
}
|
||||
+7
-2
@@ -7,7 +7,8 @@ import Calendar from './calendar'
|
||||
import CycleDay from './cycle-day/cycle-day-overview'
|
||||
import symptomViews from './cycle-day/symptoms'
|
||||
import Chart from './chart/chart'
|
||||
import Settings from './settings'
|
||||
import SettingsMenu from './settings/settings-menu'
|
||||
import settingsViews from './settings'
|
||||
import Stats from './stats'
|
||||
import {headerTitles, menuTitles} from '../i18n/en/labels'
|
||||
import setupNotifications from '../lib/notifications'
|
||||
@@ -24,6 +25,7 @@ const menuTitlesLowerCase = Object.keys(menuTitles).reduce((acc, curr) => {
|
||||
}, {})
|
||||
|
||||
const isSymptomView = name => Object.keys(symptomViews).includes(name)
|
||||
const isSettingsView = name => Object.keys(settingsViews).includes(name)
|
||||
const isMenuItem = name => Object.keys(menuTitles).includes(name)
|
||||
|
||||
export default class App extends Component {
|
||||
@@ -58,6 +60,8 @@ export default class App extends Component {
|
||||
this.navigate(
|
||||
this.originForSymptomView, { date: this.state.currentProps.date }
|
||||
)
|
||||
} else if (isSettingsView(this.state.currentPage)) {
|
||||
this.navigate('SettingsMenu')
|
||||
} else if(this.state.currentPage === 'CycleDay') {
|
||||
this.navigate(this.menuOrigin)
|
||||
} else {
|
||||
@@ -68,7 +72,7 @@ export default class App extends Component {
|
||||
|
||||
render() {
|
||||
const page = {
|
||||
Home, Calendar, CycleDay, Chart, Settings, Stats, ...symptomViews
|
||||
Home, Calendar, CycleDay, Chart, SettingsMenu, ...settingsViews, Stats, ...symptomViews
|
||||
}[this.state.currentPage]
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
@@ -81,6 +85,7 @@ export default class App extends Component {
|
||||
title={headerTitlesLowerCase[this.state.currentPage]}
|
||||
isSymptomView={true}
|
||||
goBack={this.handleBackButtonPress}
|
||||
date={this.state.currentProps.date}
|
||||
/>}
|
||||
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ export default class CycleChart extends Component {
|
||||
this.chartSymptoms.push('temperature')
|
||||
}
|
||||
|
||||
const columnData = this.makeColumnInfo(nfpLines(), this.chartSymptoms)
|
||||
const columnData = this.makeColumnInfo()
|
||||
this.setState({
|
||||
columns: columnData,
|
||||
chartHeight: height
|
||||
|
||||
@@ -52,7 +52,7 @@ export default class DayColumn extends Component {
|
||||
|
||||
this.fhmAndLtl = props.getFhmAndLtlInfo(
|
||||
props.dateString,
|
||||
props.temp,
|
||||
this.data.temperature,
|
||||
props.columnHeight
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import React, { Component } from 'react'
|
||||
import {
|
||||
View, TouchableOpacity, Text, Alert
|
||||
View, TouchableOpacity, Text, Alert, ToastAndroid
|
||||
} from 'react-native'
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||
import { saveSymptom } from '../../../db'
|
||||
import styles, {iconStyles} from '../../../styles'
|
||||
import {sharedDialogs as labels} from '../../../i18n/en/cycle-day'
|
||||
|
||||
|
||||
export default class ActionButtonFooter extends Component {
|
||||
render() {
|
||||
const {
|
||||
@@ -43,19 +44,26 @@ export default class ActionButtonFooter extends Component {
|
||||
}, {
|
||||
title: labels.save,
|
||||
action: () => {
|
||||
saveAction()
|
||||
if (autoShowDayView) navigateToOverView()
|
||||
if(saveDisabled) {
|
||||
ToastAndroid.show(labels.disabledInfo, ToastAndroid.LONG);
|
||||
console.log()
|
||||
} else {
|
||||
saveAction()
|
||||
if (autoShowDayView) navigateToOverView()
|
||||
}
|
||||
|
||||
},
|
||||
disabledCondition: saveDisabled,
|
||||
icon: 'content-save-outline'
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<View style={styles.menu}>
|
||||
{buttons.map(({ title, action, disabledCondition, icon }, i) => {
|
||||
const textStyle = [styles.menuText]
|
||||
if (disabledCondition) textStyle.push(styles.menuTextInActive)
|
||||
if (disabledCondition) {
|
||||
textStyle.push(styles.menuTextInActive);
|
||||
}
|
||||
const iconStyle = disabledCondition ?
|
||||
Object.assign(
|
||||
{},
|
||||
@@ -68,7 +76,6 @@ export default class ActionButtonFooter extends Component {
|
||||
<TouchableOpacity
|
||||
onPress={action}
|
||||
style={styles.menuItem}
|
||||
disabled={disabledCondition}
|
||||
key={i.toString()}
|
||||
>
|
||||
<Icon name={icon} {...iconStyle} />
|
||||
@@ -76,9 +83,10 @@ export default class ActionButtonFooter extends Component {
|
||||
{title.toLowerCase()}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import styles from '../../../styles'
|
||||
import { saveSymptom } from '../../../db'
|
||||
import { mucus as labels } from '../../../i18n/en/cycle-day'
|
||||
import computeSensiplanValue from '../../../lib/sensiplan-mucus'
|
||||
import computeNfpValue from '../../../lib/nfp-mucus'
|
||||
import ActionButtonFooter from './action-button-footer'
|
||||
import SelectTabGroup from '../select-tab-group'
|
||||
import SymptomSection from './symptom-section'
|
||||
@@ -80,7 +80,7 @@ export default class Mucus extends Component {
|
||||
saveSymptom('mucus', this.props.date, {
|
||||
feeling,
|
||||
texture,
|
||||
value: computeSensiplanValue(feeling, texture),
|
||||
value: computeNfpValue(feeling, texture),
|
||||
exclude: Boolean(this.state.exclude)
|
||||
})
|
||||
}}
|
||||
|
||||
@@ -2,17 +2,9 @@ import React from 'react'
|
||||
import {
|
||||
View,
|
||||
Text} from 'react-native'
|
||||
import { LocalDate } from 'js-joda'
|
||||
import moment from 'moment'
|
||||
import styles from '../../styles'
|
||||
import NavigationArrow from './navigation-arrow'
|
||||
|
||||
const FormattedDate = ({ date }) => {
|
||||
const today = LocalDate.now()
|
||||
const dateToDisplay = LocalDate.parse(date)
|
||||
const formattedDate = today.equals(dateToDisplay) ? 'today' : moment(date).format('MMMM Do YYYY')
|
||||
return formattedDate.toLowerCase()
|
||||
}
|
||||
import formatDate from '../helpers/format-date'
|
||||
|
||||
export default function CycleDayHeader({ date, ...props }) {
|
||||
return (<View style={[styles.header, styles.headerCycleDay]}>
|
||||
@@ -23,7 +15,7 @@ export default function CycleDayHeader({ date, ...props }) {
|
||||
<NavigationArrow direction='left' {...props}/>
|
||||
<View>
|
||||
<Text style={styles.dateHeader}>
|
||||
<FormattedDate date={date} />
|
||||
{formatDate(date)}
|
||||
</Text>
|
||||
{props.cycleDayNumber &&
|
||||
<Text style={styles.cycleDayNumber}>
|
||||
@@ -33,4 +25,4 @@ export default function CycleDayHeader({ date, ...props }) {
|
||||
<NavigationArrow direction='right' {...props}/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
import styles, { iconStyles } from '../../styles'
|
||||
import FeatherIcon from 'react-native-vector-icons/Feather'
|
||||
import NavigationArrow from './navigation-arrow'
|
||||
import formatDate from '../helpers/format-date'
|
||||
|
||||
export default function SymptomViewHeader(props) {
|
||||
return (
|
||||
@@ -21,6 +22,9 @@ export default function SymptomViewHeader(props) {
|
||||
<Text style={styles.dateHeader}>
|
||||
{props.title}
|
||||
</Text>
|
||||
<Text style={styles.cycleDayNumber}>
|
||||
{formatDate(props.date)}
|
||||
</Text>
|
||||
</View >
|
||||
<FeatherIcon
|
||||
name='info'
|
||||
@@ -29,4 +33,4 @@ export default function SymptomViewHeader(props) {
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { LocalDate } from 'js-joda'
|
||||
import moment from 'moment'
|
||||
|
||||
export default function (date) {
|
||||
const today = LocalDate.now()
|
||||
const dateToDisplay = LocalDate.parse(date)
|
||||
const formattedDate = today.equals(dateToDisplay) ? 'today' : moment(date).format('MMMM Do YYYY')
|
||||
return formattedDate.toLowerCase()
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import { getCycleDaysSortedByDate } from '../db'
|
||||
import { getFertilityStatusForDay } from '../lib/sympto-adapter'
|
||||
import styles from '../styles'
|
||||
import AppText, { AppTextLight } from './app-text'
|
||||
import nothingChanged from '../db/db-unchanged'
|
||||
import DripHomeIcon from '../assets/drip-home-icons'
|
||||
|
||||
const HomeButton = ({ backgroundColor, children }) => {
|
||||
@@ -42,23 +41,6 @@ export default class Home extends Component {
|
||||
}
|
||||
|
||||
this.cycleDays = getCycleDaysSortedByDate()
|
||||
this.cycleDays.addListener(this.updateState)
|
||||
}
|
||||
|
||||
updateState = (_, changes) => {
|
||||
if (nothingChanged(changes)) return
|
||||
const prediction = this.getBleedingPrediction()
|
||||
const fertilityStatus = getFertilityStatusForDay(this.todayDateString)
|
||||
this.setState({
|
||||
cycleDayNumber: this.getCycleDayNumber(this.todayDateString),
|
||||
predictionText: determinePredictionText(prediction),
|
||||
bleedingPredictionRange: getBleedingPredictionRange(prediction),
|
||||
...fertilityStatus
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.cycleDays.removeListener(this.updateState)
|
||||
}
|
||||
|
||||
passTodayTo(componentName) {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from 'react'
|
||||
import { Linking } from 'react-native'
|
||||
import AppText from "./app-text"
|
||||
import styles from '../styles';
|
||||
|
||||
export default function Link(props) {
|
||||
return (
|
||||
<AppText
|
||||
style={styles.link}
|
||||
onPress={() => Linking.openURL(props.href)}
|
||||
>{props.text}</AppText>
|
||||
)
|
||||
}
|
||||
+1
-1
@@ -38,7 +38,7 @@ export default class Menu extends Component {
|
||||
{ title: t.Calendar, icon: 'calendar-range', onPress: () => this.goTo('Calendar') },
|
||||
{ title: t.Chart, icon: 'chart-line', onPress: () => this.goTo('Chart') },
|
||||
{ title: t.Stats, icon: 'chart-pie', onPress: () => this.goTo('Stats') },
|
||||
{ title: t.Settings, icon: 'settings', onPress: () => this.goTo('Settings') },
|
||||
{ title: t.Settings, icon: 'settings', onPress: () => this.goTo('SettingsMenu') },
|
||||
].map(this.makeMenuItem)}
|
||||
</View >
|
||||
)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import React, { Component } from 'react'
|
||||
import { View, ScrollView } from 'react-native'
|
||||
import AppText from '../app-text'
|
||||
import styles from '../../styles/index'
|
||||
import labels from '../../i18n/en/settings'
|
||||
export default class AboutSection extends Component {
|
||||
render() {
|
||||
return (
|
||||
<ScrollView>
|
||||
<View style={styles.settingsSegment}>
|
||||
<AppText style={styles.settingsSegmentTitle}>{`${labels.aboutSection.title} `}</AppText>
|
||||
<AppText>{`${labels.aboutSection.segmentExplainer} `}</AppText>
|
||||
</View>
|
||||
<View style={[styles.settingsSegment, styles.settingsSegmentLast]}>
|
||||
<AppText style={styles.settingsSegmentTitle}>{`${labels.credits.title} `}</AppText>
|
||||
<AppText>{`${labels.credits.note}`}</AppText>
|
||||
</View>
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
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 '../../i18n/en/settings'
|
||||
|
||||
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,43 @@
|
||||
import Share from 'react-native-share'
|
||||
|
||||
import { getCycleDaysSortedByDate } from '../../../db'
|
||||
import getDataAsCsvDataUri from '../../../lib/import-export/export-to-csv'
|
||||
import alertError from '../alert-error'
|
||||
import settings from '../../../i18n/en/settings'
|
||||
import RNFS from 'react-native-fs'
|
||||
|
||||
export default async function exportData() {
|
||||
let data
|
||||
const labels = settings.export
|
||||
const cycleDaysByDate = getCycleDaysSortedByDate()
|
||||
|
||||
if (!cycleDaysByDate.length) return alertError(labels.errors.noData)
|
||||
|
||||
try {
|
||||
data = getDataAsCsvDataUri(cycleDaysByDate)
|
||||
if (!data) {
|
||||
return alertError(labels.errors.noData)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
return alertError(labels.errors.couldNotConvert)
|
||||
}
|
||||
|
||||
try {
|
||||
const path = RNFS.DocumentDirectoryPath + '/data.csv'
|
||||
await RNFS.writeFile(path, data)
|
||||
|
||||
await Share.open({
|
||||
title: labels.title,
|
||||
url: `file://${path}`,
|
||||
subject: labels.subject,
|
||||
type: 'text/csv',
|
||||
showAppsToView: true
|
||||
})
|
||||
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
return alertError(labels.errors.problemSharing)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
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 { shared as sharedLabels } from '../../i18n/en/labels'
|
||||
import { settings as labels } from '../../i18n/en/settings'
|
||||
import alertError from './alert-error'
|
||||
import importCsv from '../../../lib/import-export/import-from-csv'
|
||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
import alertError from '../alert-error'
|
||||
|
||||
export default function openImportDialogAndImport() {
|
||||
Alert.alert(
|
||||
@@ -0,0 +1,50 @@
|
||||
import React, { Component } from 'react'
|
||||
import {
|
||||
View, ScrollView,
|
||||
TouchableOpacity,
|
||||
} from 'react-native'
|
||||
import styles from '../../../styles/index'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
import AppText from '../../app-text'
|
||||
import openImportDialogAndImport from './import-dialog'
|
||||
import openShareDialogAndExport from './export-dialog'
|
||||
|
||||
export default class Settings extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollView>
|
||||
<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>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,67 +1,9 @@
|
||||
import React, { Component } from 'react'
|
||||
import {
|
||||
View,
|
||||
TouchableOpacity,
|
||||
ScrollView,
|
||||
} from 'react-native'
|
||||
import styles from '../../styles/index'
|
||||
import { settings as labels } from '../../i18n/en/settings'
|
||||
import AppText from '../app-text'
|
||||
import TempReminderPicker from './temp-reminder-picker'
|
||||
import PeriodReminderPicker from './period-reminder'
|
||||
import TempSlider from './temp-slider'
|
||||
import openImportDialogAndImport from './import-dialog'
|
||||
import openShareDialogAndExport from './export-dialog'
|
||||
import PasswordSetting from './password'
|
||||
import UseCervixSetting from './use-cervix'
|
||||
import Reminders from './reminders'
|
||||
import NfpSettings from './nfp-settings'
|
||||
import ImportExport from './import-export'
|
||||
import Password from './password'
|
||||
import About from './about'
|
||||
|
||||
export default class Settings extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollView>
|
||||
<TempReminderPicker/>
|
||||
<UseCervixSetting/>
|
||||
<View style={styles.settingsSegment}>
|
||||
<AppText style={styles.settingsSegmentTitle}>
|
||||
{labels.tempScale.segmentTitle}
|
||||
</AppText>
|
||||
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
||||
<TempSlider/>
|
||||
</View>
|
||||
<PeriodReminderPicker/>
|
||||
<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>
|
||||
)
|
||||
}
|
||||
export default {
|
||||
Reminders, NfpSettings, ImportExport, Password, About
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import React, { Component } from 'react'
|
||||
import {
|
||||
ScrollView, View
|
||||
} from 'react-native'
|
||||
import styles, { iconStyles } from '../../../styles'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
import AppText from '../../app-text'
|
||||
import TempSlider from './temp-slider'
|
||||
import UseCervixSetting from './use-cervix'
|
||||
import Icon from 'react-native-vector-icons/Entypo'
|
||||
import Link from '../../link'
|
||||
|
||||
export default class Settings extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollView>
|
||||
<UseCervixSetting/>
|
||||
<View style={styles.settingsSegment}>
|
||||
<AppText style={styles.settingsSegmentTitle}>
|
||||
{labels.tempScale.segmentTitle}
|
||||
</AppText>
|
||||
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
||||
<TempSlider/>
|
||||
</View>
|
||||
<View style={[styles.settingsSegment, styles.settingsSegmentLast]}>
|
||||
<View style={{flexDirection: 'row', alignItems: 'center'}}>
|
||||
<Icon name="info-with-circle" style={iconStyles.infoInHeading}/>
|
||||
<AppText style={styles.settingsSegmentTitle}>{`${labels.preOvu.title} `}</AppText>
|
||||
</View>
|
||||
<AppText>
|
||||
{labels.preOvu.note1}
|
||||
<Link text={labels.preOvu.link} href="https://gitlab.com/bloodyhealth/drip/wikis/home" />
|
||||
{labels.preOvu.note2}
|
||||
</AppText>
|
||||
</View>
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -1,15 +1,15 @@
|
||||
import React, { Component } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import Slider from '@ptomasroos/react-native-multi-slider'
|
||||
import AppText from '../app-text'
|
||||
import AppText from '../../app-text'
|
||||
import {
|
||||
scaleObservable,
|
||||
saveTempScale,
|
||||
} from '../../local-storage'
|
||||
import { secondaryColor } from '../../styles/index'
|
||||
import { settings as labels } from '../../i18n/en/settings'
|
||||
import config from '../../config'
|
||||
import alertError from './alert-error'
|
||||
} from '../../../local-storage'
|
||||
import { secondaryColor } from '../../../styles/index'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
import config from '../../../config'
|
||||
import alertError from '../alert-error'
|
||||
|
||||
export default class TempSlider extends Component {
|
||||
constructor(props) {
|
||||
@@ -4,13 +4,13 @@ import {
|
||||
TouchableOpacity,
|
||||
Switch
|
||||
} from 'react-native'
|
||||
import AppText from '../app-text'
|
||||
import AppText from '../../app-text'
|
||||
import {
|
||||
useCervixObservable,
|
||||
saveUseCervix
|
||||
} from '../../local-storage'
|
||||
import styles from '../../styles/index'
|
||||
import { settings as labels } from '../../i18n/en/settings'
|
||||
} from '../../../local-storage'
|
||||
import styles from '../../../styles/index'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
|
||||
export default class UseCervixSetting extends Component {
|
||||
constructor() {
|
||||
@@ -1,59 +1,15 @@
|
||||
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 } from '../../../i18n/en/settings'
|
||||
import { requestHash, changeEncryptionAndRestartApp } from '../../../db'
|
||||
import PasswordField from './password-field'
|
||||
import { View } from 'react-native'
|
||||
import settings from '../../../i18n/en/settings'
|
||||
import EnterNewPassword from './enter-new-password'
|
||||
import SettingsButton from './settings-button'
|
||||
import showBackUpReminder from './show-backup-reminder'
|
||||
|
||||
const SettingsButton = ({ children, ...props }) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.settingsButton,
|
||||
props.disabled ? styles.settingsButtonDisabled : null
|
||||
]}
|
||||
{ ...props }
|
||||
>
|
||||
<AppText style={styles.settingsButtonText}>
|
||||
{children}
|
||||
</AppText>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
export default class CreatePassword extends Component {
|
||||
constructor() {
|
||||
super()
|
||||
this.state = {
|
||||
isSettingPassword: false,
|
||||
password: '',
|
||||
passwordConfirmation: '',
|
||||
shouldShowErrorMessage: false,
|
||||
}
|
||||
nodejs.channel.addListener(
|
||||
'create-pw-hash',
|
||||
changeEncryptionAndRestartApp,
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
nodejs.channel.removeListener('create-pw-hash', changeEncryptionAndRestartApp)
|
||||
}
|
||||
|
||||
savePassword = () => {
|
||||
if (this.comparePasswords()) {
|
||||
requestHash('create-pw-hash', this.state.password)
|
||||
} else {
|
||||
this.setState({
|
||||
shouldShowErrorMessage: true
|
||||
})
|
||||
isSettingPassword: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,35 +22,12 @@ export default class CreatePassword extends Component {
|
||||
showBackUpReminder(this.toggleSettingPassword)
|
||||
}
|
||||
|
||||
comparePasswords = () => {
|
||||
return this.state.password === this.state.passwordConfirmation
|
||||
}
|
||||
|
||||
handlePasswordInput = (password) => {
|
||||
this.setState({ password })
|
||||
}
|
||||
|
||||
handleConfirmationInput = (passwordConfirmation) => {
|
||||
const { password } = this.state
|
||||
this.setState({
|
||||
passwordConfirmation,
|
||||
isPasswordsMatch: passwordConfirmation === password
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
isSettingPassword,
|
||||
password,
|
||||
passwordConfirmation,
|
||||
shouldShowErrorMessage,
|
||||
isSettingPassword
|
||||
} = this.state
|
||||
const labels = settings.passwordSettings
|
||||
|
||||
const isSaveButtonDisabled =
|
||||
!password.length ||
|
||||
!passwordConfirmation.length
|
||||
|
||||
if (!isSettingPassword) {
|
||||
return (
|
||||
<View>
|
||||
@@ -104,33 +37,7 @@ export default class CreatePassword extends Component {
|
||||
</View>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<View>
|
||||
<PasswordField
|
||||
placeholder={labels.enterNew}
|
||||
value={password}
|
||||
onChangeText={this.handlePasswordInput}
|
||||
/>
|
||||
<PasswordField
|
||||
autoFocus={false}
|
||||
placeholder={labels.confirmPassword}
|
||||
value={passwordConfirmation}
|
||||
onChangeText={this.handleConfirmationInput}
|
||||
/>
|
||||
{
|
||||
shouldShowErrorMessage &&
|
||||
<AppText style={styles.errorMessage}>
|
||||
{labels.passwordsDontMatch}
|
||||
</AppText>
|
||||
}
|
||||
<SettingsButton
|
||||
onPress={this.savePassword}
|
||||
disabled={isSaveButtonDisabled}
|
||||
>
|
||||
{labels.savePassword}
|
||||
</SettingsButton>
|
||||
</View>
|
||||
)
|
||||
return <EnterNewPassword />
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
import nodejs from 'nodejs-mobile-react-native'
|
||||
import AppText from '../../app-text'
|
||||
import styles from '../../../styles'
|
||||
import { settings as labels } from '../../../i18n/en/settings'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
import { requestHash, changeEncryptionAndRestartApp } from '../../../db'
|
||||
import PasswordField from './password-field'
|
||||
import showBackUpReminder from './show-backup-reminder'
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import React, { Component } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import nodejs from 'nodejs-mobile-react-native'
|
||||
|
||||
import { requestHash, changeEncryptionAndRestartApp } from '../../../db'
|
||||
import AppText from '../../app-text'
|
||||
import PasswordField from './password-field'
|
||||
import SettingsButton from './settings-button'
|
||||
|
||||
import styles from '../../../styles'
|
||||
import settings from '../../../i18n/en/settings'
|
||||
|
||||
const LISTENER_TYPE = 'create-or-change-pw'
|
||||
|
||||
export default class EnterNewPassword extends Component {
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.state = {
|
||||
password: '',
|
||||
passwordConfirmation: '',
|
||||
shouldShowErrorMessage: false,
|
||||
}
|
||||
nodejs.channel.addListener(
|
||||
LISTENER_TYPE,
|
||||
changeEncryptionAndRestartApp,
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
nodejs.channel.removeListener(LISTENER_TYPE, changeEncryptionAndRestartApp)
|
||||
}
|
||||
|
||||
savePassword = () => {
|
||||
if (this.comparePasswords()) {
|
||||
requestHash(LISTENER_TYPE, this.state.password)
|
||||
} else {
|
||||
this.setState({
|
||||
shouldShowErrorMessage: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
comparePasswords = () => {
|
||||
return this.state.password === this.state.passwordConfirmation
|
||||
}
|
||||
|
||||
handlePasswordInput = (password) => {
|
||||
this.setState({ password })
|
||||
}
|
||||
|
||||
handleConfirmationInput = (passwordConfirmation) => {
|
||||
this.setState({ passwordConfirmation })
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
password,
|
||||
passwordConfirmation,
|
||||
shouldShowErrorMessage,
|
||||
} = this.state
|
||||
const labels = settings.passwordSettings
|
||||
|
||||
const isSaveButtonDisabled =
|
||||
!password.length ||
|
||||
!passwordConfirmation.length
|
||||
|
||||
return (
|
||||
<View>
|
||||
<PasswordField
|
||||
placeholder={labels.enterNew}
|
||||
value={password}
|
||||
onChangeText={this.handlePasswordInput}
|
||||
/>
|
||||
<PasswordField
|
||||
autoFocus={false}
|
||||
placeholder={labels.confirmPassword}
|
||||
value={passwordConfirmation}
|
||||
onChangeText={this.handleConfirmationInput}
|
||||
/>
|
||||
{
|
||||
shouldShowErrorMessage &&
|
||||
<AppText style={styles.errorMessage}>
|
||||
{labels.passwordsDontMatch}
|
||||
</AppText>
|
||||
}
|
||||
<SettingsButton
|
||||
onPress={this.savePassword}
|
||||
disabled={isSaveButtonDisabled}
|
||||
>
|
||||
{labels.savePassword}
|
||||
</SettingsButton>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { Component } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import { View, ScrollView } from 'react-native'
|
||||
import CreatePassword from './create'
|
||||
import ChangePassword from './update'
|
||||
import DeletePassword from './delete'
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
hasEncryptionObservable
|
||||
} from '../../../local-storage'
|
||||
import styles from '../../../styles/index'
|
||||
import { settings as labels } from '../../../i18n/en/settings'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
|
||||
export default class PasswordSetting extends Component {
|
||||
constructor(props) {
|
||||
@@ -21,30 +21,32 @@ export default class PasswordSetting extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.settingsSegment}>
|
||||
<ScrollView>
|
||||
<View style={styles.settingsSegment}>
|
||||
|
||||
<AppText style={styles.settingsSegmentTitle}>
|
||||
{labels.passwordSettings.title}
|
||||
</AppText>
|
||||
<AppText style={styles.settingsSegmentTitle}>
|
||||
{labels.passwordSettings.title}
|
||||
</AppText>
|
||||
|
||||
{this.state.showUpdateAndDelete ?
|
||||
<AppText>{labels.passwordSettings.explainerEnabled}</AppText>
|
||||
:
|
||||
<AppText>{labels.passwordSettings.explainerDisabled}</AppText>
|
||||
}
|
||||
{this.state.showUpdateAndDelete ?
|
||||
<AppText>{labels.passwordSettings.explainerEnabled}</AppText>
|
||||
:
|
||||
<AppText>{labels.passwordSettings.explainerDisabled}</AppText>
|
||||
}
|
||||
|
||||
{this.state.showUpdateAndDelete &&
|
||||
{this.state.showUpdateAndDelete &&
|
||||
<View>
|
||||
<ChangePassword/>
|
||||
<DeletePassword/>
|
||||
</View>
|
||||
}
|
||||
}
|
||||
|
||||
{this.state.showCreate &&
|
||||
{this.state.showCreate &&
|
||||
<CreatePassword/>
|
||||
}
|
||||
}
|
||||
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { TouchableOpacity } from 'react-native'
|
||||
import AppText from '../../app-text'
|
||||
import styles from '../../../styles'
|
||||
|
||||
const SettingsButton = ({ children, ...props }) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.settingsButton,
|
||||
props.disabled ? styles.settingsButtonDisabled : null
|
||||
]}
|
||||
{ ...props }
|
||||
>
|
||||
<AppText style={styles.settingsButtonText}>
|
||||
{children}
|
||||
</AppText>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
SettingsButton.propTypes = {
|
||||
onPress: PropTypes.func.isRequired,
|
||||
disabled: PropTypes.bool
|
||||
}
|
||||
|
||||
export default SettingsButton
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Alert } from 'react-native'
|
||||
import { shared } from '../../../i18n/en/labels'
|
||||
import { settings as labels } from '../../../i18n/en/settings'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
|
||||
export default function showBackUpReminder(okHandler, isDelete) {
|
||||
let title, message
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
|
||||
import React, { Component } from 'react'
|
||||
import {
|
||||
View,
|
||||
TouchableOpacity} from 'react-native'
|
||||
import { View } from 'react-native'
|
||||
import nodejs from 'nodejs-mobile-react-native'
|
||||
import AppText from '../../app-text'
|
||||
import styles from '../../../styles'
|
||||
import { shared } from '../../../i18n/en/labels'
|
||||
import { settings as labels } from '../../../i18n/en/settings'
|
||||
import { requestHash, changeEncryptionAndRestartApp } from '../../../db'
|
||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
||||
import settings from '../../../i18n/en/settings'
|
||||
import { requestHash } from '../../../db'
|
||||
import EnterNewPassword from './enter-new-password'
|
||||
import PasswordField from './password-field'
|
||||
import SettingsButton from './settings-button'
|
||||
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
|
||||
enteringCurrentPassword: false,
|
||||
enteringNewPassword: false
|
||||
}
|
||||
|
||||
nodejs.channel.addListener(
|
||||
@@ -28,17 +25,10 @@ export default class ChangePassword extends Component {
|
||||
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 => {
|
||||
@@ -53,77 +43,67 @@ export default class ChangePassword extends Component {
|
||||
|
||||
if (passwordCorrect) {
|
||||
this.setState({
|
||||
enteringCurrentPassword: false,
|
||||
currentPassword: null,
|
||||
enteringNewPassword: true
|
||||
enteringNewPassword: true,
|
||||
enteringCurrentPassword: false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
startChangingPassword = () => {
|
||||
showBackUpReminder(() => {
|
||||
this.setState({ enteringCurrentPassword: true })
|
||||
})
|
||||
}
|
||||
|
||||
handleCurrentPasswordInput = (currentPassword) => {
|
||||
this.setState({ currentPassword })
|
||||
}
|
||||
|
||||
checkCurrentPassword = () => {
|
||||
requestHash('pre-change-pw-check', this.state.currentPassword)
|
||||
}
|
||||
|
||||
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>
|
||||
}
|
||||
const {
|
||||
enteringCurrentPassword,
|
||||
enteringNewPassword,
|
||||
currentPassword
|
||||
} = this.state
|
||||
|
||||
{this.state.enteringNewPassword &&
|
||||
const labels = settings.passwordSettings
|
||||
|
||||
if (enteringCurrentPassword) {
|
||||
return (
|
||||
<View>
|
||||
<PasswordField
|
||||
style={styles.passwordField}
|
||||
onChangeText={val => {
|
||||
this.setState({
|
||||
newPassword: val
|
||||
})
|
||||
}}
|
||||
value={this.state.changedPassword}
|
||||
placeholder={labels.passwordSettings.enterNew}
|
||||
placeholder={labels.enterCurrent}
|
||||
value={currentPassword}
|
||||
onChangeText={this.handleCurrentPasswordInput}
|
||||
/>
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={() => requestHash('change-pw', this.state.newPassword)}
|
||||
disabled={ !this.state.newPassword }
|
||||
style={styles.settingsButton}>
|
||||
<AppText style={styles.settingsButtonText}>
|
||||
{labels.passwordSettings.changePassword}
|
||||
</AppText>
|
||||
</TouchableOpacity>
|
||||
<SettingsButton
|
||||
onPress={this.checkCurrentPassword}
|
||||
disabled={!currentPassword}
|
||||
>
|
||||
{sharedLabels.unlock}
|
||||
</SettingsButton>
|
||||
</View>
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (enteringNewPassword) {
|
||||
return <EnterNewPassword />
|
||||
}
|
||||
|
||||
return (
|
||||
<View>
|
||||
<SettingsButton
|
||||
onPress={this.startChangingPassword}
|
||||
disabled={currentPassword}
|
||||
>
|
||||
{labels.changePassword}
|
||||
</SettingsButton>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import React, { Component } from 'react'
|
||||
import {
|
||||
ScrollView,
|
||||
} from 'react-native'
|
||||
import TempReminderPicker from './temp-reminder-picker'
|
||||
import PeriodReminderPicker from './period-reminder'
|
||||
|
||||
export default class Settings extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollView>
|
||||
<TempReminderPicker/>
|
||||
<PeriodReminderPicker/>
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -3,13 +3,13 @@ import {
|
||||
View,
|
||||
Switch
|
||||
} from 'react-native'
|
||||
import AppText from '../app-text'
|
||||
import AppText from '../../app-text'
|
||||
import {
|
||||
periodReminderObservable,
|
||||
savePeriodReminder
|
||||
} from '../../local-storage'
|
||||
import styles from '../../styles/index'
|
||||
import { settings as labels } from '../../i18n/en/settings'
|
||||
} from '../../../local-storage'
|
||||
import styles from '../../../styles/index'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
|
||||
export default class PeriodReminderPicker extends Component {
|
||||
constructor(props) {
|
||||
+5
-5
@@ -5,14 +5,14 @@ import {
|
||||
Switch
|
||||
} from 'react-native'
|
||||
import DateTimePicker from 'react-native-modal-datetime-picker-nevo'
|
||||
import AppText from '../app-text'
|
||||
import AppText from '../../app-text'
|
||||
import {
|
||||
tempReminderObservable,
|
||||
saveTempReminder
|
||||
} from '../../local-storage'
|
||||
import styles from '../../styles/index'
|
||||
import { settings as labels } from '../../i18n/en/settings'
|
||||
import padWithZeros from '../helpers/pad-time-with-zeros'
|
||||
} from '../../../local-storage'
|
||||
import styles from '../../../styles/index'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
import padWithZeros from '../../helpers/pad-time-with-zeros'
|
||||
|
||||
export default class TempReminderPicker extends Component {
|
||||
constructor(props) {
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
TouchableOpacity,
|
||||
ScrollView,
|
||||
} from 'react-native'
|
||||
import styles from '../../styles/index'
|
||||
import settingsLabels from '../../i18n/en/settings'
|
||||
import AppText from '../app-text'
|
||||
|
||||
console.log(settingsLabels.menuTitles)
|
||||
const labels = settingsLabels.menuTitles
|
||||
console.log(settingsLabels.menuTitles)
|
||||
|
||||
const menu = [
|
||||
{title: labels.reminders, component: 'Reminders'},
|
||||
{title: labels.nfpSettings, component: 'NfpSettings'},
|
||||
{title: labels.importExport, component: 'ImportExport'},
|
||||
{title: labels.password, component: 'Password'},
|
||||
{title: labels.about, component: 'About'}
|
||||
]
|
||||
|
||||
export default function SettingsMenu(props) {
|
||||
return (
|
||||
<ScrollView>
|
||||
{ menu.map(menuItem)}
|
||||
</ScrollView>
|
||||
)
|
||||
|
||||
function menuItem(item) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={styles.settingsSegment}
|
||||
key={item.title}
|
||||
onPress={() => props.navigate(item.component)}
|
||||
>
|
||||
<AppText>{item.title}</AppText>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -92,5 +92,6 @@ export const sharedDialogs = {
|
||||
areYouSureToUnset: 'Are you sure you want to unset all entered data?',
|
||||
reallyUnsetData: 'Yes, I am sure',
|
||||
save: 'Save',
|
||||
unset: 'Unset'
|
||||
unset: 'Unset',
|
||||
disabledInfo: 'There is some data missing'
|
||||
}
|
||||
|
||||
+9
-1
@@ -1,3 +1,6 @@
|
||||
import labels from './settings'
|
||||
const settingsTitles = labels.menuTitles
|
||||
|
||||
export const shared = {
|
||||
cancel: 'Cancel',
|
||||
save: 'Save',
|
||||
@@ -21,7 +24,12 @@ export const headerTitles = {
|
||||
Calendar: 'Calendar',
|
||||
Chart: 'Chart',
|
||||
Stats: 'Statistics',
|
||||
Settings: 'Settings',
|
||||
SettingsMenu: 'Settings',
|
||||
Reminders: settingsTitles.reminders,
|
||||
NfpSettings: settingsTitles.nfpSettings,
|
||||
ImportExport: settingsTitles.importExport,
|
||||
Password: settingsTitles.password,
|
||||
About: settingsTitles.about,
|
||||
BleedingEditView: 'Bleeding',
|
||||
TemperatureEditView: 'Temperature',
|
||||
MucusEditView: 'Mucus',
|
||||
|
||||
+23
-1
@@ -1,4 +1,12 @@
|
||||
export const settings = {
|
||||
|
||||
export default {
|
||||
menuTitles: {
|
||||
reminders: 'Reminders',
|
||||
importExport: 'Import and Export',
|
||||
nfpSettings: 'NFP settings',
|
||||
password: 'Password',
|
||||
about: 'About'
|
||||
},
|
||||
export: {
|
||||
errors: {
|
||||
noData: 'There is no data to export',
|
||||
@@ -67,5 +75,19 @@ export const settings = {
|
||||
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.',
|
||||
},
|
||||
aboutSection: {
|
||||
title: 'About',
|
||||
segmentExplainer: 'Please note that your data is stored locally on your phone and not on a server. We want to ensure that you stay in control of those sensitive information. If you are planning to switch or reset your phone, please remember to export your data before doing so. You can reinstall the app afterwards and import your data.\n\nIf you encounter any technical issues, don\'t hesitate to contact us via email (bl00dyhealth@mailbox.org). You can also contribute to the code base on GitLab (https://gitlab.com/bloodyhealth/drip/).',
|
||||
},
|
||||
preOvu: {
|
||||
title: 'Infertile days at cycle start',
|
||||
note1: "drip applies NFP's rules for calculating infertile days at the start of the cycle (see the ",
|
||||
link: 'wiki',
|
||||
note2: " for more info). However, drip does not currently apply the so called 20-day-rule, which determines infertile days at the cycle start from past cycle lengths in case no past symptothermal info is available."
|
||||
},
|
||||
credits: {
|
||||
title: 'Credits',
|
||||
note: 'Thanks and lots of <3 to all of our contributors, as well as, and especially, Susanne Umscheid for the wonderful visual and logo design, and Paula Härtel for the symptom icons'
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -39,7 +39,8 @@ export default function config(opts) {
|
||||
const targetDate = LocalDate.parse(targetDateString)
|
||||
const lastMensesLocalDate = LocalDate.parse(lastMensesStart.date)
|
||||
const diffInDays = lastMensesLocalDate.until(targetDate, DAYS)
|
||||
|
||||
// take maxCycleLength into account (we don't display cycle day numbers higher than 99 at the moment)
|
||||
if (diffInDays >= 99) return null
|
||||
// cycle starts at day 1
|
||||
return diffInDays + 1
|
||||
}
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
import objectPath from 'object-path'
|
||||
import { Base64 } from 'js-base64'
|
||||
import { getCycleDaysSortedByDate } from '../../db'
|
||||
import getColumnNamesForCsv from './get-csv-column-names'
|
||||
|
||||
export default function makeDataURI() {
|
||||
const cycleDaysSortedByDate = getCycleDaysSortedByDate()
|
||||
if (!cycleDaysSortedByDate.length) return null
|
||||
|
||||
const csv = transformToCsv(cycleDaysSortedByDate)
|
||||
const encoded = Base64.encodeURI(csv)
|
||||
// this is the MIME type android/libcore/MimeUtils expects, so we oblige
|
||||
return `data:text/comma-separated-values;base64,${encoded}`
|
||||
}
|
||||
|
||||
function transformToCsv(cycleDays) {
|
||||
export default function transformToCsv(cycleDays) {
|
||||
const columnNames = getColumnNamesForCsv()
|
||||
const rows = cycleDays
|
||||
.map(day => {
|
||||
@@ -23,7 +12,6 @@ function transformToCsv(cycleDays) {
|
||||
})
|
||||
})
|
||||
.map(row => row.join(','))
|
||||
|
||||
rows.unshift(columnNames.join(','))
|
||||
return rows.join('\n')
|
||||
}
|
||||
|
||||
+23
-11
@@ -1,16 +1,17 @@
|
||||
import getFertilityStatus from './sympto'
|
||||
import cycleModule from './cycle'
|
||||
import { fertilityStatus } from '../i18n/en/labels'
|
||||
import { useCervixObservable } from '../local-storage'
|
||||
import { fertilityStatus as labels } from '../i18n/en/labels'
|
||||
|
||||
export function getFertilityStatusForDay(dateString) {
|
||||
const status = getCycleStatusForDay(dateString)
|
||||
if (!status) return {
|
||||
status: fertilityStatus.fertile,
|
||||
status: labels.fertile,
|
||||
phase: null
|
||||
}
|
||||
|
||||
const phaseNameForDay = Object.keys(status.phases).find(phaseName => {
|
||||
const phases = Object.keys(status.phases)
|
||||
const phaseNameForDay = phases.find(phaseName => {
|
||||
const phase = status.phases[phaseName]
|
||||
const dayIsAfterPhaseStart = dateString >= phase.start.date
|
||||
let dayIsBeforePhaseEnd
|
||||
@@ -22,6 +23,12 @@ export function getFertilityStatusForDay(dateString) {
|
||||
return dayIsAfterPhaseStart && dayIsBeforePhaseEnd
|
||||
})
|
||||
|
||||
// if there's only cycle data for the pre phase and the target day is after its end,
|
||||
// the day is in the peri phase
|
||||
if (phases.length === 1 && phases[0] === 'preOvulatory' && !phaseNameForDay) {
|
||||
return formatStatus('periOvulatory', dateString, {phases: {periOvulatory: {}}})
|
||||
}
|
||||
|
||||
return formatStatus(phaseNameForDay, dateString, status)
|
||||
}
|
||||
|
||||
@@ -58,27 +65,32 @@ function formatStatus(phaseNameForDay, dateString, status) {
|
||||
const mapping = {
|
||||
preOvulatory: () => {
|
||||
return {
|
||||
status: fertilityStatus.infertile,
|
||||
status: labels.infertile,
|
||||
phase: 1,
|
||||
statusText: fertilityStatus.preOvuText
|
||||
statusText: labels.preOvuText
|
||||
}
|
||||
},
|
||||
periOvulatory: (dateString, status) => {
|
||||
const phaseEnd = status.phases.periOvulatory.end
|
||||
//there might not actually be any data for the phase
|
||||
const peri = status.phases.periOvulatory
|
||||
const phaseEnd = peri && peri.end
|
||||
let s
|
||||
if (phaseEnd && phaseEnd.date === dateString) {
|
||||
return fertilityStatus.fertileUntilEvening
|
||||
s = labels.fertileUntilEvening
|
||||
} else {
|
||||
s = labels.fertile
|
||||
}
|
||||
return {
|
||||
status: fertilityStatus.fertile,
|
||||
status: s,
|
||||
phase: 2,
|
||||
statusText: fertilityStatus.periOvuText
|
||||
statusText: labels.periOvuText
|
||||
}
|
||||
},
|
||||
postOvulatory: (dateString, status) => {
|
||||
return {
|
||||
status: fertilityStatus.infertile,
|
||||
status: labels.infertile,
|
||||
phase: 3,
|
||||
statusText: fertilityStatus.postOvuText(status.temperatureShift.rule)
|
||||
statusText: labels.postOvuText(status.temperatureShift.rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ function checkIfFirstHighMeasurement(temp, i, temperatureDays, ltl) {
|
||||
function getResultForRegularRule(nextDaysAfterPotentialFhm, ltl) {
|
||||
if (!nextDaysAfterPotentialFhm.every(day => day.temp > ltl)) return false
|
||||
const thirdDay = nextDaysAfterPotentialFhm[1]
|
||||
if (rounded(thirdDay.temp - ltl, 0.1) < 0.2) return false
|
||||
if (isLessThan0Point2(thirdDay.temp - ltl)) return false
|
||||
return {
|
||||
detected: true,
|
||||
rule: 0,
|
||||
@@ -77,7 +77,7 @@ function getResultForSecondExceptionRule(nextDaysAfterPotentialFhm, ltl) {
|
||||
if (nextDaysAfterPotentialFhm.length < 3) return false
|
||||
if (secondOrThirdTempIsAtOrBelowLtl(nextDaysAfterPotentialFhm, ltl)) {
|
||||
const fourthDay = nextDaysAfterPotentialFhm[2]
|
||||
if (rounded(fourthDay.temp - ltl, 0.1) >= 0.2) {
|
||||
if (isBiggerOrEqual0Point2(fourthDay.temp - ltl)) {
|
||||
return {
|
||||
detected: true,
|
||||
rule: 2,
|
||||
@@ -104,3 +104,19 @@ function rounded(val, step) {
|
||||
// we round the difference because of JS decimal weirdness
|
||||
return Math.round(val * inverted) / inverted
|
||||
}
|
||||
|
||||
|
||||
// since we're dealing with floats, there is some imprecision in comparisons,
|
||||
// so we add an error margin that is definitely much smaller than any possible
|
||||
// actual difference between values
|
||||
// see https://floating-point-gui.de/errors/comparison/ for background
|
||||
|
||||
const errorMargin = 0.0001
|
||||
|
||||
function isLessThan0Point2(val) {
|
||||
return val < (0.2 - errorMargin)
|
||||
}
|
||||
|
||||
function isBiggerOrEqual0Point2(val) {
|
||||
return val >= (0.2 - errorMargin)
|
||||
}
|
||||
Generated
+234
-214
@@ -771,12 +771,26 @@
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "4.11.8",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
|
||||
"integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.1.tgz",
|
||||
"integrity": "sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==",
|
||||
"requires": {
|
||||
"co": "^4.6.0",
|
||||
"json-stable-stringify": "^1.0.1"
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ajv-keywords": {
|
||||
@@ -1248,9 +1262,9 @@
|
||||
}
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
|
||||
"integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ="
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"assertion-error": {
|
||||
"version": "1.1.0",
|
||||
@@ -1287,9 +1301,9 @@
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
|
||||
"integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8="
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.7.0",
|
||||
@@ -2218,18 +2232,11 @@
|
||||
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
|
||||
},
|
||||
"basic-auth": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz",
|
||||
"integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
|
||||
"integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||
}
|
||||
"safe-buffer": "5.1.2"
|
||||
}
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
@@ -2255,27 +2262,11 @@
|
||||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"block-stream": {
|
||||
"version": "0.0.9",
|
||||
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
|
||||
"integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
|
||||
"requires": {
|
||||
"inherits": "~2.0.0"
|
||||
}
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
|
||||
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
|
||||
},
|
||||
"boom": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
|
||||
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
|
||||
"requires": {
|
||||
"hoek": "2.x.x"
|
||||
}
|
||||
},
|
||||
"bplist-creator": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.7.tgz",
|
||||
@@ -2721,14 +2712,6 @@
|
||||
"which": "^1.2.9"
|
||||
}
|
||||
},
|
||||
"cryptiles": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
|
||||
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
|
||||
"requires": {
|
||||
"boom": "2.x.x"
|
||||
}
|
||||
},
|
||||
"csvtojson": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/csvtojson/-/csvtojson-2.0.8.tgz",
|
||||
@@ -3640,12 +3623,12 @@
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
|
||||
"integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.5",
|
||||
"combined-stream": "^1.0.6",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
@@ -3677,6 +3660,14 @@
|
||||
"klaw": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
|
||||
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
|
||||
"requires": {
|
||||
"minipass": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
@@ -4144,27 +4135,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"fstream": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
|
||||
"integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"inherits": "~2.0.0",
|
||||
"mkdirp": ">=0.5 0",
|
||||
"rimraf": "2"
|
||||
}
|
||||
},
|
||||
"fstream-ignore": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz",
|
||||
"integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=",
|
||||
"requires": {
|
||||
"fstream": "^1.0.0",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
@@ -4313,17 +4283,17 @@
|
||||
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE="
|
||||
},
|
||||
"har-schema": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
|
||||
"integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4="
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
|
||||
"integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
|
||||
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
|
||||
"requires": {
|
||||
"ajv": "^4.9.1",
|
||||
"har-schema": "^1.0.5"
|
||||
"ajv": "^6.5.5",
|
||||
"har-schema": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"has": {
|
||||
@@ -4400,28 +4370,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"hawk": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
|
||||
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
|
||||
"requires": {
|
||||
"boom": "2.x.x",
|
||||
"cryptiles": "2.x.x",
|
||||
"hoek": "2.x.x",
|
||||
"sntp": "1.x.x"
|
||||
}
|
||||
},
|
||||
"he": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
|
||||
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
|
||||
"dev": true
|
||||
},
|
||||
"hoek": {
|
||||
"version": "2.16.3",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||
},
|
||||
"home-or-tmp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
|
||||
@@ -4482,11 +4436,11 @@
|
||||
"integrity": "sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM="
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
|
||||
"integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"requires": {
|
||||
"assert-plus": "^0.2.0",
|
||||
"assert-plus": "^1.0.0",
|
||||
"jsprim": "^1.2.2",
|
||||
"sshpk": "^1.7.0"
|
||||
}
|
||||
@@ -4510,6 +4464,14 @@
|
||||
"integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
|
||||
"dev": true
|
||||
},
|
||||
"ignore-walk": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
|
||||
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
|
||||
"requires": {
|
||||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"image-size": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz",
|
||||
@@ -5184,9 +5146,9 @@
|
||||
}
|
||||
},
|
||||
"merge": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz",
|
||||
"integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo="
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz",
|
||||
"integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ=="
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "1.0.1",
|
||||
@@ -5629,13 +5591,13 @@
|
||||
"integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y="
|
||||
},
|
||||
"morgan": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz",
|
||||
"integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=",
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz",
|
||||
"integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==",
|
||||
"requires": {
|
||||
"basic-auth": "~2.0.0",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.1",
|
||||
"depd": "~1.1.2",
|
||||
"on-finished": "~2.3.0",
|
||||
"on-headers": "~1.0.1"
|
||||
}
|
||||
@@ -5653,8 +5615,7 @@
|
||||
"nan": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.11.0.tgz",
|
||||
"integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==",
|
||||
"optional": true
|
||||
"integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw=="
|
||||
},
|
||||
"nanomatch": {
|
||||
"version": "1.2.13",
|
||||
@@ -5719,6 +5680,23 @@
|
||||
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
|
||||
"integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M="
|
||||
},
|
||||
"needle": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz",
|
||||
"integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==",
|
||||
"requires": {
|
||||
"debug": "^2.1.2",
|
||||
"iconv-lite": "^0.4.4",
|
||||
"sax": "^1.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"negotiator": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
|
||||
@@ -5738,6 +5716,11 @@
|
||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||
"integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
|
||||
},
|
||||
"node-machine-id": {
|
||||
"version": "1.1.10",
|
||||
"resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.10.tgz",
|
||||
"integrity": "sha512-6SVxo3Ic2Qc09z1rCJh3No7ubizPLszImsMQnZZWfzeOC6SYU4orN214++c3ikB8uaP/A6dwSlO88A3ohI5oNA=="
|
||||
},
|
||||
"node-modules-regexp": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz",
|
||||
@@ -5755,21 +5738,20 @@
|
||||
}
|
||||
},
|
||||
"node-pre-gyp": {
|
||||
"version": "0.6.39",
|
||||
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz",
|
||||
"integrity": "sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ==",
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz",
|
||||
"integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==",
|
||||
"requires": {
|
||||
"detect-libc": "^1.0.2",
|
||||
"hawk": "3.1.3",
|
||||
"mkdirp": "^0.5.1",
|
||||
"needle": "^2.2.1",
|
||||
"nopt": "^4.0.1",
|
||||
"npm-packlist": "^1.1.6",
|
||||
"npmlog": "^4.0.2",
|
||||
"rc": "^1.1.7",
|
||||
"request": "2.81.0",
|
||||
"rc": "^1.2.7",
|
||||
"rimraf": "^2.6.1",
|
||||
"semver": "^5.3.0",
|
||||
"tar": "^2.2.1",
|
||||
"tar-pack": "^3.4.0"
|
||||
"tar": "^4"
|
||||
},
|
||||
"dependencies": {
|
||||
"gauge": {
|
||||
@@ -5806,35 +5788,6 @@
|
||||
"set-blocking": "~2.0.0"
|
||||
}
|
||||
},
|
||||
"request": {
|
||||
"version": "2.81.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
|
||||
"integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
|
||||
"requires": {
|
||||
"aws-sign2": "~0.6.0",
|
||||
"aws4": "^1.2.1",
|
||||
"caseless": "~0.12.0",
|
||||
"combined-stream": "~1.0.5",
|
||||
"extend": "~3.0.0",
|
||||
"forever-agent": "~0.6.1",
|
||||
"form-data": "~2.1.1",
|
||||
"har-validator": "~4.2.1",
|
||||
"hawk": "~3.1.3",
|
||||
"http-signature": "~1.1.0",
|
||||
"is-typedarray": "~1.0.0",
|
||||
"isstream": "~0.1.2",
|
||||
"json-stringify-safe": "~5.0.1",
|
||||
"mime-types": "~2.1.7",
|
||||
"oauth-sign": "~0.8.1",
|
||||
"performance-now": "^0.2.0",
|
||||
"qs": "~6.4.0",
|
||||
"safe-buffer": "^5.0.1",
|
||||
"stringstream": "~0.0.4",
|
||||
"tough-cookie": "~2.3.0",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||
@@ -5937,6 +5890,20 @@
|
||||
"remove-trailing-separator": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"npm-bundled": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz",
|
||||
"integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g=="
|
||||
},
|
||||
"npm-packlist": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.12.tgz",
|
||||
"integrity": "sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g==",
|
||||
"requires": {
|
||||
"ignore-walk": "^3.0.1",
|
||||
"npm-bundled": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"npm-run-path": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
|
||||
@@ -6258,9 +6225,9 @@
|
||||
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
|
||||
"integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU="
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
@@ -6387,20 +6354,25 @@
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.1.31",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
|
||||
"integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw=="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
|
||||
"integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM="
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"querystringify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz",
|
||||
"integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw=="
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz",
|
||||
"integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg=="
|
||||
},
|
||||
"randomatic": {
|
||||
"version": "3.1.0",
|
||||
@@ -6746,26 +6718,32 @@
|
||||
}
|
||||
},
|
||||
"realm": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/realm/-/realm-2.14.0.tgz",
|
||||
"integrity": "sha512-HiCj/ZE3iZNOyWexVkhDetNEfcTtSdgsg5lop7g7rcCsE+4NM3hDRxvBjrBSk/mgs6HXBAhHohzGmREbs6piRg==",
|
||||
"version": "2.21.0",
|
||||
"resolved": "https://registry.npmjs.org/realm/-/realm-2.21.0.tgz",
|
||||
"integrity": "sha512-2XxkVogKOObhwBUcP7NPvyA9kU/HIeopVbAGgKanJWYw5z09J+I+q1CN2gCVR5EC4+H55Ht4loEhjDud5+LEYQ==",
|
||||
"requires": {
|
||||
"command-line-args": "^4.0.6",
|
||||
"decompress": "^4.2.0",
|
||||
"deepmerge": "2.1.0",
|
||||
"fs-extra": "^4.0.2",
|
||||
"ini": "^1.3.4",
|
||||
"nan": "2.8.0",
|
||||
"nan": "^2.10.0",
|
||||
"node-fetch": "^1.6.3",
|
||||
"node-pre-gyp": "^0.6.36",
|
||||
"node-machine-id": "^1.1.10",
|
||||
"node-pre-gyp": "^0.11.0",
|
||||
"progress": "^2.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"request": "^2.78.0",
|
||||
"request": "^2.88.0",
|
||||
"stream-counter": "^1.0.0",
|
||||
"sync-request": "^3.0.1",
|
||||
"url-parse": "^1.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"aws4": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
|
||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
|
||||
@@ -6784,10 +6762,46 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz",
|
||||
"integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo="
|
||||
"oauth-sign": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
|
||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
||||
},
|
||||
"request": {
|
||||
"version": "2.88.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
|
||||
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
"caseless": "~0.12.0",
|
||||
"combined-stream": "~1.0.6",
|
||||
"extend": "~3.0.2",
|
||||
"forever-agent": "~0.6.1",
|
||||
"form-data": "~2.3.2",
|
||||
"har-validator": "~5.1.0",
|
||||
"http-signature": "~1.2.0",
|
||||
"is-typedarray": "~1.0.0",
|
||||
"isstream": "~0.1.2",
|
||||
"json-stringify-safe": "~5.0.1",
|
||||
"mime-types": "~2.1.19",
|
||||
"oauth-sign": "~0.9.0",
|
||||
"performance-now": "^2.1.0",
|
||||
"qs": "~6.5.2",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"tough-cookie": "~2.4.3",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
|
||||
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
|
||||
"requires": {
|
||||
"psl": "^1.1.24",
|
||||
"punycode": "^1.4.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -7698,14 +7712,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sntp": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
|
||||
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
|
||||
"requires": {
|
||||
"hoek": "2.x.x"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
@@ -7891,11 +7897,6 @@
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"stringstream": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz",
|
||||
"integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA=="
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
@@ -8000,41 +8001,50 @@
|
||||
}
|
||||
},
|
||||
"tar": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
|
||||
"integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
|
||||
"version": "4.4.8",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
|
||||
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
|
||||
"requires": {
|
||||
"block-stream": "*",
|
||||
"fstream": "^1.0.2",
|
||||
"inherits": "2"
|
||||
}
|
||||
},
|
||||
"tar-pack": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.1.tgz",
|
||||
"integrity": "sha512-PPRybI9+jM5tjtCbN2cxmmRU7YmqT3Zv/UDy48tAh2XRkLa9bAORtSWLkVc13+GJF+cdTh1yEnHEk3cpTaL5Kg==",
|
||||
"requires": {
|
||||
"debug": "^2.2.0",
|
||||
"fstream": "^1.0.10",
|
||||
"fstream-ignore": "^1.0.5",
|
||||
"once": "^1.3.3",
|
||||
"readable-stream": "^2.1.4",
|
||||
"rimraf": "^2.5.1",
|
||||
"tar": "^2.2.1",
|
||||
"uid-number": "^0.0.6"
|
||||
"chownr": "^1.1.1",
|
||||
"fs-minipass": "^1.2.5",
|
||||
"minipass": "^2.3.4",
|
||||
"minizlib": "^1.1.1",
|
||||
"mkdirp": "^0.5.0",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"chownr": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
|
||||
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
|
||||
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
|
||||
"requires": {
|
||||
"minipass": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
|
||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"tar-stream": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.1.tgz",
|
||||
"integrity": "sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==",
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
|
||||
"requires": {
|
||||
"bl": "^1.0.0",
|
||||
"buffer-alloc": "^1.1.0",
|
||||
"buffer-alloc": "^1.2.0",
|
||||
"end-of-stream": "^1.0.0",
|
||||
"fs-constants": "^1.0.0",
|
||||
"readable-stream": "^2.3.0",
|
||||
"to-buffer": "^1.1.0",
|
||||
"to-buffer": "^1.1.1",
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
@@ -8299,20 +8309,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"uid-number": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
|
||||
"integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE="
|
||||
},
|
||||
"ultron": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
|
||||
"integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po="
|
||||
},
|
||||
"unbzip2-stream": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz",
|
||||
"integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz",
|
||||
"integrity": "sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw==",
|
||||
"requires": {
|
||||
"buffer": "^3.0.1",
|
||||
"through": "^2.3.6"
|
||||
@@ -8425,15 +8430,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"urix": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
|
||||
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.3.tgz",
|
||||
"integrity": "sha512-rh+KuAW36YKo0vClhQzLLveoj8FwPJNu65xLb7Mrt+eZht0IPT0IXgSv8gcMegZ6NvjJUALf6Mf25POlMwD1Fw==",
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz",
|
||||
"integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==",
|
||||
"requires": {
|
||||
"querystringify": "^2.0.0",
|
||||
"requires-port": "^1.0.0"
|
||||
|
||||
+4
-2
@@ -12,7 +12,8 @@
|
||||
"log": "react-native log-android",
|
||||
"test": "mocha --recursive --require @babel/register test && npm run lint",
|
||||
"test-watch": "mocha --recursive --require @babel/register --watch test",
|
||||
"lint": "eslint components lib test"
|
||||
"lint": "eslint components lib test",
|
||||
"devtool": "adb shell input keyevent 82"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ptomasroos/react-native-multi-slider": "^1.0.0",
|
||||
@@ -26,6 +27,7 @@
|
||||
"nodejs-mobile-react-native": "^0.3.0",
|
||||
"object-path": "^0.11.4",
|
||||
"obv": "0.0.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "16.4.1",
|
||||
"react-native": "~0.56.0",
|
||||
"react-native-calendars": "^1.19.3",
|
||||
@@ -36,7 +38,7 @@
|
||||
"react-native-restart": "0.0.7",
|
||||
"react-native-share": "^1.1.3",
|
||||
"react-native-vector-icons": "^5.0.0",
|
||||
"realm": "^2.7.1"
|
||||
"realm": "^2.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/register": "^7.0.0-beta.55",
|
||||
|
||||
@@ -43,6 +43,10 @@ export default StyleSheet.create({
|
||||
fontWeight: 'bold',
|
||||
fontFamily: textFont
|
||||
},
|
||||
link: {
|
||||
color: cycleDayColor,
|
||||
textDecorationLine: 'underline'
|
||||
},
|
||||
title: {
|
||||
fontSize: 18,
|
||||
color: 'black',
|
||||
@@ -263,6 +267,9 @@ export default StyleSheet.create({
|
||||
padding: 7,
|
||||
fontFamily: 'textFont'
|
||||
},
|
||||
settingsSegmentLast: {
|
||||
marginBottom: defaultTopMargin,
|
||||
},
|
||||
settingsSegmentTitle: {
|
||||
fontWeight: 'bold',
|
||||
fontFamily: 'textFont'
|
||||
@@ -414,4 +421,8 @@ export const iconStyles = {
|
||||
menuIconInactive: {
|
||||
color: colorInActive,
|
||||
},
|
||||
infoInHeading: {
|
||||
marginRight: 5,
|
||||
color: 'black'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import dirtyChai from 'dirty-chai'
|
||||
const expect = chai.expect
|
||||
chai.use(dirtyChai)
|
||||
|
||||
import getSensiplanMucus from '../lib/sensiplan-mucus'
|
||||
import getSensiplanMucus from '../lib/nfp-mucus'
|
||||
|
||||
describe('getSensiplanMucus', () => {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user