diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 102531a..f4ce2d9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,6 +9,7 @@ cache: test_async: script: - npm install npm@7.0.1 -g + - npm install - npm test variables: diff --git a/.gitlab/issue_templates/bug-template.md b/.gitlab/issue_templates/bug-template.md index 47712b4..605b081 100644 --- a/.gitlab/issue_templates/bug-template.md +++ b/.gitlab/issue_templates/bug-template.md @@ -1,26 +1,29 @@ -## oh no a bug ๐Ÿ› +## ๐Ÿ› Oh no, a bug ๐Ÿ› -### Description what has happened +### What happened? -Short overview how the bug manifests. +Short overview of how the bug manifests. -### which OS + version is your device +### What is the expected behaviour? + +_It's supposed to show ... and not ..._ + +### Which OS + version is your device? - [ ] Android _number_ - [ ] iOS _number_ +- [ ] Simulator _number_ -### which drip version number are you using +### Which drip version number are you using? -_On your phone go to โžž menu on the top right โžž about, scroll to the very bottom and find the version number_ +_On your phone, go to โžž menu on the top right โžž about, scroll to the very bottom, and find the version number_ -### how did it happen +### How did it happen? -_what triggered the bug/behavior, always/sometimes, is it reproducible(how)?_ +_What triggered the bug/behavior, always/sometimes, is it reproducible(how)?_ -### describe how it looks or add screenshot +### Describe how it looks or add a screenshot -feel free to attach a file ๐Ÿ“Ž +Feel free to attach a file ๐Ÿ“Ž -### any idea to solve it - -๐Ÿ’ก +### Any ideas on how to solve it? ๐Ÿ’ก diff --git a/.gitlab/issue_templates/chore-template.md b/.gitlab/issue_templates/chore-template.md index 14018b4..4254e89 100644 --- a/.gitlab/issue_templates/chore-template.md +++ b/.gitlab/issue_templates/chore-template.md @@ -1,22 +1,23 @@ -## This has to be done ๐Ÿช  +## ๐Ÿช  This has to be done ๐Ÿช  -### Description what has to be done +### What has to be done? Short overview -### is it urgent? โณ +### Is it urgent? โณ - [ ] Yes - [ ] No -- [ ] something in between +- [ ] Something in between _Explain the urgency if possible, e.g. is it a security vulnerability for potentially everyone?_ +If it is a security vulnerability for potentially everyone, please reach out ASAP to drip@mailbox.org. -### which OS +### Which OS? - [ ] Android - [ ] iOS -### what shall be the ideal outcome ๐ŸŽ† +### What should the ideal outcome be? ๐ŸŽ† -_You can e.g. specify here the version number for a library update_ +_You can, e.g., specify the version number for a library update_ diff --git a/.gitlab/issue_templates/feature-template.md b/.gitlab/issue_templates/feature-template.md index 7abcba8..60b505f 100644 --- a/.gitlab/issue_templates/feature-template.md +++ b/.gitlab/issue_templates/feature-template.md @@ -1,19 +1,26 @@ -## Yeah a feature idea ๐Ÿงฉ +## ๐Ÿงฉ Yeah, a feature idea! ๐Ÿงฉ -### what should this feature do or solve? ๐Ÿช„ +### This feature is a ... + +- [ ] period tracking feature (add more data points etc.) +- [ ] technological feature (password, design, settings, etc.) + +### What should this feature do or solve? ๐Ÿช„ Please give a short overview so as many people as possible would be able to understand. -### what is particularly important to the people who would use this feature? +### Who is this feature for? -Do you have certain user groups in mind? +### What is particularly important to the people who would use this feature? -### Any idea where it shall be placed in the app? +### Where in the app should the feature be added? -### is it connected with or dependent on some other feature? +### Is it connected with or dependent on some other feature? -### any idea how it shall look (sketch?) +### How should the feature look (sketch or mock-up)? -feel free to attach a file ๐Ÿ“Ž +Feel free to attach a file ๐Ÿ“Ž -### what could be difficulties (with other components) ๐Ÿช† +### What could be difficulties (esp. integrating with other components)? ๐Ÿช† + +### Do you want to work on this yourself? diff --git a/components/chart/chart.js b/components/chart/chart.js index c475ae2..b394129 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -21,6 +21,7 @@ import { noteTrackingCategoryObservable, painTrackingCategoryObservable, sexTrackingCategoryObservable, + temperatureTrackingCategoryObservable, } from '../../local-storage' import { makeColumnInfo } from '../helpers/chart' @@ -84,7 +85,11 @@ const CycleChart = ({ navigate, setDate }) => { } }) - const shouldShowTemperatureColumn = chartSymptoms.indexOf('temperature') > -1 + const isTemperatureEnabled = temperatureTrackingCategoryObservable.value + const shouldShowTemperatureColumn = + isTemperatureEnabled && chartSymptoms.indexOf('temperature') > -1 + const shouldShowNoDataWarning = + isTemperatureEnabled && chartSymptoms.indexOf('temperature') <= -1 const { width, height } = Dimensions.get('window') const numberOfColumnsToRender = Math.round(width / CHART_COLUMN_WIDTH) @@ -135,7 +140,7 @@ const CycleChart = ({ navigate, setDate }) => { > {shouldShowHint && } - {!shouldShowTemperatureColumn && } + {shouldShowNoDataWarning && } { } const allEnabledSymptoms = SYMPTOMS.map((symptom) => { - if (symptom === 'sex') { + if (symptom === 'temperature') { + return temperatureTrackingCategoryObservable.value ? symptom : null + } else if (symptom === 'sex') { return sexTrackingCategoryObservable.value ? symptom : null } else if (symptom === 'desire') { return desireTrackingCategoryObservable.value ? symptom : null diff --git a/components/settings/customization/index.js b/components/settings/customization/index.js index 537773c..a8e0ab2 100644 --- a/components/settings/customization/index.js +++ b/components/settings/customization/index.js @@ -1,4 +1,5 @@ import React, { useState } from 'react' +import { Alert, Pressable } from 'react-native' import AppPage from '../../common/app-page' import AppSwitch from '../../common/app-switch' @@ -12,18 +13,21 @@ import { noteTrackingCategoryObservable, painTrackingCategoryObservable, sexTrackingCategoryObservable, + temperatureTrackingCategoryObservable, saveDesireTrackingCategory, saveMoodTrackingCategory, saveNoteTrackingCategory, savePainTrackingCategory, savePeriodPrediction, saveSexTrackingCategory, + saveTemperatureTrackingCategory, saveUseCervix, periodPredictionObservable, useCervixObservable, } from '../../../local-storage' import { Colors } from '../../../styles' import labels from '../../../i18n/en/settings' +import { SYMPTOMS } from '../../../config' const Settings = () => { const [shouldUseCervix, setShouldUseCervix] = useState( @@ -34,6 +38,9 @@ const Settings = () => { periodPredictionObservable.value ) + const [isTemperatureTrackingCategoryEnabled, setTemperatureTrackingCategory] = + useState(temperatureTrackingCategoryObservable.value) + const [isSexTrackingCategoryEnabled, setSexTrackingCategory] = useState( sexTrackingCategoryObservable.value ) @@ -57,6 +64,11 @@ const Settings = () => { const [isEnabled, setIsEnabled] = useState(false) const toggleSwitch = () => setIsEnabled((previousState) => !previousState) + const temperatureTrackingCategoryToggle = (value) => { + setTemperatureTrackingCategory(value) + saveTemperatureTrackingCategory(value) + } + const sexTrackingCategoryToggle = (value) => { setSexTrackingCategory(value) saveSexTrackingCategory(value) @@ -97,36 +109,47 @@ const Settings = () => { ? labels.useCervix.cervixModeOn : labels.useCervix.cervixModeOff + const sliderDisabledPrompt = () => { + if (!isTemperatureTrackingCategoryEnabled) { + Alert.alert(labels.disabled.title, labels.disabled.message) + } + } return ( + @@ -141,19 +164,35 @@ const Settings = () => { /> - - {labels.tempScale.segmentExplainer} - - + + + {isTemperatureTrackingCategoryEnabled && ( + <> + {labels.tempScale.segmentExplainer} + + + )} + {!isTemperatureTrackingCategoryEnabled && ( + {labels.disabled.message} + )} + + - - - + + + {isTemperatureTrackingCategoryEnabled && ( + + )} + {!isTemperatureTrackingCategoryEnabled && ( + {labels.disabled.message} + )} + + { key={item.label} onPress={() => navigate(item.componentName)} > - + {t(`${item.label}.name`)} {!!item.label && {t(`${item.label}.text`)}} - + ) @@ -44,6 +48,13 @@ const styles = StyleSheet.create({ color: Colors.purple, fontSize: Sizes.subtitle, }, + textContainer: { + flex: 5, + }, + chevronContainer: { + textAlign: 'right', + flex: 1, + }, }) export default MenuItem diff --git a/components/settings/reminders/reminders.js b/components/settings/reminders/reminders.js index 518886b..1279d29 100644 --- a/components/settings/reminders/reminders.js +++ b/components/settings/reminders/reminders.js @@ -9,6 +9,7 @@ import { periodReminderObservable, savePeriodReminder, periodPredictionObservable, + temperatureTrackingCategoryObservable, } from '../../../local-storage' import labels from '../../../i18n/en/settings' @@ -34,6 +35,14 @@ const Reminders = () => { } } + const tempReminderDisabledPrompt = () => { + if (!temperatureTrackingCategoryObservable.value) { + Alert.alert( + labels.tempReminder.alertNoTempReminder.title, + labels.tempReminder.alertNoTempReminder.message + ) + } + } return ( @@ -46,9 +55,11 @@ const Reminders = () => { /> - - - + + + + + ) } diff --git a/components/settings/reminders/temperature-reminder.js b/components/settings/reminders/temperature-reminder.js index d5fb874..5b06b19 100644 --- a/components/settings/reminders/temperature-reminder.js +++ b/components/settings/reminders/temperature-reminder.js @@ -7,6 +7,7 @@ import AppSwitch from '../../common/app-switch' import { saveTempReminder, tempReminderObservable, + temperatureTrackingCategoryObservable, } from '../../../local-storage' import padWithZeros from '../../helpers/pad-time-with-zeros' @@ -51,6 +52,7 @@ const TemperatureReminder = () => { onToggle={temperatureReminderToggle} text={tempReminderText} value={isEnabled} + disabled={!temperatureTrackingCategoryObservable.value} /> { return ( 'We detected a temperature shift (' + ['regular', '1st exception', '2nd exception'][tempRule] + - ' temperature rule), as well as a cervical mucus/cervix shift according to NFP rules. In the evening today you may assume infertility, but ' + + ' temperature rule), as well as a cervical mucus/cervix shift according to the sympto-thermal method. In the evening today you may assume infertility, but ' + 'always remember to double-check for yourself. Make sure the data makes sense to you.' ) }, @@ -85,7 +85,7 @@ export const fertilityStatus = { return ( 'We detected a temperature shift (' + ['regular', '1st exception', '2nd exception'][tempRule] + - ' temperature rule), as well as a cervical mucus/cervix shift according to NFP rules. You may assume infertility, but always remember to ' + + ' temperature rule), as well as a cervical mucus/cervix shift according to the sympto-thermal method. You may assume infertility, but always remember to ' + 'double-check for yourself. Make sure the data makes sense to you.' ) }, diff --git a/i18n/en/settings.js b/i18n/en/settings.js index 15ea950..68b9ffc 100644 --- a/i18n/en/settings.js +++ b/i18n/en/settings.js @@ -38,11 +38,21 @@ export default { loadError: 'Could not load saved temperature scale settings', saveError: 'Could not save temperature scale settings', }, + disabled: { + title: 'This feature is turned off', + message: + 'Please first enable the temperature tracking category in the customization settings.', + }, tempReminder: { title: 'Temperature reminder', noTimeSet: 'Set a time for a daily reminder to take your temperature', timeSet: (time) => `Daily reminder set for ${time}`, notification: 'Record your morning temperature', + alertNoTempReminder: { + title: 'Temperature turned off', + message: + 'To use the temperature reminder please first enable the temperature tracking category in the customization settings.', + }, }, periodReminder: { title: 'Next period reminder', @@ -109,6 +119,6 @@ Making any changes to your password setting will keep your data as it was before }, preOvu: { title: 'Infertile days at cycle start', - note: `drip. applies NFP's rules 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 symptothermal info is available.`, }, } diff --git a/i18n/en/symptom-info.js b/i18n/en/symptom-info.js index 76f35b4..fb124e3 100644 --- a/i18n/en/symptom-info.js +++ b/i18n/en/symptom-info.js @@ -11,7 +11,7 @@ export const generalInfo = { 3. and menstrual bleeding the app helps you identify in which phase of the menstrual cycle you are. -drip. makes period predictions for you and helps you apply NFP fertility awareness rules. But please remember that this app is made by humans, and humans make mistakes. Always think for yourself: "Does this make sense?" Remember, you don't need an app to understand your cycle! However, drip. wants to support you and make period tracking easier, more transparent and secure. +drip. makes period predictions for you and helps you apply the sympto-thermal method for fertility awareness. But please remember that this app is made by humans, and humans make mistakes. Always think for yourself: "Does this make sense?" Remember, you don't need an app to understand your cycle! However, drip. wants to support you and make period tracking easier, more transparent and secure. Please find more info on the sympto-thermal method in ${links.wiki.url}.`, noNfpSymptom: `The app allows you to track this symptom for your information, it is not taken into account for any calculation. On the chart you can check how often you track this symptom.`, @@ -39,7 +39,7 @@ ${generalInfo.nfpTfyReminder}`, Tracking how open or closed and how firm or soft the cervix feels can help determine in which phase of the menstrual cycle you are. -By default, the secondary symptom the app uses for NFP evaluation is cervical mucus, but you can change it to cervix in "Settings" -> "NFP Settings". +By default, the secondary symptom the app uses for the sympto-thermal method is cervical mucus, but you can change it to cervix in "Settings" -> "Customization". ยท How to identify a fertile cervix? A fertile cervix is open and feels soft like your earlobes. In contrast, an infertile cervix feels closed and hard, like the tip of your nose. If the cervix feels anything other than closed and hard, drip. takes it as a sign of fertility. On the chart, a fertile cervix is colored in dark yellow, and infertile cervix is colored in light yellow. @@ -74,10 +74,10 @@ ${generalInfo.curiousNfp}`, title: 'Tracking cervical mucus', text: `Cervical mucus can help determine in which phase of the menstrual cycle you are. -By default the secondary symptom the app uses for NFP evaluation is cervical mucus. +By default the secondary symptom the app uses for the sympto-thermal method is cervical mucus. ยท How to identify fertile cervical mucus? -Tracking the feeling and the texture of your cervical mucus on a daily basis helps you identify changes of the quality of the cervical mucus. The values you enter for both feeling and texture of your cervical mucus are combined by drip. into one of five NFP-conforming values. +Tracking the feeling and the texture of your cervical mucus on a daily basis helps you identify changes of the quality of the cervical mucus. The values you enter for both feeling and texture of your cervical mucus are combined by drip. into one of five values following the sympto-thermal method. From lowest to best quality: ยท t = (dry feeling + no texture), ยท โˆ… = (no feeling + no texture), @@ -87,7 +87,7 @@ From lowest to best quality: On the chart, cervical mucus is colored in blue: the darker the shade of blue the better the quality of your cervical mucus. -Please note that drip. does not yet support "parenthesis values": According to NFP rules, you can qualify a cervical mucus value by putting parentheses around it, to indicate that it doesn't fully meet the descriptors of one of the five categories, and instead is in between. This functionality will be supported in the future. +Please note that drip. does not yet support "parenthesis values": According to the sympto-thermal method, you can qualify a cervical mucus value by putting parentheses around it, to indicate that it doesn't fully meet the descriptors of one of the five categories, and instead is in between. This functionality will be supported in the future. ${generalInfo.chartNfp} @@ -125,7 +125,7 @@ ${generalInfo.curiousNfp}`, title: 'Tracking body basal temperature', text: `One of the body signs you need to track for knowing your fertility status is your body basal temperature. The body temperature changes over the course of a menstrual cycle, it rises after ovulation. -By default the secondary symptom is cervical mucus, but you can change it to cervix in "Settings" -> "NFP Settings". +By default the secondary symptom is cervical mucus, but you can change it to cervix in "Settings" -> "Customization". ยท What is body basal temperature? It's your temperature after lying still for at least 6 hours. For many, this is when they are waking up in the morning after sleeping at least 6 hours and before getting up. diff --git a/ios/Podfile b/ios/Podfile index 380bd49..3997e1c 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -32,6 +32,5 @@ target 'drip' do post_install do |installer| react_native_post_install(installer) - __apply_Xcode_12_5_M1_post_install_workaround(installer) - end + end end diff --git a/local-storage.js b/local-storage.js index c5e0060..ece4355 100644 --- a/local-storage.js +++ b/local-storage.js @@ -92,6 +92,21 @@ export async function setChartFlag() { await AsyncStorage.setItem('isFirstChartView', JSON.stringify(false)) } +export const temperatureTrackingCategoryObservable = Observable() +setObvWithInitValue('temperature', temperatureTrackingCategoryObservable, true) + +export async function saveTemperatureTrackingCategory(bool) { + await AsyncStorage.setItem('temperature', JSON.stringify(bool)) + temperatureTrackingCategoryObservable.set(bool) + + if (!temperatureTrackingCategoryObservable.value) { + const result = await AsyncStorage.getItem('tempReminder') + if (JSON.parse(result).enabled) { + tempReminderObservable.set(false) + } + } +} + export const sexTrackingCategoryObservable = Observable() setObvWithInitValue('sex', sexTrackingCategoryObservable, true) diff --git a/package.json b/package.json index 646b137..6bb4ee5 100644 --- a/package.json +++ b/package.json @@ -34,9 +34,9 @@ "dependencies": { "@js-joda/core": "^5.3.0", "@ptomasroos/react-native-multi-slider": "^2.2.0", - "@react-native-async-storage/async-storage": "^1.17.9", + "@react-native-async-storage/async-storage": "^1.18.2", "@react-native-community/art": "^1.2.0", - "@react-native-community/datetimepicker": "^6.3.1", + "@react-native-community/datetimepicker": "^7.2.0", "@react-native-community/push-notification-ios": "^1.11.0", "csvtojson": "^2.0.8", "i18next": "^22.0.2", diff --git a/yarn.lock b/yarn.lock index 020c7b5..7c44be2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1320,10 +1320,10 @@ resolved "https://registry.yarnpkg.com/@ptomasroos/react-native-multi-slider/-/react-native-multi-slider-2.2.2.tgz#35a97fb8c355627c6a2ded010b360ac5728b44ad" integrity sha512-HWyCnRD3Z3SbHK2FLWYmBBqd1B4iXipeKv1+AK0FoY/CElEDTEixHE8hN60TsqxalPrznn798LE2Q4tHuCiyaA== -"@react-native-async-storage/async-storage@^1.17.9": - version "1.19.3" - resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.19.3.tgz#ad5fe3ed0a82d4624aa4500321c1e09c02daeb46" - integrity sha512-CwGfoHCWdPOTPS+2fW6YRE1fFBpT9++ahLEroX5hkgwyoQ+TkmjOaUxixdEIoVua9Pz5EF2pGOIJzqOTMWfBlA== +"@react-native-async-storage/async-storage@^1.18.2": + version "1.18.2" + resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.18.2.tgz#ec8fd487a0b6c9500b43ece4b8779d1561f12e91" + integrity sha512-dM8AfdoeIxlh+zqgr0o5+vCTPQ0Ru1mrPzONZMsr7ufp5h+6WgNxQNza7t0r5qQ6b04AJqTlBNixTWZxqP649Q== dependencies: merge-options "^3.0.4" @@ -1505,10 +1505,10 @@ sudo-prompt "^9.0.0" wcwidth "^1.0.1" -"@react-native-community/datetimepicker@^6.3.1": - version "6.7.5" - resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-6.7.5.tgz#214796f2d131b6af9cb9d4dea69d4a1981fa2236" - integrity sha512-E2Zh6mwvZ6CFEMKP++rdxxjJiB45fYPpdZhJwdZ2vUVwqovqu1cQRDLZmz4XrcHSyuacgR4WUnkYFf0F2nnNIg== +"@react-native-community/datetimepicker@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-7.2.0.tgz#db8c03dbf49bf3c24b06b617a8467d8b05511f62" + integrity sha512-dO1sQy83M/EvnHE2egto05iwXZX7EYn5f/VDMp6afZFRFXRiRo7CzB3VFg4B55gJRJMNBv06NYMLPM3SlpnEGQ== dependencies: invariant "^2.2.4"