diff --git a/app.js b/app.js index 2cfc07e746f97001ae8d7cc5d4a2ff13dd5e2eff..b6e9ff58cce48d259493d2f6ef7bc08d20421d3c 100644 --- a/app.js +++ b/app.js @@ -1,11 +1,11 @@ import React, { Component } from 'react' -import { View, BackHandler } from 'react-native' +import { View, BackHandler, ScrollView } from 'react-native' import Header from './components/header' import Menu from './components/menu' import Home from './components/home' import Calendar from './components/calendar' import CycleDay from './components/cycle-day/cycle-day-overview' -import SymptomView from './components/cycle-day/symptoms' +import symptomViews from './components/cycle-day/symptoms' import Chart from './components/chart/chart' import Settings from './components/settings' import Stats from './components/stats' @@ -13,8 +13,11 @@ import Stats from './components/stats' // this is until react native fixes this bugg, see // https://github.com/facebook/react-native/issues/18868#issuecomment-382671739 import { YellowBox } from 'react-native' +import ActionButtonFooter from './components/cycle-day/symptoms/action-button-footer'; YellowBox.ignoreWarnings(['Warning: isMounted(...) is deprecated']) +const isSymptomView = name => Object.keys(symptomViews).indexOf(name) > -1 + export default class App extends Component { constructor(props) { super(props) @@ -24,9 +27,11 @@ export default class App extends Component { const handleBackButtonPress = function() { if (this.state.currentPage === 'Home') return false - // this is handled in the SymptomView - if (this.state.currentPage === 'SymptomView') return true - this.navigate('Home') + if (isSymptomView(this.state.currentPage)) { + this.navigate('CycleDay', {cycleDay: this.state.currentProps.cycleDay}) + } else { + this.navigate('Home') + } return true }.bind(this) @@ -41,34 +46,40 @@ export default class App extends Component { this.setState({currentPage: pageName, currentProps: props}) } + setActionButtonState(actionButtonInfo) { + this.setState({actionButtonInfo}) + } + + unsetActionButtonState() { + this.setState({actionButtonInfo: null}) + } + render() { + const page = { + Home, Calendar, CycleDay, Chart, Settings, Stats, ...symptomViews + }[this.state.currentPage] return ( <View style={{height: '100%', justifyContent: 'space-between' }}> <View> {this.state.currentPage != 'CycleDay' && <Header title={this.state.currentPage}/>} - <View> - <CurrentPage - page={this.state.currentPage} - navigate={this.navigate.bind(this)} - props={this.state.currentProps} - /> - </View> + <ScrollView> + {React.createElement(page, { + navigate: this.navigate.bind(this), + setActionButtonState: this.setActionButtonState.bind(this), + unsetActionButtonState: this.unsetActionButtonState.bind(this), + ...this.state.currentProps + })} + </ScrollView> </View> - <Menu navigate={this.navigate.bind(this)} /> + {isSymptomView(this.state.currentPage) && this.state.actionButtonInfo ? + <ActionButtonFooter + {...this.state.actionButtonInfo} + navigate={this.navigate.bind(this)} + /> + : + <Menu navigate={this.navigate.bind(this)}/> + } </View> ) } -} - -class CurrentPage extends Component { - render () { - const page = { - Home, Calendar, CycleDay, SymptomView, Chart, Settings, Stats - }[this.props.page] - const props = this.props.props || {} - return React.createElement(page, { - navigate: this.props.navigate, - ...props - }) - } } \ No newline at end of file diff --git a/components/cycle-day/action-buttons.js b/components/cycle-day/action-buttons.js deleted file mode 100644 index 0a6b0a07e0dde983bf386a53420e8d856a2494d0..0000000000000000000000000000000000000000 --- a/components/cycle-day/action-buttons.js +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react' -import { - View, - Button, -} from 'react-native' -import { saveSymptom } from '../../db' - -export default function (navigateToOverView) { - return function ({ symptom, cycleDay, saveAction, saveDisabled}) { - const buttons = [ - { - title: 'Cancel', - action: () => navigateToOverView() - }, - { - title: 'Delete', - action: () => { - saveSymptom(symptom, cycleDay) - navigateToOverView() - }, - disabledCondition: !cycleDay[symptom] - }, { - title: 'Save', - action: () => { - saveAction() - navigateToOverView() - }, - disabledCondition: saveDisabled - } - ] - - return buttons.map(({ title, action, disabledCondition }, i) => { - const style = { flex: 1, marginHorizontal: 10 } - if (i === 0) style.marginLeft = 0 - if (i === buttons.length - 1) style.marginRight = 0 - return ( - <View style={style} key={i}> - <Button - onPress={action} - disabled={disabledCondition} - title={title}> - </Button> - </View > - ) - }) - } -} \ No newline at end of file diff --git a/components/cycle-day/cycle-day-overview.js b/components/cycle-day/cycle-day-overview.js index 0076aa206a59222c8c3b82abd587b243fd1e57ff..9ab32254c9705d6aec4f255337ccbe394305288b 100644 --- a/components/cycle-day/cycle-day-overview.js +++ b/components/cycle-day/cycle-day-overview.js @@ -40,9 +40,8 @@ export default class CycleDayOverView extends Component { } navigate(symptom) { - this.props.navigate('SymptomView', { - symptom, - cycleDay: this.state.cycleDay + this.props.navigate(symptom, { + cycleDay: this.state.cycleDay, }) } diff --git a/components/cycle-day/symptoms/action-button-footer.js b/components/cycle-day/symptoms/action-button-footer.js index 0f05a7bc2077919173577a00b06eef88f008dc52..be0cd6ae40b3fa2c12dbc5754ca3506dcc3ce93c 100644 --- a/components/cycle-day/symptoms/action-button-footer.js +++ b/components/cycle-day/symptoms/action-button-footer.js @@ -1,19 +1,20 @@ import React, { Component } from 'react' import { - View, - Button, + View, TouchableOpacity, Text } from 'react-native' +import Icon from 'react-native-vector-icons/MaterialCommunityIcons' import { saveSymptom } from '../../../db' -import styles from '../../../styles' +import styles, {iconStyles} from '../../../styles' export default class ActionButtonFooter extends Component { render() { const { symptom, cycleDay, saveAction, saveDisabled, navigate} = this.props - const navigateToOverView = () => navigate('CycleDay', cycleDay) + const navigateToOverView = () => navigate('CycleDay', {cycleDay}) const buttons = [ { title: 'Cancel', - action: () => navigateToOverView() + action: () => navigateToOverView(), + icon: 'cancel' }, { title: 'Delete', @@ -21,31 +22,34 @@ export default class ActionButtonFooter extends Component { saveSymptom(symptom, cycleDay) navigateToOverView() }, - disabledCondition: !cycleDay[symptom] + disabledCondition: !cycleDay[symptom], + icon: 'delete-outline' }, { title: 'Save', action: () => { saveAction() navigateToOverView() }, - disabledCondition: saveDisabled + disabledCondition: saveDisabled, + icon: 'content-save-outline' } ] return ( - <View style={styles.actionButtonRow}> - {buttons.map(({ title, action, disabledCondition }, i) => { - const style = { flex: 1, marginHorizontal: 10 } - if (i === 0) style.marginLeft = 0 - if (i === buttons.length - 1) style.marginRight = 0 + <View style={styles.menu}> + {buttons.map(({ title, action, disabledCondition, icon }, i) => { return ( - <View style={style} key={i}> - <Button - onPress={action} - disabled={disabledCondition} - title={title}> - </Button> - </View > + <TouchableOpacity + onPress={action} + style={styles.menuItem} + disabled={disabledCondition} + key={i.toString()} + > + <Icon name={icon} {...iconStyles.menuIcon} /> + <Text style={styles.menuText}> + {title} + </Text> + </TouchableOpacity> ) })} </View> diff --git a/components/cycle-day/symptoms/index.js b/components/cycle-day/symptoms/index.js index 4ce40106de45c3334885aa0f40eb02c8b0e6a7f9..12622b73c88b75d29edba5def57ee217b355d28e 100644 --- a/components/cycle-day/symptoms/index.js +++ b/components/cycle-day/symptoms/index.js @@ -1,7 +1,3 @@ -import React, { Component } from 'react' -import { ScrollView, BackHandler } from 'react-native' -import Header from '../../header' -import actionButtonModule from '../action-buttons' import BleedingEditView from './bleeding' import TemperatureEditView from './temperature' import MucusEditView from './mucus' @@ -10,7 +6,7 @@ import NoteEditView from './note' import DesireEditView from './desire' import SexEditView from './sex' -const symptomViews = { +export default { BleedingEditView, TemperatureEditView, MucusEditView, @@ -18,54 +14,4 @@ const symptomViews = { NoteEditView, DesireEditView, SexEditView -} -const titles = { - BleedingEditView: 'Bleeding', - TemperatureEditView: 'Temperature', - MucusEditView: 'Mucus', - CervixEditView: 'Cervix', - NoteEditView: 'Note', - DesireEditView: 'Desire', - SexEditView: 'Sex' -} - -export default class SymptomView extends Component { - constructor(props) { - super(props) - - this.state = { - visibleComponent: props.symptom, - cycleDay: props.cycleDay - } - - this.makeActionButtons = actionButtonModule(() => { - this.props.navigate('CycleDay', {cycleDay: this.state.cycleDay}) - }) - - const handleBackButtonPress = function() { - this.props.navigate('CycleDay', {cycleDay: this.state.cycleDay}) - return true - }.bind(this) - - this.backHandler = BackHandler.addEventListener('hardwareBackPress', handleBackButtonPress) - } - - componentWillUnmount() { - this.backHandler.remove() - } - - render() { - return ( - <ScrollView> - <Header title={titles[this.state.visibleComponent]}/> - {React.createElement( - symptomViews[this.state.visibleComponent], - { - cycleDay: this.state.cycleDay, - makeActionButtons: this.makeActionButtons - } - )} - </ScrollView > - ) - } -} +} \ No newline at end of file diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index 7296883201ddb475bb2aa0ba5dac3bc0c6513144..a7bd55e7eff2f0352bde2b807773d39e5ab8100a 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -4,7 +4,7 @@ import { Text, TextInput, Switch, - Keyboard + Keyboard, } from 'react-native' import DateTimePicker from 'react-native-modal-datetime-picker-nevo' @@ -37,10 +37,27 @@ export default class Temp extends Component { time: this.time || LocalTime.now().truncatedTo(MINUTES).toString(), isTimePickerVisible: false } + + props.setActionButtonState({ + symptom : 'temperature', + cycleDay: props.cycleDay, + saveAction: () => { + const dataToSave = { + value: Number(this.state.currentValue), + exclude: this.state.exclude, + time: this.state.time + } + saveSymptom('temperature', props.cycleDay, dataToSave) + }, + saveDisabled: this.state.currentValue === '' || isInvalidTime(this.state.time) + }) + } + + componentWillUnmount() { + this.props.unsetActionButtonState() } render() { - const cycleDay = this.cycleDay return ( <View style={styles.symptomEditView}> <View style={styles.symptomViewRowInline}> @@ -61,7 +78,7 @@ export default class Temp extends Component { style={styles.temperatureTextInput} onFocus={() => { Keyboard.dismiss() - this.setState({isTimePickerVisible: true}) + this.setState({ isTimePickerVisible: true }) }} value={this.state.time} /> @@ -75,7 +92,7 @@ export default class Temp extends Component { isTimePickerVisible: false }) }} - onCancel={() => this.setState({isTimePickerVisible: false})} + onCancel={() => this.setState({ isTimePickerVisible: false })} /> <View style={styles.symptomViewRowInline}> <Text style={styles.symptomDayView}>Exclude</Text> @@ -86,21 +103,6 @@ export default class Temp extends Component { value={this.state.exclude} /> </View> - <View style={styles.actionButtonRow}> - {this.makeActionButtons({ - symptom: 'temperature', - cycleDay: this.cycleDay, - saveAction: () => { - const dataToSave = { - value: Number(this.state.currentValue), - exclude: this.state.exclude, - time: this.state.time - } - saveSymptom('temperature', cycleDay, dataToSave) - }, - saveDisabled: this.state.currentValue === '' || isInvalidTime(this.state.time) - })} - </View> </View> ) } diff --git a/components/menu.js b/components/menu.js index 1a8bed769dd9baeed49596d3cf175d8a8cc02093..8a5518774db8bfb2e15ba652c5af17ab2779ac1c 100644 --- a/components/menu.js +++ b/components/menu.js @@ -8,11 +8,12 @@ import styles, { iconStyles } from '../styles' import Icon from 'react-native-vector-icons/MaterialCommunityIcons' export default class Menu extends Component { - makeMenuItem({ title, icon, componentName }) { + makeMenuItem({ title, icon, onPress}, i) { return ( <TouchableOpacity - onPress={() => this.props.navigate(componentName)} + onPress={onPress} style={styles.menuItem} + key={i.toString()} > <Icon name={icon} {...iconStyles.menuIcon} /> <Text style={styles.menuText}> @@ -21,20 +22,22 @@ export default class Menu extends Component { </TouchableOpacity> ) } + + goTo(componentName) { + this.props.navigate(componentName) + } + render() { return ( - this.props.symptomView ? - placeActionButtons() - : - <View style={styles.menu}> - {[ - {title: 'Home', icon: 'home', componentName: 'Home'}, - {title: 'Calendar', icon: 'calendar-range', componentName: 'Calendar'}, - {title: 'Chart', icon: 'chart-line', componentName: 'Chart'}, - {title: 'Stats', icon: 'chart-pie', componentName: 'Stats'}, - {title: 'Settings', icon: 'settings', componentName: 'Settings'}, - ].map(this.makeMenuItem.bind(this))} - </View > + <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') }, + ].map(this.makeMenuItem.bind(this))} + </View > ) } }