Merge branch '676-feature-customisation-not-display-mucus-cervix' into 'main'
Disable and switch secondary symptom depending on cervical mucus and cervix turned on or off. Closes #676 See merge request bloodyhealth/drip!656
This commit is contained in:
+2
-2
@@ -33,9 +33,10 @@ We are an open source project and we highly appreciate contributions. At the sam
|
|||||||
- 🔮 open source
|
- 🔮 open source
|
||||||
- 🩸 feminist and gender inclusive
|
- 🩸 feminist and gender inclusive
|
||||||
- 🔒 secure: data entered stays with that person/on their device
|
- 🔒 secure: data entered stays with that person/on their device
|
||||||
- 🔬 science based: we implemented the symptothermal method
|
- 🔬 science-based: we implemented the sympto-thermal method
|
||||||
|
|
||||||
This means that we will never implement anything that contradicts these core values. Some examples: We will never build a cloud integration, we will never make an ovulation prediction.
|
This means that we will never implement anything that contradicts these core values. Some examples: We will never build a cloud integration, we will never make an ovulation prediction.
|
||||||
|
|
||||||
- If you would like to make a sustainable contribution to the project, we would be happy to join the game.
|
- If you would like to make a sustainable contribution to the project, we would be happy to join the game.
|
||||||
|
|
||||||
### Reporting Bugs or Making Suggestions
|
### Reporting Bugs or Making Suggestions
|
||||||
@@ -48,7 +49,6 @@ If you found a bug or have suggestions, please :one: first review the [list of e
|
|||||||
- If you want to open a merge request, yeah :tada: exciting! We are using a template for merge requests to make sure we explain what we have done and why.
|
- If you want to open a merge request, yeah :tada: exciting! We are using a template for merge requests to make sure we explain what we have done and why.
|
||||||
- Keep in mind that people who will review your merge request are more motivated to do so when the merge request is well explained and ideally not too big.
|
- Keep in mind that people who will review your merge request are more motivated to do so when the merge request is well explained and ideally not too big.
|
||||||
|
|
||||||
|
|
||||||
### Thank you
|
### Thank you
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
+7
-3
@@ -14,7 +14,10 @@ import {
|
|||||||
determinePredictionText,
|
determinePredictionText,
|
||||||
formatWithOrdinalSuffix,
|
formatWithOrdinalSuffix,
|
||||||
} from './helpers/home'
|
} from './helpers/home'
|
||||||
import { periodPredictionObservable } from '../local-storage'
|
import {
|
||||||
|
fertilityTrackingObservable,
|
||||||
|
periodPredictionObservable,
|
||||||
|
} from '../local-storage'
|
||||||
|
|
||||||
import { Colors, Fonts, Sizes, Spacing } from '../styles'
|
import { Colors, Fonts, Sizes, Spacing } from '../styles'
|
||||||
import { LocalDate } from '@js-joda/core'
|
import { LocalDate } from '@js-joda/core'
|
||||||
@@ -28,11 +31,12 @@ const Home = ({ navigate, setDate }) => {
|
|||||||
navigate('CycleDay')
|
navigate('CycleDay')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isFertilityTrackingEnabled = fertilityTrackingObservable.value
|
||||||
const todayDateString = LocalDate.now().toString()
|
const todayDateString = LocalDate.now().toString()
|
||||||
const { getCycleDayNumber, getPredictedMenses } = cycleModule()
|
const { getCycleDayNumber, getPredictedMenses } = cycleModule()
|
||||||
const cycleDayNumber = getCycleDayNumber(todayDateString)
|
const cycleDayNumber = getCycleDayNumber(todayDateString)
|
||||||
const { status, phase, statusText } =
|
const { status, phase, statusText } =
|
||||||
getFertilityStatusForDay(todayDateString)
|
isFertilityTrackingEnabled && getFertilityStatusForDay(todayDateString)
|
||||||
const isPeriodPredictionEnabled = periodPredictionObservable.value
|
const isPeriodPredictionEnabled = periodPredictionObservable.value
|
||||||
const prediction = determinePredictionText(getPredictedMenses(), t)
|
const prediction = determinePredictionText(getPredictedMenses(), t)
|
||||||
|
|
||||||
@@ -55,7 +59,7 @@ const Home = ({ navigate, setDate }) => {
|
|||||||
</AppText>
|
</AppText>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{phase && (
|
{isFertilityTrackingEnabled && phase && (
|
||||||
<View style={styles.line}>
|
<View style={styles.line}>
|
||||||
<AppText style={styles.whiteSubtitle}>
|
<AppText style={styles.whiteSubtitle}>
|
||||||
{formatWithOrdinalSuffix(phase)}
|
{formatWithOrdinalSuffix(phase)}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import {
|
|||||||
painTrackingCategoryObservable,
|
painTrackingCategoryObservable,
|
||||||
sexTrackingCategoryObservable,
|
sexTrackingCategoryObservable,
|
||||||
temperatureTrackingCategoryObservable,
|
temperatureTrackingCategoryObservable,
|
||||||
|
mucusTrackingCategoryObservable,
|
||||||
|
cervixTrackingCategoryObservable,
|
||||||
} from '../../local-storage'
|
} from '../../local-storage'
|
||||||
import { makeColumnInfo } from '../helpers/chart'
|
import { makeColumnInfo } from '../helpers/chart'
|
||||||
|
|
||||||
@@ -72,6 +74,10 @@ const CycleChart = ({ navigate, setDate }) => {
|
|||||||
const symptomRowEnabledSymptoms = symptomRowSymptoms.filter((symptom) => {
|
const symptomRowEnabledSymptoms = symptomRowSymptoms.filter((symptom) => {
|
||||||
if (symptom === 'sex') {
|
if (symptom === 'sex') {
|
||||||
return sexTrackingCategoryObservable.value ? symptom : null
|
return sexTrackingCategoryObservable.value ? symptom : null
|
||||||
|
} else if (symptom === 'mucus') {
|
||||||
|
return mucusTrackingCategoryObservable.value ? symptom : null
|
||||||
|
} else if (symptom === 'cervix') {
|
||||||
|
return cervixTrackingCategoryObservable.value ? symptom : null
|
||||||
} else if (symptom === 'desire') {
|
} else if (symptom === 'desire') {
|
||||||
return desireTrackingCategoryObservable.value ? symptom : null
|
return desireTrackingCategoryObservable.value ? symptom : null
|
||||||
} else if (symptom === 'pain') {
|
} else if (symptom === 'pain') {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { StyleSheet, Switch, View } from 'react-native'
|
import { Platform, StyleSheet, Switch, View } from 'react-native'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
import AppText from './app-text'
|
import AppText from './app-text'
|
||||||
|
|
||||||
import { Colors, Containers } from '../../styles'
|
import { Colors, Containers, Spacing } from '../../styles'
|
||||||
|
|
||||||
const AppSwitch = ({ onToggle, text, value, disabled }) => {
|
const AppSwitch = ({ onToggle, text, value, disabled }) => {
|
||||||
const trackColor = { true: Colors.turquoiseDark }
|
const trackColor = { true: Colors.turquoiseDark }
|
||||||
@@ -34,9 +34,14 @@ AppSwitch.propTypes = {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
...Containers.rowContainer,
|
...Containers.rowContainer,
|
||||||
|
marginTop: Spacing.tiny,
|
||||||
},
|
},
|
||||||
switch: {
|
switch: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
transform:
|
||||||
|
Platform.OS === 'ios'
|
||||||
|
? [{ scaleX: 0.8 }, { scaleY: 0.8 }]
|
||||||
|
: [{ scaleX: 1 }, { scaleY: 1 }],
|
||||||
},
|
},
|
||||||
textContainer: {
|
textContainer: {
|
||||||
flex: 4,
|
flex: 4,
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { Platform, StyleSheet, Switch, View } from 'react-native'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
import AppText from './app-text'
|
||||||
|
|
||||||
|
import DripIcon from '../../assets/drip-icons'
|
||||||
|
import { Colors, Containers, Sizes, Spacing } from '../../styles'
|
||||||
|
|
||||||
|
const TrackingCategorySwitch = ({ onToggle, symptom, text, value }) => {
|
||||||
|
const trackColor = { true: Colors.turquoiseDark }
|
||||||
|
const iconColor = value ? Colors.iconColors[symptom].color : Colors.grey
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.iconContainer}>
|
||||||
|
<DripIcon
|
||||||
|
color={iconColor}
|
||||||
|
name={`drip-icon-${symptom}`}
|
||||||
|
size={Sizes.title}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.textContainer}>
|
||||||
|
<AppText>{text}</AppText>
|
||||||
|
</View>
|
||||||
|
<Switch
|
||||||
|
onValueChange={onToggle}
|
||||||
|
style={styles.appSwitch}
|
||||||
|
value={value}
|
||||||
|
trackColor={trackColor}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackingCategorySwitch.propTypes = {
|
||||||
|
onToggle: PropTypes.func.isRequired,
|
||||||
|
symptom: PropTypes.string,
|
||||||
|
text: PropTypes.string,
|
||||||
|
value: PropTypes.bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
...Containers.rowContainer,
|
||||||
|
marginVertical: Spacing.tiny,
|
||||||
|
},
|
||||||
|
iconContainer: {
|
||||||
|
marginRight: Spacing.tiny,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
textContainer: {
|
||||||
|
flex: 5,
|
||||||
|
},
|
||||||
|
appSwitch: {
|
||||||
|
flex: 2,
|
||||||
|
transform:
|
||||||
|
Platform.OS === 'ios'
|
||||||
|
? [{ scaleX: 0.8 }, { scaleY: 0.8 }]
|
||||||
|
: [{ scaleX: 1 }, { scaleY: 1 }],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default TrackingCategorySwitch
|
||||||
@@ -16,6 +16,8 @@ import {
|
|||||||
painTrackingCategoryObservable,
|
painTrackingCategoryObservable,
|
||||||
sexTrackingCategoryObservable,
|
sexTrackingCategoryObservable,
|
||||||
temperatureTrackingCategoryObservable,
|
temperatureTrackingCategoryObservable,
|
||||||
|
mucusTrackingCategoryObservable,
|
||||||
|
cervixTrackingCategoryObservable,
|
||||||
} from '../../local-storage'
|
} from '../../local-storage'
|
||||||
import { Spacing } from '../../styles'
|
import { Spacing } from '../../styles'
|
||||||
import { SYMPTOMS } from '../../config'
|
import { SYMPTOMS } from '../../config'
|
||||||
@@ -40,6 +42,10 @@ const CycleDayOverView = ({ date, setDate, isTemperatureEditView }) => {
|
|||||||
return temperatureTrackingCategoryObservable.value ? symptom : null
|
return temperatureTrackingCategoryObservable.value ? symptom : null
|
||||||
} else if (symptom === 'sex') {
|
} else if (symptom === 'sex') {
|
||||||
return sexTrackingCategoryObservable.value ? symptom : null
|
return sexTrackingCategoryObservable.value ? symptom : null
|
||||||
|
} else if (symptom === 'mucus') {
|
||||||
|
return mucusTrackingCategoryObservable.value ? symptom : null
|
||||||
|
} else if (symptom === 'cervix') {
|
||||||
|
return cervixTrackingCategoryObservable.value ? symptom : null
|
||||||
} else if (symptom === 'desire') {
|
} else if (symptom === 'desire') {
|
||||||
return desireTrackingCategoryObservable.value ? symptom : null
|
return desireTrackingCategoryObservable.value ? symptom : null
|
||||||
} else if (symptom === 'pain') {
|
} else if (symptom === 'pain') {
|
||||||
|
|||||||
@@ -1,22 +1,58 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { StyleSheet, TouchableOpacity, View } from 'react-native'
|
import { Alert, StyleSheet, TouchableOpacity, View } from 'react-native'
|
||||||
|
|
||||||
import AppText from '../common/app-text'
|
import AppText from '../common/app-text'
|
||||||
|
|
||||||
import { Colors, Containers } from '../../styles'
|
import { Colors, Containers } from '../../styles'
|
||||||
|
import labels from '../../i18n/en/settings'
|
||||||
|
|
||||||
|
export default function SelectTabGroup({
|
||||||
|
activeButton,
|
||||||
|
buttons,
|
||||||
|
onSelect,
|
||||||
|
disabled,
|
||||||
|
}) {
|
||||||
|
// TODO https://gitlab.com/bloodyhealth/drip/-/issues/707
|
||||||
|
const oneTimeTransformIntoNumber =
|
||||||
|
typeof activeButton === 'boolean' && Number(activeButton)
|
||||||
|
const isSecondarySymptomSwitch =
|
||||||
|
buttons[0]['label'] === labels.secondarySymptom.mucus
|
||||||
|
|
||||||
|
// Disable is only used for secondarySymptom in customization, if more come up maybe consider more tidy solution
|
||||||
|
const showDisabledAlert = (label) => {
|
||||||
|
if (label === 'cervix' || label === 'mucus') {
|
||||||
|
Alert.alert(
|
||||||
|
labels.secondarySymptom.disabled.title,
|
||||||
|
labels.secondarySymptom.disabled.message
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default function SelectTabGroup({ activeButton, buttons, onSelect }) {
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
{buttons.map(({ label, value }, i) => {
|
{buttons.map(({ label, value }, i) => {
|
||||||
const isActive = value === activeButton
|
const isActive =
|
||||||
const boxStyle = [styles.box, isActive && styles.boxActive]
|
value === activeButton || value === oneTimeTransformIntoNumber
|
||||||
const textStyle = [styles.text, isActive && styles.textActive]
|
const boxStyle = [
|
||||||
|
styles.box,
|
||||||
|
isActive && styles.boxActive,
|
||||||
|
isSecondarySymptomSwitch && styles.purpleBox,
|
||||||
|
isSecondarySymptomSwitch && isActive && styles.activePurpleBox,
|
||||||
|
disabled && styles.disabledBox,
|
||||||
|
]
|
||||||
|
const textStyle = [
|
||||||
|
styles.text,
|
||||||
|
isSecondarySymptomSwitch && styles.purpleText,
|
||||||
|
isActive && styles.textActive,
|
||||||
|
disabled && styles.greyText,
|
||||||
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => onSelect(value)}
|
onPress={() =>
|
||||||
|
!disabled ? onSelect(value) : showDisabledAlert(label)
|
||||||
|
}
|
||||||
key={i}
|
key={i}
|
||||||
style={boxStyle}
|
style={boxStyle}
|
||||||
>
|
>
|
||||||
@@ -32,6 +68,7 @@ SelectTabGroup.propTypes = {
|
|||||||
activeButton: PropTypes.number,
|
activeButton: PropTypes.number,
|
||||||
buttons: PropTypes.array.isRequired,
|
buttons: PropTypes.array.isRequired,
|
||||||
onSelect: PropTypes.func.isRequired,
|
onSelect: PropTypes.func.isRequired,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
@@ -50,4 +87,20 @@ const styles = StyleSheet.create({
|
|||||||
textActive: {
|
textActive: {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
},
|
},
|
||||||
|
purpleBox: {
|
||||||
|
borderColor: Colors.purple,
|
||||||
|
},
|
||||||
|
activePurpleBox: {
|
||||||
|
backgroundColor: Colors.purple,
|
||||||
|
},
|
||||||
|
purpleText: {
|
||||||
|
color: Colors.purple,
|
||||||
|
},
|
||||||
|
greyText: {
|
||||||
|
color: Colors.grey,
|
||||||
|
},
|
||||||
|
disabledBox: {
|
||||||
|
borderColor: Colors.grey,
|
||||||
|
backgroundColor: Colors.turquoiseLight,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const SymptomBox = ({
|
|||||||
editedSymptom,
|
editedSymptom,
|
||||||
setEditedSymptom,
|
setEditedSymptom,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation(null, { keyPrefix: 'cycleDay.symptomBox' })
|
const { t } = useTranslation(null, { keyPrefix: 'symptoms' })
|
||||||
const isSymptomEdited = editedSymptom === symptom
|
const isSymptomEdited = editedSymptom === symptom
|
||||||
const isSymptomDisabled = isDateInFuture(date) && symptom !== 'note'
|
const isSymptomDisabled = isDateInFuture(date) && symptom !== 'note'
|
||||||
const isExcluded = symptomData !== null ? symptomData.exclude : false
|
const isExcluded = symptomData !== null ? symptomData.exclude : false
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { LocalDate } from '@js-joda/core'
|
import { LocalDate } from '@js-joda/core'
|
||||||
|
|
||||||
import { scaleObservable, unitObservable } from '../../local-storage'
|
import {
|
||||||
|
fertilityTrackingObservable,
|
||||||
|
scaleObservable,
|
||||||
|
unitObservable,
|
||||||
|
} from '../../local-storage'
|
||||||
import { getCycleStatusForDay } from '../../lib/sympto-adapter'
|
import { getCycleStatusForDay } from '../../lib/sympto-adapter'
|
||||||
import { getCycleDay, getAmountOfCycleDays } from '../../db'
|
import { getCycleDay, getAmountOfCycleDays } from '../../db'
|
||||||
|
|
||||||
@@ -270,7 +274,8 @@ export function nfpLines() {
|
|||||||
if (dateString < cycle.startDate) updateCurrentCycle(dateString)
|
if (dateString < cycle.startDate) updateCurrentCycle(dateString)
|
||||||
if (cycle.noMoreCycles) return ret
|
if (cycle.noMoreCycles) return ret
|
||||||
|
|
||||||
const tempShift = cycle.status.temperatureShift
|
const tempShift =
|
||||||
|
fertilityTrackingObservable.value && cycle.status.temperatureShift
|
||||||
|
|
||||||
if (tempShift) {
|
if (tempShift) {
|
||||||
if (tempShift.firstHighMeasurementDay.date === dateString) {
|
if (tempShift.firstHighMeasurementDay.date === dateString) {
|
||||||
|
|||||||
@@ -1,37 +1,47 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { Alert, Pressable } from 'react-native'
|
import { Alert, Pressable } from 'react-native'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import AppPage from '../../common/app-page'
|
import AppPage from '../../common/app-page'
|
||||||
import AppSwitch from '../../common/app-switch'
|
import AppSwitch from '../../common/app-switch'
|
||||||
import AppText from '../../common/app-text'
|
import AppText from '../../common/app-text'
|
||||||
import TemperatureSlider from './temperature-slider'
|
import TemperatureSlider from './temperature-slider'
|
||||||
import Segment from '../../common/segment'
|
import Segment from '../../common/segment'
|
||||||
|
import TrackingCategorySwitch from '../../common/tracking-category-switch'
|
||||||
|
import SelectTabGroup from '../../cycle-day/select-tab-group'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
desireTrackingCategoryObservable,
|
desireTrackingCategoryObservable,
|
||||||
|
fertilityTrackingObservable,
|
||||||
moodTrackingCategoryObservable,
|
moodTrackingCategoryObservable,
|
||||||
noteTrackingCategoryObservable,
|
noteTrackingCategoryObservable,
|
||||||
painTrackingCategoryObservable,
|
painTrackingCategoryObservable,
|
||||||
sexTrackingCategoryObservable,
|
sexTrackingCategoryObservable,
|
||||||
temperatureTrackingCategoryObservable,
|
temperatureTrackingCategoryObservable,
|
||||||
|
mucusTrackingCategoryObservable,
|
||||||
|
cervixTrackingCategoryObservable,
|
||||||
|
periodPredictionObservable,
|
||||||
|
useCervixAsSecondarySymptomObservable,
|
||||||
saveDesireTrackingCategory,
|
saveDesireTrackingCategory,
|
||||||
|
saveFertilityTrackingEnabled,
|
||||||
saveMoodTrackingCategory,
|
saveMoodTrackingCategory,
|
||||||
saveNoteTrackingCategory,
|
saveNoteTrackingCategory,
|
||||||
savePainTrackingCategory,
|
savePainTrackingCategory,
|
||||||
|
saveMucusTrackingCategory,
|
||||||
|
saveCervixTrackingCategory,
|
||||||
savePeriodPrediction,
|
savePeriodPrediction,
|
||||||
saveSexTrackingCategory,
|
saveSexTrackingCategory,
|
||||||
saveTemperatureTrackingCategory,
|
saveTemperatureTrackingCategory,
|
||||||
saveUseCervix,
|
saveUseCervixAsSecondarySymptom,
|
||||||
periodPredictionObservable,
|
|
||||||
useCervixObservable,
|
|
||||||
} from '../../../local-storage'
|
} from '../../../local-storage'
|
||||||
import labels from '../../../i18n/en/settings'
|
import labels from '../../../i18n/en/settings'
|
||||||
import { SYMPTOMS } from '../../../config'
|
import { SYMPTOMS } from '../../../config'
|
||||||
|
|
||||||
const Settings = () => {
|
const Settings = () => {
|
||||||
const [shouldUseCervix, setShouldUseCervix] = useState(
|
const { t } = useTranslation(null, { keyPrefix: 'symptoms' })
|
||||||
useCervixObservable.value
|
|
||||||
)
|
const [useCervixAsSecondarySymptom, setUseCervixAsSecondarySymptom] =
|
||||||
|
useState(useCervixAsSecondarySymptomObservable.value)
|
||||||
|
|
||||||
const [isPeriodPredictionEnabled, setPeriodPrediction] = useState(
|
const [isPeriodPredictionEnabled, setPeriodPrediction] = useState(
|
||||||
periodPredictionObservable.value
|
periodPredictionObservable.value
|
||||||
@@ -40,6 +50,14 @@ const Settings = () => {
|
|||||||
const [isTemperatureTrackingCategoryEnabled, setTemperatureTrackingCategory] =
|
const [isTemperatureTrackingCategoryEnabled, setTemperatureTrackingCategory] =
|
||||||
useState(temperatureTrackingCategoryObservable.value)
|
useState(temperatureTrackingCategoryObservable.value)
|
||||||
|
|
||||||
|
const [isMucusTrackingCategoryEnabled, setMucusTrackingCategory] = useState(
|
||||||
|
mucusTrackingCategoryObservable.value
|
||||||
|
)
|
||||||
|
|
||||||
|
const [isCervixTrackingCategoryEnabled, setCervixTrackingCategory] = useState(
|
||||||
|
cervixTrackingCategoryObservable.value
|
||||||
|
)
|
||||||
|
|
||||||
const [isSexTrackingCategoryEnabled, setSexTrackingCategory] = useState(
|
const [isSexTrackingCategoryEnabled, setSexTrackingCategory] = useState(
|
||||||
sexTrackingCategoryObservable.value
|
sexTrackingCategoryObservable.value
|
||||||
)
|
)
|
||||||
@@ -60,19 +78,33 @@ const Settings = () => {
|
|||||||
noteTrackingCategoryObservable.value
|
noteTrackingCategoryObservable.value
|
||||||
)
|
)
|
||||||
|
|
||||||
const [isEnabled, setIsEnabled] = useState(false)
|
const [isFertilityTrackingEnabled, setFertilityTrackingEnabled] = useState(
|
||||||
const toggleSwitch = () => setIsEnabled((previousState) => !previousState)
|
fertilityTrackingObservable.value
|
||||||
|
)
|
||||||
|
|
||||||
|
const fertilityTrackingToggle = (value) => {
|
||||||
|
setFertilityTrackingEnabled(value)
|
||||||
|
saveFertilityTrackingEnabled(value)
|
||||||
|
}
|
||||||
|
|
||||||
const temperatureTrackingCategoryToggle = (value) => {
|
const temperatureTrackingCategoryToggle = (value) => {
|
||||||
setTemperatureTrackingCategory(value)
|
setTemperatureTrackingCategory(value)
|
||||||
saveTemperatureTrackingCategory(value)
|
saveTemperatureTrackingCategory(value)
|
||||||
|
if (!value) {
|
||||||
|
setFertilityTrackingEnabled(false)
|
||||||
|
saveFertilityTrackingEnabled(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const mucusTrackingCategoryToggle = (value) => {
|
||||||
|
manageSecondarySymptom(cervixTrackingCategoryObservable.value, value)
|
||||||
|
}
|
||||||
|
const cervixTrackingCategoryToggle = (value) => {
|
||||||
|
manageSecondarySymptom(value, mucusTrackingCategoryObservable.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const sexTrackingCategoryToggle = (value) => {
|
const sexTrackingCategoryToggle = (value) => {
|
||||||
setSexTrackingCategory(value)
|
setSexTrackingCategory(value)
|
||||||
saveSexTrackingCategory(value)
|
saveSexTrackingCategory(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const desireTrackingCategoryToggle = (value) => {
|
const desireTrackingCategoryToggle = (value) => {
|
||||||
setDesireTrackingCategory(value)
|
setDesireTrackingCategory(value)
|
||||||
saveDesireTrackingCategory(value)
|
saveDesireTrackingCategory(value)
|
||||||
@@ -89,99 +121,187 @@ const Settings = () => {
|
|||||||
setNoteTrackingCategory(value)
|
setNoteTrackingCategory(value)
|
||||||
saveNoteTrackingCategory(value)
|
saveNoteTrackingCategory(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPeriodPredictionToggle = (value) => {
|
const onPeriodPredictionToggle = (value) => {
|
||||||
setPeriodPrediction(value)
|
setPeriodPrediction(value)
|
||||||
savePeriodPrediction(value)
|
savePeriodPrediction(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fertilityTrackingText = isFertilityTrackingEnabled
|
||||||
|
? labels.fertilityTracking.on
|
||||||
|
: labels.fertilityTracking.off
|
||||||
|
|
||||||
const periodPredictionText = isPeriodPredictionEnabled
|
const periodPredictionText = isPeriodPredictionEnabled
|
||||||
? labels.periodPrediction.on
|
? labels.periodPrediction.on
|
||||||
: labels.periodPrediction.off
|
: labels.periodPrediction.off
|
||||||
|
|
||||||
const onCervixToggle = (value) => {
|
const secondarySymptomButtons = [
|
||||||
setShouldUseCervix(value)
|
{
|
||||||
saveUseCervix(value)
|
label: labels.secondarySymptom.mucus,
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: labels.secondarySymptom.cervix,
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const onSelectTab = (value) => {
|
||||||
|
if (isMucusTrackingCategoryEnabled && isCervixTrackingCategoryEnabled) {
|
||||||
|
setUseCervixAsSecondarySymptom(value)
|
||||||
|
saveUseCervixAsSecondarySymptom(value)
|
||||||
|
} else {
|
||||||
|
secondarySymptomDisabledPrompt()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cervixText = shouldUseCervix
|
// is needed so secondary symptom is set correct on load
|
||||||
? labels.useCervix.cervixModeOn
|
useEffect(() => {
|
||||||
: labels.useCervix.cervixModeOff
|
manageSecondarySymptom(
|
||||||
|
cervixTrackingCategoryObservable.value,
|
||||||
|
mucusTrackingCategoryObservable.value
|
||||||
|
)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const manageSecondarySymptom = (cervix, mucus) => {
|
||||||
|
if (!cervix && mucus) {
|
||||||
|
setUseCervixAsSecondarySymptom(0)
|
||||||
|
saveUseCervixAsSecondarySymptom(0)
|
||||||
|
} else if (cervix && !mucus) {
|
||||||
|
setUseCervixAsSecondarySymptom(1)
|
||||||
|
saveUseCervixAsSecondarySymptom(1)
|
||||||
|
} else if (!cervix && !mucus) {
|
||||||
|
setFertilityTrackingEnabled(false)
|
||||||
|
saveFertilityTrackingEnabled(false)
|
||||||
|
}
|
||||||
|
setMucusTrackingCategory(mucus)
|
||||||
|
saveMucusTrackingCategory(mucus)
|
||||||
|
setCervixTrackingCategory(cervix)
|
||||||
|
saveCervixTrackingCategory(cervix)
|
||||||
|
}
|
||||||
|
|
||||||
|
const secondarySymptomDisabledPrompt = () => {
|
||||||
|
if (!isFertilityTrackingEnabled) {
|
||||||
|
Alert.alert(
|
||||||
|
labels.secondarySymptom.disabled.title,
|
||||||
|
labels.secondarySymptom.disabled.message
|
||||||
|
)
|
||||||
|
} else if (
|
||||||
|
!isMucusTrackingCategoryEnabled == isCervixTrackingCategoryEnabled
|
||||||
|
) {
|
||||||
|
Alert.alert(
|
||||||
|
labels.secondarySymptom.disabled.title,
|
||||||
|
labels.secondarySymptom.disabled.noSecondaryEnabled
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const manageFertilityFeature =
|
||||||
|
isTemperatureTrackingCategoryEnabled &&
|
||||||
|
(isMucusTrackingCategoryEnabled || isCervixTrackingCategoryEnabled)
|
||||||
|
|
||||||
|
const cervixText = useCervixAsSecondarySymptom
|
||||||
|
? labels.secondarySymptom.cervixModeOn
|
||||||
|
: labels.secondarySymptom.cervixModeOff
|
||||||
|
|
||||||
const sliderDisabledPrompt = () => {
|
const sliderDisabledPrompt = () => {
|
||||||
if (!isTemperatureTrackingCategoryEnabled) {
|
if (!isTemperatureTrackingCategoryEnabled) {
|
||||||
Alert.alert(labels.disabled.title, labels.disabled.message)
|
Alert.alert(labels.tempScale.disabled, labels.tempScale.disabledMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fertilityDisabledPrompt = () => {
|
||||||
|
if (!manageFertilityFeature) {
|
||||||
|
Alert.alert(
|
||||||
|
labels.fertilityTracking.disabledTitle,
|
||||||
|
labels.fertilityTracking.disabled
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppPage title={'Customization'}>
|
<AppPage title={labels.customization.title}>
|
||||||
<Segment title={'Tracking categories'}>
|
<Segment title={labels.customization.trackingCategories}>
|
||||||
<AppSwitch
|
<TrackingCategorySwitch
|
||||||
onToggle={temperatureTrackingCategoryToggle}
|
onToggle={temperatureTrackingCategoryToggle}
|
||||||
text={SYMPTOMS[1]}
|
text={t(SYMPTOMS[1])}
|
||||||
value={isTemperatureTrackingCategoryEnabled}
|
value={isTemperatureTrackingCategoryEnabled}
|
||||||
|
symptom={SYMPTOMS[1]}
|
||||||
/>
|
/>
|
||||||
<AppSwitch
|
<TrackingCategorySwitch
|
||||||
|
onToggle={(enabled) => {
|
||||||
|
mucusTrackingCategoryToggle(enabled)
|
||||||
|
}}
|
||||||
|
text={t(SYMPTOMS[2])}
|
||||||
|
value={isMucusTrackingCategoryEnabled}
|
||||||
|
symptom={SYMPTOMS[2]}
|
||||||
|
/>
|
||||||
|
<TrackingCategorySwitch
|
||||||
|
onToggle={(enabled) => {
|
||||||
|
cervixTrackingCategoryToggle(enabled)
|
||||||
|
}}
|
||||||
|
text={t(SYMPTOMS[3])}
|
||||||
|
value={isCervixTrackingCategoryEnabled}
|
||||||
|
symptom={SYMPTOMS[3]}
|
||||||
|
/>
|
||||||
|
<TrackingCategorySwitch
|
||||||
onToggle={sexTrackingCategoryToggle}
|
onToggle={sexTrackingCategoryToggle}
|
||||||
text={SYMPTOMS[4]}
|
text={t(SYMPTOMS[4])}
|
||||||
value={isSexTrackingCategoryEnabled}
|
value={isSexTrackingCategoryEnabled}
|
||||||
|
symptom={SYMPTOMS[4]}
|
||||||
/>
|
/>
|
||||||
<AppSwitch
|
<TrackingCategorySwitch
|
||||||
onToggle={desireTrackingCategoryToggle}
|
onToggle={desireTrackingCategoryToggle}
|
||||||
text={SYMPTOMS[5]}
|
text={t(SYMPTOMS[5])}
|
||||||
value={isDesireTrackingCategoryEnabled}
|
value={isDesireTrackingCategoryEnabled}
|
||||||
|
symptom={SYMPTOMS[5]}
|
||||||
/>
|
/>
|
||||||
<AppSwitch
|
<TrackingCategorySwitch
|
||||||
onToggle={painTrackingCategoryToggle}
|
onToggle={painTrackingCategoryToggle}
|
||||||
text={SYMPTOMS[6]}
|
text={t(SYMPTOMS[6])}
|
||||||
value={isPainTrackingCategoryEnabled}
|
value={isPainTrackingCategoryEnabled}
|
||||||
|
symptom={SYMPTOMS[6]}
|
||||||
/>
|
/>
|
||||||
<AppSwitch
|
<TrackingCategorySwitch
|
||||||
onToggle={moodTrackingCategoryToggle}
|
onToggle={moodTrackingCategoryToggle}
|
||||||
text={SYMPTOMS[7]}
|
text={t(SYMPTOMS[7])}
|
||||||
value={isMoodTrackingCategoryEnabled}
|
value={isMoodTrackingCategoryEnabled}
|
||||||
|
symptom={SYMPTOMS[7]}
|
||||||
/>
|
/>
|
||||||
<AppSwitch
|
<TrackingCategorySwitch
|
||||||
onToggle={noteTrackingCategoryToggle}
|
onToggle={noteTrackingCategoryToggle}
|
||||||
text={SYMPTOMS[8]}
|
text={t(SYMPTOMS[8])}
|
||||||
value={isNoteTrackingCategoryEnabled}
|
value={isNoteTrackingCategoryEnabled}
|
||||||
|
symptom={SYMPTOMS[8]}
|
||||||
/>
|
/>
|
||||||
</Segment>
|
</Segment>
|
||||||
|
<Pressable onPress={fertilityDisabledPrompt}>
|
||||||
<Segment title={'Fertility feature'}>
|
<Segment title={labels.fertilityTracking.title}>
|
||||||
|
<AppText>{labels.fertilityTracking.message}</AppText>
|
||||||
<AppSwitch
|
<AppSwitch
|
||||||
onToggle={toggleSwitch}
|
onToggle={fertilityTrackingToggle}
|
||||||
text={'If turned on ...'}
|
text={fertilityTrackingText}
|
||||||
value={isEnabled}
|
value={isFertilityTrackingEnabled}
|
||||||
|
disabled={!manageFertilityFeature}
|
||||||
/>
|
/>
|
||||||
</Segment>
|
</Segment>
|
||||||
|
|
||||||
<Pressable onPress={sliderDisabledPrompt}>
|
|
||||||
<Segment title={labels.tempScale.segmentTitle}>
|
|
||||||
{isTemperatureTrackingCategoryEnabled && (
|
|
||||||
<>
|
|
||||||
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
|
||||||
<TemperatureSlider />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{!isTemperatureTrackingCategoryEnabled && (
|
|
||||||
<AppText>{labels.disabled.message}</AppText>
|
|
||||||
)}
|
|
||||||
</Segment>
|
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
|
||||||
<Pressable onPress={sliderDisabledPrompt}>
|
<Pressable onPress={sliderDisabledPrompt}>
|
||||||
<Segment title={labels.useCervix.title}>
|
<Segment title={labels.tempScale.segmentTitle}>
|
||||||
{isTemperatureTrackingCategoryEnabled && (
|
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
||||||
<AppSwitch
|
<TemperatureSlider disabled={!isTemperatureTrackingCategoryEnabled} />
|
||||||
onToggle={onCervixToggle}
|
</Segment>
|
||||||
text={cervixText}
|
</Pressable>
|
||||||
value={shouldUseCervix}
|
|
||||||
|
<Pressable onPress={secondarySymptomDisabledPrompt}>
|
||||||
|
<Segment title={labels.secondarySymptom.title}>
|
||||||
|
<AppText>{cervixText}</AppText>
|
||||||
|
<SelectTabGroup
|
||||||
|
activeButton={useCervixAsSecondarySymptom}
|
||||||
|
buttons={secondarySymptomButtons}
|
||||||
|
onSelect={(value) => onSelectTab(value)}
|
||||||
|
disabled={!isFertilityTrackingEnabled}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
{!isTemperatureTrackingCategoryEnabled && (
|
|
||||||
<AppText>{labels.disabled.message}</AppText>
|
|
||||||
)}
|
|
||||||
</Segment>
|
</Segment>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { StyleSheet, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
import Slider from '@ptomasroos/react-native-multi-slider'
|
import Slider from '@ptomasroos/react-native-multi-slider'
|
||||||
|
|
||||||
import alertError from '../common/alert-error'
|
import alertError from '../common/alert-error'
|
||||||
@@ -10,7 +11,7 @@ import { Colors, Sizes } from '../../../styles'
|
|||||||
import labels from '../../../i18n/en/settings'
|
import labels from '../../../i18n/en/settings'
|
||||||
import { TEMP_MIN, TEMP_MAX, TEMP_SLIDER_STEP } from '../../../config'
|
import { TEMP_MIN, TEMP_MAX, TEMP_SLIDER_STEP } from '../../../config'
|
||||||
|
|
||||||
const TemperatureSlider = () => {
|
const TemperatureSlider = ({ disabled }) => {
|
||||||
const savedValue = scaleObservable.value
|
const savedValue = scaleObservable.value
|
||||||
const [minTemperature, setMinTemperature] = useState(savedValue.min)
|
const [minTemperature, setMinTemperature] = useState(savedValue.min)
|
||||||
const [maxTemperature, setMaxTemperature] = useState(savedValue.max)
|
const [maxTemperature, setMaxTemperature] = useState(savedValue.max)
|
||||||
@@ -25,6 +26,14 @@ const TemperatureSlider = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sliderAccentBackground = disabled
|
||||||
|
? styles.disabledSliderAccentBackground
|
||||||
|
: styles.sliderAccentBackground
|
||||||
|
|
||||||
|
const sliderBackground = disabled
|
||||||
|
? styles.disabledSliderBackground
|
||||||
|
: styles.sliderBackground
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Slider
|
<Slider
|
||||||
@@ -35,11 +44,13 @@ const TemperatureSlider = () => {
|
|||||||
max={TEMP_MAX}
|
max={TEMP_MAX}
|
||||||
min={TEMP_MIN}
|
min={TEMP_MIN}
|
||||||
onValuesChange={onTemperatureSliderChange}
|
onValuesChange={onTemperatureSliderChange}
|
||||||
selectedStyle={styles.sliderAccentBackground}
|
|
||||||
step={TEMP_SLIDER_STEP}
|
step={TEMP_SLIDER_STEP}
|
||||||
trackStyle={styles.slider}
|
trackStyle={styles.slider}
|
||||||
unselectedStyle={styles.sliderBackground}
|
|
||||||
values={[minTemperature, maxTemperature]}
|
values={[minTemperature, maxTemperature]}
|
||||||
|
enabledOne={!disabled}
|
||||||
|
enabledTwo={!disabled}
|
||||||
|
selectedStyle={sliderAccentBackground}
|
||||||
|
unselectedStyle={sliderBackground}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
@@ -47,6 +58,10 @@ const TemperatureSlider = () => {
|
|||||||
|
|
||||||
export default TemperatureSlider
|
export default TemperatureSlider
|
||||||
|
|
||||||
|
TemperatureSlider.propTypes = {
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -54,6 +69,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
marker: {
|
marker: {
|
||||||
backgroundColor: Colors.turquoiseDark,
|
backgroundColor: Colors.turquoiseDark,
|
||||||
|
|
||||||
borderRadius: 50,
|
borderRadius: 50,
|
||||||
elevation: 4,
|
elevation: 4,
|
||||||
height: Sizes.subtitle,
|
height: Sizes.subtitle,
|
||||||
@@ -66,7 +82,13 @@ const styles = StyleSheet.create({
|
|||||||
sliderAccentBackground: {
|
sliderAccentBackground: {
|
||||||
backgroundColor: Colors.turquoiseDark,
|
backgroundColor: Colors.turquoiseDark,
|
||||||
},
|
},
|
||||||
|
disabledSliderAccentBackground: {
|
||||||
|
backgroundColor: Colors.grey,
|
||||||
|
},
|
||||||
sliderBackground: {
|
sliderBackground: {
|
||||||
backgroundColor: Colors.turquoise,
|
backgroundColor: Colors.turquoise,
|
||||||
},
|
},
|
||||||
|
disabledSliderBackground: {
|
||||||
|
backgroundColor: Colors.greyLight,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-3
@@ -7,8 +7,7 @@
|
|||||||
"chart": {
|
"chart": {
|
||||||
"tutorial": "You can swipe the chart to view more dates."
|
"tutorial": "You can swipe the chart to view more dates."
|
||||||
},
|
},
|
||||||
"cycleDay": {
|
"symptoms": {
|
||||||
"symptomBox": {
|
|
||||||
"bleeding": "bleeding",
|
"bleeding": "bleeding",
|
||||||
"temperature": "temperature",
|
"temperature": "temperature",
|
||||||
"mucus": "cervical mucus",
|
"mucus": "cervical mucus",
|
||||||
@@ -18,7 +17,6 @@
|
|||||||
"sex": "sex",
|
"sex": "sex",
|
||||||
"pain": "pain",
|
"pain": "pain",
|
||||||
"mood": "mood"
|
"mood": "mood"
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"bleedingPrediction": {
|
"bleedingPrediction": {
|
||||||
|
|||||||
+33
-11
@@ -1,6 +1,10 @@
|
|||||||
import links from './links'
|
import links from './links'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
customization: {
|
||||||
|
title: 'Customization',
|
||||||
|
trackingCategories: 'Tracking categories',
|
||||||
|
},
|
||||||
export: {
|
export: {
|
||||||
errors: {
|
errors: {
|
||||||
noData: 'There is no data to export',
|
noData: 'There is no data to export',
|
||||||
@@ -32,17 +36,16 @@ export default {
|
|||||||
tempScale: {
|
tempScale: {
|
||||||
segmentTitle: 'Temperature scale',
|
segmentTitle: 'Temperature scale',
|
||||||
segmentExplainer:
|
segmentExplainer:
|
||||||
'Change the minimum and maximum value for the temperature chart',
|
'Change the minimum and maximum value for the temperature chart.',
|
||||||
min: 'Min',
|
min: 'Min',
|
||||||
max: 'Max',
|
max: 'Max',
|
||||||
loadError: 'Could not load saved temperature scale settings',
|
loadError: 'Could not load saved temperature scale settings',
|
||||||
saveError: 'Could not save temperature scale settings',
|
saveError: 'Could not save temperature scale settings',
|
||||||
|
disabled: 'Disabled',
|
||||||
|
disabledMessage:
|
||||||
|
'To use the temperature scale please first enable temperature tracking above.',
|
||||||
},
|
},
|
||||||
disabled: {
|
|
||||||
title: 'This feature is turned off',
|
|
||||||
message:
|
|
||||||
'Please first enable the temperature tracking category in the customization settings.',
|
|
||||||
},
|
|
||||||
tempReminder: {
|
tempReminder: {
|
||||||
title: 'Temperature reminder',
|
title: 'Temperature reminder',
|
||||||
noTimeSet: 'Set a time for a daily reminder to take your temperature',
|
noTimeSet: 'Set a time for a daily reminder to take your temperature',
|
||||||
@@ -66,16 +69,35 @@ export default {
|
|||||||
'To use the period reminder please first enable period predictions in the customization settings.',
|
'To use the period reminder please first enable period predictions in the customization settings.',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
useCervix: {
|
fertilityTracking: {
|
||||||
|
title: 'Fertility phases calculation',
|
||||||
|
disabledTitle: 'Disabled',
|
||||||
|
disabled:
|
||||||
|
'To use fertility phases calculation please enable temperature tracking and cervical mucus or cervix tracking above.',
|
||||||
|
message:
|
||||||
|
'If you enter menstrual bleeding, temperature and cervical mucus or cervix data according to the sympto-thermal method, drip will calculate cycle phases with the provided data.',
|
||||||
|
on: 'If you switch this off, drip will not show fertility related information.',
|
||||||
|
off: 'If you switch this on, drip will show fertility related information.',
|
||||||
|
},
|
||||||
|
secondarySymptom: {
|
||||||
title: 'Secondary symptom',
|
title: 'Secondary symptom',
|
||||||
cervixModeOn:
|
cervixModeOn:
|
||||||
'Cervix values are being used for symptothermal fertility detection. You can switch here to use cervical mucus values for symptothermal fertility detection',
|
'Cervix values are being used for fertility detection according to the sympto-thermal method.',
|
||||||
cervixModeOff:
|
cervixModeOff:
|
||||||
'By default, cervical mucus values are being used for symptothermal fertility detection. You can switch here to use cervix values for symptothermal fertility detection',
|
'Cervical mucus values are being used for fertility detection according to the sympto-thermal method.',
|
||||||
|
disabled: {
|
||||||
|
title: 'Disabled',
|
||||||
|
message:
|
||||||
|
'To set a secondary symptom please first enable the cervical mucus or cervix tracking category as well as temperature and fertility phases calculation above.',
|
||||||
|
noSecondaryEnabled:
|
||||||
|
'To switch the secondary symptom both cervical mucus and cervix need to be enabled above.',
|
||||||
|
},
|
||||||
|
mucus: 'cervical mucus',
|
||||||
|
cervix: 'cervix',
|
||||||
},
|
},
|
||||||
periodPrediction: {
|
periodPrediction: {
|
||||||
title: 'Period predictions',
|
title: 'Period predictions',
|
||||||
on: 'drip predicts your 3 next menstrual bleedings based on the statistics of your previously tracked cycles, min 3 complete cycles.',
|
on: 'drip predicts your 3 next menstrual bleedings based on statistics if you previously tracked at least 3 complete cycles.',
|
||||||
off: 'There are no predictions for menstrual cycles displayed. If turned on the calendar and the home screen will display period predictions.',
|
off: 'There are no predictions for menstrual cycles displayed. If turned on the calendar and the home screen will display period predictions.',
|
||||||
},
|
},
|
||||||
passwordSettings: {
|
passwordSettings: {
|
||||||
@@ -119,6 +141,6 @@ Making any changes to your password setting will keep your data as it was before
|
|||||||
},
|
},
|
||||||
preOvu: {
|
preOvu: {
|
||||||
title: 'Infertile days at cycle start',
|
title: 'Infertile days at cycle start',
|
||||||
note: `drip. applies the sympto-thermal method for calculating infertile days at the start of the cycle (see ${links.wiki.url} for more info). However, drip. does not currently apply the so called 20-day-rule, which determines infertile days at the cycle start from past cycle lengths in case no past symptothermal info is available.`,
|
note: `drip. applies the sympto-thermal method for calculating infertile days at the start of the cycle (see ${links.wiki.url} for more info). However, drip. does not currently apply the so called 20-day-rule, which determines infertile days at the cycle start from past cycle lengths in case no past sympto-thermal info is available.`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-2
@@ -1,9 +1,15 @@
|
|||||||
import getFertilityStatus from 'sympto'
|
import getFertilityStatus from 'sympto'
|
||||||
import cycleModule from './cycle'
|
import cycleModule from './cycle'
|
||||||
import { useCervixObservable } from '../local-storage'
|
import { fertilityTrackingObservable, useCervixAsSecondarySymptomObservable } from '../local-storage'
|
||||||
import { fertilityStatus as labels } from '../i18n/en/labels'
|
import { fertilityStatus as labels } from '../i18n/en/labels'
|
||||||
|
|
||||||
|
const isFertilityTrackingEnabled = fertilityTrackingObservable.value
|
||||||
|
|
||||||
export function getFertilityStatusForDay(dateString) {
|
export function getFertilityStatusForDay(dateString) {
|
||||||
|
if (!isFertilityTrackingEnabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const status = getCycleStatusForDay(dateString)
|
const status = getCycleStatusForDay(dateString)
|
||||||
if (!status) return {
|
if (!status) return {
|
||||||
status: labels.fertile,
|
status: labels.fertile,
|
||||||
@@ -34,6 +40,10 @@ export function getFertilityStatusForDay(dateString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getCycleStatusForDay(dateString, opts = {}) {
|
export function getCycleStatusForDay(dateString, opts = {}) {
|
||||||
|
if (!isFertilityTrackingEnabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getCycleForDay,
|
getCycleForDay,
|
||||||
getCyclesBefore,
|
getCyclesBefore,
|
||||||
@@ -57,7 +67,7 @@ export function getCycleStatusForDay(dateString, opts = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cycleInfo.secondarySymptom = useCervixObservable.value ? 'cervix' : 'mucus'
|
cycleInfo.secondarySymptom = useCervixAsSecondarySymptomObservable.value ? 'cervix' : 'mucus'
|
||||||
|
|
||||||
return getFertilityStatus(cycleInfo)
|
return getFertilityStatus(cycleInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-7
@@ -59,12 +59,19 @@ export async function savePeriodPrediction(bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useCervixObservable = Observable()
|
export const useCervixAsSecondarySymptomObservable = Observable()
|
||||||
setObvWithInitValue('useCervix', useCervixObservable, false)
|
setObvWithInitValue(
|
||||||
|
'useCervixAsSecondarySymptom',
|
||||||
|
useCervixAsSecondarySymptomObservable,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
export async function saveUseCervix(bool) {
|
export async function saveUseCervixAsSecondarySymptom(value) {
|
||||||
await AsyncStorage.setItem('useCervix', JSON.stringify(bool))
|
await AsyncStorage.setItem(
|
||||||
useCervixObservable.set(bool)
|
'useCervixAsSecondarySymptom',
|
||||||
|
JSON.stringify(value)
|
||||||
|
)
|
||||||
|
useCervixAsSecondarySymptomObservable.set(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hasEncryptionObservable = Observable()
|
export const hasEncryptionObservable = Observable()
|
||||||
@@ -100,13 +107,30 @@ export async function saveTemperatureTrackingCategory(bool) {
|
|||||||
temperatureTrackingCategoryObservable.set(bool)
|
temperatureTrackingCategoryObservable.set(bool)
|
||||||
|
|
||||||
if (!temperatureTrackingCategoryObservable.value) {
|
if (!temperatureTrackingCategoryObservable.value) {
|
||||||
const result = await AsyncStorage.getItem('tempReminder')
|
// if temperature tracking is turned off, the temperature reminder gets disabled
|
||||||
if (JSON.parse(result).enabled) {
|
const tempReminderResult = await AsyncStorage.getItem('tempReminder')
|
||||||
|
if (tempReminderResult && JSON.parse(tempReminderResult).enabled) {
|
||||||
tempReminderObservable.set(false)
|
tempReminderObservable.set(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const mucusTrackingCategoryObservable = Observable()
|
||||||
|
setObvWithInitValue('mucus', mucusTrackingCategoryObservable, true)
|
||||||
|
|
||||||
|
export async function saveMucusTrackingCategory(bool) {
|
||||||
|
await AsyncStorage.setItem('mucus', JSON.stringify(bool))
|
||||||
|
mucusTrackingCategoryObservable.set(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cervixTrackingCategoryObservable = Observable()
|
||||||
|
setObvWithInitValue('cervix', cervixTrackingCategoryObservable, true)
|
||||||
|
|
||||||
|
export async function saveCervixTrackingCategory(bool) {
|
||||||
|
await AsyncStorage.setItem('cervix', JSON.stringify(bool))
|
||||||
|
cervixTrackingCategoryObservable.set(bool)
|
||||||
|
}
|
||||||
|
|
||||||
export const sexTrackingCategoryObservable = Observable()
|
export const sexTrackingCategoryObservable = Observable()
|
||||||
setObvWithInitValue('sex', sexTrackingCategoryObservable, true)
|
setObvWithInitValue('sex', sexTrackingCategoryObservable, true)
|
||||||
|
|
||||||
@@ -147,6 +171,14 @@ export async function saveNoteTrackingCategory(bool) {
|
|||||||
noteTrackingCategoryObservable.set(bool)
|
noteTrackingCategoryObservable.set(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fertilityTrackingObservable = Observable()
|
||||||
|
setObvWithInitValue('fertilityTracking', fertilityTrackingObservable, true)
|
||||||
|
|
||||||
|
export async function saveFertilityTrackingEnabled(bool) {
|
||||||
|
await AsyncStorage.setItem('fertilityTracking', JSON.stringify(bool))
|
||||||
|
fertilityTrackingObservable.set(bool)
|
||||||
|
}
|
||||||
|
|
||||||
async function setObvWithInitValue(key, obv, defaultValue) {
|
async function setObvWithInitValue(key, obv, defaultValue) {
|
||||||
const result = await AsyncStorage.getItem(key)
|
const result = await AsyncStorage.getItem(key)
|
||||||
let value
|
let value
|
||||||
|
|||||||
+5
-1
@@ -18,6 +18,7 @@ const shadesOfPink = ['#c485a6', '#b15c89', pinkColor] // light to dark
|
|||||||
const lightGreenColor = '#bccd67'
|
const lightGreenColor = '#bccd67'
|
||||||
const orangeColor = '#bc6642'
|
const orangeColor = '#bc6642'
|
||||||
const mintColor = '#6ca299'
|
const mintColor = '#6ca299'
|
||||||
|
const turquoiseDark = '#69CBC1'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
greyDark: '#555',
|
greyDark: '#555',
|
||||||
@@ -27,7 +28,7 @@ export default {
|
|||||||
orange: '#F38337',
|
orange: '#F38337',
|
||||||
purple: '#3A2671',
|
purple: '#3A2671',
|
||||||
purpleLight: '#938EB2',
|
purpleLight: '#938EB2',
|
||||||
turquoiseDark: '#69CBC1',
|
turquoiseDark: turquoiseDark,
|
||||||
turquoise: '#CFECEA',
|
turquoise: '#CFECEA',
|
||||||
turquoiseLight: '#E9F2ED',
|
turquoiseLight: '#E9F2ED',
|
||||||
iconColors: {
|
iconColors: {
|
||||||
@@ -35,6 +36,9 @@ export default {
|
|||||||
color: redColor,
|
color: redColor,
|
||||||
shades: shadesOfRed,
|
shades: shadesOfRed,
|
||||||
},
|
},
|
||||||
|
temperature: {
|
||||||
|
color: turquoiseDark,
|
||||||
|
},
|
||||||
mucus: {
|
mucus: {
|
||||||
color: violetColor,
|
color: violetColor,
|
||||||
shades: shadesOfViolet,
|
shades: shadesOfViolet,
|
||||||
|
|||||||
Reference in New Issue
Block a user