From 7b8b905550223019effc58888e8c09569774b26a Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Sun, 30 Sep 2018 15:02:11 +0200 Subject: [PATCH] Add new home screen --- assets/drip_drip.svg | 17 -- assets/home-circle.js | 2 +- assets/home-drop.js | 14 + components/app-text.js | 12 +- components/app.js | 16 +- components/chart/chart.js | 2 +- components/chart/y-axis.js | 2 +- components/cycle-day/cycle-day-overview.js | 4 +- components/cycle-day/{labels => }/labels.js | 7 - components/cycle-day/labels/format.js | 5 - components/cycle-day/select-box-group.js | 2 +- components/cycle-day/select-tab-group.js | 2 +- .../symptoms/action-button-footer.js | 2 +- components/cycle-day/symptoms/bleeding.js | 2 +- components/cycle-day/symptoms/cervix.js | 2 +- components/cycle-day/symptoms/desire.js | 2 +- components/cycle-day/symptoms/mucus.js | 2 +- components/cycle-day/symptoms/note.js | 2 +- components/cycle-day/symptoms/pain.js | 2 +- components/cycle-day/symptoms/sex.js | 2 +- .../cycle-day/symptoms/symptom-section.js | 2 +- components/cycle-day/symptoms/temperature.js | 2 +- components/header.js | 5 +- components/home.js | 244 +++++++++++++----- components/labels.js | 38 ++- components/password-prompt.js | 2 +- components/settings/index.js | 2 +- components/settings/password/create.js | 2 +- components/settings/password/delete.js | 2 +- components/settings/password/index.js | 2 +- components/settings/password/update.js | 2 +- components/settings/period-reminder.js | 2 +- components/settings/temp-reminder-picker.js | 2 +- components/settings/temp-slider.js | 2 +- components/stats.js | 2 +- db/fixtures.js | 152 ----------- db/index.js | 58 ----- lib/sympto-adapter.js | 35 ++- lib/sympto/index.js | 1 + styles/index.js | 65 ++++- 40 files changed, 367 insertions(+), 356 deletions(-) delete mode 100644 assets/drip_drip.svg create mode 100644 assets/home-drop.js rename components/cycle-day/{labels => }/labels.js (92%) delete mode 100644 components/cycle-day/labels/format.js delete mode 100644 db/fixtures.js diff --git a/assets/drip_drip.svg b/assets/drip_drip.svg deleted file mode 100644 index 2ec99a2..0000000 --- a/assets/drip_drip.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - diff --git a/assets/home-circle.js b/assets/home-circle.js index f8c9bc5..3dcdfba 100644 --- a/assets/home-circle.js +++ b/assets/home-circle.js @@ -3,7 +3,7 @@ import Svg, { G, Path } from 'react-native-svg' export default function HomeCycleIcon() { return ( - + + + + + + ) +} diff --git a/components/app-text.js b/components/app-text.js index c553445..eabab32 100644 --- a/components/app-text.js +++ b/components/app-text.js @@ -2,7 +2,7 @@ import React, { Component } from 'react' import { Text } from 'react-native' import styles from "../styles" -export class AppText extends Component { +export default class AppText extends Component { render() { return ( @@ -12,6 +12,16 @@ export class AppText extends Component { } } +export class AppTextLight extends Component { + render() { + return ( + + {this.props.children} + + ) + } +} + export class SymptomSectionHeader extends Component { render() { return ( diff --git a/components/app.js b/components/app.js index aea1c6f..48ed442 100644 --- a/components/app.js +++ b/components/app.js @@ -40,20 +40,18 @@ export default class App extends Component { } navigate = (pageName, props) => { - const curr = this.state.currentPage - if (navigatingToCycleDayFromMainMenuEntry(pageName, curr)) { - this.cycleDayOrigin = curr - } + this.origin = this.state.currentPage this.setState({currentPage: pageName, currentProps: props}) } handleBackButtonPress = () => { if (this.state.currentPage === 'Home') return false if (isSymptomView(this.state.currentPage)) { - this.navigate('CycleDay', { cycleDay: this.state.currentProps.cycleDay }) + this.navigate( + this.origin, { cycleDay: this.state.currentProps.cycleDay } + ) } else if(this.state.currentPage === 'CycleDay') { - this.navigate(this.cycleDayOrigin || 'Home') - this.cycleDayOrigin = null + this.navigate(this.origin) } else { this.navigate('Home') } @@ -93,7 +91,3 @@ export default class App extends Component { ) } } - -function navigatingToCycleDayFromMainMenuEntry(target, curr) { - return target === 'CycleDay' && ['Home', 'Calendar', 'Chart'].indexOf(curr) > -1 -} \ No newline at end of file diff --git a/components/chart/chart.js b/components/chart/chart.js index 8ea7f31..8b96f74 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -10,7 +10,7 @@ import { getCycleDay, getCycleDaysSortedByDate, getAmountOfCycleDays } from '../ import styles from './styles' import { scaleObservable } from '../../local-storage' import config from '../../config' -import { AppText } from '../app-text' +import AppText from '../app-text' import { shared as labels } from '../labels' import BleedingIcon from '../../assets/bleeding' import CervixIcon from '../../assets/cervix' diff --git a/components/chart/y-axis.js b/components/chart/y-axis.js index e1e0d6f..1f33736 100644 --- a/components/chart/y-axis.js +++ b/components/chart/y-axis.js @@ -3,7 +3,7 @@ import { View } from 'react-native' import config from '../../config' import styles from './styles' import { scaleObservable, unitObservable } from '../../local-storage' -import { AppText } from '../app-text' +import AppText from '../app-text' export function makeYAxisLabels(columnHeight) { const units = unitObservable.value diff --git a/components/cycle-day/cycle-day-overview.js b/components/cycle-day/cycle-day-overview.js index 775e299..aded1e0 100644 --- a/components/cycle-day/cycle-day-overview.js +++ b/components/cycle-day/cycle-day-overview.js @@ -11,8 +11,8 @@ import Header from '../header' import { getOrCreateCycleDay } from '../../db' import cycleModule from '../../lib/cycle' import styles from '../../styles' -import * as labels from './labels/labels' -import { AppText } from '../app-text' +import * as labels from './labels' +import AppText from '../app-text' import BleedingIcon from '../../assets/bleeding' import CervixIcon from '../../assets/cervix' import DesireIcon from '../../assets/desire' diff --git a/components/cycle-day/labels/labels.js b/components/cycle-day/labels.js similarity index 92% rename from components/cycle-day/labels/labels.js rename to components/cycle-day/labels.js index aeff7bc..b35cf3c 100644 --- a/components/cycle-day/labels/labels.js +++ b/components/cycle-day/labels.js @@ -65,13 +65,6 @@ export const pain = { explainer: 'How did your body feel today?' } -export const fertilityStatus = { - fertile: 'fertile', - infertile: 'infertile', - fertileUntilEvening: 'Fertile phase ends in the evening', - unknown: 'We cannot show any cycle information because no menses has been entered' -} - export const temperature = { outOfRangeWarning: 'This temperature value is out of the current range for the temperature chart. You can change the range in the settings.', outOfAbsoluteRangeWarning: 'This temperature value is too high or low to be shown on the temperature chart.', diff --git a/components/cycle-day/labels/format.js b/components/cycle-day/labels/format.js deleted file mode 100644 index d8250ed..0000000 --- a/components/cycle-day/labels/format.js +++ /dev/null @@ -1,5 +0,0 @@ -import moment from "moment" - -export function formatDateForViewHeader(date) { - return moment(date).format('MMMM Do YYYY') -} \ No newline at end of file diff --git a/components/cycle-day/select-box-group.js b/components/cycle-day/select-box-group.js index ca14494..043c5ff 100644 --- a/components/cycle-day/select-box-group.js +++ b/components/cycle-day/select-box-group.js @@ -4,7 +4,7 @@ import { TouchableOpacity, } from 'react-native' import styles from '../../styles' -import { AppText } from '../app-text' +import AppText from '../app-text' export default class SelectBoxGroup extends Component { render() { diff --git a/components/cycle-day/select-tab-group.js b/components/cycle-day/select-tab-group.js index b960d95..24a601f 100644 --- a/components/cycle-day/select-tab-group.js +++ b/components/cycle-day/select-tab-group.js @@ -4,7 +4,7 @@ import { TouchableOpacity, } from 'react-native' import styles from '../../styles' -import { AppText } from '../app-text' +import AppText from '../app-text' export default class SelectTabGroup extends Component { render() { diff --git a/components/cycle-day/symptoms/action-button-footer.js b/components/cycle-day/symptoms/action-button-footer.js index e923d8b..b4af8ba 100644 --- a/components/cycle-day/symptoms/action-button-footer.js +++ b/components/cycle-day/symptoms/action-button-footer.js @@ -5,7 +5,7 @@ import { import Icon from 'react-native-vector-icons/MaterialCommunityIcons' import { saveSymptom } from '../../../db' import styles, {iconStyles} from '../../../styles' -import {sharedDialogs as labels} from '../labels/labels' +import {sharedDialogs as labels} from '../labels' export default class ActionButtonFooter extends Component { render() { diff --git a/components/cycle-day/symptoms/bleeding.js b/components/cycle-day/symptoms/bleeding.js index 3c88ec5..5259b4d 100644 --- a/components/cycle-day/symptoms/bleeding.js +++ b/components/cycle-day/symptoms/bleeding.js @@ -6,7 +6,7 @@ import { } from 'react-native' import styles from '../../../styles' import { saveSymptom } from '../../../db' -import { bleeding as labels } from '../labels/labels' +import { bleeding as labels } from '../labels' import ActionButtonFooter from './action-button-footer' import SelectTabGroup from '../select-tab-group' import SymptomSection from './symptom-section' diff --git a/components/cycle-day/symptoms/cervix.js b/components/cycle-day/symptoms/cervix.js index ccb1cbd..d8e49e4 100644 --- a/components/cycle-day/symptoms/cervix.js +++ b/components/cycle-day/symptoms/cervix.js @@ -6,7 +6,7 @@ import { } from 'react-native' import styles from '../../../styles' import { saveSymptom } from '../../../db' -import { cervix as labels } from '../labels/labels' +import { cervix as labels } from '../labels' import ActionButtonFooter from './action-button-footer' import SelectTabGroup from '../select-tab-group' import SymptomSection from './symptom-section' diff --git a/components/cycle-day/symptoms/desire.js b/components/cycle-day/symptoms/desire.js index ea8800f..9cbaa1b 100644 --- a/components/cycle-day/symptoms/desire.js +++ b/components/cycle-day/symptoms/desire.js @@ -5,7 +5,7 @@ import { } from 'react-native' import styles from '../../../styles' import { saveSymptom } from '../../../db' -import { intensity, desire } from '../labels/labels' +import { intensity, desire } from '../labels' import ActionButtonFooter from './action-button-footer' import SelectTabGroup from '../select-tab-group' import SymptomSection from './symptom-section' diff --git a/components/cycle-day/symptoms/mucus.js b/components/cycle-day/symptoms/mucus.js index a517fcd..de74709 100644 --- a/components/cycle-day/symptoms/mucus.js +++ b/components/cycle-day/symptoms/mucus.js @@ -6,7 +6,7 @@ import { } from 'react-native' import styles from '../../../styles' import { saveSymptom } from '../../../db' -import { mucus as labels } from '../labels/labels' +import { mucus as labels } from '../labels' import computeSensiplanValue from '../../../lib/sensiplan-mucus' import ActionButtonFooter from './action-button-footer' import SelectTabGroup from '../select-tab-group' diff --git a/components/cycle-day/symptoms/note.js b/components/cycle-day/symptoms/note.js index 93d8e19..836c283 100644 --- a/components/cycle-day/symptoms/note.js +++ b/components/cycle-day/symptoms/note.js @@ -9,7 +9,7 @@ import styles from '../../../styles' import { saveSymptom } from '../../../db' import ActionButtonFooter from './action-button-footer' import SymptomSection from './symptom-section' -import { noteExplainer } from '../labels/labels' +import { noteExplainer } from '../labels' export default class Note extends Component { constructor(props) { diff --git a/components/cycle-day/symptoms/pain.js b/components/cycle-day/symptoms/pain.js index 9005d1e..5957d2a 100644 --- a/components/cycle-day/symptoms/pain.js +++ b/components/cycle-day/symptoms/pain.js @@ -5,7 +5,7 @@ import { View } from 'react-native' import { saveSymptom } from '../../../db' -import { pain as labels } from '../labels/labels' +import { pain as labels } from '../labels' import ActionButtonFooter from './action-button-footer' import SelectBoxGroup from '../select-box-group' import SymptomSection from './symptom-section' diff --git a/components/cycle-day/symptoms/sex.js b/components/cycle-day/symptoms/sex.js index 1e14b06..74ff94f 100644 --- a/components/cycle-day/symptoms/sex.js +++ b/components/cycle-day/symptoms/sex.js @@ -6,7 +6,7 @@ import { } from 'react-native' import styles from '../../../styles' import { saveSymptom } from '../../../db' -import { sex as labels } from '../labels/labels' +import { sex as labels } from '../labels' import ActionButtonFooter from './action-button-footer' import SelectBoxGroup from '../select-box-group' import SymptomSection from './symptom-section' diff --git a/components/cycle-day/symptoms/symptom-section.js b/components/cycle-day/symptoms/symptom-section.js index d29d7fb..9055062 100644 --- a/components/cycle-day/symptoms/symptom-section.js +++ b/components/cycle-day/symptoms/symptom-section.js @@ -1,6 +1,6 @@ import React, { Component } from 'react' import { View } from 'react-native' -import { SymptomSectionHeader, AppText } from '../../app-text' +import AppText, { SymptomSectionHeader } from '../../app-text' export default class SymptomSection extends Component { render() { diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index 1e7c750..413746d 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -12,7 +12,7 @@ import DateTimePicker from 'react-native-modal-datetime-picker-nevo' import { getPreviousTemperature, saveSymptom } from '../../../db' import styles from '../../../styles' import { LocalTime, ChronoUnit } from 'js-joda' -import { temperature as labels } from '../labels/labels' +import { temperature as labels } from '../labels' import { scaleObservable } from '../../../local-storage' import { shared } from '../../labels' import ActionButtonFooter from './action-button-footer' diff --git a/components/header.js b/components/header.js index 3cc76d9..9ebbe58 100644 --- a/components/header.js +++ b/components/header.js @@ -4,11 +4,10 @@ import { Text, Dimensions } from 'react-native' +import moment from 'moment' import styles, { iconStyles } from '../styles' import Icon from 'react-native-vector-icons/Entypo' import FeatherIcon from 'react-native-vector-icons/Feather' -import { formatDateForViewHeader } from '../components/cycle-day/labels/format' - export default class Header extends Component { render() { @@ -27,7 +26,7 @@ export default class Header extends Component { /> - {formatDateForViewHeader(this.props.date)} + {moment(this.props.date).format('MMMM Do YYYY')} {this.props.cycleDayNumber && diff --git a/components/home.js b/components/home.js index fffe693..56e59e8 100644 --- a/components/home.js +++ b/components/home.js @@ -1,108 +1,234 @@ import React, { Component } from 'react' -import { - View, - Button, - Text, - ScrollView -} from 'react-native' +import { ScrollView, View, TouchableOpacity, TouchableHighlight, Dimensions } from 'react-native' import { LocalDate, ChronoUnit } from 'js-joda' -import styles from '../styles/index' +import Icon from 'react-native-vector-icons/Entypo' +import { secondaryColor, cycleDayColor, periodColor } from '../styles' +import { home as labels, bleedingPrediction as predictLabels, shared } from './labels' +import CycleCircle from '../assets/home-circle' +import Drop from '../assets/home-drop' import cycleModule from '../lib/cycle' -import { getOrCreateCycleDay, getBleedingDaysSortedByDate, fillWithMucusDummyData, fillWithCervixDummyData } from '../db' -import {bleedingPrediction as labels} from './labels' +import { getOrCreateCycleDay, getCycleDaysSortedByDate } from '../db' +import { getFertilityStatusForDay } from '../lib/sympto-adapter' +import styles from '../styles' +import AppText, { AppTextLight } from './app-text' export default class Home extends Component { constructor(props) { super(props) this.getCycleDayNumber = cycleModule().getCycleDayNumber + this.getBleedingPrediction = cycleModule().getPredictedMenses this.todayDateString = LocalDate.now().toString() - const cycleDayNumber = this.getCycleDayNumber(this.todayDateString) + const prediction = this.getBleedingPrediction() + const fertilityStatus = getFertilityStatusForDay(this.todayDateString) this.state = { - welcomeText: determineWelcomeText(cycleDayNumber), - predictionText: determinePredictionText() + cycleDayNumber: this.getCycleDayNumber(this.todayDateString), + predictionText: determinePredictionText(prediction), + bleedingPredictionRange: getBleedingPredictionRange(prediction), + ...fertilityStatus } - this.bleedingDays = getBleedingDaysSortedByDate() - this.bleedingDays.addListener(this.setStateWithCurrentText) + this.cycleDays = getCycleDaysSortedByDate() + this.cycleDays.addListener(this.updateState) } - setStateWithCurrentText = () => { - const cycleDayNumber = this.getCycleDayNumber(this.todayDateString) + updateState = () => { + const prediction = this.getBleedingPrediction() + const fertilityStatus = getFertilityStatusForDay(this.todayDateString) this.setState({ - welcomeText: determineWelcomeText(cycleDayNumber), - predictionText: determinePredictionText() + cycleDayNumber: this.getCycleDayNumber(this.todayDateString), + predictionText: determinePredictionText(prediction), + bleedingPredictionRange: getBleedingPredictionRange(prediction), + ...fertilityStatus }) } componentWillUnmount() { - this.bleedingDays.removeListener(this.setStateWithCurrentText) + this.cycleDays.removeListener(this.updateState) } - passTodayToDayView() { + passTodayTo(componentName) { const todayDateString = LocalDate.now().toString() const cycleDay = getOrCreateCycleDay(todayDateString) const navigate = this.props.navigate - navigate('CycleDay', { cycleDay }) + navigate(componentName, { cycleDay }) } render() { + const cycleDayMoreText = this.state.cycleDayNumber ? + labels.cycleDayKnown(this.state.cycleDayNumber) + : + labels.cycleDayNotEnoughInfo + + const {height, width} = Dimensions.get('window') return ( - - {this.state.welcomeText} - {this.state.predictionText} - - - + + + + this.passTodayTo('CycleDay')} + style={styles.homeIconElement} + > + + + + + + {this.state.cycleDayNumber || labels.unknown} + + + + { this.state.showMore && + {cycleDayMoreText} + } + + + {labels.editToday} + + + + + this.passTodayTo('BleedingEditView')} + style={styles.homeIconElement} + > + + + + + + {this.state.bleedingPredictionRange} + + + + {this.state.showMore && + + {this.state.predictionText} + + } + + + {labels.trackPeriod} + + + + + this.props.navigate('Chart')} + style={styles.homeIconElement} + > + + + {this.state.phase ? + this.state.phase.toString() + : + labels.unknown + } + + + {this.state.phase && + + {`${labels.phase(this.state.phase)} (${this.state.status})`} + + } + {this.state.showMore && + + {this.state.statusText} + + } + + + {labels.checkFertility} + + + - - - - - - - - + + + + {!this.state.showMore && + this.setState({showMore: true})} + style={[styles.showMore, { + top: height / 2 - styles.header.height - 30, + left: width - 40 + }]} + > + + {shared.more} + + + + } + + {this.state.showMore && + this.setState({showMore: false})} + style={[styles.showLess, { + top: height / 2 - styles.header.height - 30, + left: 10 + }]} + > + + {shared.less} + + + + } + ) } } -function determineWelcomeText(cycleDayNumber) { - const welcomeTextWithCycleDay = `Welcome! Today is day ${cycleDayNumber} of your current cycle` - const welcomeText = `Welcome! We don't have enough information to know what your current cycle day is` - return cycleDayNumber ? welcomeTextWithCycleDay : welcomeText -} - -function determinePredictionText() { - const bleedingPrediction = cycleModule().getPredictedMenses() - if (!bleedingPrediction.length) return labels.noPrediction +function determinePredictionText(bleedingPrediction) { + if (!bleedingPrediction.length) return predictLabels.noPrediction const todayDate = LocalDate.now() const bleedingStart = LocalDate.parse(bleedingPrediction[0][0]) - const bleedingEnd = LocalDate.parse(bleedingPrediction[0][ bleedingPrediction[0].length - 1 ]) + const bleedingEnd = LocalDate.parse( + bleedingPrediction[0][ bleedingPrediction[0].length - 1 ] + ) if (todayDate.isBefore(bleedingStart)) { - return labels.predictionInFuture( + return predictLabels.predictionInFuture( todayDate.until(bleedingStart, ChronoUnit.DAYS), todayDate.until(bleedingEnd, ChronoUnit.DAYS) ) } if (todayDate.isAfter(bleedingEnd)) { - return labels.predictionInPast(bleedingStart.toString(), bleedingEnd.toString()) + return predictLabels.predictionInPast( + bleedingStart.toString(), bleedingEnd.toString() + ) } const daysToEnd = todayDate.until(bleedingEnd, ChronoUnit.DAYS) if (daysToEnd === 0) { - return labels.predictionStartedNoDaysLeft + return predictLabels.predictionStartedNoDaysLeft } else if (daysToEnd === 1) { - return labels.predictionStarted1DayLeft + return predictLabels.predictionStarted1DayLeft } else { - return labels.predictionStartedXDaysLeft(daysToEnd) + return predictLabels.predictionStartedXDaysLeft(daysToEnd) } } + +function getBleedingPredictionRange(prediction) { + if (!prediction.length) return labels.unknown + const todayDate = LocalDate.now() + const bleedingStart = LocalDate.parse(prediction[0][0]) + const bleedingEnd = LocalDate.parse(prediction[0][ prediction[0].length - 1 ]) + if (todayDate.isBefore(bleedingStart)) { + return `${todayDate.until(bleedingStart, ChronoUnit.DAYS)}-${todayDate.until(bleedingEnd, ChronoUnit.DAYS)}` + } + if (todayDate.isAfter(bleedingEnd)) { + return labels.unknown + } + return '0' +} \ No newline at end of file diff --git a/components/labels.js b/components/labels.js index e728bd5..6a9709c 100644 --- a/components/labels.js +++ b/components/labels.js @@ -11,7 +11,9 @@ export const shared = { unlock: 'Unlock', date: 'Date', cycleDayWithLinebreak: 'Cycle\nday', - loading: 'Loading ...' + loading: 'Loading ...', + more: 'more', + less: 'less' } export const settings = { @@ -137,4 +139,36 @@ export const passwordPrompt = { areYouSureTitle: 'Are you sure?', areYouSure: 'Are you absolutely sure you want to permanently delete all your data?', reallyDeleteData: 'Yes, I am sure' -} \ No newline at end of file +} + +export const home = { + editToday: 'add data for today', + cycleDayNotEnoughInfo: "We don't have enough information to know what your current cycle day is.", + unknown: '?', + cycleDayKnown: d => `Your last period started ${getDaysDescriptor(d)}.`, + trackPeriod: 'track your period', + checkFertility: 'check your fertility', + phase: n => `${['1st', '2nd', '3rd'][n - 1]} cycle phase` +} + +const getDaysDescriptor = cycleDayNumber => { + if (cycleDayNumber === 1) return 'today' + if (cycleDayNumber === 2) return 'yesterday' + return `${cycleDayNumber - 1} days ago` +} + +export const fertilityStatus = { + fertile: 'fertile', + infertile: 'infertile', + fertileUntilEvening: 'Fertile phase ends in the evening', + unknown: 'We cannot show any cycle information because no period data has been added.', + preOvuText: "With NFP rules, you may assume 5 days of infertility at the beginning of your cycle, provided you don't observe any fertile mucus or cervix values.", + periOvuText: "We have not been able to detect both a temperature shift and mucus or cervix shift.", + postOvuText: tempRule => { + return ( + 'We have detected a temperature shift (' + ['regular', '1st exception', '2nd exception'][tempRule] + + ' temperature rule), as well as a mucus shift according to NFP rules. You may assume infertility, but always remember to ' + + 'double-check for yourself. Make sure the data makes sense to you.' + ) + } +} diff --git a/components/password-prompt.js b/components/password-prompt.js index ce91221..f9e63ee 100644 --- a/components/password-prompt.js +++ b/components/password-prompt.js @@ -2,7 +2,7 @@ import React, { Component } from 'react' import { View, TextInput, TouchableOpacity, Alert, Image } from 'react-native' import nodejs from 'nodejs-mobile-react-native' import { saveEncryptionFlag } from '../local-storage' -import { AppText } from './app-text' +import AppText from './app-text' import styles from '../styles' import { passwordPrompt as labels, shared } from './labels' import { requestHash, deleteDbAndOpenNew, openDb } from '../db' diff --git a/components/settings/index.js b/components/settings/index.js index 1180f24..fd432f8 100644 --- a/components/settings/index.js +++ b/components/settings/index.js @@ -6,7 +6,7 @@ import { } from 'react-native' import styles from '../../styles/index' import { settings as labels } from '../labels' -import { AppText } from '../app-text' +import AppText from '../app-text' import TempReminderPicker from './temp-reminder-picker' import PeriodReminderPicker from './period-reminder' import TempSlider from './temp-slider' diff --git a/components/settings/password/create.js b/components/settings/password/create.js index 97559ee..7e04294 100644 --- a/components/settings/password/create.js +++ b/components/settings/password/create.js @@ -4,7 +4,7 @@ import { TouchableOpacity, } from 'react-native' import nodejs from 'nodejs-mobile-react-native' -import { AppText } from '../../app-text' +import AppText from '../../app-text' import styles from '../../../styles' import { settings as labels } from '../../labels' import { requestHash, changeEncryptionAndRestartApp } from '../../../db' diff --git a/components/settings/password/delete.js b/components/settings/password/delete.js index 58666f5..74fcd6b 100644 --- a/components/settings/password/delete.js +++ b/components/settings/password/delete.js @@ -4,7 +4,7 @@ import { TouchableOpacity } from 'react-native' import nodejs from 'nodejs-mobile-react-native' -import { AppText } from '../../app-text' +import AppText from '../../app-text' import styles from '../../../styles' import { settings as labels } from '../../labels' import { requestHash, changeEncryptionAndRestartApp } from '../../../db' diff --git a/components/settings/password/index.js b/components/settings/password/index.js index 87ece3d..7a11744 100644 --- a/components/settings/password/index.js +++ b/components/settings/password/index.js @@ -3,7 +3,7 @@ import { View } from 'react-native' import CreatePassword from './create' import ChangePassword from './update' import DeletePassword from './delete' -import { AppText } from '../../app-text' +import AppText from '../../app-text' import { hasEncryptionObservable } from '../../../local-storage' diff --git a/components/settings/password/update.js b/components/settings/password/update.js index 12af518..2681d2e 100644 --- a/components/settings/password/update.js +++ b/components/settings/password/update.js @@ -4,7 +4,7 @@ import { View, TouchableOpacity} from 'react-native' import nodejs from 'nodejs-mobile-react-native' -import { AppText } from '../../app-text' +import AppText from '../../app-text' import styles from '../../../styles' import { settings as labels, shared } from '../../labels' import { requestHash, changeEncryptionAndRestartApp } from '../../../db' diff --git a/components/settings/period-reminder.js b/components/settings/period-reminder.js index 70ec0fc..3624e2f 100644 --- a/components/settings/period-reminder.js +++ b/components/settings/period-reminder.js @@ -3,7 +3,7 @@ import { View, Switch } from 'react-native' -import { AppText } from '../app-text' +import AppText from '../app-text' import { periodReminderObservable, savePeriodReminder diff --git a/components/settings/temp-reminder-picker.js b/components/settings/temp-reminder-picker.js index 8cfbf86..bb11909 100644 --- a/components/settings/temp-reminder-picker.js +++ b/components/settings/temp-reminder-picker.js @@ -5,7 +5,7 @@ import { Switch } from 'react-native' import DateTimePicker from 'react-native-modal-datetime-picker-nevo' -import { AppText } from '../app-text' +import AppText from '../app-text' import { tempReminderObservable, saveTempReminder diff --git a/components/settings/temp-slider.js b/components/settings/temp-slider.js index f21fd74..bd1034c 100644 --- a/components/settings/temp-slider.js +++ b/components/settings/temp-slider.js @@ -1,7 +1,7 @@ import React, { Component } from 'react' import { View } from 'react-native' import Slider from '@ptomasroos/react-native-multi-slider' -import { AppText } from '../app-text' +import AppText from '../app-text' import { scaleObservable, saveTempScale, diff --git a/components/stats.js b/components/stats.js index 897a1dd..b02e03f 100644 --- a/components/stats.js +++ b/components/stats.js @@ -8,7 +8,7 @@ import styles from '../styles/index' import cycleModule from '../lib/cycle' import {getCycleLengthStats as getCycleInfo} from '../lib/cycle-length' import {stats as labels} from './labels' -import { AppText } from './app-text' +import AppText from './app-text' export default class Stats extends Component { render() { diff --git a/db/fixtures.js b/db/fixtures.js deleted file mode 100644 index 421bcb8..0000000 --- a/db/fixtures.js +++ /dev/null @@ -1,152 +0,0 @@ -function convertToSymptoFormat(val) { - const sympto = { date: val.date } - if (val.bleeding) sympto.bleeding = { - value: val.bleeding, - exclude: false - } - if (val.temperature) sympto.temperature = { - value: val.temperature, - time: '08:00', - exclude: false - } - if (val.mucus) sympto.mucus = { - value: val.mucus, - feeling: val.mucus, - texture: val.mucus, - exclude: false - } - if (val.cervix && typeof val.cervix.opening === 'number' && typeof val.cervix.firmness === 'number') sympto.cervix = { - opening: val.cervix.opening, - firmness: val.cervix.firmness, - exclude: false - } - return sympto -} - -export const cycleWithFhmMucus = [ - { date: '2018-07-01', bleeding: 2 }, - { date: '2018-07-02', bleeding: 1 }, - { date: '2018-07-06', temperature: 36.2}, - { date: '2018-07-07', temperature: 36.35 }, - { date: '2018-07-09', temperature: 36.6 }, - { date: '2018-07-10', temperature: 36.45 }, - { date: '2018-07-12', temperature: 36.7, mucus: 0 }, - { date: '2018-07-13', temperature: 36.8, mucus: 4 }, - { date: '2018-07-15', temperature: 36.9, mucus: 2 }, - { date: '2018-07-16', temperature: 36.95, mucus: 2 }, - { date: '2018-07-17', temperature: 36.9, mucus: 2 }, - { date: '2018-07-18', temperature: 36.9, mucus: 2 } -].map(convertToSymptoFormat).reverse() - -export const longAndComplicatedCycleWithMucus = [ - { date: '2018-06-01', temperature: 36.6, bleeding: 2 }, - { date: '2018-06-02', temperature: 36.65 }, - { date: '2018-06-04', temperature: 36.6 }, - { date: '2018-06-05', temperature: 36.55 }, - { date: '2018-06-06', temperature: 36.7, mucus: 0 }, - { date: '2018-06-09', temperature: 36.5, mucus: 4 }, - { date: '2018-06-10', temperature: 36.4, mucus: 2 }, - { date: '2018-06-13', temperature: 36.45, mucus: 3 }, - { date: '2018-06-14', temperature: 36.5, mucus: 4 }, - { date: '2018-06-15', temperature: 36.55, mucus: 4 }, - { date: '2018-06-16', temperature: 36.7, mucus: 3 }, - { date: '2018-06-17', temperature: 36.65, mucus: 3 }, - { date: '2018-06-18', temperature: 36.75, mucus: 4 }, - { date: '2018-06-19', temperature: 36.8, mucus: 1 }, - { date: '2018-06-20', temperature: 36.85, mucus: 2 }, - { date: '2018-06-21', temperature: 36.8, mucus: 2 }, - { date: '2018-06-22', temperature: 36.9, mucus: 2 }, - { date: '2018-06-25', temperature: 36.9, mucus: 1 }, - { date: '2018-06-26', temperature: 36.8, mucus: 1 }, - { date: '2018-06-27', temperature: 36.9, mucus: 1 } -].map(convertToSymptoFormat).reverse() - -export const cycleWithTempAndNoMucusShift = [ - { date: '2018-05-01', temperature: 36.6, bleeding: 2 }, - { date: '2018-05-02', temperature: 36.65 }, - { date: '2018-05-05', temperature: 36.55 }, - { date: '2018-05-06', temperature: 36.7, mucus: 0 }, - { date: '2018-05-08', temperature: 36.45, mucus: 1 }, - { date: '2018-05-09', temperature: 36.5, mucus: 4 }, - { date: '2018-05-10', temperature: 36.4, mucus: 2 }, - { date: '2018-05-11', temperature: 36.5, mucus: 3 }, - { date: '2018-05-13', temperature: 36.45, mucus: 3 }, - { date: '2018-05-14', temperature: 36.5, mucus: 4 }, - { date: '2018-05-15', temperature: 36.55, mucus: 4 }, - { date: '2018-05-16', temperature: 36.7, mucus: 3 }, - { date: '2018-05-17', temperature: 36.65, mucus: 3 }, - { date: '2018-05-18', temperature: 36.75, mucus: 4 }, - { date: '2018-05-19', temperature: 36.8, mucus: 4 }, - { date: '2018-05-20', temperature: 36.85, mucus: 4 }, - { date: '2018-05-23', temperature: 36.9, mucus: 3 }, - { date: '2018-05-24', temperature: 36.85, mucus: 4 }, - { date: '2018-05-26', temperature: 36.8, mucus: 4 }, - { date: '2018-05-27', temperature: 36.9, mucus: 4 } -].map(convertToSymptoFormat).reverse() - -export const cervixShiftAndFhmOnSameDay = [ - { date: '2018-08-01', bleeding: 2 }, - { date: '2018-08-02', bleeding: 1 }, - { date: '2018-08-03', bleeding: 0 }, - { date: '2018-08-04', bleeding: 0 }, - { date: '2018-08-05', temperature: 36.07 }, - { date: '2018-08-06', temperature: 36.2 }, - { date: '2018-08-07', temperature: 36.35 }, - { date: '2018-08-08', temperature: 36.4 }, - { date: '2018-08-09', temperature: 36.3 }, - { date: '2018-08-10', temperature: 36.45 }, - { date: '2018-08-11', temperature: 36.45 }, - { date: '2018-08-12', temperature: 36.7, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-08-13', temperature: 36.8, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-08-14', temperature: 36.75, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-08-15', temperature: 36.9, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-08-16', temperature: 36.95, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-08-17', temperature: 36.9, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-08-18', temperature: 36.9, cervix: { opening: 1, firmness: 0 } } -].map(convertToSymptoFormat).reverse() - -export const longAndComplicatedCycleWithCervix = [ - { date: '2018-06-01', temperature: 36.6, bleeding: 2 }, - { date: '2018-06-02', temperature: 36.65 }, - { date: '2018-06-04', temperature: 36.6 }, - { date: '2018-06-05', temperature: 36.55 }, - { date: '2018-06-06', temperature: 36.7, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-06-09', temperature: 36.5, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-06-10', temperature: 36.4, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-06-13', temperature: 36.45, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-06-14', temperature: 36.5, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-06-15', temperature: 36.55, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-06-16', temperature: 36.7, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-06-17', temperature: 36.65, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-06-18', temperature: 36.75, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-06-19', temperature: 36.8, cervix: { opening: 1, firmness: 0 } }, - { date: '2018-06-20', temperature: 36.85, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-06-21', temperature: 36.8, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-06-22', temperature: 36.9, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-06-25', temperature: 36.9, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-06-26', temperature: 36.8, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-06-27', temperature: 36.9, cervix: { opening: 1, firmness: 1 } } -].map(convertToSymptoFormat).reverse() - -export const cycleWithTempAndNoCervixShift = [ - { date: '2018-07-01', temperature: 36.6, bleeding: 2 }, - { date: '2018-07-02', temperature: 36.65 }, - { date: '2018-07-05', temperature: 36.55 }, - { date: '2018-07-06', temperature: 36.7, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-07-08', temperature: 36.45, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-07-09', temperature: 36.5, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-07-10', temperature: 36.4, cervix: { opening: 0, firmness: 0 } }, - { date: '2018-07-11', temperature: 36.5, cervix: { opening: 0, firmness: 1 } }, - { date: '2018-07-13', temperature: 36.45, cervix: { opening: 0, firmness: 1 } }, - { date: '2018-07-14', temperature: 36.5, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-07-15', temperature: 36.55, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-07-16', temperature: 36.7, cervix: { opening: 0, firmness: 1 } }, - { date: '2018-07-17', temperature: 36.65, cervix: { opening: 0, firmness: 1 } }, - { date: '2018-07-18', temperature: 36.75, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-07-19', temperature: 36.8, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-07-20', temperature: 36.85, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-07-23', temperature: 36.9, cervix: { opening: 0, firmness: 1 } }, - { date: '2018-07-24', temperature: 36.85, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-07-26', temperature: 36.8, cervix: { opening: 1, firmness: 1 } }, - { date: '2018-07-27', temperature: 36.9, cervix: { opening: 1, firmness: 1 } } -].map(convertToSymptoFormat).reverse() diff --git a/db/index.js b/db/index.js index 34afd23..ce0212a 100644 --- a/db/index.js +++ b/db/index.js @@ -3,14 +3,6 @@ import { LocalDate, ChronoUnit } from 'js-joda' import nodejs from 'nodejs-mobile-react-native' import fs from 'react-native-fs' import restart from 'react-native-restart' -import { - cycleWithFhmMucus, - longAndComplicatedCycleWithMucus, - cycleWithTempAndNoMucusShift, - cervixShiftAndFhmOnSameDay, - longAndComplicatedCycleWithCervix, - cycleWithTempAndNoCervixShift -} from './fixtures' import schemas from './schemas' let db @@ -75,56 +67,6 @@ export function getCycleDay(localDate) { return db.objectForPrimaryKey('CycleDay', localDate) } -export function fillWithMucusDummyData() { - const dummyCycles = [ - cycleWithFhmMucus, - longAndComplicatedCycleWithMucus, - cycleWithTempAndNoMucusShift - ] - - db.write(() => { - db.deleteAll() - dummyCycles.forEach(cycle => { - cycle.forEach(day => { - const existing = getCycleDay(day.date) - if (existing) { - Object.keys(day).forEach(key => { - if (key === 'date') return - existing[key] = day[key] - }) - } else { - db.create('CycleDay', day) - } - }) - }) - }) -} - -export function fillWithCervixDummyData() { - const dummyCycles = [ - cervixShiftAndFhmOnSameDay, - longAndComplicatedCycleWithCervix, - cycleWithTempAndNoCervixShift - ] - - db.write(() => { - db.deleteAll() - dummyCycles.forEach(cycle => { - cycle.forEach(day => { - const existing = getCycleDay(day.date) - if (existing) { - Object.keys(day).forEach(key => { - if (key === 'date') return - existing[key] = day[key] - }) - } else { - db.create('CycleDay', day) - } - }) - }) - }) -} - export function getPreviousTemperature(cycleDay) { cycleDay.wrappedDate = LocalDate.parse(cycleDay.date) const winner = getTemperatureDaysSortedByDate().find(day => { diff --git a/lib/sympto-adapter.js b/lib/sympto-adapter.js index 363538e..278f9c9 100644 --- a/lib/sympto-adapter.js +++ b/lib/sympto-adapter.js @@ -1,10 +1,13 @@ import getFertilityStatus from './sympto' import cycleModule from './cycle' -import { fertilityStatus } from '../components/cycle-day/labels/labels' +import { fertilityStatus } from '../components/labels' -export function getFertilityStatusStringForDay(dateString) { +export function getFertilityStatusForDay(dateString) { const status = getCycleStatusForDay(dateString) - if (!status) return fertilityStatus.unknown + if (!status) return { + status: fertilityStatus.fertile, + phase: null + } const phaseNameForDay = Object.keys(status.phases).find(phaseName => { const phase = status.phases[phaseName] @@ -18,7 +21,7 @@ export function getFertilityStatusStringForDay(dateString) { return dayIsAfterPhaseStart && dayIsBeforePhaseEnd }) - return mapToString(phaseNameForDay, dateString, status) + return formatStatus(phaseNameForDay, dateString, status) } export function getCycleStatusForDay(dateString) { @@ -46,17 +49,33 @@ export function getCycleStatusForDay(dateString) { return getFertilityStatus(cycleInfo) } -function mapToString(phaseNameForDay, dateString, status) { +function formatStatus(phaseNameForDay, dateString, status) { const mapping = { - preOvulatory: () => fertilityStatus.infertile, + preOvulatory: () => { + return { + status: fertilityStatus.infertile, + phase: 1, + statusText: fertilityStatus.preOvuText + } + }, periOvulatory: (dateString, status) => { const phaseEnd = status.phases.periOvulatory.end if (phaseEnd && phaseEnd.date === dateString) { return fertilityStatus.fertileUntilEvening } - return fertilityStatus.fertile + return { + status: fertilityStatus.fertile, + phase: 2, + statusText: fertilityStatus.periOvuText + } }, - postOvulatory: () => fertilityStatus.infertile + postOvulatory: (dateString, status) => { + return { + status: fertilityStatus.infertile, + phase: 3, + statusText: fertilityStatus.postOvuText(status.temperatureShift.rule) + } + } } return mapping[phaseNameForDay](dateString, status) diff --git a/lib/sympto/index.js b/lib/sympto/index.js index 96e2b49..f698dc0 100644 --- a/lib/sympto/index.js +++ b/lib/sympto/index.js @@ -35,6 +35,7 @@ export default function getSymptoThermalStatus(cycleInfo) { } } + // TODO maybe add indicator if there was no preovuphase? status.phases.periOvulatory = { start: { date: null }, cycleDays: [] diff --git a/styles/index.js b/styles/index.js index 3d19cf3..c8712c7 100644 --- a/styles/index.js +++ b/styles/index.js @@ -10,6 +10,8 @@ export const shadesOfRed = [ '#cf323d', '#c3000d' ] // light to dark +export const cycleDayColor = '#29287f' +export const periodColor = '#802249' const fontRegular = 'Prompt-Light' const fontLight = 'Prompt-Thin' @@ -27,6 +29,11 @@ export default StyleSheet.create({ fontFamily: fontRegular, fontSize: regularSize }, + appTextLight: { + color: 'black', + fontFamily: fontLight, + fontSize: regularSize + }, paragraph: { marginBottom: defaultBottomMargin }, @@ -69,6 +76,58 @@ export default StyleSheet.create({ borderRadius: 100, position: 'absolute' }, + homeView: { + marginHorizontal: 50, + marginTop: 20, + }, + homeButton: { + paddingVertical: 10, + paddingHorizontal: 20, + borderRadius: 5, + alignItems: 'center', + width: 200, + }, + homeButtonText: { + color: fontOnPrimaryColor + }, + homeIconElement: { + alignItems: 'center', + marginBottom: 10 + }, + homeIconTextWrapper: { + alignItems: 'center', + justifyContent: 'center', + marginBottom: 10, + }, + wrapperCycle: { + width: 70, + height: 75 + }, + wrapperDrop: { + width: 80, + height: 80, + marginTop: 20 + }, + homeCircle: { + borderRadius: 100, + borderWidth: 0.5, + width: 80, + height: 80, + alignItems: 'center', + justifyContent: 'center', + borderColor: secondaryColor, + }, + iconText: { + fontSize: 25 + }, + showMore: { + transform: [{rotate: '90deg'}], + position: 'absolute', + }, + showLess: { + transform: [{rotate: '270deg'}], + position: 'absolute' + }, cycleDayNumber: { fontSize: 15, color: fontOnPrimaryColor, @@ -168,12 +227,6 @@ export default StyleSheet.create({ fontSize: 60, color: fontOnPrimaryColor }, - homeButtons: { - marginHorizontal: 15 - }, - homeButton: { - marginBottom: 15 - }, temperatureTextInput: { fontSize: 20, color: 'black',