Merge branch 'chore/refactor-customization' into '676-feature-customisation-not-display-mucus-cervix'

Chore/refactor customization

See merge request bloodyhealth/drip!672
This commit is contained in:
wunderfisch
2024-03-14 11:04:51 +00:00
4 changed files with 111 additions and 57 deletions
+32 -4
View File
@@ -1,18 +1,34 @@
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' import labels from '../../i18n/en/settings'
export default function SelectTabGroup({ activeButton, buttons, onSelect }) { export default function SelectTabGroup({
// TODO https://gitlab.com/bloodyhealth/drip/-/issues/707 activeButton,
buttons,
onSelect,
disabled,
}) {
// TODO https://gitlab.com/bloodyhealth/drip/-/issues/707
const oneTimeTransformIntoNumber = const oneTimeTransformIntoNumber =
typeof activeButton === 'boolean' && Number(activeButton) typeof activeButton === 'boolean' && Number(activeButton)
const isSecondarySymptomSwitch = const isSecondarySymptomSwitch =
buttons[0]['label'] === labels.secondarySymptom.mucus 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
)
}
}
return ( return (
<View style={styles.container}> <View style={styles.container}>
{buttons.map(({ label, value }, i) => { {buttons.map(({ label, value }, i) => {
@@ -23,16 +39,20 @@ export default function SelectTabGroup({ activeButton, buttons, onSelect }) {
isActive && styles.boxActive, isActive && styles.boxActive,
isSecondarySymptomSwitch && styles.purpleBox, isSecondarySymptomSwitch && styles.purpleBox,
isSecondarySymptomSwitch && isActive && styles.activePurpleBox, isSecondarySymptomSwitch && isActive && styles.activePurpleBox,
disabled && styles.disabledBox,
] ]
const textStyle = [ const textStyle = [
styles.text, styles.text,
isSecondarySymptomSwitch && styles.purpleText, isSecondarySymptomSwitch && styles.purpleText,
isActive && styles.textActive, 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}
> >
@@ -48,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({
@@ -75,4 +96,11 @@ const styles = StyleSheet.create({
purpleText: { purpleText: {
color: Colors.purple, color: Colors.purple,
}, },
greyText: {
color: Colors.grey,
},
disabledBox: {
borderColor: Colors.grey,
backgroundColor: Colors.turquoiseLight,
},
}) })
+42 -40
View File
@@ -20,6 +20,8 @@ import {
temperatureTrackingCategoryObservable, temperatureTrackingCategoryObservable,
mucusTrackingCategoryObservable, mucusTrackingCategoryObservable,
cervixTrackingCategoryObservable, cervixTrackingCategoryObservable,
periodPredictionObservable,
useCervixAsSecondarySymptomObservable,
saveDesireTrackingCategory, saveDesireTrackingCategory,
saveFertilityTrackingEnabled, saveFertilityTrackingEnabled,
saveMoodTrackingCategory, saveMoodTrackingCategory,
@@ -31,8 +33,6 @@ import {
saveSexTrackingCategory, saveSexTrackingCategory,
saveTemperatureTrackingCategory, saveTemperatureTrackingCategory,
saveUseCervixAsSecondarySymptom, saveUseCervixAsSecondarySymptom,
periodPredictionObservable,
useCervixAsSecondarySymptomObservable,
} 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'
@@ -81,6 +81,7 @@ const Settings = () => {
const [isFertilityTrackingEnabled, setFertilityTrackingEnabled] = useState( const [isFertilityTrackingEnabled, setFertilityTrackingEnabled] = useState(
fertilityTrackingObservable.value fertilityTrackingObservable.value
) )
const fertilityTrackingToggle = (value) => { const fertilityTrackingToggle = (value) => {
setFertilityTrackingEnabled(value) setFertilityTrackingEnabled(value)
saveFertilityTrackingEnabled(value) saveFertilityTrackingEnabled(value)
@@ -179,7 +180,14 @@ const Settings = () => {
} }
const secondarySymptomDisabledPrompt = () => { const secondarySymptomDisabledPrompt = () => {
if (!isMucusTrackingCategoryEnabled == isCervixTrackingCategoryEnabled) { if (!isFertilityTrackingEnabled) {
Alert.alert(
labels.secondarySymptom.disabled.title,
labels.secondarySymptom.disabled.message
)
} else if (
!isMucusTrackingCategoryEnabled == isCervixTrackingCategoryEnabled
) {
Alert.alert( Alert.alert(
labels.secondarySymptom.disabled.title, labels.secondarySymptom.disabled.title,
labels.secondarySymptom.disabled.noSecondaryEnabled labels.secondarySymptom.disabled.noSecondaryEnabled
@@ -187,13 +195,26 @@ const Settings = () => {
} }
} }
const manageFertilityFeature =
isTemperatureTrackingCategoryEnabled &&
(isMucusTrackingCategoryEnabled || isCervixTrackingCategoryEnabled)
const cervixText = useCervixAsSecondarySymptom const cervixText = useCervixAsSecondarySymptom
? labels.secondarySymptom.cervixModeOn ? labels.secondarySymptom.cervixModeOn
: labels.secondarySymptom.cervixModeOff : 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
)
} }
} }
@@ -253,53 +274,34 @@ const Settings = () => {
symptom={SYMPTOMS[8]} symptom={SYMPTOMS[8]}
/> />
</Segment> </Segment>
<Pressable onPress={sliderDisabledPrompt}> <Pressable onPress={fertilityDisabledPrompt}>
<Segment title={labels.fertilityTracking.title}> <Segment title={labels.fertilityTracking.title}>
{isTemperatureTrackingCategoryEnabled && <AppText>{labels.fertilityTracking.message}</AppText>
(isMucusTrackingCategoryEnabled || <AppSwitch
isCervixTrackingCategoryEnabled) ? ( onToggle={fertilityTrackingToggle}
<> text={fertilityTrackingText}
<AppText>{labels.fertilityTracking.message}</AppText> value={isFertilityTrackingEnabled}
<AppSwitch disabled={!manageFertilityFeature}
onToggle={fertilityTrackingToggle} />
text={fertilityTrackingText}
value={isFertilityTrackingEnabled}
/>
</>
) : (
<AppText>{labels.disabled.message}</AppText>
)}
</Segment> </Segment>
</Pressable> </Pressable>
<Pressable onPress={sliderDisabledPrompt}> <Pressable onPress={sliderDisabledPrompt}>
<Segment title={labels.tempScale.segmentTitle}> <Segment title={labels.tempScale.segmentTitle}>
{isTemperatureTrackingCategoryEnabled && ( <AppText>{labels.tempScale.segmentExplainer}</AppText>
<> <TemperatureSlider disabled={!isTemperatureTrackingCategoryEnabled} />
<AppText>{labels.tempScale.segmentExplainer}</AppText>
<TemperatureSlider />
</>
)}
{!isTemperatureTrackingCategoryEnabled && (
<AppText>{labels.disabled.message}</AppText>
)}
</Segment> </Segment>
</Pressable> </Pressable>
<Pressable onPress={secondarySymptomDisabledPrompt}> <Pressable onPress={secondarySymptomDisabledPrompt}>
<Segment title={labels.secondarySymptom.title}> <Segment title={labels.secondarySymptom.title}>
{!isFertilityTrackingEnabled ? ( <AppText>{cervixText}</AppText>
<AppText>{labels.secondarySymptom.disabled.message}</AppText> <SelectTabGroup
) : ( activeButton={useCervixAsSecondarySymptom}
<> buttons={secondarySymptomButtons}
<AppText>{cervixText}</AppText> onSelect={(value) => onSelectTab(value)}
<SelectTabGroup disabled={!isFertilityTrackingEnabled}
activeButton={useCervixAsSecondarySymptom} />
buttons={secondarySymptomButtons}
onSelect={(value) => onSelectTab(value)}
/>
</>
)}
</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,
},
}) })
+12 -10
View File
@@ -36,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:
'To use the temperature scale please first enable the temperature tracking category above.',
},
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',
@@ -72,21 +71,24 @@ export default {
}, },
fertilityTracking: { fertilityTracking: {
title: 'Fertility phases calculation', title: 'Fertility phases calculation',
disabledTitle: 'Disabled',
disabled:
'To use fertility phases calculation please enable temperature tracking and cervical mucus or cervix tracking above.',
message: message:
'If you enter menstrual bleeding, temperature and cervical mucus or cervix data according to the sympto-thermal rules, drip will calculate cycle phases with the provided data.', '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.', 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.', off: 'If you switch this on, drip will show fertility related information.',
}, },
secondarySymptom: { secondarySymptom: {
title: 'Secondary symptom', title: 'Secondary symptom',
cervixModeOn: cervixModeOn:
'Cervix values are being used for sympto-thermal fertility detection. You can switch here to use cervical mucus values for sympto-thermal 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 sympto-thermal fertility detection. You can switch here to use cervix values for sympto-thermal fertility detection', 'Cervical mucus values are being used for fertility detection according to the sympto-thermal method.',
disabled: { disabled: {
title: 'Disabled', title: 'Disabled',
message: message:
'To set a secondary symptom please first enable the temperature, cervical mucus or cervix tracking category as well as the fertility feature above.', '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: noSecondaryEnabled:
'To switch the secondary symptom both cervical mucus and cervix need to be enabled above.', 'To switch the secondary symptom both cervical mucus and cervix need to be enabled above.',
}, },