Merge branch 'master' into link-nfp-rules
This commit is contained in:
@@ -13,14 +13,6 @@ export default function AppText(props) {
|
||||
)
|
||||
}
|
||||
|
||||
export function AppTextLight(props) {
|
||||
return (
|
||||
<Text style={[styles.appTextLight, props.style]}>
|
||||
{props.children}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
export function ActionHint(props) {
|
||||
if(props.isVisible) {
|
||||
return (
|
||||
|
||||
+79
-37
@@ -11,6 +11,7 @@ import SettingsMenu from './settings/settings-menu'
|
||||
import settingsViews from './settings'
|
||||
import Stats from './stats'
|
||||
import {headerTitles, menuTitles} from '../i18n/en/labels'
|
||||
import InfoSymptom from './cycle-day/symptoms/info-symptom'
|
||||
import setupNotifications from '../lib/notifications'
|
||||
|
||||
// design wants everyhting lowercased, but we don't
|
||||
@@ -19,20 +20,17 @@ 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).includes(name)
|
||||
const isSettingsView = name => Object.keys(settingsViews).includes(name)
|
||||
const isMenuItem = name => Object.keys(menuTitles).includes(name)
|
||||
const HOME_PAGE = 'Home'
|
||||
const INFO_SYMPTOM_PAGE = 'InfoSymptom'
|
||||
const CYCLE_DAY_PAGE = 'CycleDay'
|
||||
const SETTINGS_MENU_PAGE = 'SettingsMenu'
|
||||
|
||||
export default class App extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
currentPage: 'Home'
|
||||
currentPage: HOME_PAGE
|
||||
}
|
||||
this.backHandler = BackHandler.addEventListener('hardwareBackPress', this.handleBackButtonPress)
|
||||
setupNotifications(this.navigate)
|
||||
@@ -43,63 +41,107 @@ export default class App extends Component {
|
||||
}
|
||||
|
||||
navigate = (pageName, props) => {
|
||||
const { currentPage } = this.state
|
||||
// for the back button to work properly, we want to
|
||||
// remember two origins: which menu item we came from
|
||||
// and from where we navigated to the symptom view (day
|
||||
// view or home page)
|
||||
if (isMenuItem(this.state.currentPage)) {
|
||||
this.menuOrigin = this.state.currentPage
|
||||
if (this.isMenuItem()) {
|
||||
this.menuOrigin = currentPage
|
||||
}
|
||||
this.originForSymptomView = this.state.currentPage
|
||||
this.setState({currentPage: pageName, currentProps: props})
|
||||
if (!this.isSymptomView() && !this.isInfoSymptomView()) {
|
||||
this.originForSymptomView = currentPage
|
||||
}
|
||||
this.setState({ currentPage: pageName, currentProps: props })
|
||||
}
|
||||
|
||||
handleBackButtonPress = () => {
|
||||
if (this.state.currentPage === 'Home') return false
|
||||
if (isSymptomView(this.state.currentPage)) {
|
||||
const { currentPage, currentProps } = this.state
|
||||
if (currentPage === HOME_PAGE) return false
|
||||
if (this.isSymptomView()) {
|
||||
this.navigate(
|
||||
this.originForSymptomView, { date: this.state.currentProps.date }
|
||||
this.originForSymptomView, { date: currentProps.date }
|
||||
)
|
||||
} else if (isSettingsView(this.state.currentPage)) {
|
||||
this.navigate('SettingsMenu')
|
||||
} else if(this.state.currentPage === 'CycleDay') {
|
||||
} else if (this.isSettingsView()) {
|
||||
this.navigate(SETTINGS_MENU_PAGE)
|
||||
} else if (currentPage === CYCLE_DAY_PAGE) {
|
||||
this.navigate(this.menuOrigin)
|
||||
} else if (this.isInfoSymptomView()) {
|
||||
const { date, cycleDay, symptomView } = currentProps
|
||||
this.navigate(
|
||||
symptomView, { date, cycleDay })
|
||||
} else {
|
||||
this.navigate('Home')
|
||||
this.navigate(HOME_PAGE)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
isMenuItem() {
|
||||
return Object.keys(menuTitles).includes(this.state.currentPage)
|
||||
}
|
||||
|
||||
isSymptomView() {
|
||||
return Object.keys(symptomViews).includes(this.state.currentPage)
|
||||
}
|
||||
|
||||
isInfoSymptomView() {
|
||||
return this.state.currentPage === INFO_SYMPTOM_PAGE
|
||||
}
|
||||
|
||||
isSettingsView() {
|
||||
return Object.keys(settingsViews).includes(this.state.currentPage)
|
||||
}
|
||||
|
||||
isDefaultView() {
|
||||
const { currentPage } = this.state
|
||||
return currentPage !== CYCLE_DAY_PAGE &&
|
||||
!this.isSymptomView() &&
|
||||
!this.isInfoSymptomView()
|
||||
}
|
||||
|
||||
render() {
|
||||
const page = {
|
||||
Home, Calendar, CycleDay, Chart, SettingsMenu, ...settingsViews, Stats, ...symptomViews
|
||||
}[this.state.currentPage]
|
||||
const { currentPage, currentProps } = this.state
|
||||
const pages = {
|
||||
Home,
|
||||
Calendar,
|
||||
CycleDay,
|
||||
Chart,
|
||||
InfoSymptom,
|
||||
SettingsMenu,
|
||||
...settingsViews,
|
||||
Stats,
|
||||
...symptomViews
|
||||
}
|
||||
const page = pages[currentPage]
|
||||
const title = headerTitlesLowerCase[currentPage]
|
||||
const isSymptomView = this.isSymptomView()
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
{this.state.currentPage != 'CycleDay' && !isSymptomView(this.state.currentPage) &&
|
||||
{this.isDefaultView() &&
|
||||
<Header title={title} />
|
||||
}
|
||||
{this.isInfoSymptomView() &&
|
||||
<Header title={title} goBack={this.handleBackButtonPress} />
|
||||
}
|
||||
{isSymptomView &&
|
||||
<Header
|
||||
title={headerTitlesLowerCase[this.state.currentPage]}
|
||||
/>}
|
||||
{isSymptomView(this.state.currentPage) &&
|
||||
<Header
|
||||
title={headerTitlesLowerCase[this.state.currentPage]}
|
||||
title={title}
|
||||
isSymptomView={true}
|
||||
goBack={this.handleBackButtonPress}
|
||||
date={this.state.currentProps.date}
|
||||
date={currentProps.date}
|
||||
goToSymptomInfo={() => this.navigate(INFO_SYMPTOM_PAGE, {
|
||||
symptomView: currentPage,
|
||||
...currentProps
|
||||
})}
|
||||
/>}
|
||||
|
||||
|
||||
{React.createElement(page, {
|
||||
navigate: this.navigate,
|
||||
...this.state.currentProps
|
||||
...currentProps
|
||||
})}
|
||||
|
||||
{!isSymptomView(this.state.currentPage) &&
|
||||
<Menu
|
||||
navigate={this.navigate}
|
||||
titles={menuTitlesLowerCase}
|
||||
currentPage={this.state.currentPage}
|
||||
/>
|
||||
{!isSymptomView &&
|
||||
<Menu navigate={this.navigate} currentPage={currentPage} />
|
||||
}
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -23,6 +23,7 @@ const symptomIcons = {
|
||||
desire: <DripIcon size={16} name='drip-icon-desire' color={styles.iconShades.desire[2]}/>,
|
||||
sex: <DripIcon size={16} name='drip-icon-sex' color={styles.iconShades.sex[2]}/>,
|
||||
pain: <DripIcon size={16} name='drip-icon-pain' color={styles.iconShades.pain[0]}/>,
|
||||
mood: <DripIcon size={16} name='drip-icon-mood' color={styles.iconShades.mood[0]}/>,
|
||||
note: <DripIcon size={16} name='drip-icon-note' color={styles.iconShades.note[0]}/>
|
||||
}
|
||||
|
||||
@@ -62,6 +63,7 @@ export default class CycleChart extends Component {
|
||||
'sex',
|
||||
'desire',
|
||||
'pain',
|
||||
'mood',
|
||||
'note'
|
||||
].filter((symptomName) => {
|
||||
return this.cycleDaysSortedByDate.some(cycleDay => {
|
||||
|
||||
@@ -44,6 +44,10 @@ export default class DayColumn extends Component {
|
||||
// is any pain documented?
|
||||
acc.pain = cycleDay.pain &&
|
||||
Object.values(cycleDay.pain).some(x => x === true)
|
||||
} else if (symptom === 'mood') {
|
||||
// is mood documented?
|
||||
acc.mood = cycleDay.mood &&
|
||||
Object.values(cycleDay.mood).some(x => x === true)
|
||||
}
|
||||
acc[`${symptom}Exclude`] = cycleDay[symptom] && cycleDay[symptom].exclude
|
||||
return acc
|
||||
@@ -214,6 +218,18 @@ export default class DayColumn extends Component {
|
||||
/>
|
||||
</SymptomIconView>
|
||||
),
|
||||
mood: (
|
||||
<SymptomIconView
|
||||
value={this.data.mood}
|
||||
symptomHeight={symptomHeight}
|
||||
key='mood'
|
||||
>
|
||||
<View
|
||||
{...styles.symptomIcon}
|
||||
backgroundColor={styles.iconShades.mood}
|
||||
/>
|
||||
</SymptomIconView>
|
||||
),
|
||||
note: (
|
||||
<SymptomIconView
|
||||
value={this.data.note}
|
||||
|
||||
@@ -77,7 +77,8 @@ const styles = {
|
||||
'#9e346c',
|
||||
],
|
||||
'pain': ['#bccd67'],
|
||||
'note': ['#6CA299']
|
||||
'mood': ['#bc6642'],
|
||||
'note': ['#6ca299']
|
||||
},
|
||||
yAxis: {
|
||||
width: 27,
|
||||
|
||||
@@ -14,7 +14,7 @@ import * as labels from '../../i18n/en/cycle-day'
|
||||
import AppText from '../app-text'
|
||||
import DripIcon from '../../assets/drip-icons'
|
||||
|
||||
const bleedingLabels = labels.bleeding
|
||||
const bleedingLabels = labels.bleeding.labels
|
||||
const feelingLabels = labels.mucus.feeling.categories
|
||||
const textureLabels = labels.mucus.texture.categories
|
||||
const openingLabels = labels.cervix.opening.categories
|
||||
@@ -24,6 +24,7 @@ const intensityLabels = labels.intensity
|
||||
const sexLabels = labels.sex.categories
|
||||
const contraceptiveLabels = labels.contraceptives.categories
|
||||
const painLabels = labels.pain.categories
|
||||
const moodLabels = labels.mood.categories
|
||||
|
||||
export default class CycleDayOverView extends Component {
|
||||
constructor(props) {
|
||||
@@ -56,7 +57,7 @@ export default class CycleDayOverView extends Component {
|
||||
const l = {
|
||||
bleeding: bleeding => {
|
||||
if (isNumber(bleeding.value)) {
|
||||
let bleedingLabel = `${bleedingLabels[bleeding.value]}`
|
||||
let bleedingLabel = bleedingLabels[bleeding.value]
|
||||
if (bleeding.exclude) bleedingLabel = "( " + bleedingLabel + " )"
|
||||
return bleedingLabel
|
||||
}
|
||||
@@ -143,6 +144,25 @@ export default class CycleDayOverView extends Component {
|
||||
painLabel = painLabel.join(', ')
|
||||
return painLabel
|
||||
}
|
||||
},
|
||||
mood: mood => {
|
||||
let moodLabel = []
|
||||
if (mood && Object.values(mood).some(val => val)){
|
||||
Object.keys(mood).forEach(key => {
|
||||
if(mood[key] && key !== 'other' && key !== 'note') {
|
||||
moodLabel.push(moodLabels[key])
|
||||
}
|
||||
if(key === 'other' && mood.other) {
|
||||
let label = moodLabels[key]
|
||||
if(mood.note) {
|
||||
label = `${label} (${mood.note})`
|
||||
}
|
||||
moodLabel.push(label)
|
||||
}
|
||||
})
|
||||
moodLabel = moodLabel.join(', ')
|
||||
return moodLabel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +246,14 @@ export default class CycleDayOverView extends Component {
|
||||
iconName='drip-icon-pain'
|
||||
>
|
||||
</SymptomBox>
|
||||
<SymptomBox
|
||||
title='Mood'
|
||||
onPress={() => this.navigate('MoodEditView')}
|
||||
data={this.getLabel('mood')}
|
||||
disabled={dateInFuture}
|
||||
iconName='drip-icon-mood'
|
||||
>
|
||||
</SymptomBox>
|
||||
<SymptomBox
|
||||
title='Note'
|
||||
onPress={() => this.navigate('NoteEditView')}
|
||||
@@ -236,9 +264,9 @@ export default class CycleDayOverView extends Component {
|
||||
{/* this is just to make the last row adhere to the grid
|
||||
(and) because there are no pseudo properties in RN */}
|
||||
<FillerBoxes />
|
||||
</View >
|
||||
</ScrollView >
|
||||
</View >
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -248,9 +276,9 @@ export default class CycleDayOverView extends Component {
|
||||
|
||||
class SymptomBox extends Component {
|
||||
render() {
|
||||
const d = this.props.data
|
||||
const boxActive = d ? styles.symptomBoxActive : {}
|
||||
const textActive = d ? styles.symptomTextActive : {}
|
||||
const hasData = this.props.data
|
||||
const boxActive = hasData ? styles.symptomBoxActive : {}
|
||||
const textActive = hasData ? styles.symptomTextActive : {}
|
||||
const disabledStyle = this.props.disabled ? styles.symptomInFuture : {}
|
||||
|
||||
return (
|
||||
@@ -259,7 +287,7 @@ class SymptomBox extends Component {
|
||||
disabled={this.props.disabled}
|
||||
>
|
||||
<View style={[styles.symptomBox, boxActive, disabledStyle]}>
|
||||
<DripIcon name={this.props.iconName} size={50} color={d ? 'white' : 'black'}/>
|
||||
<DripIcon name={this.props.iconName} size={50} color={hasData ? 'white' : 'black'}/>
|
||||
<AppText style={[textActive, disabledStyle]}>
|
||||
{this.props.title.toLowerCase()}
|
||||
</AppText>
|
||||
|
||||
@@ -6,6 +6,7 @@ import NoteEditView from './note'
|
||||
import DesireEditView from './desire'
|
||||
import SexEditView from './sex'
|
||||
import PainEditView from './pain'
|
||||
import MoodEditView from './mood'
|
||||
|
||||
export default {
|
||||
BleedingEditView,
|
||||
@@ -15,5 +16,6 @@ export default {
|
||||
NoteEditView,
|
||||
DesireEditView,
|
||||
SexEditView,
|
||||
PainEditView
|
||||
PainEditView,
|
||||
MoodEditView
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import React, { Component } from 'react'
|
||||
import {
|
||||
View,
|
||||
ScrollView
|
||||
} from 'react-native'
|
||||
import styles from '../../../styles'
|
||||
import AppText from '../../app-text'
|
||||
import * as labels from '../../../i18n/en/symptom-info.js'
|
||||
|
||||
export default class InfoSymptom extends Component {
|
||||
render() {
|
||||
const symptomView = this.props.symptomView
|
||||
const symptomMapping = {
|
||||
BleedingEditView: 'bleeding',
|
||||
CervixEditView: 'cervix',
|
||||
DesireEditView: 'desire',
|
||||
MucusEditView: 'mucus',
|
||||
NoteEditView: 'note',
|
||||
PainEditView: 'pain',
|
||||
SexEditView: 'sex',
|
||||
TemperatureEditView: 'temperature'
|
||||
}
|
||||
const currentSymptom = symptomMapping[symptomView]
|
||||
const currentSymptomText = labels.symptomInfo[currentSymptom]
|
||||
const currentSymptomTitle = labels.symptomTitle[currentSymptom]
|
||||
return (
|
||||
<ScrollView>
|
||||
<View style={[styles.textWrappingView]}>
|
||||
<AppText style={styles.title}>
|
||||
{currentSymptomTitle}
|
||||
</AppText>
|
||||
<AppText style={styles.paragraph}>
|
||||
{currentSymptomText}
|
||||
{labels.symptomTitle.currentSymptomTitle}
|
||||
</AppText>
|
||||
<AppText style={styles.paragraph}>
|
||||
{labels.symptomInfo.currentSymptomText}
|
||||
</AppText>
|
||||
</View>
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import React, { Component } from 'react'
|
||||
import {
|
||||
ScrollView,
|
||||
TextInput,
|
||||
View
|
||||
} from 'react-native'
|
||||
import { saveSymptom } from '../../../db'
|
||||
import { mood as labels } from '../../../i18n/en/cycle-day'
|
||||
import ActionButtonFooter from './action-button-footer'
|
||||
import SelectBoxGroup from '../select-box-group'
|
||||
import SymptomSection from './symptom-section'
|
||||
import styles from '../../../styles'
|
||||
|
||||
export default class Mood extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
const cycleDay = props.cycleDay
|
||||
if (cycleDay && cycleDay.mood) {
|
||||
this.state = Object.assign({}, cycleDay.mood)
|
||||
} else {
|
||||
this.state = {}
|
||||
}
|
||||
if (this.state.note) {
|
||||
this.state.other = true
|
||||
}
|
||||
}
|
||||
|
||||
toggleState = (key) => {
|
||||
const curr = this.state[key]
|
||||
this.setState({[key]: !curr})
|
||||
if (key === 'other' && !curr) {
|
||||
this.setState({focusTextArea: true})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<ScrollView style={styles.page}>
|
||||
<SymptomSection
|
||||
explainer={labels.explainer}
|
||||
>
|
||||
<SelectBoxGroup
|
||||
labels={labels.categories}
|
||||
onSelect={this.toggleState}
|
||||
optionsState={this.state}
|
||||
/>
|
||||
{ this.state.other &&
|
||||
<TextInput
|
||||
autoFocus={this.state.focusTextArea}
|
||||
multiline={true}
|
||||
placeholder="Enter"
|
||||
value={this.state.note}
|
||||
onChangeText={(val) => {
|
||||
this.setState({note: val})
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</SymptomSection>
|
||||
</ScrollView>
|
||||
<ActionButtonFooter
|
||||
symptom='mood'
|
||||
date={this.props.date}
|
||||
currentSymptomValue={this.state}
|
||||
saveAction={() => {
|
||||
const copyOfState = Object.assign({}, this.state)
|
||||
if (!copyOfState.other) {
|
||||
copyOfState.note = null
|
||||
}
|
||||
saveSymptom('mood', this.props.date, copyOfState)
|
||||
}}
|
||||
saveDisabled={Object.values(this.state).every(value => !value)}
|
||||
navigate={this.props.navigate}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
View,
|
||||
Text} from 'react-native'
|
||||
import styles from '../../styles'
|
||||
|
||||
export default function DefaultHeader(props) {
|
||||
return (
|
||||
<View style={styles.header}>
|
||||
<View style={styles.accentCircle} />
|
||||
<Text style={styles.headerText}>
|
||||
{props.title}
|
||||
</Text>
|
||||
</View >
|
||||
)
|
||||
}
|
||||
+17
-20
@@ -1,27 +1,24 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
Dimensions
|
||||
} from 'react-native'
|
||||
import styles from '../../styles'
|
||||
import { Dimensions } from 'react-native'
|
||||
import CycleDayHeader from './cycle-day'
|
||||
import DefaultHeader from './default'
|
||||
import InfoSymptomHeader from './info-symptom'
|
||||
import SymptomViewHeader from './symptom-view'
|
||||
|
||||
export default function Header(p) {
|
||||
const middle = Dimensions.get('window').width / 2
|
||||
const props = Object.assign({}, p, {middle})
|
||||
return (
|
||||
props.isCycleDayOverView ?
|
||||
<CycleDayHeader {...props} />
|
||||
: props.isSymptomView ?
|
||||
<SymptomViewHeader {...props}/>
|
||||
:
|
||||
<View style={styles.header}>
|
||||
<View style={styles.accentCircle} />
|
||||
<Text style={styles.headerText}>
|
||||
{props.title}
|
||||
</Text>
|
||||
</View >
|
||||
)
|
||||
}
|
||||
|
||||
if (props.isCycleDayOverView) {
|
||||
return (<CycleDayHeader {...props} />)
|
||||
}
|
||||
else if (props.isSymptomView) {
|
||||
return (<SymptomViewHeader {...props} />)
|
||||
}
|
||||
else if (props.title === 'info') {
|
||||
return (<InfoSymptomHeader {...props} />)
|
||||
}
|
||||
else {
|
||||
return (<DefaultHeader {...props} />)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native'
|
||||
import styles, { iconStyles } from '../../styles'
|
||||
import NavigationArrow from './navigation-arrow'
|
||||
import Icon from 'react-native-vector-icons/Entypo'
|
||||
|
||||
export default function InfoSymptomHeader(props) {
|
||||
return (
|
||||
<View style={[styles.header, styles.headerCycleDay, styles.headerSymptom]}>
|
||||
<View
|
||||
style={styles.accentCircle}
|
||||
left={props.middle - styles.accentCircle.width / 2}
|
||||
/>
|
||||
<NavigationArrow direction='left' {...props}/>
|
||||
<View>
|
||||
<Text style={styles.headerText}>
|
||||
{props.title}
|
||||
</Text>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.hiddenIcon}>
|
||||
<Icon
|
||||
name={'chevron-thin-right'}
|
||||
{...iconStyles.hiddenIcon}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
View,
|
||||
Text} from 'react-native'
|
||||
Text,
|
||||
TouchableOpacity
|
||||
} from 'react-native'
|
||||
import styles, { iconStyles } from '../../styles'
|
||||
import FeatherIcon from 'react-native-vector-icons/Feather'
|
||||
import NavigationArrow from './navigation-arrow'
|
||||
@@ -26,11 +28,17 @@ export default function SymptomViewHeader(props) {
|
||||
{formatDate(props.date)}
|
||||
</Text>
|
||||
</View >
|
||||
<FeatherIcon
|
||||
name='info'
|
||||
style={styles.symptomInfoIcon}
|
||||
{...iconStyles.symptomHeaderIcons}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
onPress={() => props.goToSymptomInfo()}
|
||||
style={styles.infoButton}
|
||||
>
|
||||
<FeatherIcon
|
||||
name="info"
|
||||
style={styles.symptomInfoIcon}
|
||||
{...iconStyles.symptomHeaderIcons}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,5 +2,8 @@ import {links} from '../../i18n/en/settings'
|
||||
|
||||
export default function(url) {
|
||||
const link = Object.values(links).find(link => link.url === url)
|
||||
if (url === 'mailto:bloodyhealth@mailbox.org') {
|
||||
console.log(links.email.url === url)
|
||||
}
|
||||
return link ? link.text : url
|
||||
}
|
||||
+17
-15
@@ -1,16 +1,20 @@
|
||||
import React, { Component } from 'react'
|
||||
import { ScrollView, View, TouchableOpacity, TouchableHighlight, Dimensions } from 'react-native'
|
||||
import { ScrollView, View, TouchableHighlight, TouchableOpacity, Dimensions } from 'react-native'
|
||||
import { LocalDate, ChronoUnit } from 'js-joda'
|
||||
import Icon from 'react-native-vector-icons/Entypo'
|
||||
import Hyperlink from 'react-native-hyperlink'
|
||||
import { secondaryColor, cycleDayColor, periodColor } from '../styles'
|
||||
import { home as labels, bleedingPrediction as predictLabels, shared, links } from '../i18n/en/labels'
|
||||
import {
|
||||
home as labels,
|
||||
bleedingPrediction as predictLabels,
|
||||
shared,
|
||||
} from '../i18n/en/labels'
|
||||
import links from '../i18n/en/links'
|
||||
import cycleModule from '../lib/cycle'
|
||||
import { getCycleDaysSortedByDate } from '../db'
|
||||
import { getFertilityStatusForDay } from '../lib/sympto-adapter'
|
||||
import replace from './helpers/replace-url-with-text'
|
||||
import styles from '../styles'
|
||||
import AppText, { AppTextLight } from './app-text'
|
||||
import AppText from './app-text'
|
||||
import DripHomeIcon from '../assets/drip-home-icons'
|
||||
import Button from './button'
|
||||
|
||||
@@ -36,9 +40,9 @@ const ShowMoreToggler = ({ isShowingMore, onToggle }) => {
|
||||
const IconText = ({ children, wrapperStyles }) => {
|
||||
return (
|
||||
<View style={[styles.homeIconTextWrapper, wrapperStyles]}>
|
||||
<AppTextLight style={styles.iconText}>
|
||||
<AppText style={styles.iconText}>
|
||||
{ children }
|
||||
</AppTextLight>
|
||||
</AppText>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -76,8 +80,6 @@ export default class Home extends Component {
|
||||
bleedingPredictionRange: getBleedingPredictionRange(prediction),
|
||||
...fertilityStatus
|
||||
}
|
||||
|
||||
this.cycleDays = getCycleDaysSortedByDate()
|
||||
}
|
||||
|
||||
passTodayTo(componentName) {
|
||||
@@ -96,7 +98,7 @@ export default class Home extends Component {
|
||||
labels.cycleDayKnown(cycleDayNumber) :
|
||||
labels.cycleDayNotEnoughInfo
|
||||
|
||||
const { statusText } = this.state;
|
||||
const { statusText } = this.state
|
||||
|
||||
return (
|
||||
<View flex={1}>
|
||||
@@ -156,12 +158,12 @@ export default class Home extends Component {
|
||||
}
|
||||
{ isShowingMore &&
|
||||
<View>
|
||||
<AppText styles={styles.paragraph}>
|
||||
{ statusText && <AppText>{ `${status}.` }</AppText> }
|
||||
<Hyperlink linkStyle={styles.link} linkText={replace}>
|
||||
<AppText>${links.moreToNfp.url}`}</AppText>
|
||||
</Hyperlink>
|
||||
</AppText>
|
||||
<Hyperlink linkStyle={styles.link} linkText={replace}>
|
||||
<AppText styles={styles.paragraph}>
|
||||
{ statusText }
|
||||
</AppText>
|
||||
<AppText>{links.moreAboutNfp.url}</AppText>
|
||||
</Hyperlink>
|
||||
</View>
|
||||
}
|
||||
</HomeElement>
|
||||
|
||||
@@ -13,7 +13,7 @@ const labels = settingsLabels.license
|
||||
export default function License({setLicense}) {
|
||||
return (
|
||||
<ScrollView style={styles.licensePage}>
|
||||
<Hyperlink linkStyle={styles.link} linkText={replace}>
|
||||
<Hyperlink linkStyle={styles.link} linkText={replace} linkDefault>
|
||||
<AppText style={styles.settingsSegmentTitle}>{labels.title}</AppText>
|
||||
<AppText>{labels.text}</AppText>
|
||||
</Hyperlink>
|
||||
|
||||
+72
-34
@@ -1,46 +1,84 @@
|
||||
import React, { Component } from 'react'
|
||||
import React from 'react'
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
TouchableOpacity
|
||||
} from 'react-native'
|
||||
|
||||
import settingsViews from './settings'
|
||||
|
||||
import { menuTitles } from '../i18n/en/labels'
|
||||
|
||||
import styles, { iconStyles, secondaryColor } from '../styles'
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||
|
||||
export default class Menu extends Component {
|
||||
makeMenuItem = ({ title, icon, onPress}, i) => {
|
||||
const styleActive = (this.props.currentPage.toLowerCase() === title) ?
|
||||
{color: secondaryColor} : {}
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
style={styles.menuItem}
|
||||
key={i.toString()}
|
||||
>
|
||||
<Icon name={icon} {...iconStyles.menuIcon} {...styleActive} />
|
||||
<Text style={[styles.menuText, styleActive]}>
|
||||
{title}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
const menuTitlesLowerCase = Object.keys(menuTitles).reduce((acc, curr) => {
|
||||
acc[curr] = menuTitles[curr].toLowerCase()
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
goTo(componentName) {
|
||||
this.props.navigate(componentName)
|
||||
const menuItems = [
|
||||
{
|
||||
labelKey: 'Home',
|
||||
icon: 'home',
|
||||
component: 'Home',
|
||||
},
|
||||
{
|
||||
labelKey: 'Calendar',
|
||||
icon: 'calendar-range',
|
||||
component: 'Calendar',
|
||||
},
|
||||
{
|
||||
labelKey: 'Chart',
|
||||
icon: 'chart-line',
|
||||
component: 'Chart',
|
||||
},
|
||||
{
|
||||
labelKey: 'Stats',
|
||||
icon: 'chart-pie',
|
||||
component: 'Stats',
|
||||
},
|
||||
{
|
||||
labelKey: 'Settings',
|
||||
icon: 'settings',
|
||||
component: 'SettingsMenu',
|
||||
children: Object.keys(settingsViews),
|
||||
}
|
||||
]
|
||||
|
||||
render() {
|
||||
const t = this.props.titles
|
||||
return (
|
||||
<View style={styles.menu}>
|
||||
{[
|
||||
{ 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('SettingsMenu') },
|
||||
].map(this.makeMenuItem)}
|
||||
</View >
|
||||
)
|
||||
}
|
||||
const MenuItem = ({ icon, labelKey, active, onPress }) => {
|
||||
const styleActive = active ? { color: secondaryColor } : null
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={styles.menuItem}
|
||||
onPress={onPress}
|
||||
>
|
||||
<Icon name={icon} {...iconStyles.menuIcon} {...styleActive} />
|
||||
<Text style={[styles.menuText, styleActive]}>
|
||||
{menuTitlesLowerCase[labelKey]}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
const Menu = ({ currentPage, navigate }) => {
|
||||
return (
|
||||
<View style={styles.menu}>
|
||||
{ menuItems.map(({ icon, labelKey, component, children }) => {
|
||||
const isActive = (component === currentPage) ||
|
||||
(children && children.indexOf(currentPage) !== -1)
|
||||
return (
|
||||
<MenuItem
|
||||
key={labelKey}
|
||||
labelKey={labelKey}
|
||||
icon={icon}
|
||||
active={isActive}
|
||||
onPress={() => navigate(component)}
|
||||
/>
|
||||
)}
|
||||
)}
|
||||
</View >
|
||||
)
|
||||
}
|
||||
|
||||
export default Menu
|
||||
@@ -12,7 +12,7 @@ export default class AboutSection extends Component {
|
||||
return (
|
||||
<ScrollView>
|
||||
<SettingsSegment title={labels.aboutSection.title}>
|
||||
<Hyperlink linkStyle={styles.link} linkText={replace}>
|
||||
<Hyperlink linkStyle={styles.link} linkText={replace} linkDefault>
|
||||
<AppText>{labels.aboutSection.text}</AppText>
|
||||
</Hyperlink>
|
||||
</SettingsSegment>
|
||||
@@ -23,7 +23,7 @@ export default class AboutSection extends Component {
|
||||
<AppText>{labels.credits.note}</AppText>
|
||||
</SettingsSegment>
|
||||
<SettingsSegment title={labels.website.title}>
|
||||
<Hyperlink linkStyle={styles.link}>
|
||||
<Hyperlink linkStyle={styles.link} linkDefault>
|
||||
<AppText>{links.website.url}</AppText>
|
||||
</Hyperlink>
|
||||
</SettingsSegment>
|
||||
|
||||
@@ -11,7 +11,7 @@ export default class License extends Component {
|
||||
return (
|
||||
<ScrollView>
|
||||
<View style={styles.settingsSegment}>
|
||||
<Hyperlink linkStyle={styles.link} linkText={replace}>
|
||||
<Hyperlink linkStyle={styles.link} linkText={replace} linkDefault>
|
||||
<AppText style={styles.settingsSegmentTitle}>{`${labels.license.title} `}</AppText>
|
||||
<AppText>{`${labels.license.text} `}</AppText>
|
||||
</Hyperlink>
|
||||
|
||||
@@ -33,7 +33,7 @@ export default class Settings extends Component {
|
||||
<Icon name="info-with-circle" style={iconStyles.infoInHeading}/>
|
||||
<AppText style={styles.settingsSegmentTitle}>{`${labels.preOvu.title} `}</AppText>
|
||||
</View>
|
||||
<Hyperlink linkStyle={styles.link} linkText={replaceUrlWithText}>
|
||||
<Hyperlink linkStyle={styles.link} linkText={replaceUrlWithText} linkDefault>
|
||||
<AppText>{labels.preOvu.note}</AppText>
|
||||
</Hyperlink>
|
||||
</SettingsSegment>
|
||||
|
||||
@@ -64,7 +64,6 @@ export default class ConfirmWithPassword extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const { password } = this.state
|
||||
const labels = settings.passwordSettings
|
||||
|
||||
@@ -75,12 +74,27 @@ export default class ConfirmWithPassword extends Component {
|
||||
value={password}
|
||||
onChangeText={this.handlePasswordInput}
|
||||
/>
|
||||
<SettingsButton
|
||||
onPress={this.initPasswordCheck}
|
||||
disabled={!password}
|
||||
>
|
||||
{shared.confirmToProceed}
|
||||
</SettingsButton>
|
||||
<View style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between'
|
||||
}}>
|
||||
<SettingsButton
|
||||
onPress={this.props.onCancel}
|
||||
secondary
|
||||
>
|
||||
{shared.cancel}
|
||||
</SettingsButton>
|
||||
<SettingsButton
|
||||
onPress={this.initPasswordCheck}
|
||||
disabled={!password}
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{shared.confirmToProceed}
|
||||
</SettingsButton>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
|
||||
|
||||
@@ -5,16 +5,22 @@ import { TouchableOpacity } from 'react-native'
|
||||
import AppText from '../../app-text'
|
||||
import styles from '../../../styles'
|
||||
|
||||
const SettingsButton = ({ children, ...props }) => {
|
||||
const SettingsButton = ({ children, style, secondary, ...props }) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.settingsButton,
|
||||
props.disabled ? styles.settingsButtonDisabled : null
|
||||
secondary ? null : styles.settingsButtonAccent,
|
||||
props.disabled ? styles.settingsButtonDisabled : null,
|
||||
style
|
||||
]}
|
||||
{ ...props }
|
||||
>
|
||||
<AppText style={styles.settingsButtonText}>
|
||||
<AppText style={
|
||||
secondary ?
|
||||
styles.settingsButtonSecondaryText :
|
||||
styles.settingsButtonText
|
||||
}>
|
||||
{children}
|
||||
</AppText>
|
||||
</TouchableOpacity>
|
||||
|
||||
Reference in New Issue
Block a user