merges master into branch
This commit is contained in:
+19
-5
@@ -9,9 +9,20 @@ import symptomViews from './cycle-day/symptoms'
|
||||
import Chart from './chart/chart'
|
||||
import Settings from './settings'
|
||||
import Stats from './stats'
|
||||
import {headerTitles as titles} from './labels'
|
||||
import {headerTitles, menuTitles} from './labels'
|
||||
import setupNotifications from '../lib/notifications'
|
||||
|
||||
// design wants everyhting lowercased, but we don't
|
||||
// have CSS pseudo properties
|
||||
const headerTitlesLowerCase = Object.keys(headerTitles).reduce((acc, curr) => {
|
||||
acc[curr] = headerTitles[curr].toLowerCase()
|
||||
return acc
|
||||
}, {})
|
||||
const menuTitlesLowerCase = Object.keys(menuTitles).reduce((acc, curr) => {
|
||||
acc[curr] = menuTitles[curr].toLowerCase()
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const isSymptomView = name => Object.keys(symptomViews).indexOf(name) > -1
|
||||
|
||||
export default class App extends Component {
|
||||
@@ -55,25 +66,28 @@ export default class App extends Component {
|
||||
}[this.state.currentPage]
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
|
||||
{this.state.currentPage != 'CycleDay' && !isSymptomView(this.state.currentPage) &&
|
||||
<Header
|
||||
title={titles[this.state.currentPage]}
|
||||
title={headerTitlesLowerCase[this.state.currentPage]}
|
||||
/>}
|
||||
{isSymptomView(this.state.currentPage) &&
|
||||
<Header
|
||||
title={titles[this.state.currentPage]}
|
||||
title={headerTitlesLowerCase[this.state.currentPage]}
|
||||
isSymptomView={true}
|
||||
goBack={this.handleBackButtonPress}
|
||||
/>}
|
||||
|
||||
|
||||
{React.createElement(page, {
|
||||
navigate: this.navigate,
|
||||
...this.state.currentProps
|
||||
})}
|
||||
|
||||
{!isSymptomView(this.state.currentPage) &&
|
||||
<Menu navigate={this.navigate} />
|
||||
<Menu
|
||||
navigate={this.navigate}
|
||||
titles={menuTitlesLowerCase}
|
||||
/>
|
||||
}
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -10,6 +10,7 @@ import styles from './styles'
|
||||
import { scaleObservable } from '../../local-storage'
|
||||
import config from '../../config'
|
||||
import { AppText } from '../app-text'
|
||||
import { shared as labels } from '../labels'
|
||||
|
||||
export default class CycleChart extends Component {
|
||||
constructor(props) {
|
||||
@@ -111,7 +112,7 @@ export default class CycleChart extends Component {
|
||||
(cycleDay.cervix.opening + cycleDay.cervix.firmness)
|
||||
} else if (symptom === 'sex') {
|
||||
// solo = 1 + partner = 2
|
||||
acc.sex = cycleDay.sex && (cycleDay.sex.solo + cycleDay.sex.partner)
|
||||
acc.sex = cycleDay.sex && (cycleDay.sex.solo + 2 * cycleDay.sex.partner)
|
||||
} else if (symptom === 'pain') {
|
||||
// is any pain documented?
|
||||
acc.pain = cycleDay.pain &&
|
||||
@@ -144,20 +145,33 @@ export default class CycleChart extends Component {
|
||||
>
|
||||
{!this.state.chartLoaded &&
|
||||
<View style={{width: '100%', justifyContent: 'center', alignItems: 'center'}}>
|
||||
<AppText>Loading...</AppText>
|
||||
<AppText>{labels.loading}</AppText>
|
||||
</View>
|
||||
}
|
||||
|
||||
{this.state.chartHeight && this.state.chartLoaded &&
|
||||
<View
|
||||
style={[styles.yAxis, {
|
||||
height: this.columnHeight,
|
||||
marginTop: this.symptomRowHeight
|
||||
}]}
|
||||
>
|
||||
{makeYAxisLabels(this.columnHeight)}
|
||||
<View>
|
||||
<View style={[styles.yAxis, {height: this.symptomRowHeight}]}>
|
||||
{this.symptomRowSymptoms.map(symptomName => {
|
||||
return <View key={symptomName} style={{flex: 1}}>
|
||||
<AppText>{symptomName[0]}</AppText>
|
||||
</View>
|
||||
})}
|
||||
</View>
|
||||
<View style={[styles.yAxis, {height: this.columnHeight}]}>
|
||||
{makeYAxisLabels(this.columnHeight)}
|
||||
</View>
|
||||
<View style={[styles.yAxis, {height: this.xAxisHeight}]}>
|
||||
<AppText style = {[styles.column.label.number, styles.yAxisLabels.cycleDayLabel]}>
|
||||
{labels.cycleDayWithLinebreak}
|
||||
</AppText>
|
||||
<AppText style={[styles.column.label.date,styles.yAxisLabels.dateLabel]}>
|
||||
{labels.date}
|
||||
</AppText>
|
||||
</View>
|
||||
</View>}
|
||||
|
||||
|
||||
{this.state.chartHeight && this.state.chartLoaded &&
|
||||
makeHorizontalGrid(this.columnHeight, this.symptomRowHeight)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ import {
|
||||
Text, View, TouchableOpacity
|
||||
} from 'react-native'
|
||||
import Svg,{ G, Rect, Line } from 'react-native-svg'
|
||||
import Icon from 'react-native-vector-icons/Entypo'
|
||||
import { LocalDate } from 'js-joda'
|
||||
import moment from 'moment'
|
||||
import styles from './styles'
|
||||
import config from '../../config'
|
||||
import { getOrCreateCycleDay } from '../../db'
|
||||
@@ -88,13 +89,18 @@ export default class DayColumn extends Component {
|
||||
}
|
||||
|
||||
const cycleDayNumber = this.getCycleDayNumber(dateString)
|
||||
const shortDate = dateString.split('-').slice(1).join('-')
|
||||
const dayDate = LocalDate.parse(dateString)
|
||||
const shortDate = dayDate.dayOfMonth() === 1 ?
|
||||
moment(dateString, "YYYY-MM-DD").format('MMM')
|
||||
:
|
||||
moment(dateString, "YYYY-MM-DD").format('Do')
|
||||
const boldDateLabel = dayDate.dayOfMonth() === 1 ? {fontWeight: 'bold'} : {}
|
||||
const cycleDayLabel = (
|
||||
<Text style = {label.number}>
|
||||
{cycleDayNumber ? cycleDayNumber : ' '}
|
||||
</Text>)
|
||||
const dateLabel = (
|
||||
<Text style = {label.date}>
|
||||
<Text style = {[label.date, boldDateLabel]}>
|
||||
{shortDate}
|
||||
</Text>
|
||||
)
|
||||
@@ -116,10 +122,9 @@ export default class DayColumn extends Component {
|
||||
symptomHeight={symptomHeight}
|
||||
key='bleeding'
|
||||
>
|
||||
<Icon
|
||||
name='drop'
|
||||
size={12}
|
||||
color={styles.bleedingIconShades[this.props.bleeding]}
|
||||
<View
|
||||
{...styles.symptomIcon}
|
||||
backgroundColor={styles.iconShades.bleeding[this.props.bleeding]}
|
||||
/>
|
||||
</SymptomIconView>
|
||||
),
|
||||
@@ -130,8 +135,8 @@ export default class DayColumn extends Component {
|
||||
key='mucus'
|
||||
>
|
||||
<View
|
||||
{...styles.mucusIcon}
|
||||
backgroundColor={styles.mucusIconShades[this.props.mucus]}
|
||||
{...styles.symptomIcon}
|
||||
backgroundColor={styles.iconShades.mucus[this.props.mucus]}
|
||||
/>
|
||||
</SymptomIconView>
|
||||
),
|
||||
@@ -142,9 +147,9 @@ export default class DayColumn extends Component {
|
||||
key='cervix'
|
||||
>
|
||||
<View
|
||||
{...styles.mucusIcon}
|
||||
{...styles.symptomIcon}
|
||||
// cervix is sum of openess and firmness - fertile only when closed and hard (=0)
|
||||
backgroundColor={this.props.cervix > 0 ? 'blue' : 'green'}
|
||||
backgroundColor={this.props.cervix > 0 ? styles.iconShades.cervix[2] : styles.iconShades.cervix[0]}
|
||||
/>
|
||||
</SymptomIconView>
|
||||
),
|
||||
@@ -155,8 +160,8 @@ export default class DayColumn extends Component {
|
||||
key='sex'
|
||||
>
|
||||
<View
|
||||
{...styles.mucusIcon}
|
||||
backgroundColor='orange'
|
||||
{...styles.symptomIcon}
|
||||
backgroundColor={styles.iconShades.sex[this.props.sex - 1]}
|
||||
/>
|
||||
</SymptomIconView>
|
||||
),
|
||||
@@ -167,8 +172,8 @@ export default class DayColumn extends Component {
|
||||
key='desire'
|
||||
>
|
||||
<View
|
||||
{...styles.mucusIcon}
|
||||
backgroundColor='red'
|
||||
{...styles.symptomIcon}
|
||||
backgroundColor={styles.iconShades.desire[this.props.desire]}
|
||||
/>
|
||||
</SymptomIconView>
|
||||
),
|
||||
@@ -179,8 +184,8 @@ export default class DayColumn extends Component {
|
||||
key='pain'
|
||||
>
|
||||
<View
|
||||
{...styles.mucusIcon}
|
||||
backgroundColor='blue'
|
||||
{...styles.symptomIcon}
|
||||
backgroundColor={styles.iconShades.pain}
|
||||
/>
|
||||
</SymptomIconView>
|
||||
),
|
||||
@@ -191,8 +196,8 @@ export default class DayColumn extends Component {
|
||||
key='note'
|
||||
>
|
||||
<View
|
||||
{...styles.mucusIcon}
|
||||
backgroundColor='green'
|
||||
{...styles.symptomIcon}
|
||||
backgroundColor={styles.iconShades.note}
|
||||
/>
|
||||
</SymptomIconView>
|
||||
)
|
||||
|
||||
+50
-23
@@ -8,6 +8,7 @@ const lineWidth = 1.5
|
||||
const colorLtl = '#feb47b'
|
||||
const gridColor = 'lightgrey'
|
||||
const gridLineWidth = 0.5
|
||||
const numberLabelFontSize = 13
|
||||
|
||||
const styles = {
|
||||
curve: {
|
||||
@@ -32,10 +33,11 @@ const styles = {
|
||||
color: 'grey',
|
||||
fontSize: 9,
|
||||
fontWeight: '100',
|
||||
textAlign: 'center',
|
||||
},
|
||||
number: {
|
||||
color: primaryColor,
|
||||
fontSize: 13,
|
||||
fontSize: numberLabelFontSize,
|
||||
textAlign: 'center',
|
||||
}
|
||||
},
|
||||
@@ -48,37 +50,62 @@ const styles = {
|
||||
fill: 'transparent'
|
||||
}
|
||||
},
|
||||
bleedingIcon: {
|
||||
fill: '#fb2e01',
|
||||
scale: 0.6,
|
||||
x: 6,
|
||||
y: 3
|
||||
},
|
||||
bleedingIconShades: shadesOfRed,
|
||||
mucusIcon: {
|
||||
symptomIcon: {
|
||||
width: 12,
|
||||
height: 12,
|
||||
borderRadius: 50,
|
||||
},
|
||||
mucusIconShades: [
|
||||
'#fef0e4',
|
||||
'#fee1ca',
|
||||
'#fed2af',
|
||||
'#fec395',
|
||||
'#feb47b'
|
||||
],
|
||||
iconShades: {
|
||||
'bleeding': shadesOfRed,
|
||||
'mucus': [
|
||||
'#e3e7ed',
|
||||
'#c8cfdc',
|
||||
'#acb8cb',
|
||||
'#91a0ba',
|
||||
'#7689a9'
|
||||
],
|
||||
'cervix': [
|
||||
'#f0e19d',
|
||||
'#e9d26d',
|
||||
'#e2c33c',
|
||||
'#dbb40c',
|
||||
],
|
||||
'sex': [
|
||||
'#a87ca2',
|
||||
'#8b5083',
|
||||
'#6f2565',
|
||||
],
|
||||
'desire': [
|
||||
'#c485a6',
|
||||
'#b15c89',
|
||||
'#9e346c',
|
||||
],
|
||||
'pain': ['#bccd67'],
|
||||
'note': ['#6CA299']
|
||||
},
|
||||
yAxis: {
|
||||
width: 27,
|
||||
borderRightWidth: 0.5,
|
||||
borderRightWidth: 1,
|
||||
borderColor: 'lightgrey',
|
||||
borderStyle: 'solid'
|
||||
},
|
||||
yAxisLabel: {
|
||||
position: 'absolute',
|
||||
left: 3,
|
||||
color: 'grey',
|
||||
fontSize: 11,
|
||||
textAlign: 'left'
|
||||
yAxisLabels: {
|
||||
tempScale: {
|
||||
position: 'absolute',
|
||||
right: 2,
|
||||
color: 'grey',
|
||||
fontSize: 9,
|
||||
textAlign: 'left'
|
||||
},
|
||||
cycleDayLabel: {
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: Math.ceil(numberLabelFontSize / 2)
|
||||
},
|
||||
dateLabel: {
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
},
|
||||
horizontalGrid: {
|
||||
position:'absolute',
|
||||
|
||||
@@ -8,7 +8,7 @@ import { AppText } from '../app-text'
|
||||
export function makeYAxisLabels(columnHeight) {
|
||||
const units = unitObservable.value
|
||||
const scaleMax = scaleObservable.value.max
|
||||
const style = styles.yAxisLabel
|
||||
const style = styles.yAxisLabels.tempScale
|
||||
|
||||
return getTickPositions(columnHeight).map((y, i) => {
|
||||
const tick = scaleMax - i * units
|
||||
@@ -17,10 +17,10 @@ export function makeYAxisLabels(columnHeight) {
|
||||
let tickBold
|
||||
if (units === 0.1) {
|
||||
showTick = (tick * 10 % 2) ? false : true
|
||||
tickBold = tick * 10 % 5 ? {} : {fontWeight: 'bold'}
|
||||
tickBold = tick * 10 % 5 ? {} : {fontWeight: 'bold', fontSize: 11}
|
||||
} else {
|
||||
showTick = (tick * 10 % 5) ? false : true
|
||||
tickBold = tick * 10 % 10 ? {} : {fontWeight: 'bold'}
|
||||
tickBold = tick * 10 % 10 ? {} : {fontWeight: 'bold', fontSize: 11}
|
||||
}
|
||||
// this eyeballing is sadly necessary because RN does not
|
||||
// support percentage values for transforms, which we'd need
|
||||
|
||||
@@ -6,13 +6,21 @@ import {
|
||||
Dimensions
|
||||
} from 'react-native'
|
||||
import { LocalDate } from 'js-joda'
|
||||
import Svg, { G } from 'react-native-svg'
|
||||
import Header from '../header'
|
||||
import { getOrCreateCycleDay } from '../../db'
|
||||
import cycleModule from '../../lib/cycle'
|
||||
import Icon from 'react-native-vector-icons/FontAwesome'
|
||||
import styles, { iconStyles } from '../../styles'
|
||||
import styles from '../../styles'
|
||||
import * as labels from './labels/labels'
|
||||
import { AppText } from '../app-text'
|
||||
import BleedingIcon from '../../assets/bleeding'
|
||||
import CervixIcon from '../../assets/cervix'
|
||||
import DesireIcon from '../../assets/desire'
|
||||
import MucusIcon from '../../assets/mucus'
|
||||
import NoteIcon from '../../assets/note'
|
||||
import PainIcon from '../../assets/pain'
|
||||
import SexIcon from '../../assets/sex'
|
||||
import TemperatureIcon from '../../assets/temperature'
|
||||
|
||||
const bleedingLabels = labels.bleeding
|
||||
const feelingLabels = labels.mucus.feeling.categories
|
||||
@@ -68,47 +76,64 @@ export default class CycleDayOverView extends Component {
|
||||
onPress={() => this.navigate('BleedingEditView')}
|
||||
data={getLabel('bleeding', cycleDay.bleeding)}
|
||||
disabled={dateInFuture}
|
||||
/>
|
||||
>
|
||||
<BleedingIcon viewBox='10 10 320 400' />
|
||||
</SymptomBox>
|
||||
<SymptomBox
|
||||
title='Temperature'
|
||||
onPress={() => this.navigate('TemperatureEditView')}
|
||||
data={getLabel('temperature', cycleDay.temperature)}
|
||||
disabled={dateInFuture}
|
||||
/>
|
||||
>
|
||||
<TemperatureIcon viewBox='10 10 320 400' />
|
||||
</SymptomBox>
|
||||
<SymptomBox
|
||||
title='Mucus'
|
||||
onPress={() => this.navigate('MucusEditView')}
|
||||
data={getLabel('mucus', cycleDay.mucus)}
|
||||
disabled={dateInFuture}
|
||||
/>
|
||||
>
|
||||
<MucusIcon viewBox='10 10 320 400' />
|
||||
</SymptomBox>
|
||||
<SymptomBox
|
||||
title='Cervix'
|
||||
onPress={() => this.navigate('CervixEditView')}
|
||||
data={getLabel('cervix', cycleDay.cervix)}
|
||||
disabled={dateInFuture}
|
||||
/>
|
||||
>
|
||||
<CervixIcon viewBox='10 10 320 440' />
|
||||
</SymptomBox>
|
||||
<SymptomBox
|
||||
title='Desire'
|
||||
onPress={() => this.navigate('DesireEditView')}
|
||||
data={getLabel('desire', cycleDay.desire)}
|
||||
disabled={dateInFuture}
|
||||
/>
|
||||
>
|
||||
<DesireIcon viewBox='10 10 320 380' />
|
||||
</SymptomBox>
|
||||
<SymptomBox
|
||||
title='Sex'
|
||||
onPress={() => this.navigate('SexEditView')}
|
||||
data={getLabel('sex', cycleDay.sex)}
|
||||
disabled={dateInFuture}
|
||||
/>
|
||||
>
|
||||
<SexIcon viewBox='10 10 320 400' />
|
||||
</SymptomBox>
|
||||
<SymptomBox
|
||||
title='Pain'
|
||||
onPress={() => this.navigate('PainEditView')}
|
||||
data={getLabel('pain', cycleDay.pain)}
|
||||
/>
|
||||
disabled={dateInFuture}
|
||||
>
|
||||
<PainIcon viewBox='10 10 300 400' />
|
||||
</SymptomBox>
|
||||
<SymptomBox
|
||||
title='Note'
|
||||
onPress={() => this.navigate('NoteEditView')}
|
||||
data={getLabel('note', cycleDay.note)}
|
||||
/>
|
||||
>
|
||||
<NoteIcon viewBox='10 10 270 400' />
|
||||
</SymptomBox>
|
||||
{/* this is just to make the last row adhere to the grid
|
||||
(and) because there are no pseudo properties in RN */}
|
||||
<FillerBoxes />
|
||||
@@ -221,10 +246,6 @@ class SymptomBox extends Component {
|
||||
render() {
|
||||
const d = this.props.data
|
||||
const boxActive = d ? styles.symptomBoxActive : {}
|
||||
const iconActive = d ? iconStyles.symptomBoxActive : {}
|
||||
const iconStyle = Object.assign(
|
||||
{}, iconStyles.symptomBox, iconActive, disabledStyle
|
||||
)
|
||||
const textActive = d ? styles.symptomTextActive : {}
|
||||
const disabledStyle = this.props.disabled ? styles.symptomInFuture : {}
|
||||
|
||||
@@ -234,10 +255,20 @@ class SymptomBox extends Component {
|
||||
disabled={this.props.disabled}
|
||||
>
|
||||
<View style={[styles.symptomBox, boxActive, disabledStyle]}>
|
||||
<Icon
|
||||
name='thermometer'
|
||||
{...iconStyle}
|
||||
/>
|
||||
|
||||
{this.props.children ?
|
||||
React.Children.map(this.props.children, child => {
|
||||
return (
|
||||
<Svg width={100} height={50} viewBox={child.props.viewBox}>
|
||||
<G fill={d ? 'white' : 'black'}>
|
||||
{child}
|
||||
</G>
|
||||
</Svg>
|
||||
)
|
||||
})
|
||||
: null
|
||||
}
|
||||
|
||||
<AppText style={[textActive, disabledStyle]}>
|
||||
{this.props.title}
|
||||
</AppText>
|
||||
|
||||
@@ -43,6 +43,8 @@ export const sex = {
|
||||
patch: 'Patch',
|
||||
ring: 'Ring',
|
||||
implant: 'Implant',
|
||||
diaphragm: 'Diaphragm',
|
||||
none: 'None',
|
||||
other: 'Other',
|
||||
activityExplainer: 'Were you sexually active today?',
|
||||
contraceptiveExplainer: 'Did you use contraceptives?'
|
||||
|
||||
@@ -53,7 +53,8 @@ export default class ActionButtonFooter extends Component {
|
||||
return (
|
||||
<View style={styles.menu}>
|
||||
{buttons.map(({ title, action, disabledCondition, icon }, i) => {
|
||||
const textStyle = disabledCondition ? styles.menuTextInActive : styles.menuText
|
||||
const textStyle = [styles.menuText]
|
||||
if (disabledCondition) textStyle.push(styles.menuTextInActive)
|
||||
const iconStyle = disabledCondition ?
|
||||
Object.assign({}, iconStyles.menuIcon, iconStyles.menuIconInactive) :
|
||||
iconStyles.menuIcon
|
||||
|
||||
@@ -37,6 +37,12 @@ const contraceptiveBoxes = [{
|
||||
}, {
|
||||
label: labels.implant,
|
||||
stateKey: 'implant'
|
||||
}, {
|
||||
label: labels.diaphragm,
|
||||
stateKey: 'diaphragm'
|
||||
}, {
|
||||
label: labels.none,
|
||||
stateKey: 'none'
|
||||
}, {
|
||||
label: labels.other,
|
||||
stateKey: 'other'
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { Component } from 'react'
|
||||
import {
|
||||
View,
|
||||
Text
|
||||
Text,
|
||||
Dimensions
|
||||
} from 'react-native'
|
||||
import styles, { iconStyles } from '../styles'
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||
@@ -10,9 +11,11 @@ import { formatDateForViewHeader } from '../components/cycle-day/labels/format'
|
||||
|
||||
export default class Header extends Component {
|
||||
render() {
|
||||
const middle = Dimensions.get('window').width / 2
|
||||
return (
|
||||
this.props.isCycleDayOverView ?
|
||||
<View style={[styles.header, styles.headerCycleDay]}>
|
||||
<View style={styles.accentCircle} left={middle - styles.accentCircle.width / 2}/>
|
||||
<Icon
|
||||
name='arrow-left-drop-circle'
|
||||
{...iconStyles.navigationArrow}
|
||||
@@ -35,6 +38,7 @@ export default class Header extends Component {
|
||||
</View >
|
||||
: this.props.isSymptomView ?
|
||||
<View style={[styles.header, styles.headerSymptom]}>
|
||||
<View style={styles.accentCircle} left={middle - styles.accentCircle.width / 2}/>
|
||||
<Icon
|
||||
name='keyboard-backspace'
|
||||
{...iconStyles.symptomHeaderIcons}
|
||||
@@ -53,7 +57,8 @@ export default class Header extends Component {
|
||||
</View>
|
||||
:
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.dateHeader}>
|
||||
<View style={styles.accentCircle} />
|
||||
<Text style={styles.headerText}>
|
||||
{this.props.title}
|
||||
</Text>
|
||||
</View >
|
||||
|
||||
+17
-1
@@ -8,7 +8,10 @@ export const shared = {
|
||||
incorrectPasswordMessage: 'That password is incorrect.',
|
||||
tryAgain: 'Try again',
|
||||
ok: 'OK',
|
||||
unlock: 'Unlock'
|
||||
unlock: 'Unlock',
|
||||
date: 'Date',
|
||||
cycleDayWithLinebreak: 'Cycle\nday',
|
||||
loading: 'Loading ...'
|
||||
}
|
||||
|
||||
export const settings = {
|
||||
@@ -54,6 +57,11 @@ export const settings = {
|
||||
timeSet: time => `Daily reminder set for ${time}`,
|
||||
notification: 'Record your morning temperature'
|
||||
},
|
||||
periodReminder: {
|
||||
title: 'Next period reminder',
|
||||
reminderText: 'Get a notification 3 days before your next period is likely to start.',
|
||||
notification: daysToEndOfPrediction => `Your next period is likely to start in 3 to ${daysToEndOfPrediction} days.`
|
||||
},
|
||||
passwordSettings: {
|
||||
title: 'App password',
|
||||
explainerDisabled: "Encrypt the app's database with a password. You need to enter the password every time the app is started.",
|
||||
@@ -86,6 +94,14 @@ export const headerTitles = {
|
||||
PainEditView: 'Pain'
|
||||
}
|
||||
|
||||
export const menuTitles = {
|
||||
Home: 'Home',
|
||||
Calendar: 'Calendar',
|
||||
Chart: 'Chart',
|
||||
Stats: 'Stats',
|
||||
Settings: 'Settings',
|
||||
}
|
||||
|
||||
export const stats = {
|
||||
cycleLengthTitle: 'Cycle length',
|
||||
cycleLengthExplainer: 'Basic statistics about the length of your cycles.',
|
||||
|
||||
+6
-5
@@ -28,14 +28,15 @@ export default class Menu extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const t = this.props.titles
|
||||
return (
|
||||
<View style={styles.menu}>
|
||||
{[
|
||||
{ title: 'Home', icon: 'home', onPress: () => this.goTo('Home') },
|
||||
{ title: 'Calendar', icon: 'calendar-range', onPress: () => this.goTo('Calendar') },
|
||||
{ title: 'Chart', icon: 'chart-line', onPress: () => this.goTo('Chart') },
|
||||
{ title: 'Stats', icon: 'chart-pie', onPress: () => this.goTo('Stats') },
|
||||
{ title: 'Settings', icon: 'settings', onPress: () => this.goTo('Settings') },
|
||||
{ title: t.Home, icon: 'home', onPress: () => this.goTo('Home') },
|
||||
{ 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') },
|
||||
].map(this.makeMenuItem)}
|
||||
</View >
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ import styles from '../../styles/index'
|
||||
import { settings as labels } from '../labels'
|
||||
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'
|
||||
@@ -30,6 +31,7 @@ export default class Settings extends Component {
|
||||
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
||||
<TempSlider/>
|
||||
</View>
|
||||
<PeriodReminderPicker/>
|
||||
<PasswordSetting />
|
||||
<View style={styles.settingsSegment}>
|
||||
<AppText style={styles.settingsSegmentTitle}>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import React, { Component } from 'react'
|
||||
import {
|
||||
View,
|
||||
Switch
|
||||
} from 'react-native'
|
||||
import { AppText } from '../app-text'
|
||||
import {
|
||||
periodReminderObservable,
|
||||
savePeriodReminder
|
||||
} from '../../local-storage'
|
||||
import styles from '../../styles/index'
|
||||
import { settings as labels } from '../labels'
|
||||
|
||||
export default class PeriodReminderPicker extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = periodReminderObservable.value
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.settingsSegment}>
|
||||
<AppText style={styles.settingsSegmentTitle}>
|
||||
{labels.periodReminder.title}
|
||||
</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>
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user