Merge branch 'refactoring-settings-view' into 'master'
Refactoring settings view Closes #275 See merge request bloodyhealth/drip!147
This commit is contained in:
@@ -2,7 +2,7 @@ import React, { Component } from 'react'
|
|||||||
import { ScrollView } from 'react-native'
|
import { ScrollView } from 'react-native'
|
||||||
import Hyperlink from 'react-native-hyperlink'
|
import Hyperlink from 'react-native-hyperlink'
|
||||||
import AppText from '../app-text'
|
import AppText from '../app-text'
|
||||||
import SettingsSegment from './settings-segment'
|
import SettingsSegment from './shared/settings-segment'
|
||||||
import styles from '../../styles/index'
|
import styles from '../../styles/index'
|
||||||
import labels, { links } from '../../i18n/en/settings'
|
import labels, { links } from '../../i18n/en/settings'
|
||||||
import replace from '../helpers/replace-url-with-text'
|
import replace from '../helpers/replace-url-with-text'
|
||||||
@@ -13,21 +13,21 @@ export default class AboutSection extends Component {
|
|||||||
<ScrollView>
|
<ScrollView>
|
||||||
<SettingsSegment title={labels.aboutSection.title}>
|
<SettingsSegment title={labels.aboutSection.title}>
|
||||||
<Hyperlink linkStyle={styles.link} linkText={replace}>
|
<Hyperlink linkStyle={styles.link} linkText={replace}>
|
||||||
<AppText>{`${labels.aboutSection.text} `}</AppText>
|
<AppText>{labels.aboutSection.text}</AppText>
|
||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
</SettingsSegment>
|
</SettingsSegment>
|
||||||
<SettingsSegment title={labels.philosophy.title}>
|
<SettingsSegment title={labels.philosophy.title}>
|
||||||
<AppText>{labels.philosophy.text}</AppText>
|
<AppText>{labels.philosophy.text}</AppText>
|
||||||
</SettingsSegment>
|
</SettingsSegment>
|
||||||
<SettingsSegment title={labels.credits.title}>
|
<SettingsSegment title={labels.credits.title}>
|
||||||
<AppText>{`${labels.credits.note}`}</AppText>
|
<AppText>{labels.credits.note}</AppText>
|
||||||
</SettingsSegment>
|
</SettingsSegment>
|
||||||
<SettingsSegment title={labels.website.title}>
|
<SettingsSegment title={labels.website.title}>
|
||||||
<Hyperlink linkStyle={styles.link}>
|
<Hyperlink linkStyle={styles.link}>
|
||||||
<AppText>{links.website.url}</AppText>
|
<AppText>{links.website.url}</AppText>
|
||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
</SettingsSegment>
|
</SettingsSegment>
|
||||||
<SettingsSegment title={labels.version.title} last={true}>
|
<SettingsSegment title={labels.version.title} last>
|
||||||
<AppText>{require('../../package.json').version}</AppText>
|
<AppText>{require('../../package.json').version}</AppText>
|
||||||
</SettingsSegment>
|
</SettingsSegment>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import { Alert, ToastAndroid } from 'react-native'
|
|||||||
|
|
||||||
import { clearDb, isDbEmpty } from '../../../db'
|
import { clearDb, isDbEmpty } from '../../../db'
|
||||||
import { hasEncryptionObservable } from '../../../local-storage'
|
import { hasEncryptionObservable } from '../../../local-storage'
|
||||||
import SettingsButton from '../settings-button'
|
import SettingsButton from '../shared/settings-button'
|
||||||
import ConfirmWithPassword from './confirm-with-password'
|
import ConfirmWithPassword from '../shared/confirm-with-password'
|
||||||
import alertError from '../alert-error'
|
import alertError from '../shared/alert-error'
|
||||||
|
|
||||||
import settings from '../../../i18n/en/settings'
|
import settings from '../../../i18n/en/settings'
|
||||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import Share from 'react-native-share'
|
|||||||
|
|
||||||
import { getCycleDaysSortedByDate } from '../../../db'
|
import { getCycleDaysSortedByDate } from '../../../db'
|
||||||
import getDataAsCsvDataUri from '../../../lib/import-export/export-to-csv'
|
import getDataAsCsvDataUri from '../../../lib/import-export/export-to-csv'
|
||||||
import alertError from '../alert-error'
|
import alertError from '../shared/alert-error'
|
||||||
import settings from '../../../i18n/en/settings'
|
import settings from '../../../i18n/en/settings'
|
||||||
import { EXPORT_FILE_NAME } from './constants'
|
import { EXPORT_FILE_NAME } from './constants'
|
||||||
import RNFS from 'react-native-fs'
|
import RNFS from 'react-native-fs'
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import rnfs from 'react-native-fs'
|
|||||||
import importCsv from '../../../lib/import-export/import-from-csv'
|
import importCsv from '../../../lib/import-export/import-from-csv'
|
||||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
||||||
import labels from '../../../i18n/en/settings'
|
import labels from '../../../i18n/en/settings'
|
||||||
import alertError from '../alert-error'
|
import alertError from '../shared/alert-error'
|
||||||
|
|
||||||
export default function openImportDialogAndImport() {
|
export default function openImportDialogAndImport() {
|
||||||
Alert.alert(
|
Alert.alert(
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ScrollView } from 'react-native'
|
import { ScrollView } from 'react-native'
|
||||||
import AppText from '../../app-text'
|
import AppText from '../../app-text'
|
||||||
import SettingsSegment from '../settings-segment'
|
import SettingsSegment from '../shared/settings-segment'
|
||||||
import SettingsButton from '../settings-button'
|
import SettingsButton from '../shared/settings-button'
|
||||||
import openImportDialogAndImport from './import-dialog'
|
import openImportDialogAndImport from './import-dialog'
|
||||||
import openShareDialogAndExport from './export-dialog'
|
import openShareDialogAndExport from './export-dialog'
|
||||||
import DeleteData from './delete-data'
|
import DeleteData from './delete-data'
|
||||||
@@ -25,7 +25,7 @@ const DataManagement = () => {
|
|||||||
</SettingsSegment>
|
</SettingsSegment>
|
||||||
<SettingsSegment
|
<SettingsSegment
|
||||||
title={labels.deleteSegment.title}
|
title={labels.deleteSegment.title}
|
||||||
last={true}
|
last
|
||||||
>
|
>
|
||||||
<AppText>{labels.deleteSegment.explainer}</AppText>
|
<AppText>{labels.deleteSegment.explainer}</AppText>
|
||||||
<DeleteData />
|
<DeleteData />
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Hyperlink from 'react-native-hyperlink'
|
|||||||
import styles, { iconStyles } from '../../../styles'
|
import styles, { iconStyles } from '../../../styles'
|
||||||
import labels from '../../../i18n/en/settings'
|
import labels from '../../../i18n/en/settings'
|
||||||
import AppText from '../../app-text'
|
import AppText from '../../app-text'
|
||||||
|
import SettingsSegment from '../shared/settings-segment'
|
||||||
import TempSlider from './temp-slider'
|
import TempSlider from './temp-slider'
|
||||||
import UseCervixSetting from './use-cervix'
|
import UseCervixSetting from './use-cervix'
|
||||||
import Icon from 'react-native-vector-icons/Entypo'
|
import Icon from 'react-native-vector-icons/Entypo'
|
||||||
@@ -20,15 +21,14 @@ export default class Settings extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<UseCervixSetting/>
|
<SettingsSegment title={labels.useCervix.title}>
|
||||||
<View style={styles.settingsSegment}>
|
<UseCervixSetting/>
|
||||||
<AppText style={styles.settingsSegmentTitle}>
|
</SettingsSegment>
|
||||||
{labels.tempScale.segmentTitle}
|
<SettingsSegment title={labels.tempScale.segmentTitle}>
|
||||||
</AppText>
|
|
||||||
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
||||||
<TempSlider/>
|
<TempSlider/>
|
||||||
</View>
|
</SettingsSegment>
|
||||||
<View style={[styles.settingsSegment, styles.settingsSegmentLast]}>
|
<SettingsSegment style={styles.settingsSegmentLast} >
|
||||||
<View style={{flexDirection: 'row', alignItems: 'center'}}>
|
<View style={{flexDirection: 'row', alignItems: 'center'}}>
|
||||||
<Icon name="info-with-circle" style={iconStyles.infoInHeading}/>
|
<Icon name="info-with-circle" style={iconStyles.infoInHeading}/>
|
||||||
<AppText style={styles.settingsSegmentTitle}>{`${labels.preOvu.title} `}</AppText>
|
<AppText style={styles.settingsSegmentTitle}>{`${labels.preOvu.title} `}</AppText>
|
||||||
@@ -36,7 +36,7 @@ export default class Settings extends Component {
|
|||||||
<Hyperlink linkStyle={styles.link} linkText={replaceUrlWithText}>
|
<Hyperlink linkStyle={styles.link} linkText={replaceUrlWithText}>
|
||||||
<AppText>{labels.preOvu.note}</AppText>
|
<AppText>{labels.preOvu.note}</AppText>
|
||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
</View>
|
</SettingsSegment>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
import { secondaryColor } from '../../../styles/index'
|
import { secondaryColor } from '../../../styles/index'
|
||||||
import labels from '../../../i18n/en/settings'
|
import labels from '../../../i18n/en/settings'
|
||||||
import config from '../../../config'
|
import config from '../../../config'
|
||||||
import alertError from '../alert-error'
|
import alertError from '../shared/alert-error'
|
||||||
|
|
||||||
export default class TempSlider extends Component {
|
export default class TempSlider extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import {
|
import {
|
||||||
View,
|
View,
|
||||||
TouchableOpacity,
|
|
||||||
Switch
|
Switch
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import AppText from '../../app-text'
|
import AppText from '../../app-text'
|
||||||
@@ -9,7 +8,6 @@ import {
|
|||||||
useCervixObservable,
|
useCervixObservable,
|
||||||
saveUseCervix
|
saveUseCervix
|
||||||
} from '../../../local-storage'
|
} from '../../../local-storage'
|
||||||
import styles from '../../../styles/index'
|
|
||||||
import labels from '../../../i18n/en/settings'
|
import labels from '../../../i18n/en/settings'
|
||||||
|
|
||||||
export default class UseCervixSetting extends Component {
|
export default class UseCervixSetting extends Component {
|
||||||
@@ -20,29 +18,22 @@ export default class UseCervixSetting extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
style={styles.settingsSegment}
|
<View style={{ flex: 1 }}>
|
||||||
>
|
{this.state.useCervix ?
|
||||||
<AppText style={styles.settingsSegmentTitle}>
|
<AppText>{labels.useCervix.cervixModeOn}</AppText>
|
||||||
{labels.useCervix.title}
|
:
|
||||||
</AppText>
|
<AppText>{labels.useCervix.cervixModeOff}</AppText>
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
}
|
||||||
<View style={{ flex: 1 }}>
|
|
||||||
{this.state.useCervix ?
|
|
||||||
<AppText>{labels.useCervix.cervixModeOn}</AppText>
|
|
||||||
:
|
|
||||||
<AppText>{labels.useCervix.cervixModeOff}</AppText>
|
|
||||||
}
|
|
||||||
</View>
|
|
||||||
<Switch
|
|
||||||
value={this.state.useCervix}
|
|
||||||
onValueChange={bool => {
|
|
||||||
this.setState({ useCervix: bool })
|
|
||||||
saveUseCervix(bool)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
<Switch
|
||||||
|
value={this.state.useCervix}
|
||||||
|
onValueChange={bool => {
|
||||||
|
this.setState({ useCervix: bool })
|
||||||
|
saveUseCervix(bool)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
import { Alert } from 'react-native'
|
|
||||||
import { openDb } from '../../../db'
|
|
||||||
import { shared } from '../../../i18n/en/labels'
|
|
||||||
|
|
||||||
export default async function checkPassword({hash, onCancel, onTryAgain }) {
|
|
||||||
try {
|
|
||||||
await openDb(hash)
|
|
||||||
return true
|
|
||||||
} catch (err) {
|
|
||||||
Alert.alert(
|
|
||||||
shared.incorrectPassword,
|
|
||||||
shared.incorrectPasswordMessage,
|
|
||||||
[{
|
|
||||||
text: shared.cancel,
|
|
||||||
onPress: onCancel
|
|
||||||
}, {
|
|
||||||
text: shared.tryAgain,
|
|
||||||
onPress: onTryAgain
|
|
||||||
}]
|
|
||||||
)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@ import React, { Component } from 'react'
|
|||||||
import { View } from 'react-native'
|
import { View } from 'react-native'
|
||||||
import settings from '../../../i18n/en/settings'
|
import settings from '../../../i18n/en/settings'
|
||||||
import EnterNewPassword from './enter-new-password'
|
import EnterNewPassword from './enter-new-password'
|
||||||
import SettingsButton from '../settings-button'
|
import SettingsButton from '../shared/settings-button'
|
||||||
import showBackUpReminder from './show-backup-reminder'
|
import showBackUpReminder from './show-backup-reminder'
|
||||||
|
|
||||||
export default class CreatePassword extends Component {
|
export default class CreatePassword extends Component {
|
||||||
|
|||||||
@@ -1,80 +1,47 @@
|
|||||||
import React, { Component } from 'react'
|
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 labels from '../../../i18n/en/settings'
|
import labels from '../../../i18n/en/settings'
|
||||||
import { requestHash, changeEncryptionAndRestartApp } from '../../../db'
|
import { changeEncryptionAndRestartApp } from '../../../db'
|
||||||
import PasswordField from './password-field'
|
import ConfirmWithPassword from '../shared/confirm-with-password'
|
||||||
import showBackUpReminder from './show-backup-reminder'
|
import SettingsButton from '../shared/settings-button'
|
||||||
import checkCurrentPassword from './check-current-password'
|
|
||||||
|
|
||||||
export default class DeletePassword extends Component {
|
export default class DeletePassword extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.state = {
|
this.state = {
|
||||||
enteringCurrentPassword: false,
|
enteringCurrentPassword: false
|
||||||
currentPassword: null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nodejs.channel.addListener(
|
|
||||||
'pre-delete-pw-check',
|
|
||||||
this.removeEncryption,
|
|
||||||
this
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
startConfirmWithPassword = () => {
|
||||||
nodejs.channel.removeListener('pre-delete-pw-check', this.removeEncryption)
|
this.setState({ enteringCurrentPassword: true })
|
||||||
|
this.props.onStartDeletingPassword()
|
||||||
}
|
}
|
||||||
|
|
||||||
removeEncryption = async hash => {
|
startDeletePassword = async () => {
|
||||||
const passwordIsCorrect = await checkCurrentPassword({
|
await changeEncryptionAndRestartApp()
|
||||||
hash,
|
}
|
||||||
onTryAgain: () => this.setState({currentPassword: null}),
|
|
||||||
onCancel: () => this.setState({
|
|
||||||
enteringCurrentPassword: false,
|
|
||||||
currentPassword: null
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if (passwordIsCorrect) await changeEncryptionAndRestartApp()
|
cancelConfirmationWithPassword = () => {
|
||||||
|
this.setState({ enteringCurrentPassword: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
|
const { enteringCurrentPassword } = this.state
|
||||||
|
|
||||||
|
if (enteringCurrentPassword) {
|
||||||
|
return (
|
||||||
|
<ConfirmWithPassword
|
||||||
|
onSuccess={this.startDeletePassword}
|
||||||
|
onCancel={this.cancelConfirmationWithPassword}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<SettingsButton onPress={this.startConfirmWithPassword} >
|
||||||
{this.state.enteringCurrentPassword &&
|
{labels.passwordSettings.deletePassword}
|
||||||
<PasswordField
|
</SettingsButton>
|
||||||
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>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,8 +4,8 @@ import nodejs from 'nodejs-mobile-react-native'
|
|||||||
|
|
||||||
import { requestHash, changeEncryptionAndRestartApp } from '../../../db'
|
import { requestHash, changeEncryptionAndRestartApp } from '../../../db'
|
||||||
import AppText from '../../app-text'
|
import AppText from '../../app-text'
|
||||||
import PasswordField from './password-field'
|
import PasswordField from '../shared/password-field'
|
||||||
import SettingsButton from '../settings-button'
|
import SettingsButton from '../shared/settings-button'
|
||||||
|
|
||||||
import styles from '../../../styles'
|
import styles from '../../../styles'
|
||||||
import settings from '../../../i18n/en/settings'
|
import settings from '../../../i18n/en/settings'
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { View, ScrollView } from 'react-native'
|
import { ScrollView } from 'react-native'
|
||||||
import CreatePassword from './create'
|
import CreatePassword from './create'
|
||||||
import ChangePassword from './update'
|
import ChangePassword from './update'
|
||||||
import DeletePassword from './delete'
|
import DeletePassword from './delete'
|
||||||
import SettingsSegment from '../settings-segment'
|
import SettingsSegment from '../shared/settings-segment'
|
||||||
import AppText from '../../app-text'
|
import AppText from '../../app-text'
|
||||||
import {
|
import {
|
||||||
hasEncryptionObservable
|
hasEncryptionObservable
|
||||||
@@ -14,33 +14,54 @@ export default class PasswordSetting extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
showUpdateAndDelete: hasEncryptionObservable.value,
|
isPasswordSet: hasEncryptionObservable.value,
|
||||||
showCreate: !hasEncryptionObservable.value
|
isChangingPassword: false,
|
||||||
|
isDeletingPassword: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onChangingPassword = () => {
|
||||||
|
this.setState({ isChangingPassword: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeletingPassword = () => {
|
||||||
|
this.setState({ isDeletingPassword: true })
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
|
const {
|
||||||
|
isPasswordSet,
|
||||||
|
isChangingPassword,
|
||||||
|
isDeletingPassword,
|
||||||
|
} = this.state
|
||||||
|
|
||||||
|
const {
|
||||||
|
title,
|
||||||
|
explainerEnabled,
|
||||||
|
explainerDisabled
|
||||||
|
} = labels.passwordSettings
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<SettingsSegment title={labels.passwordSettings.title}>
|
<SettingsSegment title={title}>
|
||||||
|
<AppText>
|
||||||
|
{ isPasswordSet ? explainerEnabled : explainerDisabled }
|
||||||
|
</AppText>
|
||||||
|
|
||||||
{this.state.showUpdateAndDelete ?
|
{ !isPasswordSet && <CreatePassword/> }
|
||||||
<AppText>{labels.passwordSettings.explainerEnabled}</AppText>
|
|
||||||
:
|
|
||||||
<AppText>{labels.passwordSettings.explainerDisabled}</AppText>
|
|
||||||
}
|
|
||||||
|
|
||||||
{this.state.showUpdateAndDelete &&
|
{ (isPasswordSet && !isDeletingPassword) && (
|
||||||
<View>
|
<ChangePassword
|
||||||
<ChangePassword/>
|
onStartChangingPassword = {this.onChangingPassword}
|
||||||
<DeletePassword/>
|
/>
|
||||||
</View>
|
)}
|
||||||
}
|
|
||||||
|
|
||||||
{this.state.showCreate &&
|
|
||||||
<CreatePassword/>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
{ (isPasswordSet && !isChangingPassword) && (
|
||||||
|
<DeletePassword
|
||||||
|
onStartDeletingPassword = {this.onDeletingPassword}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</SettingsSegment>
|
</SettingsSegment>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { View } from 'react-native'
|
|
||||||
import nodejs from 'nodejs-mobile-react-native'
|
|
||||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
|
||||||
import settings from '../../../i18n/en/settings'
|
import settings from '../../../i18n/en/settings'
|
||||||
import { requestHash } from '../../../db'
|
|
||||||
import EnterNewPassword from './enter-new-password'
|
import EnterNewPassword from './enter-new-password'
|
||||||
import PasswordField from './password-field'
|
import SettingsButton from '../shared/settings-button'
|
||||||
import SettingsButton from '../settings-button'
|
|
||||||
import showBackUpReminder from './show-backup-reminder'
|
import showBackUpReminder from './show-backup-reminder'
|
||||||
import checkCurrentPassword from './check-current-password'
|
import ConfirmWithPassword from '../shared/confirm-with-password'
|
||||||
|
|
||||||
|
|
||||||
export default class ChangePassword extends Component {
|
export default class ChangePassword extends Component {
|
||||||
@@ -19,49 +14,29 @@ export default class ChangePassword extends Component {
|
|||||||
enteringCurrentPassword: false,
|
enteringCurrentPassword: false,
|
||||||
enteringNewPassword: false
|
enteringNewPassword: false
|
||||||
}
|
}
|
||||||
|
|
||||||
nodejs.channel.addListener(
|
|
||||||
'pre-change-pw-check',
|
|
||||||
this.openNewPasswordField,
|
|
||||||
this
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
nodejs.channel.removeListener('pre-change-pw-check', this.openNewPasswordField)
|
|
||||||
}
|
|
||||||
|
|
||||||
openNewPasswordField = async hash => {
|
|
||||||
const passwordCorrect = await checkCurrentPassword({
|
|
||||||
hash,
|
|
||||||
onTryAgain: () => this.setState({ currentPassword: null }),
|
|
||||||
onCancel: () => this.setState({
|
|
||||||
enteringCurrentPassword: false,
|
|
||||||
currentPassword: null
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if (passwordCorrect) {
|
|
||||||
this.setState({
|
|
||||||
currentPassword: null,
|
|
||||||
enteringNewPassword: true,
|
|
||||||
enteringCurrentPassword: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startChangingPassword = () => {
|
startChangingPassword = () => {
|
||||||
showBackUpReminder(() => {
|
showBackUpReminder(() => {
|
||||||
this.setState({ enteringCurrentPassword: true })
|
this.setState({ enteringCurrentPassword: true })
|
||||||
})
|
})
|
||||||
|
this.props.onStartChangingPassword()
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCurrentPasswordInput = (currentPassword) => {
|
startEnteringNewPassword = () => {
|
||||||
this.setState({ currentPassword })
|
this.setState({
|
||||||
|
currentPassword: null,
|
||||||
|
enteringNewPassword: true,
|
||||||
|
enteringCurrentPassword: false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
checkCurrentPassword = () => {
|
cancelConfirmationWithPassword = () => {
|
||||||
requestHash('pre-change-pw-check', this.state.currentPassword)
|
this.setState({
|
||||||
|
currentPassword: null,
|
||||||
|
enteringNewPassword: false,
|
||||||
|
enteringCurrentPassword: false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -76,19 +51,10 @@ export default class ChangePassword extends Component {
|
|||||||
|
|
||||||
if (enteringCurrentPassword) {
|
if (enteringCurrentPassword) {
|
||||||
return (
|
return (
|
||||||
<View>
|
<ConfirmWithPassword
|
||||||
<PasswordField
|
onSuccess={this.startEnteringNewPassword}
|
||||||
placeholder={labels.enterCurrent}
|
onCancel={this.cancelConfirmationWithPassword}
|
||||||
value={currentPassword}
|
/>
|
||||||
onChangeText={this.handleCurrentPasswordInput}
|
|
||||||
/>
|
|
||||||
<SettingsButton
|
|
||||||
onPress={this.checkCurrentPassword}
|
|
||||||
disabled={!currentPassword}
|
|
||||||
>
|
|
||||||
{sharedLabels.unlock}
|
|
||||||
</SettingsButton>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,14 +63,12 @@ export default class ChangePassword extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<SettingsButton
|
||||||
<SettingsButton
|
onPress={this.startChangingPassword}
|
||||||
onPress={this.startChangingPassword}
|
disabled={currentPassword}
|
||||||
disabled={currentPassword}
|
>
|
||||||
>
|
{labels.changePassword}
|
||||||
{labels.changePassword}
|
</SettingsButton>
|
||||||
</SettingsButton>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,12 @@ import React, { Component } from 'react'
|
|||||||
import {
|
import {
|
||||||
ScrollView,
|
ScrollView,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
|
import SettingsSegment from '../shared/settings-segment'
|
||||||
import TempReminderPicker from './temp-reminder-picker'
|
import TempReminderPicker from './temp-reminder-picker'
|
||||||
import PeriodReminderPicker from './period-reminder'
|
import PeriodReminderPicker from './period-reminder'
|
||||||
|
|
||||||
|
import labels from '../../../i18n/en/settings'
|
||||||
|
|
||||||
export default class Settings extends Component {
|
export default class Settings extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
@@ -14,8 +17,12 @@ export default class Settings extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<TempReminderPicker/>
|
<SettingsSegment title={labels.tempReminder.title}>
|
||||||
<PeriodReminderPicker/>
|
<TempReminderPicker/>
|
||||||
|
</SettingsSegment>
|
||||||
|
<SettingsSegment title={labels.periodReminder.title}>
|
||||||
|
<PeriodReminderPicker/>
|
||||||
|
</SettingsSegment>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
periodReminderObservable,
|
periodReminderObservable,
|
||||||
savePeriodReminder
|
savePeriodReminder
|
||||||
} from '../../../local-storage'
|
} from '../../../local-storage'
|
||||||
import styles from '../../../styles/index'
|
|
||||||
import labels from '../../../i18n/en/settings'
|
import labels from '../../../i18n/en/settings'
|
||||||
|
|
||||||
export default class PeriodReminderPicker extends Component {
|
export default class PeriodReminderPicker extends Component {
|
||||||
@@ -19,22 +18,17 @@ export default class PeriodReminderPicker extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.settingsSegment}>
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
<AppText style={styles.settingsSegmentTitle}>
|
<View style={{ flex: 1 }}>
|
||||||
{labels.periodReminder.title}
|
<AppText>{labels.periodReminder.reminderText}</AppText>
|
||||||
</AppText>
|
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
||||||
<View style={{ flex: 1 }}>
|
|
||||||
<AppText>{labels.periodReminder.reminderText}</AppText>
|
|
||||||
</View>
|
|
||||||
<Switch
|
|
||||||
value={this.state.enabled}
|
|
||||||
onValueChange={switchOn => {
|
|
||||||
this.setState({ enabled: switchOn })
|
|
||||||
savePeriodReminder({enabled: switchOn})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
|
<Switch
|
||||||
|
value={this.state.enabled}
|
||||||
|
onValueChange={switchOn => {
|
||||||
|
this.setState({ enabled: switchOn })
|
||||||
|
savePeriodReminder({enabled: switchOn})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,64 +10,63 @@ import {
|
|||||||
tempReminderObservable,
|
tempReminderObservable,
|
||||||
saveTempReminder
|
saveTempReminder
|
||||||
} from '../../../local-storage'
|
} from '../../../local-storage'
|
||||||
import styles from '../../../styles/index'
|
|
||||||
import labels from '../../../i18n/en/settings'
|
import labels from '../../../i18n/en/settings'
|
||||||
import padWithZeros from '../../helpers/pad-time-with-zeros'
|
import padWithZeros from '../../helpers/pad-time-with-zeros'
|
||||||
|
|
||||||
export default class TempReminderPicker extends Component {
|
export default class TempReminderPicker extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = Object.assign({}, tempReminderObservable.value)
|
const { time, enabled } = tempReminderObservable.value
|
||||||
|
this.state = {
|
||||||
|
time,
|
||||||
|
enabled,
|
||||||
|
isTimePickerVisible: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.settingsSegment}
|
style={{ flexDirection: 'row', alignItems: 'center' }}
|
||||||
onPress={() => this.setState({ isTimePickerVisible: true })}
|
onPress={() => this.setState({ isTimePickerVisible: true })}
|
||||||
>
|
>
|
||||||
<AppText style={styles.settingsSegmentTitle}>
|
<View style={{ flex: 1 }}>
|
||||||
{labels.tempReminder.title}
|
{this.state.time && this.state.enabled ?
|
||||||
</AppText>
|
<AppText>{labels.tempReminder.timeSet(this.state.time)}</AppText>
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
:
|
||||||
<View style={{ flex: 1 }}>
|
<AppText>{labels.tempReminder.noTimeSet}</AppText>
|
||||||
{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)
|
|
||||||
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>
|
</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)
|
||||||
|
this.setState({
|
||||||
|
time,
|
||||||
|
isTimePickerVisible: false,
|
||||||
|
enabled: true
|
||||||
|
})
|
||||||
|
saveTempReminder({
|
||||||
|
time,
|
||||||
|
enabled: true
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
onCancel={() => {
|
||||||
|
this.setState({ isTimePickerVisible: false })
|
||||||
|
if (!this.state.time) this.setState({enabled: false})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Alert } from 'react-native'
|
import { Alert } from 'react-native'
|
||||||
import { shared as sharedLabels } from '../../i18n/en/labels'
|
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
||||||
|
|
||||||
export default function alertError(msg) {
|
export default function alertError(msg) {
|
||||||
Alert.alert(sharedLabels.errorTitle, msg)
|
Alert.alert(sharedLabels.errorTitle, msg)
|
||||||
+3
-3
@@ -4,8 +4,8 @@ import { View, Alert } from 'react-native'
|
|||||||
import nodejs from 'nodejs-mobile-react-native'
|
import nodejs from 'nodejs-mobile-react-native'
|
||||||
import { requestHash, openDb } from '../../../db'
|
import { requestHash, openDb } from '../../../db'
|
||||||
|
|
||||||
import PasswordField from '../password/password-field'
|
import PasswordField from './password-field'
|
||||||
import SettingsButton from '../settings-button'
|
import SettingsButton from '../shared/settings-button'
|
||||||
|
|
||||||
import settings from '../../../i18n/en/settings'
|
import settings from '../../../i18n/en/settings'
|
||||||
import { shared } from '../../../i18n/en/labels'
|
import { shared } from '../../../i18n/en/labels'
|
||||||
@@ -79,7 +79,7 @@ export default class ConfirmWithPassword extends Component {
|
|||||||
onPress={this.initPasswordCheck}
|
onPress={this.initPasswordCheck}
|
||||||
disabled={!password}
|
disabled={!password}
|
||||||
>
|
>
|
||||||
{settings.deleteSegment.title}
|
{shared.confirmToProceed}
|
||||||
</SettingsButton>
|
</SettingsButton>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
+2
-2
@@ -2,8 +2,8 @@ import React from 'react'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
import { TouchableOpacity } from 'react-native'
|
import { TouchableOpacity } from 'react-native'
|
||||||
import AppText from '../app-text'
|
import AppText from '../../app-text'
|
||||||
import styles from '../../styles'
|
import styles from '../../../styles'
|
||||||
|
|
||||||
const SettingsButton = ({ children, ...props }) => {
|
const SettingsButton = ({ children, ...props }) => {
|
||||||
return (
|
return (
|
||||||
+8
-5
@@ -2,22 +2,25 @@ import React from 'react'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
import { View } from 'react-native'
|
import { View } from 'react-native'
|
||||||
import AppText from '../app-text'
|
import AppText from '../../app-text'
|
||||||
import styles from '../../styles'
|
import styles from '../../../styles'
|
||||||
|
|
||||||
const SettingsSegment = ({ children, ...props }) => {
|
const SettingsSegment = ({ children, ...props }) => {
|
||||||
const style = [styles.settingsSegment, props.style]
|
const style = [styles.settingsSegment, props.style]
|
||||||
if (props.last) style.push(styles.settingsSegmentLast)
|
if (props.last) style.push(styles.settingsSegmentLast)
|
||||||
return (
|
return (
|
||||||
<View style={style}>
|
<View style={[styles.settingsSegment, props.style]}>
|
||||||
<AppText style={styles.settingsSegmentTitle}>{props.title}</AppText>
|
{
|
||||||
|
props.title
|
||||||
|
&& <AppText style={styles.settingsSegmentTitle}>{props.title}</AppText>
|
||||||
|
}
|
||||||
{children}
|
{children}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSegment.propTypes = {
|
SettingsSegment.propTypes = {
|
||||||
title: PropTypes.string.isRequired
|
title: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SettingsSegment
|
export default SettingsSegment
|
||||||
+1
-1
@@ -11,7 +11,7 @@ export const shared = {
|
|||||||
incorrectPasswordMessage: 'That password is incorrect.',
|
incorrectPasswordMessage: 'That password is incorrect.',
|
||||||
tryAgain: 'Try again',
|
tryAgain: 'Try again',
|
||||||
ok: 'OK',
|
ok: 'OK',
|
||||||
unlock: 'Unlock',
|
confirmToProceed: 'Confirm to proceed',
|
||||||
date: 'Date',
|
date: 'Date',
|
||||||
cycleDayWithLinebreak: 'Cycle\nday',
|
cycleDayWithLinebreak: 'Cycle\nday',
|
||||||
loading: 'Loading ...',
|
loading: 'Loading ...',
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {tempReminderObservable, periodReminderObservable} from '../local-storage
|
|||||||
import Notification from 'react-native-push-notification'
|
import Notification from 'react-native-push-notification'
|
||||||
import { LocalDate } from 'js-joda'
|
import { LocalDate } from 'js-joda'
|
||||||
import Moment from 'moment'
|
import Moment from 'moment'
|
||||||
import { settings as labels } from '../i18n/en/settings'
|
import labels from '../i18n/en/settings'
|
||||||
import { getBleedingDaysSortedByDate } from '../db'
|
import { getBleedingDaysSortedByDate } from '../db'
|
||||||
import cycleModule from './cycle'
|
import cycleModule from './cycle'
|
||||||
import nothingChanged from '../db/db-unchanged'
|
import nothingChanged from '../db/db-unchanged'
|
||||||
|
|||||||
Reference in New Issue
Block a user