Compare commits
126 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 26ec47bad2 | |||
| 5bc6be7849 | |||
| e6c253f2cb | |||
| 06fab6d2ca | |||
| b44d4c57e1 | |||
| 35224ba722 | |||
| 2ca033d6d1 | |||
| 09edaec721 | |||
| 3cedcf601e | |||
| e4d97b362f | |||
| 7bbb6eaeab | |||
| 09cb31035c | |||
| 536017914c | |||
| b2457f4751 | |||
| fd10a78a40 | |||
| d8cb679d77 | |||
| 839acfa22d | |||
| a0482291cf | |||
| 37f718d1b0 | |||
| 9b0abd5367 | |||
| c8521cf5ed | |||
| f7c6f4bfd0 | |||
| 15a0b3d270 | |||
| 4e37f1b7de | |||
| 56e90b69e6 | |||
| b481bd8352 | |||
| e33c13e5e0 | |||
| 693c766da8 | |||
| fc4bc625ce | |||
| 0e7d84874c | |||
| a93a338e6e | |||
| 003f825ef4 | |||
| fc520c4a20 | |||
| eaf01e98d5 | |||
| f5894c028e | |||
| a29c0e2eec | |||
| 18466ebcee | |||
| b65b5f3561 | |||
| 3e8f15e04e | |||
| b17c86ffd6 | |||
| 24df5cea31 | |||
| 610383a103 | |||
| ad47b4bee0 | |||
| ffe8fab822 | |||
| 661abc8aee | |||
| 46a02560e8 | |||
| 9ec52b78cf | |||
| 8a65c081a8 | |||
| 72823ef95c | |||
| 27776f93cc | |||
| ef4095d61c | |||
| 4fc11d2f7e | |||
| 37152b3fec | |||
| 405e27bdbe | |||
| 1c73509473 | |||
| 5855ea0a34 | |||
| 27bb25e6da | |||
| 8150b791ed | |||
| 3c0ea9b208 | |||
| d0d691c6af | |||
| 29c3b9b108 | |||
| c037c630d3 | |||
| 31888c3331 | |||
| faad51f4f1 | |||
| e395730d98 | |||
| 092b557396 | |||
| 4ebec41a0a | |||
| e69ca93382 | |||
| aa440742ca | |||
| 7fff6cbdf4 | |||
| 75dbe8bfde | |||
| 4921aca3c3 | |||
| cbaf6977f6 | |||
| b9ec4c7108 | |||
| d66e5f36e5 | |||
| 69c546f684 | |||
| dc304afe75 | |||
| 63bc8a1daf | |||
| 7fa130f9e1 | |||
| d338df1460 | |||
| 5f55500831 | |||
| 4eedb171a3 | |||
| 3193fa4f33 | |||
| e24c69977c | |||
| 6fb0d1fc1e | |||
| 391cac1bde | |||
| fb589815c1 | |||
| 45fce6485b | |||
| 17f74c9c1c | |||
| 5119e6778a | |||
| 601d618352 | |||
| d23b5fe420 | |||
| 311cee0e17 | |||
| 76137fc000 | |||
| 09614319e3 | |||
| ebbfd8aba5 | |||
| 1662bb29f0 | |||
| a59dfa8336 | |||
| d7f1eb81fb | |||
| 82803bbb83 | |||
| 8a8b3217fa | |||
| e11acbab78 | |||
| 1db2f3a945 | |||
| 34e672dd31 | |||
| 845e42eafc | |||
| da4d90fded | |||
| a0b275d052 | |||
| 0adea893f7 | |||
| 318fd7cfee | |||
| 5e79fdfc4b | |||
| a74b5d58e8 | |||
| 3e52275a9f | |||
| edc452381a | |||
| 9991260c38 | |||
| a289edb7f1 | |||
| 080ce0f3d3 | |||
| 6a4d5c330b | |||
| 91eb7ed29c | |||
| 55b1c5973d | |||
| ec157078b2 | |||
| fdb892ff6b | |||
| a99e6952a1 | |||
| 3799ff68bd | |||
| 7dd01c0c9b | |||
| cd176cf192 | |||
| ae3edb0a15 |
@@ -59,8 +59,9 @@ buck-out/
|
|||||||
# Bundle artifact
|
# Bundle artifact
|
||||||
*.jsbundle
|
*.jsbundle
|
||||||
|
|
||||||
# CocoaPods
|
# Ruby / CocoaPods
|
||||||
/ios/Pods/
|
/ios/Pods/
|
||||||
|
/vendor/bundle/
|
||||||
|
|
||||||
# RN android release
|
# RN android release
|
||||||
android/app/bin/
|
android/app/bin/
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ cache:
|
|||||||
test_async:
|
test_async:
|
||||||
script:
|
script:
|
||||||
- npm install npm@7.0.1 -g
|
- npm install npm@7.0.1 -g
|
||||||
|
- npm install
|
||||||
- npm test
|
- npm test
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
|
|||||||
@@ -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_
|
- [ ] Android _number_
|
||||||
- [ ] iOS _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? 💡
|
||||||
|
|
||||||
💡
|
|
||||||
|
|||||||
@@ -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
|
Short overview
|
||||||
|
|
||||||
### is it urgent? ⏳
|
### Is it urgent? ⏳
|
||||||
|
|
||||||
- [ ] Yes
|
- [ ] Yes
|
||||||
- [ ] No
|
- [ ] No
|
||||||
- [ ] something in between
|
- [ ] Something in between
|
||||||
|
|
||||||
_Explain the urgency if possible, e.g. is it a security vulnerability for potentially everyone?_
|
_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
|
- [ ] Android
|
||||||
- [ ] iOS
|
- [ ] 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_
|
||||||
|
|||||||
@@ -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.
|
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?
|
||||||
|
|||||||
@@ -2,7 +2,83 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## v1.2311.14
|
## v1.2403.19 Android & iOS
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
- Disables temperature slider if temperature tracking off
|
||||||
|
- Disables secondary symptom if fertility and or cervix/cervical mucus are off
|
||||||
|
- Disables temperature reminder if temperature tracking off
|
||||||
|
- Disabled period reminder if period predictions off
|
||||||
|
- Return from sympto adapter if fertility off
|
||||||
|
- Restructure settings menu
|
||||||
|
- Unify wording to "sympto-thermal method"
|
||||||
|
- Format decimal to x.0 instead of x.00 used for standard deviation and average cycle in stats
|
||||||
|
- Use SelectTabGroup for secondary symptom customization
|
||||||
|
|
||||||
|
- Android changes after updating React Native to 0.68.3
|
||||||
|
- Update Android Gradle plugin from 7.0.3 to 7.0.4
|
||||||
|
- Update NDK to "24.0.8215888" only for M1 users which added support for aarch64
|
||||||
|
- Update metadata phone screenshots for Fdroid store listing
|
||||||
|
- Updated dependencies:
|
||||||
|
- @react-native-community/datetimepicker from 6.3.1 to 7.2.0
|
||||||
|
- @react-native-async-storage/async-storage from ^1.17.9 to ^1.18.2
|
||||||
|
- metro-react-native-babel-preset from ^0.66.2 to ^0.67.0
|
||||||
|
|
||||||
|
### Adds
|
||||||
|
|
||||||
|
- Customization settings can turn on & off:
|
||||||
|
|
||||||
|
- Tracking categories
|
||||||
|
- Period predictions
|
||||||
|
- Fertility phases calculation
|
||||||
|
|
||||||
|
- Home displays text elements depending on customization settings
|
||||||
|
- Chart displays tracking category elements depending on customization settings
|
||||||
|
- CycleDay displays tracking category elements and exclude switch depending on customization settings
|
||||||
|
- Reminder can be disabled depending on customization settings
|
||||||
|
- Adds disabled and more styling to AppSwitch
|
||||||
|
- Adds TrackingCategorySwitch
|
||||||
|
- Adds disabled, more styling and alert to SelectTabGroup
|
||||||
|
- Adds more marginTop to License page
|
||||||
|
- Adds info text to Password menu item in Settings
|
||||||
|
|
||||||
|
## v1.2401.17 iOS
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
- Updating React Native to 0.68.3
|
||||||
|
- Minor changes in temperature chart
|
||||||
|
|
||||||
|
### Adds
|
||||||
|
|
||||||
|
- Temperature scale slider
|
||||||
|
- out of range warning messages for temperature values
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Order of import buttons
|
||||||
|
|
||||||
|
## v1.2312.11 iOS
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
- Chart: Improved readability
|
||||||
|
- Finer temperature lines and dots
|
||||||
|
- Enlarge screen space for temperature chart
|
||||||
|
- A very light grey background color for weekend days on the whole chart screen
|
||||||
|
- Homescreen: date displayed in new format
|
||||||
|
- Minor changes in "about" section
|
||||||
|
|
||||||
|
See more under v1.2311.14 Android
|
||||||
|
|
||||||
|
### Adds
|
||||||
|
|
||||||
|
- Stats: Show period details, including cycle start, cycle length and amount of days with bleeding
|
||||||
|
- Stats: Explainer text for standard deviation
|
||||||
|
- App asks for permissions for notifications right at the start, which allows you to set reminders (this is a new requirement for Android 13)
|
||||||
|
|
||||||
|
## v1.2311.14 Android
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|
||||||
@@ -64,11 +140,22 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Chart: Grid for symptoms
|
- Chart: Grid for symptoms
|
||||||
- Chart: Horizontal lines in temperature chart
|
- Chart: Horizontal lines in temperature chart
|
||||||
|
|
||||||
## Unreleased
|
### Unreleased
|
||||||
|
|
||||||
- Partially implemented translations with react-i18next
|
- Partially implemented translations with react-i18next
|
||||||
|
|
||||||
## v1.2102.28
|
## v1.2208.11 iOS
|
||||||
|
|
||||||
|
### Adds
|
||||||
|
|
||||||
|
- first iOS Release
|
||||||
|
|
||||||
|
### Unreleased
|
||||||
|
|
||||||
|
- Temperature scale slider
|
||||||
|
- Warning message for out of scope temperature values
|
||||||
|
|
||||||
|
## v1.2102.28 Android
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|
||||||
@@ -81,7 +168,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Phase text on home screen for last fertile day
|
- Phase text on home screen for last fertile day
|
||||||
- Styling improvements
|
- Styling improvements
|
||||||
|
|
||||||
## v1.2101.9
|
## v1.2101.9 Android
|
||||||
|
|
||||||
### Adds
|
### Adds
|
||||||
|
|
||||||
@@ -124,7 +211,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Fixed react-native-vector-icon
|
- Fixed react-native-vector-icon
|
||||||
- Fixed AppLoadingView component centering
|
- Fixed AppLoadingView component centering
|
||||||
|
|
||||||
## v0.2007-12.beta
|
## v0.2007-12.beta Android
|
||||||
|
|
||||||
### Adds
|
### Adds
|
||||||
|
|
||||||
@@ -159,7 +246,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
- Updates of node.js to fix security issue
|
- Updates of node.js to fix security issue
|
||||||
|
|
||||||
## v0.2005.3-beta
|
## v0.2005.3-beta Android
|
||||||
|
|
||||||
- Adds arm64-v8a and x86_64 for supporting 64-bit architecture
|
- Adds arm64-v8a and x86_64 for supporting 64-bit architecture
|
||||||
- Adds Mariya & Sofiya as contributors <3
|
- Adds Mariya & Sofiya as contributors <3
|
||||||
@@ -259,7 +346,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Adds release wizard
|
- Adds release wizard
|
||||||
- Updates nodejs-mobile to fix security issue
|
- Updates nodejs-mobile to fix security issue
|
||||||
|
|
||||||
## v0.1905.29-beta
|
## v0.1905.29-beta Android
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|
||||||
@@ -280,7 +367,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Line width in chart
|
- Line width in chart
|
||||||
- Prediction range in drop on homescreen
|
- Prediction range in drop on homescreen
|
||||||
|
|
||||||
## v0.1905.28-beta
|
## v0.1905.28-beta Android
|
||||||
|
|
||||||
- Displays all the text for Home Elements; Shortens margin btw Home Elements; Adds missing "visit" to text
|
- Displays all the text for Home Elements; Shortens margin btw Home Elements; Adds missing "visit" to text
|
||||||
- Adds donation section to about
|
- Adds donation section to about
|
||||||
@@ -355,7 +442,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Nicer formatting for past bleeding prediction
|
- Nicer formatting for past bleeding prediction
|
||||||
- Fixed prediction range in drop on homescreen
|
- Fixed prediction range in drop on homescreen
|
||||||
|
|
||||||
## v0.1905.10-beta
|
## v0.1905.10-beta Android
|
||||||
|
|
||||||
- Filter release commits from changelog
|
- Filter release commits from changelog
|
||||||
- Adds update-changelog script
|
- Adds update-changelog script
|
||||||
@@ -380,7 +467,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Delete password button bug fix
|
- Delete password button bug fix
|
||||||
- temperature screen styling update
|
- temperature screen styling update
|
||||||
|
|
||||||
## v0.0.3 - 2019-04-17
|
## v0.0.3 - 2019-04-17 Android
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|
||||||
@@ -390,9 +477,9 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
- Button functionality in settings for password
|
- Button functionality in settings for password
|
||||||
|
|
||||||
## v0.0.2 - 2019-04-09
|
## v0.0.2 - 2019-04-09 Android
|
||||||
|
|
||||||
## Second updated beta release version
|
## Second updated beta release version Android
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|
||||||
@@ -406,9 +493,9 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Delete button for sex, pain and mood
|
- Delete button for sex, pain and mood
|
||||||
- Dates on chart
|
- Dates on chart
|
||||||
|
|
||||||
## v0.0.1 - 2019-02-15
|
## v0.0.1 - 2019-02-15 Android
|
||||||
|
|
||||||
## First beta release version
|
## First beta release version Android
|
||||||
|
|
||||||
### Added (list of core functionality)
|
### Added (list of core functionality)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -1,16 +1,44 @@
|
|||||||
# How to release a new app version for Android
|
# How to release
|
||||||
|
|
||||||
_Note: You need the release-key for Android to bundle a signed release that can be uploaded and published via the Google Play Store. A similar process for Apple requires a certificate to upload and publish the app to the App Store. More documentation on 'How to release a new app version for iOS' coming soon._
|
drip is developed in React Native for iOS and Android and is released on 4 different platforms:
|
||||||
|
|
||||||
# Table of Contents
|
1. [Google Play Store](https://play.google.com/store/apps/details?id=com.drip)
|
||||||
|
2. [Apple App Store](https://apps.apple.com/us/app/drip/id1584564949)
|
||||||
|
3. [F-Droid](https://f-droid.org/packages/com.drip/)
|
||||||
|
4. [drip Website](https://dripapp.org)
|
||||||
|
|
||||||
1. [version updating](#Version-updating)
|
In an ideal world the app version is the same across platforms. In the past this has never been the case. The release v1.2403.19 is the first to be up to date on all 4 platforms!
|
||||||
2. [android building](#Building-in-Android)
|
|
||||||
- [APK](#APK)
|
|
||||||
- [AAB](#AAB)
|
|
||||||
3. [release sharing](#Share-the-release)
|
|
||||||
|
|
||||||
## Version updating
|
Releasing a new version is very exciting and brings happy changes like fixing a bug, improving a feature, updating dependencies or adding a new functionality to the app. It is more than just pressing the button "publish new version".
|
||||||
|
|
||||||
|
_Note_: You need the release-key for Android to bundle a signed release that can be uploaded and published via the Google Play Store. A similar process for Apple requires a certificate to upload and publish the app to the App Store.
|
||||||
|
|
||||||
|
## Release steps
|
||||||
|
|
||||||
|
### 1. [Code](#code)
|
||||||
|
- 1.1 [Version updating](#version-updating)
|
||||||
|
- 1.2 [Android builds](#android-builds)
|
||||||
|
- 1.3 [iOS builds](#ios-builds)
|
||||||
|
- 1.4 [User testing](#user-testing)
|
||||||
|
- 1.5 [Release tag](#release-tag)
|
||||||
|
|
||||||
|
### 2. [Documentation](#documentation)
|
||||||
|
- 2.1 [Changelog](#changelog)
|
||||||
|
- 2.2 [Release notes](#release-notes)
|
||||||
|
- 2.3 [Releases on Gitlab](#releases-on-gitlab)
|
||||||
|
- 2.4 [Phone screenshots](#phone-screenshots)
|
||||||
|
|
||||||
|
### 3. [Publishing](#publishing)
|
||||||
|
- 3.1 [Google Play Console](#google-play-console)
|
||||||
|
- 3.2 [Apple App Store Connect](#apple-app-store-connect)
|
||||||
|
- 3.3 [F-droid](#f-droid)
|
||||||
|
- 3.4 [drip website](#drip-website)
|
||||||
|
- 3.5 [Communication](#communication)
|
||||||
|
- 3.6 [Self care](#self-care)
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
### Version updating
|
||||||
|
|
||||||
When you are done with a chore, a feature or a bugfix, you may want to share it with testers and eventually publish a release. In order to identify a specific app version we can update the version name, which is created based on the following format: `1.yymm.d` e.g. `1.2311.7`. If you want to upload a new app version to Google Play you also need to update the version code.
|
When you are done with a chore, a feature or a bugfix, you may want to share it with testers and eventually publish a release. In order to identify a specific app version we can update the version name, which is created based on the following format: `1.yymm.d` e.g. `1.2311.7`. If you want to upload a new app version to Google Play you also need to update the version code.
|
||||||
|
|
||||||
@@ -25,7 +53,16 @@ yarn release
|
|||||||
|
|
||||||
The versionName and versionCode [are defined here](https://gitlab.com/bloodyhealth/drip/-/blob/5401789c46f4a02915ab900ef284581be420451c/android/app/build.gradle#L137-138) and in [package.json](https://gitlab.com/bloodyhealth/drip/-/blob/5401789c46f4a02915ab900ef284581be420451c/package.json#L3).
|
The versionName and versionCode [are defined here](https://gitlab.com/bloodyhealth/drip/-/blob/5401789c46f4a02915ab900ef284581be420451c/android/app/build.gradle#L137-138) and in [package.json](https://gitlab.com/bloodyhealth/drip/-/blob/5401789c46f4a02915ab900ef284581be420451c/package.json#L3).
|
||||||
|
|
||||||
## Building in Android
|
**Note for iOS**
|
||||||
|
|
||||||
|
Update the version number for iOS in `ios/drip/Info.plist` under:
|
||||||
|
|
||||||
|
```
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.2403.19</string>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Android builds
|
||||||
|
|
||||||
APK versus AAB
|
APK versus AAB
|
||||||
|
|
||||||
@@ -33,7 +70,7 @@ APK versus AAB
|
|||||||
|
|
||||||
(https://developer.android.com/build/building-cmdline)
|
(https://developer.android.com/build/building-cmdline)
|
||||||
|
|
||||||
### APK
|
#### APK
|
||||||
|
|
||||||
To build a release apk file, run the following command:
|
To build a release apk file, run the following command:
|
||||||
|
|
||||||
@@ -55,7 +92,7 @@ _which is a shortcut for:_ `zipalign -v -p 4 ./android/app/build/outputs/apk/rel
|
|||||||
|
|
||||||
It adds a file name `app-release_signed.apk` in the same folder in `./android/app/build/outputs/apk/release/`
|
It adds a file name `app-release_signed.apk` in the same folder in `./android/app/build/outputs/apk/release/`
|
||||||
|
|
||||||
### AAB
|
#### AAB
|
||||||
|
|
||||||
To build a release aab file, run:
|
To build a release aab file, run:
|
||||||
|
|
||||||
@@ -75,29 +112,88 @@ yarn sign-android-aab-release
|
|||||||
|
|
||||||
_which is a shortcut for:_ `jarsigner -keystore ./android/app/drip-release-key.keystore ./android/app/build/outputs/bundle/release/app-release.aab drip-release-key`
|
_which is a shortcut for:_ `jarsigner -keystore ./android/app/drip-release-key.keystore ./android/app/build/outputs/bundle/release/app-release.aab drip-release-key`
|
||||||
|
|
||||||
## Share the release
|
### iOS builds
|
||||||
|
|
||||||
### Gitlab repository
|
To build an .ipa archive file for an upload to the AppStore you need to go to xCode and select Build -> "Any iOS Device" and under "Product" -> "Archive".
|
||||||
|
|
||||||
|
Once the archiving process has completed you can chose to do the following:
|
||||||
|
|
||||||
|
"Distribute the app"
|
||||||
|
|
||||||
|
- TestFlight & App Store for when you want to upload it for external testing and/or production release
|
||||||
|
- TestFlight Internal Only for when you want to upload it for internal testing
|
||||||
|
|
||||||
|
### User testing
|
||||||
|
|
||||||
|
To enable external testing you need to remember that Google Play and Apple App Store might take up to 1 day for their review process. "External testing" for iOS allows testing drip on Testflight anonymously via a public link. "Open testing" for Android allows testing drip on Google Play as beta tester below the normal production listing.
|
||||||
|
|
||||||
For a quick and easy way to share an apk to testers who are willing to sideload drip onto their Android phones, do this: Upload a signed apk to the Gitlab repository of the drip website under `/release` https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/tree/main/release and maybe adapt the name of the apk with a more specific name than "app-release.apk". Now you can simply share a direct link to download your newly bundled apk, e.g. [a download link for v1.2311.14](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/blob/main/release/v1.2311.14.apk).
|
For a quick and easy way to share an apk to testers who are willing to sideload drip onto their Android phones, do this: Upload a signed apk to the Gitlab repository of the drip website under `/release` https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/tree/main/release and maybe adapt the name of the apk with a more specific name than "app-release.apk". Now you can simply share a direct link to download your newly bundled apk, e.g. [a download link for v1.2311.14](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/blob/main/release/v1.2311.14.apk).
|
||||||
|
|
||||||
|
### Release tag
|
||||||
|
|
||||||
|
[Tags](https://gitlab.com/bloodyhealth/drip/-/tags) can mark a specific point in the coding/commmit history and helps us identify the version status of a released app. They are named "iOS-v1.2401.17" or "Release-v1.yymm.d".
|
||||||
|
|
||||||
|
Any tag starting with "Release" or "Android" will be checked by https://gitlab.com/fdroidci
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
### Changelog
|
||||||
|
|
||||||
|
The [changelog](https://gitlab.com/bloodyhealth/drip/-/blob/main/CHANGELOG.md) should reflect the technical / code changes between a previous and the new version. Please update the changelog file with any relevant additions, fixes and changes in the following format:
|
||||||
|
|
||||||
|
>**v1.yymm.d**
|
||||||
|
>
|
||||||
|
>**Changes**
|
||||||
|
>
|
||||||
|
>Changing the color of funky button
|
||||||
|
>Updating a library from 1.2.3 to 2.3.4
|
||||||
|
>
|
||||||
|
>**Adds**
|
||||||
|
>
|
||||||
|
>New feature for calendar
|
||||||
|
>
|
||||||
|
>**Fixed**
|
||||||
|
>
|
||||||
|
>Small bug in chart
|
||||||
|
|
||||||
|
### Release notes
|
||||||
|
|
||||||
|
These notes are for the users and curious ones who may want to start using drip. They should be based on the changelog but written in a friendly and easy to understand way. The focus is on the user perspective and the impact of the changes for the user. Behind the scenes and in depth code changes are less relevant.
|
||||||
|
|
||||||
|
Google Play limits these notes to 500 characters, whereas Apple's App Store limits these notes to 4.000 characters. In Fdroid there are no release notes.
|
||||||
|
|
||||||
|
### Releases on Gitlab
|
||||||
|
|
||||||
|
Under [Releases](https://gitlab.com/bloodyhealth/drip/-/releases) we keep track of all drip releases.
|
||||||
|
|
||||||
|
### Phone screenshots
|
||||||
|
|
||||||
|
If there are visual changes in the app you may want to update the screenshots for the Google Play Store listing, which allows up to 8 and for Apple's App Store, which allows up to 10 screenshots. Keep in mind that both Google Play and Apple have specific resolution requirements. You'll find Google's in Grow -> Store presence -> Main Store Listing -> Phone screenshots and Apple's on the main App Store Connect site. Here is a link for [Apple's screenshot specifications](https://developer.apple.com/help/app-store-connect/reference/screenshot-specifications).
|
||||||
|
|
||||||
|
Please also update [phone screenshots for the website](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/tree/main/assets) and set links on [/index](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/blob/f3da9776b1943ffa32458e74ef86eeca98c1891c/index.html#L47) and [/media](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/blob/c7f999bb7ad736345321537cbffa3f4c24eeee6d/media.html#L33) that can then also be attached to a social media post.
|
||||||
|
|
||||||
|
## Publishing
|
||||||
|
|
||||||
### Google Play Console
|
### Google Play Console
|
||||||
|
|
||||||
Upload a signed aab to the [Google Play Console for developers](https://play.google.com/console/) and add it to the "App bundle explorer". This requires a higher versionCode and a different version name compared to previously uploaded aab or apk files.
|
Upload a signed aab to the [Google Play Console for developers](https://play.google.com/console/) and add it to the "App bundle explorer". This requires a higher versionCode and a different version name compared to previously uploaded aab or apk files.
|
||||||
You can decide if you want the new app version to get released for testing (internal, closed or open) or for production. Keep in mind that any track other than "internal testing" triggers an external review by Google and might take a few hours.
|
You can decide if you want the new app version to get released for testing (internal, closed or open) or for production. Keep in mind that any track other than "internal testing" triggers an external review by Google and might take a few hours.
|
||||||
|
|
||||||
#### Phone screenshots
|
### Apple App Store Connect
|
||||||
|
|
||||||
If there are visual changes in the app you may want to update the screenshots for the Google Play Store listing. Keep in mind that Google Play has specific resolution requirements. You'll find them in Grow -> Store presence -> Main Store Listing -> Phone screenshots.
|
Upload a new version and submit it for review, before it can be published.
|
||||||
|
|
||||||
|
### F-droid
|
||||||
|
|
||||||
|
This account runs automated checks for drip looking at new `Release` or `Android` [tags](https://gitlab.com/bloodyhealth/drip/-/tags/) and updates the app's metadata yaml file in Fdroid without further ado.
|
||||||
|
|
||||||
|
However this is not the full story. Please have a look at previous commits to see what necessary changes got pushed, [see here](https://gitlab.com/fdroid/fdroiddata/-/commits/master/metadata/com.drip.yml).
|
||||||
|
|
||||||
### drip website
|
### drip website
|
||||||
|
|
||||||
After a new version has been published on Google Play (or F-Droid) the apk version that is downloadable directly from the [drip website](https://dripapp.org) needs to get updated as well. Therefore you upload a signed apk to the [repository](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/) and adapt the name and link on /index.html.
|
After a new version has been published on Google Play (or F-Droid) the apk version that is downloadable directly from the [drip website](https://dripapp.org) needs to get updated as well. Therefore you upload a signed apk to the [repository](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/) as [we did in this commit](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/commit/f8c0f90c1ae9f23bf8e1bc311790b85443149a4d), and adapt the name and link on /index.html [as we did in this commit](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/commit2f8850ff5fa78615a4f335b625ea4a67d4acf03a) and [this commit](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/commit/f3da9776b1943ffa32458e74ef86eeca98c1891c). Last time I checked it was [here](f3da9776b1943ffa32458e74ef86eeca98c1891c/index.html#L114).
|
||||||
Last time I checked it was [here](f3da9776b1943ffa32458e74ef86eeca98c1891c/index.html#L114).
|
|
||||||
|
|
||||||
#### Phone screenshots
|
### Communication
|
||||||
|
|
||||||
Please also update [phone screenshots here](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/tree/main/assets) and set links on [/index](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/blob/f3da9776b1943ffa32458e74ef86eeca98c1891c/index.html#L47) and [/media](https://gitlab.com/bloodyhealth/bloodyhealth.gitlab.io/-/blob/c7f999bb7ad736345321537cbffa3f4c24eeee6d/media.html#L33) that can then also be attached to a social media post.
|
|
||||||
|
|
||||||
You probably want to share the app update by posting on one or more of these platforms:
|
You probably want to share the app update by posting on one or more of these platforms:
|
||||||
|
|
||||||
@@ -106,3 +202,7 @@ You probably want to share the app update by posting on one or more of these pla
|
|||||||
- [Ko-fi](https://ko-fi.com/dripapp)
|
- [Ko-fi](https://ko-fi.com/dripapp)
|
||||||
- [Linkedin](https://www.linkedin.com/company/34899684/)
|
- [Linkedin](https://www.linkedin.com/company/34899684/)
|
||||||
- Different tech, privacy, feminist oriented slacks
|
- Different tech, privacy, feminist oriented slacks
|
||||||
|
|
||||||
|
### Self care
|
||||||
|
|
||||||
|
Congratulations. Take a break, eat some chocolate, go see a live show of your favorite band, masturbate <3!
|
||||||
|
|||||||
@@ -134,8 +134,8 @@ android {
|
|||||||
applicationId "com.drip"
|
applicationId "com.drip"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 25
|
versionCode 33
|
||||||
versionName "1.2311.14"
|
versionName "1.2403.19"
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,6 @@
|
|||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
tools:targetApi="28"
|
tools:targetApi="28"
|
||||||
tools:ignore="GoogleAppIndexingWarning">
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
*
|
*
|
||||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||||
* directory of this source tree.
|
* directory of this source tree.
|
||||||
*/
|
*/
|
||||||
package com.rndiffapp;
|
package com.drip;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import com.facebook.flipper.android.AndroidFlipperClient;
|
import com.facebook.flipper.android.AndroidFlipperClient;
|
||||||
import com.facebook.flipper.android.utils.FlipperUtils;
|
import com.facebook.flipper.android.utils.FlipperUtils;
|
||||||
@@ -18,6 +18,7 @@ import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
|
|||||||
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
|
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
|
||||||
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
|
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
|
||||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
||||||
|
import com.facebook.react.ReactInstanceEventListener;
|
||||||
import com.facebook.react.ReactInstanceManager;
|
import com.facebook.react.ReactInstanceManager;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.modules.network.NetworkingModule;
|
import com.facebook.react.modules.network.NetworkingModule;
|
||||||
@@ -46,7 +47,7 @@ public class ReactNativeFlipper {
|
|||||||
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
|
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
|
||||||
if (reactContext == null) {
|
if (reactContext == null) {
|
||||||
reactInstanceManager.addReactInstanceEventListener(
|
reactInstanceManager.addReactInstanceEventListener(
|
||||||
new ReactInstanceManager.ReactInstanceEventListener() {
|
new ReactInstanceEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onReactContextInitialized(ReactContext reactContext) {
|
public void onReactContextInitialized(ReactContext reactContext) {
|
||||||
reactInstanceManager.removeReactInstanceEventListener(this);
|
reactInstanceManager.removeReactInstanceEventListener(this);
|
||||||
|
|||||||
@@ -57,12 +57,12 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:windowSoftInputMode="adjustPan"
|
android:windowSoftInputMode="adjustPan"
|
||||||
android:screenOrientation="sensorPortrait">
|
android:screenOrientation="sensorPortrait"
|
||||||
|
android:exported="true">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.drip;
|
package com.drip;
|
||||||
|
|
||||||
import com.facebook.react.ReactActivity;
|
import com.facebook.react.ReactActivity;
|
||||||
|
import com.facebook.react.ReactActivityDelegate;
|
||||||
|
import com.facebook.react.ReactRootView;
|
||||||
|
|
||||||
public class MainActivity extends ReactActivity {
|
public class MainActivity extends ReactActivity {
|
||||||
|
|
||||||
@@ -12,4 +14,27 @@ public class MainActivity extends ReactActivity {
|
|||||||
protected String getMainComponentName() {
|
protected String getMainComponentName() {
|
||||||
return "drip";
|
return "drip";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
|
||||||
|
* you can specify the rendered you wish to use (Fabric or the older renderer).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected ReactActivityDelegate createReactActivityDelegate() {
|
||||||
|
return new MainActivityDelegate(this, getMainComponentName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MainActivityDelegate extends ReactActivityDelegate {
|
||||||
|
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
|
||||||
|
super(activity, mainComponentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ReactRootView createRootView() {
|
||||||
|
ReactRootView reactRootView = new ReactRootView(getContext());
|
||||||
|
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
|
||||||
|
return reactRootView;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.facebook.react.ReactInstanceManager;
|
|||||||
import cl.json.ShareApplication;
|
import cl.json.ShareApplication;
|
||||||
import com.facebook.react.ReactNativeHost;
|
import com.facebook.react.ReactNativeHost;
|
||||||
import com.facebook.react.ReactPackage;
|
import com.facebook.react.ReactPackage;
|
||||||
|
import com.facebook.react.config.ReactFeatureFlags;
|
||||||
import com.facebook.soloader.SoLoader;
|
import com.facebook.soloader.SoLoader;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -62,7 +63,7 @@ public class MainApplication extends Application implements ReactApplication, Sh
|
|||||||
We use reflection here to pick up the class that initializes Flipper,
|
We use reflection here to pick up the class that initializes Flipper,
|
||||||
since Flipper library is not available in release mode
|
since Flipper library is not available in release mode
|
||||||
*/
|
*/
|
||||||
Class<?> aClass = Class.forName("com.rndiffapp.ReactNativeFlipper");
|
Class<?> aClass = Class.forName("com.drip.ReactNativeFlipper");
|
||||||
aClass
|
aClass
|
||||||
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
|
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
|
||||||
.invoke(null, context, reactInstanceManager);
|
.invoke(null, context, reactInstanceManager);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import org.apache.tools.ant.taskdefs.condition.Os
|
||||||
|
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
@@ -7,8 +9,9 @@ buildscript {
|
|||||||
}
|
}
|
||||||
ext.kotlinVersion = '1.3.40'
|
ext.kotlinVersion = '1.3.40'
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath('com.android.tools.build:gradle:7.0.3')
|
classpath('com.android.tools.build:gradle:7.0.4')
|
||||||
|
classpath("com.facebook.react:react-native-gradle-plugin")
|
||||||
|
classpath("de.undercouch:gradle-download-task:4.1.2")
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
|
||||||
@@ -50,5 +53,12 @@ ext {
|
|||||||
minSdkVersion = 21
|
minSdkVersion = 21
|
||||||
compileSdkVersion = 33
|
compileSdkVersion = 33
|
||||||
targetSdkVersion = 33
|
targetSdkVersion = 33
|
||||||
ndkVersion = "21.4.7075529"
|
|
||||||
|
if (System.properties['os.arch'] == "aarch64") {
|
||||||
|
// For M1 Users we need to use the NDK 24 which added support for aarch64
|
||||||
|
ndkVersion = "24.0.8215888"
|
||||||
|
} else {
|
||||||
|
// Otherwise we default to the side-by-side NDK version from AGP.
|
||||||
|
ndkVersion = "21.4.7075529"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
# Default value: -Xmx1024m -XX:MaxPermSize=256m
|
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
|
||||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
|
||||||
|
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
@@ -25,7 +25,16 @@ android.useAndroidX=true
|
|||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
|
||||||
# Version of flipper SDK to use with React Native
|
# Version of flipper SDK to use with React Native
|
||||||
FLIPPER_VERSION=0.99.0
|
FLIPPER_VERSION=0.125.0
|
||||||
|
|
||||||
# https://github.com/facebook/react-native/issues/30729
|
# Use this property to specify which architecture you want to build.
|
||||||
org.gradle.jvmargs=-Xmx4g
|
# You can also override it from the CLI using
|
||||||
|
# ./gradlew <task> -PreactNativeArchitectures=x86_64
|
||||||
|
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
|
||||||
|
|
||||||
|
# Use this property to enable support to the new architecture.
|
||||||
|
# This will allow you to use TurboModules and the Fabric render in
|
||||||
|
# your application. You should enable this flag either if you want
|
||||||
|
# to write custom TurboModules/Fabric components OR use libraries that
|
||||||
|
# are providing them.
|
||||||
|
newArchEnabled=false
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#Wed Oct 11 14:45:21 CEST 2023
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright 2015 the original author or authors.
|
# Copyright © 2015-2021 the original authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -17,70 +17,103 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
##
|
#
|
||||||
## Gradle start up script for UN*X
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
##
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=`basename "$0"`
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD="maximum"
|
MAX_FD=maximum
|
||||||
|
|
||||||
warn ( ) {
|
warn () {
|
||||||
echo "$*"
|
echo "$*"
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
die ( ) {
|
die () {
|
||||||
echo
|
echo
|
||||||
echo "$*"
|
echo "$*"
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit 1
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
# OS specific support (must be 'true' or 'false').
|
||||||
cygwin=false
|
cygwin=false
|
||||||
msys=false
|
msys=false
|
||||||
darwin=false
|
darwin=false
|
||||||
case "`uname`" in
|
nonstop=false
|
||||||
CYGWIN* )
|
case "$( uname )" in #(
|
||||||
cygwin=true
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
;;
|
Darwin* ) darwin=true ;; #(
|
||||||
Darwin* )
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
darwin=true
|
NONSTOP* ) nonstop=true ;;
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
|
||||||
if $cygwin ; then
|
|
||||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
PRG="$0"
|
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
|
||||||
ls=`ls -ld "$PRG"`
|
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
PRG="$link"
|
|
||||||
else
|
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >&-
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >&-
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@@ -88,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
else
|
else
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
fi
|
fi
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
@@ -99,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
|||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD="java"
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
@@ -107,80 +140,95 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
case $MAX_FD in #(
|
||||||
if [ $? -eq 0 ] ; then
|
max*)
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
warn "Could not query maximum file descriptor limit"
|
||||||
fi
|
esac
|
||||||
ulimit -n $MAX_FD
|
case $MAX_FD in #(
|
||||||
if [ $? -ne 0 ] ; then
|
'' | soft) :;; #(
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
*)
|
||||||
fi
|
ulimit -n "$MAX_FD" ||
|
||||||
else
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
||||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=`expr $i + 1`
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
0) set -- ;;
|
|
||||||
1) set -- "$args0" ;;
|
|
||||||
2) set -- "$args0" "$args1" ;;
|
|
||||||
3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Escape application args
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
save () {
|
# * args from the command line
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
# * the main class name
|
||||||
echo " "
|
# * -classpath
|
||||||
}
|
# * -D...appname settings
|
||||||
APP_ARGS=`save "$@"`
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
exec "$JAVACMD" "$@"
|
||||||
|
|||||||
@@ -3,3 +3,10 @@ rootProject.name = 'drip'
|
|||||||
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
||||||
|
|
||||||
include ':app'
|
include ':app'
|
||||||
|
|
||||||
|
includeBuild('../node_modules/react-native-gradle-plugin')
|
||||||
|
|
||||||
|
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
|
||||||
|
include(":ReactAndroid")
|
||||||
|
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
|
||||||
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
@@ -47,6 +51,7 @@ const Home = ({ navigate, setDate }) => {
|
|||||||
>
|
>
|
||||||
<AppText style={styles.title}>{moment().format('MMM Do YYYY')}</AppText>
|
<AppText style={styles.title}>{moment().format('MMM Do YYYY')}</AppText>
|
||||||
|
|
||||||
|
{/* display if at least 1 bleeding day has been entered */}
|
||||||
{cycleDayNumber && (
|
{cycleDayNumber && (
|
||||||
<View style={styles.line}>
|
<View style={styles.line}>
|
||||||
<AppText style={styles.whiteSubtitle}>{cycleDayText}</AppText>
|
<AppText style={styles.whiteSubtitle}>{cycleDayText}</AppText>
|
||||||
@@ -55,7 +60,9 @@ const Home = ({ navigate, setDate }) => {
|
|||||||
</AppText>
|
</AppText>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{phase && (
|
|
||||||
|
{/* display if fertility tracking enabled and if phase 1, 2 or 3 has been identified */}
|
||||||
|
{isFertilityTrackingEnabled && phase && (
|
||||||
<View style={styles.line}>
|
<View style={styles.line}>
|
||||||
<AppText style={styles.whiteSubtitle}>
|
<AppText style={styles.whiteSubtitle}>
|
||||||
{formatWithOrdinalSuffix(phase)}
|
{formatWithOrdinalSuffix(phase)}
|
||||||
@@ -67,11 +74,14 @@ const Home = ({ navigate, setDate }) => {
|
|||||||
<Asterisk />
|
<Asterisk />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isPeriodPredictionEnabled && (
|
{isPeriodPredictionEnabled && (
|
||||||
<View style={styles.line}>
|
<View style={styles.line}>
|
||||||
<AppText style={styles.turquoiseText}>{prediction}</AppText>
|
<AppText style={styles.turquoiseText}>{prediction}</AppText>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{!isFertilityTrackingEnabled && <View style={styles.largePadding}></View>}
|
||||||
<Button isCTA isSmall={false} onPress={navigateToCycleDayView}>
|
<Button isCTA isSmall={false} onPress={navigateToCycleDayView}>
|
||||||
{t('labels.home.addDataForToday')}
|
{t('labels.home.addDataForToday')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -110,6 +120,9 @@ const styles = StyleSheet.create({
|
|||||||
color: 'white',
|
color: 'white',
|
||||||
fontSize: Sizes.subtitle,
|
fontSize: Sizes.subtitle,
|
||||||
},
|
},
|
||||||
|
largePadding: {
|
||||||
|
padding: Spacing.large,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
Home.propTypes = {
|
Home.propTypes = {
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ import {
|
|||||||
noteTrackingCategoryObservable,
|
noteTrackingCategoryObservable,
|
||||||
painTrackingCategoryObservable,
|
painTrackingCategoryObservable,
|
||||||
sexTrackingCategoryObservable,
|
sexTrackingCategoryObservable,
|
||||||
|
temperatureTrackingCategoryObservable,
|
||||||
|
mucusTrackingCategoryObservable,
|
||||||
|
cervixTrackingCategoryObservable,
|
||||||
} from '../../local-storage'
|
} from '../../local-storage'
|
||||||
import { makeColumnInfo } from '../helpers/chart'
|
import { makeColumnInfo } from '../helpers/chart'
|
||||||
|
|
||||||
@@ -71,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') {
|
||||||
@@ -84,7 +91,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 { width, height } = Dimensions.get('window')
|
||||||
const numberOfColumnsToRender = Math.round(width / CHART_COLUMN_WIDTH)
|
const numberOfColumnsToRender = Math.round(width / CHART_COLUMN_WIDTH)
|
||||||
@@ -135,7 +146,7 @@ const CycleChart = ({ navigate, setDate }) => {
|
|||||||
>
|
>
|
||||||
<View style={styles.chartContainer}>
|
<View style={styles.chartContainer}>
|
||||||
{shouldShowHint && <Tutorial onClose={hideHint} />}
|
{shouldShowHint && <Tutorial onClose={hideHint} />}
|
||||||
{!shouldShowTemperatureColumn && <NoTemperature />}
|
{shouldShowNoDataWarning && <NoTemperature />}
|
||||||
<View style={styles.chartArea}>
|
<View style={styles.chartArea}>
|
||||||
<YAxis
|
<YAxis
|
||||||
height={columnHeight}
|
height={columnHeight}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ LoadingMoreView.propTypes = {
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
loadingContainer: {
|
loadingContainer: {
|
||||||
height: '100%',
|
height: 80,
|
||||||
backgroundColor: Colors.turquoiseLight,
|
backgroundColor: Colors.turquoiseLight,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
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 { Containers } from '../../styles'
|
import { Colors, Containers, Spacing } from '../../styles'
|
||||||
|
|
||||||
const AppSwitch = ({ onToggle, text, value, trackColor, disabled }) => {
|
const AppSwitch = ({ onToggle, text, value, disabled }) => {
|
||||||
|
const trackColor = { true: Colors.turquoiseDark }
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.textContainer}>
|
<View style={styles.textContainer}>
|
||||||
@@ -27,16 +28,20 @@ AppSwitch.propTypes = {
|
|||||||
onToggle: PropTypes.func.isRequired,
|
onToggle: PropTypes.func.isRequired,
|
||||||
text: PropTypes.string,
|
text: PropTypes.string,
|
||||||
value: PropTypes.bool,
|
value: PropTypes.bool,
|
||||||
trackColor: PropTypes.string,
|
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ import AppText from './app-text'
|
|||||||
|
|
||||||
import { Colors, Containers, Spacing, Typography } from '../../styles'
|
import { Colors, Containers, Spacing, Typography } from '../../styles'
|
||||||
|
|
||||||
const Segment = ({ children, last, title }) => {
|
const Segment = ({ children, last, title, subheader }) => {
|
||||||
const containerStyle = last ? styles.containerLast : styles.container
|
const containerStyle = last ? styles.containerLast : styles.container
|
||||||
const commonStyle = Object.assign({}, containerStyle)
|
const commonStyle = Object.assign({}, containerStyle)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={commonStyle}>
|
<View style={commonStyle}>
|
||||||
{title && <AppText style={styles.title}>{title}</AppText>}
|
{title && <AppText style={styles.title}>{title}</AppText>}
|
||||||
|
{subheader && <AppText style={styles.subheader}>{subheader}</AppText>}
|
||||||
{children}
|
{children}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
@@ -23,6 +24,7 @@ Segment.propTypes = {
|
|||||||
last: PropTypes.bool,
|
last: PropTypes.bool,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
|
subheader: PropTypes.string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
@@ -39,6 +41,11 @@ const styles = StyleSheet.create({
|
|||||||
title: {
|
title: {
|
||||||
...Typography.subtitle,
|
...Typography.subtitle,
|
||||||
},
|
},
|
||||||
|
subheader: {
|
||||||
|
...Typography.subtitle,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: Spacing.zero,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default Segment
|
export default Segment
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -15,6 +15,9 @@ import {
|
|||||||
noteTrackingCategoryObservable,
|
noteTrackingCategoryObservable,
|
||||||
painTrackingCategoryObservable,
|
painTrackingCategoryObservable,
|
||||||
sexTrackingCategoryObservable,
|
sexTrackingCategoryObservable,
|
||||||
|
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'
|
||||||
@@ -35,8 +38,14 @@ const CycleDayOverView = ({ date, setDate, isTemperatureEditView }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const allEnabledSymptoms = SYMPTOMS.map((symptom) => {
|
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
|
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,61 @@
|
|||||||
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 === labels.secondarySymptom.cervix ||
|
||||||
|
label === labels.secondarySymptom.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 +71,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 +90,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
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import Temperature from './temperature'
|
|||||||
import { blank, save, shouldShow, symtomPage } from '../helpers/cycle-day'
|
import { blank, save, shouldShow, symtomPage } from '../helpers/cycle-day'
|
||||||
import { showToast } from '../helpers/general'
|
import { showToast } from '../helpers/general'
|
||||||
|
|
||||||
|
import { fertilityTrackingObservable } from '../../local-storage'
|
||||||
import { shared as sharedLabels } from '../../i18n/en/labels'
|
import { shared as sharedLabels } from '../../i18n/en/labels'
|
||||||
import info from '../../i18n/en/symptom-info'
|
import info from '../../i18n/en/symptom-info'
|
||||||
import { Colors, Containers, Sizes, Spacing } from '../../styles'
|
import { Colors, Containers, Sizes, Spacing } from '../../styles'
|
||||||
@@ -25,6 +26,7 @@ const SymptomEditView = ({ date, onClose, symptom, symptomData }) => {
|
|||||||
const [shouldShowInfo, setShouldShowInfo] = useState(false)
|
const [shouldShowInfo, setShouldShowInfo] = useState(false)
|
||||||
const getParsedData = () => JSON.parse(JSON.stringify(data))
|
const getParsedData = () => JSON.parse(JSON.stringify(data))
|
||||||
const onPressLearnMore = () => setShouldShowInfo(!shouldShowInfo)
|
const onPressLearnMore = () => setShouldShowInfo(!shouldShowInfo)
|
||||||
|
const isFertilityTrackingEnabled = fertilityTrackingObservable.value
|
||||||
|
|
||||||
const onEditNote = (note) => {
|
const onEditNote = (note) => {
|
||||||
const parsedData = getParsedData()
|
const parsedData = getParsedData()
|
||||||
@@ -167,15 +169,18 @@ const SymptomEditView = ({ date, onClose, symptom, symptomData }) => {
|
|||||||
</Segment>
|
</Segment>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
{shouldShow(symptomConfig.excludeText) && (
|
{/* show exclude AppSwitch for bleeding, mucus, cervix, temperature */}
|
||||||
<Segment style={styles.segmentBorder}>
|
{/* but if fertility is off only for bleeding */}
|
||||||
<AppSwitch
|
{shouldShow(symptomConfig.excludeText) &&
|
||||||
onToggle={onExcludeToggle}
|
(symptom === 'bleeding' || isFertilityTrackingEnabled) && (
|
||||||
text={symtomPage[symptom].excludeText}
|
<Segment style={styles.segmentBorder}>
|
||||||
value={data.exclude}
|
<AppSwitch
|
||||||
/>
|
onToggle={onExcludeToggle}
|
||||||
</Segment>
|
text={symtomPage[symptom].excludeText}
|
||||||
)}
|
value={data.exclude}
|
||||||
|
/>
|
||||||
|
</Segment>
|
||||||
|
)}
|
||||||
{shouldShow(symptomConfig.note) && (
|
{shouldShow(symptomConfig.note) && (
|
||||||
<Segment style={styles.segmentBorder}>
|
<Segment style={styles.segmentBorder}>
|
||||||
<AppText>{symtomPage[symptom].note}</AppText>
|
<AppText>{symtomPage[symptom].note}</AppText>
|
||||||
|
|||||||
@@ -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,39 +1,65 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { Alert, Pressable, StyleSheet, View } from 'react-native'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import AppIcon from '../../common/app-icon'
|
||||||
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 { Colors, Spacing, Typography } from '../../../styles'
|
||||||
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,
|
||||||
|
mucusTrackingCategoryObservable,
|
||||||
|
cervixTrackingCategoryObservable,
|
||||||
|
periodPredictionObservable,
|
||||||
|
useCervixAsSecondarySymptomObservable,
|
||||||
saveDesireTrackingCategory,
|
saveDesireTrackingCategory,
|
||||||
|
saveFertilityTrackingEnabled,
|
||||||
saveMoodTrackingCategory,
|
saveMoodTrackingCategory,
|
||||||
saveNoteTrackingCategory,
|
saveNoteTrackingCategory,
|
||||||
savePainTrackingCategory,
|
savePainTrackingCategory,
|
||||||
|
saveMucusTrackingCategory,
|
||||||
|
saveCervixTrackingCategory,
|
||||||
savePeriodPrediction,
|
savePeriodPrediction,
|
||||||
saveSexTrackingCategory,
|
saveSexTrackingCategory,
|
||||||
saveUseCervix,
|
saveTemperatureTrackingCategory,
|
||||||
periodPredictionObservable,
|
saveUseCervixAsSecondarySymptom,
|
||||||
useCervixObservable,
|
|
||||||
} from '../../../local-storage'
|
} from '../../../local-storage'
|
||||||
import { Colors } from '../../../styles'
|
|
||||||
import labels from '../../../i18n/en/settings'
|
import labels from '../../../i18n/en/settings'
|
||||||
|
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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const [isTemperatureTrackingCategoryEnabled, setTemperatureTrackingCategory] =
|
||||||
|
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
|
||||||
)
|
)
|
||||||
@@ -54,14 +80,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) => {
|
||||||
|
setTemperatureTrackingCategory(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)
|
||||||
@@ -78,93 +123,229 @@ 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 = () => {
|
||||||
|
if (!isTemperatureTrackingCategoryEnabled) {
|
||||||
|
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}
|
||||||
|
text={t(SYMPTOMS[1])}
|
||||||
|
value={isTemperatureTrackingCategoryEnabled}
|
||||||
|
symptom={SYMPTOMS[1]}
|
||||||
|
/>
|
||||||
|
<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={"sex: when turned off it won't show"}
|
text={t(SYMPTOMS[4])}
|
||||||
value={isSexTrackingCategoryEnabled}
|
value={isSexTrackingCategoryEnabled}
|
||||||
trackColor={{ true: Colors.turquoiseDark }}
|
symptom={SYMPTOMS[4]}
|
||||||
/>
|
/>
|
||||||
<AppSwitch
|
<TrackingCategorySwitch
|
||||||
onToggle={desireTrackingCategoryToggle}
|
onToggle={desireTrackingCategoryToggle}
|
||||||
text={"desire: when turned off it won't show"}
|
text={t(SYMPTOMS[5])}
|
||||||
value={isDesireTrackingCategoryEnabled}
|
value={isDesireTrackingCategoryEnabled}
|
||||||
trackColor={{ true: Colors.turquoiseDark }}
|
symptom={SYMPTOMS[5]}
|
||||||
/>
|
/>
|
||||||
<AppSwitch
|
<TrackingCategorySwitch
|
||||||
onToggle={painTrackingCategoryToggle}
|
onToggle={painTrackingCategoryToggle}
|
||||||
text={"pain: when turned off it won't show"}
|
text={t(SYMPTOMS[6])}
|
||||||
value={isPainTrackingCategoryEnabled}
|
value={isPainTrackingCategoryEnabled}
|
||||||
trackColor={{ true: Colors.turquoiseDark }}
|
symptom={SYMPTOMS[6]}
|
||||||
/>
|
/>
|
||||||
<AppSwitch
|
<TrackingCategorySwitch
|
||||||
onToggle={moodTrackingCategoryToggle}
|
onToggle={moodTrackingCategoryToggle}
|
||||||
text={"mood: when turned off it won't show"}
|
text={t(SYMPTOMS[7])}
|
||||||
value={isMoodTrackingCategoryEnabled}
|
value={isMoodTrackingCategoryEnabled}
|
||||||
trackColor={{ true: Colors.turquoiseDark }}
|
symptom={SYMPTOMS[7]}
|
||||||
/>
|
/>
|
||||||
<AppSwitch
|
<TrackingCategorySwitch
|
||||||
onToggle={noteTrackingCategoryToggle}
|
onToggle={noteTrackingCategoryToggle}
|
||||||
text={"note: when turned off it won't show"}
|
text={t(SYMPTOMS[8])}
|
||||||
value={isNoteTrackingCategoryEnabled}
|
value={isNoteTrackingCategoryEnabled}
|
||||||
trackColor={{ true: Colors.turquoiseDark }}
|
symptom={SYMPTOMS[8]}
|
||||||
/>
|
/>
|
||||||
</Segment>
|
</Segment>
|
||||||
|
|
||||||
<Segment title={'Fertility feature'}>
|
<Pressable onPress={fertilityDisabledPrompt}>
|
||||||
<AppSwitch
|
<Segment title={labels.fertilityTracking.title}>
|
||||||
onToggle={toggleSwitch}
|
<AppText>{labels.fertilityTracking.message}</AppText>
|
||||||
text={'If turned on ...'}
|
<AppSwitch
|
||||||
value={isEnabled}
|
onToggle={fertilityTrackingToggle}
|
||||||
trackColor={{ true: Colors.turquoiseDark }}
|
text={fertilityTrackingText}
|
||||||
/>
|
value={isFertilityTrackingEnabled}
|
||||||
</Segment>
|
disabled={!manageFertilityFeature}
|
||||||
|
/>
|
||||||
|
</Segment>
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
<Segment title={labels.tempScale.segmentTitle}>
|
<Segment title={labels.periodPrediction.title}>
|
||||||
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
|
||||||
<TemperatureSlider />
|
|
||||||
</Segment>
|
|
||||||
|
|
||||||
<Segment title={labels.useCervix.title}>
|
|
||||||
<AppSwitch
|
|
||||||
onToggle={onCervixToggle}
|
|
||||||
text={cervixText}
|
|
||||||
value={shouldUseCervix}
|
|
||||||
trackColor={{ true: Colors.turquoiseDark }}
|
|
||||||
/>
|
|
||||||
</Segment>
|
|
||||||
|
|
||||||
<Segment title={labels.periodPrediction.title} last>
|
|
||||||
<AppSwitch
|
<AppSwitch
|
||||||
onToggle={onPeriodPredictionToggle}
|
onToggle={onPeriodPredictionToggle}
|
||||||
text={periodPredictionText}
|
text={periodPredictionText}
|
||||||
value={isPeriodPredictionEnabled}
|
value={isPeriodPredictionEnabled}
|
||||||
trackColor={{ true: Colors.turquoiseDark }}
|
|
||||||
/>
|
/>
|
||||||
</Segment>
|
</Segment>
|
||||||
|
|
||||||
|
<Segment
|
||||||
|
subheader={labels.customization.subheaderSymptoThermalMethod}
|
||||||
|
last
|
||||||
|
></Segment>
|
||||||
|
|
||||||
|
<Pressable onPress={sliderDisabledPrompt}>
|
||||||
|
<Segment title={labels.tempScale.segmentTitle}>
|
||||||
|
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
||||||
|
<TemperatureSlider disabled={!isTemperatureTrackingCategoryEnabled} />
|
||||||
|
</Segment>
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Pressable onPress={secondarySymptomDisabledPrompt}>
|
||||||
|
<Segment title={labels.secondarySymptom.title}>
|
||||||
|
<AppText>{cervixText}</AppText>
|
||||||
|
<SelectTabGroup
|
||||||
|
activeButton={useCervixAsSecondarySymptom}
|
||||||
|
buttons={secondarySymptomButtons}
|
||||||
|
onSelect={(value) => onSelectTab(value)}
|
||||||
|
disabled={!isFertilityTrackingEnabled}
|
||||||
|
/>
|
||||||
|
</Segment>
|
||||||
|
</Pressable>
|
||||||
|
<Segment last>
|
||||||
|
<View style={styles.line}>
|
||||||
|
<AppIcon
|
||||||
|
color={Colors.purple}
|
||||||
|
name="info-with-circle"
|
||||||
|
style={styles.icon}
|
||||||
|
/>
|
||||||
|
<AppText style={styles.title}>{labels.preOvu.title}</AppText>
|
||||||
|
</View>
|
||||||
|
<AppText>{labels.preOvu.note}</AppText>
|
||||||
|
</Segment>
|
||||||
</AppPage>
|
</AppPage>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Settings
|
export default Settings
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
icon: {
|
||||||
|
marginRight: Spacing.base,
|
||||||
|
},
|
||||||
|
line: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
...Typography.subtitle,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -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,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Alert } from 'react-native'
|
import { Alert, Platform } from 'react-native'
|
||||||
import DocumentPicker from 'react-native-document-picker'
|
import DocumentPicker from 'react-native-document-picker'
|
||||||
import rnfs from 'react-native-fs'
|
import rnfs from 'react-native-fs'
|
||||||
import importCsv from '../../../lib/import-export/import-from-csv'
|
import importCsv from '../../../lib/import-export/import-from-csv'
|
||||||
@@ -59,21 +59,28 @@ export default function ImportData({ resetIsDeletingData, setIsLoading }) {
|
|||||||
|
|
||||||
function openImportDialog() {
|
function openImportDialog() {
|
||||||
resetIsDeletingData()
|
resetIsDeletingData()
|
||||||
Alert.alert(t('dialog.title'), t('dialog.message'), [
|
|
||||||
|
let buttons = [
|
||||||
{
|
{
|
||||||
text: t('dialog.cancel'),
|
text: t('dialog.cancel'),
|
||||||
style: 'cancel',
|
style: 'cancel',
|
||||||
onPress: () => {},
|
onPress: () => {},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
text: t('dialog.delete'),
|
|
||||||
onPress: () => startImport(true),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
text: t('dialog.replace'),
|
text: t('dialog.replace'),
|
||||||
onPress: () => startImport(false),
|
onPress: () => startImport(false),
|
||||||
},
|
},
|
||||||
])
|
{
|
||||||
|
text: t('dialog.delete'),
|
||||||
|
onPress: () => startImport(true),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
if (Platform.OS === 'android') {
|
||||||
|
buttons = [buttons[0], buttons[2], buttons[1]]
|
||||||
|
}
|
||||||
|
|
||||||
|
Alert.alert(t('dialog.title'), t('dialog.message'), buttons)
|
||||||
}
|
}
|
||||||
|
|
||||||
function showImportErrorAlert(message) {
|
function showImportErrorAlert(message) {
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ const MenuItem = ({ item, last, navigate }) => {
|
|||||||
key={item.label}
|
key={item.label}
|
||||||
onPress={() => navigate(item.componentName)}
|
onPress={() => navigate(item.componentName)}
|
||||||
>
|
>
|
||||||
<View>
|
<View style={styles.textContainer}>
|
||||||
<AppText style={styles.title}>{t(`${item.label}.name`)}</AppText>
|
<AppText style={styles.title}>{t(`${item.label}.name`)}</AppText>
|
||||||
{!!item.label && <AppText>{t(`${item.label}.text`)}</AppText>}
|
{!!item.label && <AppText>{t(`${item.label}.text`)}</AppText>}
|
||||||
</View>
|
</View>
|
||||||
<AppIcon name="chevron-right" color={Colors.orange} />
|
<AppIcon
|
||||||
|
style={styles.chevronContainer}
|
||||||
|
name="chevron-right"
|
||||||
|
color={Colors.orange}
|
||||||
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</Segment>
|
</Segment>
|
||||||
)
|
)
|
||||||
@@ -44,6 +48,13 @@ const styles = StyleSheet.create({
|
|||||||
color: Colors.purple,
|
color: Colors.purple,
|
||||||
fontSize: Sizes.subtitle,
|
fontSize: Sizes.subtitle,
|
||||||
},
|
},
|
||||||
|
textContainer: {
|
||||||
|
flex: 5,
|
||||||
|
},
|
||||||
|
chevronContainer: {
|
||||||
|
textAlign: 'right',
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default MenuItem
|
export default MenuItem
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
periodReminderObservable,
|
periodReminderObservable,
|
||||||
savePeriodReminder,
|
savePeriodReminder,
|
||||||
periodPredictionObservable,
|
periodPredictionObservable,
|
||||||
|
temperatureTrackingCategoryObservable,
|
||||||
} from '../../../local-storage'
|
} from '../../../local-storage'
|
||||||
|
|
||||||
import labels from '../../../i18n/en/settings'
|
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 (
|
return (
|
||||||
<AppPage>
|
<AppPage>
|
||||||
<Pressable onPress={reminderDisabledPrompt}>
|
<Pressable onPress={reminderDisabledPrompt}>
|
||||||
@@ -46,9 +55,11 @@ const Reminders = () => {
|
|||||||
/>
|
/>
|
||||||
</Segment>
|
</Segment>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Segment title={labels.tempReminder.title} last>
|
<Pressable onPress={tempReminderDisabledPrompt}>
|
||||||
<TemperatureReminder />
|
<Segment title={labels.tempReminder.title} last>
|
||||||
</Segment>
|
<TemperatureReminder />
|
||||||
|
</Segment>
|
||||||
|
</Pressable>
|
||||||
</AppPage>
|
</AppPage>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import AppSwitch from '../../common/app-switch'
|
|||||||
import {
|
import {
|
||||||
saveTempReminder,
|
saveTempReminder,
|
||||||
tempReminderObservable,
|
tempReminderObservable,
|
||||||
|
temperatureTrackingCategoryObservable,
|
||||||
} from '../../../local-storage'
|
} from '../../../local-storage'
|
||||||
import padWithZeros from '../../helpers/pad-time-with-zeros'
|
import padWithZeros from '../../helpers/pad-time-with-zeros'
|
||||||
|
|
||||||
@@ -51,6 +52,7 @@ const TemperatureReminder = () => {
|
|||||||
onToggle={temperatureReminderToggle}
|
onToggle={temperatureReminderToggle}
|
||||||
text={tempReminderText}
|
text={tempReminderText}
|
||||||
value={isEnabled}
|
value={isEnabled}
|
||||||
|
disabled={!temperatureTrackingCategoryObservable.value}
|
||||||
/>
|
/>
|
||||||
<DateTimePicker
|
<DateTimePicker
|
||||||
isVisible={isTimePickerVisible}
|
isVisible={isTimePickerVisible}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ const menuItems = [
|
|||||||
{ label: 'reminders', componentName: 'Reminders' },
|
{ label: 'reminders', componentName: 'Reminders' },
|
||||||
{ label: 'dataManagement', componentName: 'DataManagement' },
|
{ label: 'dataManagement', componentName: 'DataManagement' },
|
||||||
{ label: 'password', componentName: 'Password' },
|
{ label: 'password', componentName: 'Password' },
|
||||||
{ label: 'info', componentName: 'Info' },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const SettingsMenu = ({ navigate }) => {
|
const SettingsMenu = ({ navigate }) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { FlatList, StyleSheet, View } from 'react-native'
|
import { FlatList, StyleSheet, View } from 'react-native'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@@ -9,6 +9,7 @@ import AppText from '../common/app-text'
|
|||||||
import cycleModule from '../../lib/cycle'
|
import cycleModule from '../../lib/cycle'
|
||||||
import { Spacing, Typography, Colors } from '../../styles'
|
import { Spacing, Typography, Colors } from '../../styles'
|
||||||
import { humanizeDate } from '../helpers/format-date'
|
import { humanizeDate } from '../helpers/format-date'
|
||||||
|
import LoadingMoreView from '../chart/loading-more'
|
||||||
|
|
||||||
const Item = ({ data }) => {
|
const Item = ({ data }) => {
|
||||||
const { t } = useTranslation(null, { keyPrefix: 'plurals' })
|
const { t } = useTranslation(null, { keyPrefix: 'plurals' })
|
||||||
@@ -39,21 +40,36 @@ Item.propTypes = {
|
|||||||
const PeriodDetailsModal = ({ onClose }) => {
|
const PeriodDetailsModal = ({ onClose }) => {
|
||||||
const renderItem = ({ item }) => <Item data={item} />
|
const renderItem = ({ item }) => <Item data={item} />
|
||||||
const data = cycleModule().getStats()
|
const data = cycleModule().getStats()
|
||||||
|
const [endReached, setEndReached] = useState(false)
|
||||||
|
|
||||||
if (!data || data.length === 0) return false
|
if (!data || data.length === 0) return false
|
||||||
|
|
||||||
|
// const ITEM_HEIGHT = 50;
|
||||||
|
|
||||||
|
// const getItemLayout = (data, index) => ({
|
||||||
|
// length: ITEM_HEIGHT,
|
||||||
|
// offset: ITEM_HEIGHT * index,
|
||||||
|
// index
|
||||||
|
// });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppModal onClose={onClose}>
|
<AppModal onClose={onClose}>
|
||||||
<View>
|
<View>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={data}
|
data={data}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
|
// getItemLayout={getItemLayout}
|
||||||
keyExtractor={(item) => item.date}
|
keyExtractor={(item) => item.date}
|
||||||
ItemSeparatorComponent={ItemDivider}
|
ItemSeparatorComponent={ItemDivider}
|
||||||
ListHeaderComponent={FlatListHeader}
|
ListHeaderComponent={FlatListHeader}
|
||||||
ListHeaderComponentStyle={styles.headerDivider}
|
ListHeaderComponentStyle={styles.headerDivider}
|
||||||
stickyHeaderIndices={[0]}
|
stickyHeaderIndices={[0]}
|
||||||
|
windowSize={4}
|
||||||
contentContainerStyle={styles.container}
|
contentContainerStyle={styles.container}
|
||||||
|
onEndReached={() => setEndReached(true)}
|
||||||
|
onEndReachedThreshold={0.1}
|
||||||
|
ListFooterComponent={<LoadingMoreView end={endReached} />}
|
||||||
|
updateCellsBatchingPeriod={100}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</AppModal>
|
</AppModal>
|
||||||
|
|||||||
@@ -7,18 +7,16 @@
|
|||||||
"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",
|
"cervix": "cervix",
|
||||||
"cervix": "cervix",
|
"note": "note",
|
||||||
"note": "note",
|
"desire": "desire",
|
||||||
"desire": "desire",
|
"sex": "sex",
|
||||||
"sex": "sex",
|
"pain": "pain",
|
||||||
"pain": "pain",
|
"mood": "mood"
|
||||||
"mood": "mood"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"bleedingPrediction": {
|
"bleedingPrediction": {
|
||||||
@@ -51,7 +49,7 @@
|
|||||||
},
|
},
|
||||||
"philosophy": {
|
"philosophy": {
|
||||||
"title": "Remember to think for yourself",
|
"title": "Remember to think for yourself",
|
||||||
"text": "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."
|
"text": "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."
|
||||||
},
|
},
|
||||||
"title": "About",
|
"title": "About",
|
||||||
"version": {
|
"version": {
|
||||||
@@ -114,19 +112,19 @@
|
|||||||
"menuItem": {
|
"menuItem": {
|
||||||
"dataManagement": {
|
"dataManagement": {
|
||||||
"name": "Data",
|
"name": "Data",
|
||||||
"text": "import, export or delete your data"
|
"text": "Import, export or delete your data"
|
||||||
},
|
},
|
||||||
"customization": {
|
"customization": {
|
||||||
"name": "Customization",
|
"name": "Customization",
|
||||||
"text": "define how you want to use drip"
|
"text": "Define how you want to use drip"
|
||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"name": "Password",
|
"name": "Password",
|
||||||
"text": ""
|
"text": "Set, edit or delete your password"
|
||||||
},
|
},
|
||||||
"reminders": {
|
"reminders": {
|
||||||
"name": "Reminders",
|
"name": "Reminders",
|
||||||
"text": "turn on/off reminders"
|
"text": "Turn on/off reminders"
|
||||||
},
|
},
|
||||||
"info": {
|
"info": {
|
||||||
"name": "Info",
|
"name": "Info",
|
||||||
|
|||||||
@@ -4,70 +4,71 @@ export const intensity = ['low', 'medium', 'high']
|
|||||||
export const bleeding = {
|
export const bleeding = {
|
||||||
labels: ['spotting', 'light', 'medium', 'heavy'],
|
labels: ['spotting', 'light', 'medium', 'heavy'],
|
||||||
heaviness: {
|
heaviness: {
|
||||||
header: "Heaviness",
|
header: 'Heaviness',
|
||||||
explainer: "How heavy is the bleeding?",
|
explainer: 'How heavy is the bleeding?',
|
||||||
},
|
},
|
||||||
exclude: {
|
exclude: {
|
||||||
header: "Exclude",
|
header: 'Exclude',
|
||||||
explainer: "You can exclude this value if it's not menstrual bleeding"
|
explainer: "You can exclude this value if it's not menstrual bleeding",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const cervix = {
|
export const cervix = {
|
||||||
subcategories: {
|
subcategories: {
|
||||||
opening: 'opening',
|
opening: 'opening',
|
||||||
firmness: 'firmness',
|
firmness: 'firmness',
|
||||||
position: 'position'
|
position: 'position',
|
||||||
},
|
},
|
||||||
opening: {
|
opening: {
|
||||||
categories: ['closed', 'medium', 'open'],
|
categories: ['closed', 'medium', 'open'],
|
||||||
explainer: 'Is your cervix open or closed?'
|
explainer: 'Is your cervix open or closed?',
|
||||||
},
|
},
|
||||||
firmness: {
|
firmness: {
|
||||||
categories: ['hard', 'soft'],
|
categories: ['hard', 'soft'],
|
||||||
explainer: "When it's hard, it might feel like the tip of your nose"
|
explainer: "When it's hard, it might feel like the tip of your nose",
|
||||||
},
|
},
|
||||||
position: {
|
position: {
|
||||||
categories: ['low', 'medium', 'high'],
|
categories: ['low', 'medium', 'high'],
|
||||||
explainer: 'How high up in the vagina is the cervix?'
|
explainer: 'How high up in the vagina is the cervix?',
|
||||||
},
|
},
|
||||||
excludeExplainer: "You can exclude this value if you don't want to use it for fertility detection.",
|
excludeExplainer:
|
||||||
actionHint: 'Choose values for at least "Opening" and "Firmness" to save.'
|
"You can exclude this value if you don't want to use it for fertility detection.",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mucus = {
|
export const mucus = {
|
||||||
subcategories: {
|
subcategories: {
|
||||||
feeling: 'feeling',
|
feeling: 'feeling',
|
||||||
texture: 'texture'
|
texture: 'texture',
|
||||||
},
|
},
|
||||||
feeling: {
|
feeling: {
|
||||||
categories: ['dry', 'nothing', 'wet', 'slippery'],
|
categories: ['dry', 'nothing', 'wet', 'slippery'],
|
||||||
explainer: 'What does your vaginal entrance feel like?'
|
explainer: 'What does your vaginal entrance feel like?',
|
||||||
},
|
},
|
||||||
texture: {
|
texture: {
|
||||||
categories: ['nothing', 'creamy', 'egg white'],
|
categories: ['nothing', 'creamy', 'egg white'],
|
||||||
explainer: "Looking at and touching your cervical mucus, which describes it best?"
|
explainer:
|
||||||
|
'Looking at and touching your cervical mucus, which describes it best?',
|
||||||
},
|
},
|
||||||
excludeExplainer: "You can exclude this value if you don't want to use it for fertility detection",
|
excludeExplainer:
|
||||||
actionHint: 'Choose values for both "Feeling" and "Texture" to save.'
|
"You can exclude this value if you don't want to use it for fertility detection",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const desire = {
|
export const desire = {
|
||||||
header: 'Intensity',
|
header: 'Intensity',
|
||||||
explainer: 'How would you rate your sexual desire?'
|
explainer: 'How would you rate your sexual desire?',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sex = {
|
export const sex = {
|
||||||
categories:{
|
categories: {
|
||||||
solo: 'solo',
|
solo: 'solo',
|
||||||
partner: 'partner',
|
partner: 'partner',
|
||||||
},
|
},
|
||||||
header: "Activity",
|
header: 'Activity',
|
||||||
explainer: 'Were you sexually active today?',
|
explainer: 'Were you sexually active today?',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const contraceptives = {
|
export const contraceptives = {
|
||||||
categories:{
|
categories: {
|
||||||
condom: 'condom',
|
condom: 'condom',
|
||||||
pill: 'pill',
|
pill: 'pill',
|
||||||
iud: 'iud',
|
iud: 'iud',
|
||||||
@@ -78,8 +79,8 @@ export const contraceptives = {
|
|||||||
none: 'none',
|
none: 'none',
|
||||||
other: 'other',
|
other: 'other',
|
||||||
},
|
},
|
||||||
header: "Contraceptives",
|
header: 'Contraceptives',
|
||||||
explainer: 'Did you use contraceptives?'
|
explainer: 'Did you use contraceptives?',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const pain = {
|
export const pain = {
|
||||||
@@ -91,9 +92,9 @@ export const pain = {
|
|||||||
nausea: 'nausea',
|
nausea: 'nausea',
|
||||||
tenderBreasts: 'tender breasts',
|
tenderBreasts: 'tender breasts',
|
||||||
migraine: 'migraine',
|
migraine: 'migraine',
|
||||||
other: 'other'
|
other: 'other',
|
||||||
},
|
},
|
||||||
explainer: 'How did your body feel today?'
|
explainer: 'How did your body feel today?',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mood = {
|
export const mood = {
|
||||||
@@ -107,34 +108,39 @@ export const mood = {
|
|||||||
energetic: 'energetic',
|
energetic: 'energetic',
|
||||||
fatigue: 'fatigue',
|
fatigue: 'fatigue',
|
||||||
angry: 'angry',
|
angry: 'angry',
|
||||||
other: 'other'
|
other: 'other',
|
||||||
},
|
},
|
||||||
explainer: 'How did you feel today?'
|
explainer: 'How did you feel today?',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const temperature = {
|
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.',
|
outOfRangeWarning:
|
||||||
outOfAbsoluteRangeWarning: 'This temperature value is too high or low to be shown on the temperature chart.',
|
'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.',
|
||||||
temperature: {
|
temperature: {
|
||||||
header: "Temperature",
|
header: 'Temperature',
|
||||||
explainer: 'Take your temperature right after waking up, before getting out of bed'
|
explainer:
|
||||||
|
'Take your temperature right after waking up, before getting out of bed',
|
||||||
},
|
},
|
||||||
time: "Time",
|
time: 'Time',
|
||||||
note: {
|
note: {
|
||||||
header: "Note",
|
header: 'Note',
|
||||||
explainer: 'Is there anything that could have influenced this value, such as bad sleep or alcohol consumption?'
|
explainer:
|
||||||
|
'Is there anything that could have influenced this value, such as bad sleep or alcohol consumption?',
|
||||||
},
|
},
|
||||||
exclude: {
|
exclude: {
|
||||||
header: "Exclude",
|
header: 'Exclude',
|
||||||
explainer: "You can exclude this value if you don't want to use it for fertility detection"
|
explainer:
|
||||||
}
|
"You can exclude this value if you don't want to use it for fertility detection",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const noteExplainer = "Anything you want to add for the day?"
|
export const noteExplainer = 'Anything you want to add for the day?'
|
||||||
|
|
||||||
export const general = {
|
export const general = {
|
||||||
cycleDayNumber: "Cycle day ",
|
cycleDayNumber: 'Cycle day ',
|
||||||
today: "Today"
|
today: 'Today',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sharedDialogs = {
|
export const sharedDialogs = {
|
||||||
@@ -144,5 +150,5 @@ export const sharedDialogs = {
|
|||||||
reallyDeleteData: 'Yes, I am sure',
|
reallyDeleteData: 'Yes, I am sure',
|
||||||
save: 'Save',
|
save: 'Save',
|
||||||
delete: 'Delete',
|
delete: 'Delete',
|
||||||
disabledInfo: 'There is some data missing'
|
disabledInfo: 'There is some data missing',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,14 +70,14 @@ export const fertilityStatus = {
|
|||||||
unknown:
|
unknown:
|
||||||
'We cannot show any cycle information because no period data has been added.',
|
'We cannot show any cycle information because no period data has been added.',
|
||||||
preOvuText:
|
preOvuText:
|
||||||
"With NFP rules, you may assume 5 days of infertility at the beginning of your cycle, provided you don't observe any fertile cervical mucus or cervix values.",
|
"According to the sympto-thermal method, you may assume 5 days of infertility at the beginning of your cycle, provided you don't observe any fertile cervical mucus or cervix values.",
|
||||||
periOvuText:
|
periOvuText:
|
||||||
'We were not able to detect both a temperature shift and cervical mucus or cervix shift.',
|
'We were not able to detect both a temperature shift and cervical mucus or cervix shift.',
|
||||||
periOvuUntilEveningText: (tempRule) => {
|
periOvuUntilEveningText: (tempRule) => {
|
||||||
return (
|
return (
|
||||||
'We detected a temperature shift (' +
|
'We detected a temperature shift (' +
|
||||||
['regular', '1st exception', '2nd exception'][tempRule] +
|
['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.'
|
'always remember to double-check for yourself. Make sure the data makes sense to you.'
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -85,7 +85,7 @@ export const fertilityStatus = {
|
|||||||
return (
|
return (
|
||||||
'We detected a temperature shift (' +
|
'We detected a temperature shift (' +
|
||||||
['regular', '1st exception', '2nd exception'][tempRule] +
|
['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.'
|
'double-check for yourself. Make sure the data makes sense to you.'
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import links from './links'
|
import links from './links'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
customization: {
|
||||||
|
title: 'Customization',
|
||||||
|
trackingCategories: 'Tracking categories',
|
||||||
|
subheaderSymptoThermalMethod: 'Sympto-thermal method settings',
|
||||||
|
},
|
||||||
export: {
|
export: {
|
||||||
errors: {
|
errors: {
|
||||||
noData: 'There is no data to export',
|
noData: 'There is no data to export',
|
||||||
@@ -32,17 +37,26 @@ 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.',
|
||||||
},
|
},
|
||||||
|
|
||||||
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',
|
||||||
timeSet: (time) => `Daily reminder set for ${time}`,
|
timeSet: (time) => `Daily reminder set for ${time}`,
|
||||||
notification: 'Record your morning temperature',
|
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: {
|
periodReminder: {
|
||||||
title: 'Next period reminder',
|
title: 'Next period reminder',
|
||||||
@@ -56,17 +70,36 @@ 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 both temperature tracking and either 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: {
|
||||||
title: 'App password',
|
title: 'App password',
|
||||||
@@ -109,6 +142,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 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 sympto-thermal info is available.`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const generalInfo = {
|
|||||||
3. and menstrual bleeding
|
3. and menstrual bleeding
|
||||||
the app helps you identify in which phase of the menstrual cycle you are.
|
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}.`,
|
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.`,
|
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.`,
|
||||||
@@ -25,7 +25,7 @@ export default {
|
|||||||
After tracking at least 3 menstrual cycles, drip. will give you an overview of
|
After tracking at least 3 menstrual cycles, drip. will give you an overview of
|
||||||
· how long your cycles last on average (in "stats"),
|
· how long your cycles last on average (in "stats"),
|
||||||
· whether the length of your cycles varied significantly (in "stats" and in bleeding predictions)
|
· whether the length of your cycles varied significantly (in "stats" and in bleeding predictions)
|
||||||
· and predict your next 3 cycles with a range of 3 or 5 days (on home screen and "calendar").
|
· and predict your next 3 cycles with a range of 3 or 5 days (on home screen and "calendar") if this functionality is enabled in the customization settings.
|
||||||
|
|
||||||
The app allows you to track different intensities of bleeding. On the chart and on the calendar, bleeding values are colored in different shades of red. The darker, the more intense your bleeding. Every bleeding value that is not excluded is taken into account for fertility calculation and period predictions.
|
The app allows you to track different intensities of bleeding. On the chart and on the calendar, bleeding values are colored in different shades of red. The darker, the more intense your bleeding. Every bleeding value that is not excluded is taken into account for fertility calculation and period predictions.
|
||||||
|
|
||||||
@@ -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.
|
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?
|
· 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.
|
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',
|
title: 'Tracking cervical mucus',
|
||||||
text: `Cervical mucus can help determine in which phase of the menstrual cycle you are.
|
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. You can change this in the customization settings.
|
||||||
|
|
||||||
· How to identify fertile 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:
|
From lowest to best quality:
|
||||||
· t = (dry feeling + no texture),
|
· t = (dry feeling + no texture),
|
||||||
· ∅ = (no 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.
|
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}
|
${generalInfo.chartNfp}
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ ${generalInfo.curiousNfp}`,
|
|||||||
title: 'Tracking body basal temperature',
|
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.
|
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?
|
· 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.
|
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.
|
||||||
|
|||||||
@@ -32,6 +32,5 @@ target 'drip' do
|
|||||||
|
|
||||||
post_install do |installer|
|
post_install do |installer|
|
||||||
react_native_post_install(installer)
|
react_native_post_install(installer)
|
||||||
__apply_Xcode_12_5_M1_post_install_workaround(installer)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -31,17 +31,16 @@
|
|||||||
5472A45A25BB7807005E81DE /* drip-icon-font.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5472A44925BB7806005E81DE /* drip-icon-font.ttf */; };
|
5472A45A25BB7807005E81DE /* drip-icon-font.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5472A44925BB7806005E81DE /* drip-icon-font.ttf */; };
|
||||||
5472A45B25BB7807005E81DE /* drip-icon-font.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5472A44925BB7806005E81DE /* drip-icon-font.ttf */; };
|
5472A45B25BB7807005E81DE /* drip-icon-font.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5472A44925BB7806005E81DE /* drip-icon-font.ttf */; };
|
||||||
5472A45E25BB7C43005E81DE /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5472A45C25BB7C42005E81DE /* Entypo.ttf */; };
|
5472A45E25BB7C43005E81DE /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5472A45C25BB7C42005E81DE /* Entypo.ttf */; };
|
||||||
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
|
|
||||||
54DFE73A25D94D6E0025C3FC /* swipe.png in Resources */ = {isa = PBXBuildFile; fileRef = 54DFE73925D94D6E0025C3FC /* swipe.png */; };
|
54DFE73A25D94D6E0025C3FC /* swipe.png in Resources */ = {isa = PBXBuildFile; fileRef = 54DFE73925D94D6E0025C3FC /* swipe.png */; };
|
||||||
54DFE73B25D94D6E0025C3FC /* swipe.png in Resources */ = {isa = PBXBuildFile; fileRef = 54DFE73925D94D6E0025C3FC /* swipe.png */; };
|
54DFE73B25D94D6E0025C3FC /* swipe.png in Resources */ = {isa = PBXBuildFile; fileRef = 54DFE73925D94D6E0025C3FC /* swipe.png */; };
|
||||||
54DFE73D25D94DED0025C3FC /* cycle-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 54DFE73C25D94DED0025C3FC /* cycle-icon.png */; };
|
54DFE73D25D94DED0025C3FC /* cycle-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 54DFE73C25D94DED0025C3FC /* cycle-icon.png */; };
|
||||||
54DFE73E25D94DED0025C3FC /* cycle-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 54DFE73C25D94DED0025C3FC /* cycle-icon.png */; };
|
54DFE73E25D94DED0025C3FC /* cycle-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 54DFE73C25D94DED0025C3FC /* cycle-icon.png */; };
|
||||||
54E1D49923E7588F003FA37B /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54E1D49823E7588F003FA37B /* JavaScriptCore.framework */; };
|
54E1D49923E7588F003FA37B /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
|
||||||
62F2A4645AC84CDC9506FF27 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AEBF0735214455AAEDF56D5 /* libc++.tbd */; };
|
62F2A4645AC84CDC9506FF27 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AEBF0735214455AAEDF56D5 /* libc++.tbd */; };
|
||||||
|
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
|
||||||
BD7041F2826E4A2CBE6CB87D /* RealmJSTests.xctest in Frameworks */ = {isa = PBXBuildFile; fileRef = F79F72C5390646E0A06AAE68 /* RealmJSTests.xctest */; };
|
BD7041F2826E4A2CBE6CB87D /* RealmJSTests.xctest in Frameworks */ = {isa = PBXBuildFile; fileRef = F79F72C5390646E0A06AAE68 /* RealmJSTests.xctest */; };
|
||||||
BEF6784666BF8E0791A27E51 /* libPods-drip-dripTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 30AC577EFD5F39ABAA1E303C /* libPods-drip-dripTests.a */; };
|
|
||||||
D6B2ED16118E4B66DE895C51 /* libPods-drip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-drip-dripTests.a */; };
|
|
||||||
D91133DCE120440893E2FD2E /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = CD8C8B91E0A747B3883A0D56 /* libz.tbd */; };
|
D91133DCE120440893E2FD2E /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = CD8C8B91E0A747B3883A0D56 /* libz.tbd */; };
|
||||||
|
DFCB30DF40F45C00CFBBE07E /* libPods-drip-dripTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-drip-dripTests.a */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -55,7 +54,6 @@
|
|||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
|
|
||||||
00E356EE1AD99517003FC87E /* dripTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = dripTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
00E356EE1AD99517003FC87E /* dripTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = dripTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
00E356F21AD99517003FC87E /* dripTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = dripTests.m; sourceTree = "<group>"; };
|
00E356F21AD99517003FC87E /* dripTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = dripTests.m; sourceTree = "<group>"; };
|
||||||
@@ -65,18 +63,14 @@
|
|||||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = drip/Images.xcassets; sourceTree = "<group>"; };
|
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = drip/Images.xcassets; sourceTree = "<group>"; };
|
||||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = drip/Info.plist; sourceTree = "<group>"; };
|
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = drip/Info.plist; sourceTree = "<group>"; };
|
||||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = drip/main.m; sourceTree = "<group>"; };
|
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = drip/main.m; sourceTree = "<group>"; };
|
||||||
2C52A2D4C769AF39D11D7017 /* Pods-drip.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-drip.release.xcconfig"; path = "Target Support Files/Pods-drip/Pods-drip.release.xcconfig"; sourceTree = "<group>"; };
|
19F6CBCC0A4E27FBF8BF4A61 /* libPods-drip-dripTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-drip-dripTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
2D16E6891FA4F8E400B85C8A /* libReact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libReact.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
2D16E6891FA4F8E400B85C8A /* libReact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libReact.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
30AC577EFD5F39ABAA1E303C /* libPods-drip-dripTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-drip-dripTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
3B4392A12AC88292D35C810B /* Pods-drip.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-drip.debug.xcconfig"; path = "Target Support Files/Pods-drip/Pods-drip.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
3BFD860D9B7CFC35432CDE5C /* Pods-drip-dripTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-drip-dripTests.debug.xcconfig"; path = "Target Support Files/Pods-drip-dripTests/Pods-drip-dripTests.debug.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
5409189625AB725F00086AE1 /* OpenSans-LightItalic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-LightItalic.ttf"; path = "../../assets/fonts/OpenSans-LightItalic.ttf"; sourceTree = "<group>"; };
|
|
||||||
540918A225AB725F00086AE1 /* Prompt-ExtraLight.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Prompt-ExtraLight.ttf"; path = "../../assets/fonts/Prompt-ExtraLight.ttf"; sourceTree = "<group>"; };
|
|
||||||
540918A325AB725F00086AE1 /* OpenSans-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Light.ttf"; path = "../../assets/fonts/OpenSans-Light.ttf"; sourceTree = "<group>"; };
|
540918A325AB725F00086AE1 /* OpenSans-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Light.ttf"; path = "../../assets/fonts/OpenSans-Light.ttf"; sourceTree = "<group>"; };
|
||||||
540918A425AB725F00086AE1 /* Jost-700-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Jost-700-Bold.otf"; path = "../../assets/fonts/Jost-700-Bold.otf"; sourceTree = "<group>"; };
|
540918A425AB725F00086AE1 /* Jost-700-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Jost-700-Bold.otf"; path = "../../assets/fonts/Jost-700-Bold.otf"; sourceTree = "<group>"; };
|
||||||
540918A525AB725F00086AE1 /* Menu.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Menu.ttf; path = ../../assets/fonts/Menu.ttf; sourceTree = "<group>"; };
|
540918A525AB725F00086AE1 /* Menu.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Menu.ttf; path = ../../assets/fonts/Menu.ttf; sourceTree = "<group>"; };
|
||||||
540918A625AB726000086AE1 /* drip-home-icons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "drip-home-icons.ttf"; path = "../../assets/fonts/drip-home-icons.ttf"; sourceTree = "<group>"; };
|
540918A625AB726000086AE1 /* drip-home-icons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "drip-home-icons.ttf"; path = "../../assets/fonts/drip-home-icons.ttf"; sourceTree = "<group>"; };
|
||||||
540918A725AB726000086AE1 /* Jost-400-Book.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Jost-400-Book.otf"; path = "../../assets/fonts/Jost-400-Book.otf"; sourceTree = "<group>"; };
|
540918A725AB726000086AE1 /* Jost-400-Book.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Jost-400-Book.otf"; path = "../../assets/fonts/Jost-400-Book.otf"; sourceTree = "<group>"; };
|
||||||
540918A825AB726000086AE1 /* drip-icon-font.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "drip-icon-font.ttf"; path = "../../assets/fonts/drip-icon-font.ttf"; sourceTree = "<group>"; };
|
|
||||||
540918A925AB726000086AE1 /* OpenSans-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-SemiBold.ttf"; path = "../../assets/fonts/OpenSans-SemiBold.ttf"; sourceTree = "<group>"; };
|
540918A925AB726000086AE1 /* OpenSans-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-SemiBold.ttf"; path = "../../assets/fonts/OpenSans-SemiBold.ttf"; sourceTree = "<group>"; };
|
||||||
5472A44125BB7806005E81DE /* drip-home-icons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "drip-home-icons.ttf"; path = "../assets/fonts/drip-home-icons.ttf"; sourceTree = "<group>"; };
|
5472A44125BB7806005E81DE /* drip-home-icons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "drip-home-icons.ttf"; path = "../assets/fonts/drip-home-icons.ttf"; sourceTree = "<group>"; };
|
||||||
5472A44225BB7806005E81DE /* OpenSans-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Light.ttf"; path = "../assets/fonts/OpenSans-Light.ttf"; sourceTree = "<group>"; };
|
5472A44225BB7806005E81DE /* OpenSans-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Light.ttf"; path = "../assets/fonts/OpenSans-Light.ttf"; sourceTree = "<group>"; };
|
||||||
@@ -88,26 +82,24 @@
|
|||||||
5472A44825BB7806005E81DE /* OpenSans-LightItalic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-LightItalic.ttf"; path = "../assets/fonts/OpenSans-LightItalic.ttf"; sourceTree = "<group>"; };
|
5472A44825BB7806005E81DE /* OpenSans-LightItalic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-LightItalic.ttf"; path = "../assets/fonts/OpenSans-LightItalic.ttf"; sourceTree = "<group>"; };
|
||||||
5472A44925BB7806005E81DE /* drip-icon-font.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "drip-icon-font.ttf"; path = "../assets/fonts/drip-icon-font.ttf"; sourceTree = "<group>"; };
|
5472A44925BB7806005E81DE /* drip-icon-font.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "drip-icon-font.ttf"; path = "../assets/fonts/drip-icon-font.ttf"; sourceTree = "<group>"; };
|
||||||
5472A45C25BB7C42005E81DE /* Entypo.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Entypo.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Entypo.ttf"; sourceTree = "<group>"; };
|
5472A45C25BB7C42005E81DE /* Entypo.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Entypo.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Entypo.ttf"; sourceTree = "<group>"; };
|
||||||
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = drip/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
|
||||||
548C3D3A2898FB0600013449 /* drip-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "drip-Bridging-Header.h"; sourceTree = "<group>"; };
|
548C3D3A2898FB0600013449 /* drip-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "drip-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
54DFE73925D94D6E0025C3FC /* swipe.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = swipe.png; path = ../assets/swipe.png; sourceTree = "<group>"; };
|
54DFE73925D94D6E0025C3FC /* swipe.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = swipe.png; path = ../assets/swipe.png; sourceTree = "<group>"; };
|
||||||
54DFE73C25D94DED0025C3FC /* cycle-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "cycle-icon.png"; path = "../assets/cycle-icon.png"; sourceTree = "<group>"; };
|
54DFE73C25D94DED0025C3FC /* cycle-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "cycle-icon.png"; path = "../assets/cycle-icon.png"; sourceTree = "<group>"; };
|
||||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
5709B34CF0A7D63546082F79 /* Pods-drip.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-drip.release.xcconfig"; path = "Target Support Files/Pods-drip/Pods-drip.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
5B7EB9410499542E8C5724F5 /* Pods-drip-dripTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-drip-dripTests.debug.xcconfig"; path = "Target Support Files/Pods-drip-dripTests/Pods-drip-dripTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
5C649EDC281151BC005FED46 /* dripRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = dripRelease.entitlements; path = drip/dripRelease.entitlements; sourceTree = "<group>"; };
|
5C649EDC281151BC005FED46 /* dripRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = dripRelease.entitlements; path = drip/dripRelease.entitlements; sourceTree = "<group>"; };
|
||||||
|
5DCACB8F33CDC322A6C60F78 /* libPods-drip.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-drip.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
7A5827160B914D2B99C47381 /* libRealmReact.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRealmReact.a; sourceTree = "<group>"; };
|
7A5827160B914D2B99C47381 /* libRealmReact.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRealmReact.a; sourceTree = "<group>"; };
|
||||||
|
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = drip/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
84CCEBD3B2C44758853BC941 /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFS.a; sourceTree = "<group>"; };
|
84CCEBD3B2C44758853BC941 /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFS.a; sourceTree = "<group>"; };
|
||||||
|
89C6BE57DB24E9ADA2F236DE /* Pods-drip-dripTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-drip-dripTests.release.xcconfig"; path = "Target Support Files/Pods-drip-dripTests/Pods-drip-dripTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
90224CB4571D41C4969E9722 /* libGCDWebServers.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libGCDWebServers.a; sourceTree = "<group>"; };
|
90224CB4571D41C4969E9722 /* libGCDWebServers.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libGCDWebServers.a; sourceTree = "<group>"; };
|
||||||
9AEBF0735214455AAEDF56D5 /* libc++.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
9AEBF0735214455AAEDF56D5 /* libc++.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||||
3B4392A12AC88292D35C810B /* Pods-drip.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-drip.debug.xcconfig"; path = "Target Support Files/Pods-drip/Pods-drip.debug.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
5709B34CF0A7D63546082F79 /* Pods-drip.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-drip.release.xcconfig"; path = "Target Support Files/Pods-drip/Pods-drip.release.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
A8B59389C2FC4F19BD30ABC3 /* libRNShare.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNShare.a; sourceTree = "<group>"; };
|
A8B59389C2FC4F19BD30ABC3 /* libRNShare.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNShare.a; sourceTree = "<group>"; };
|
||||||
AB636AA0286D45CE9B23B2C3 /* libRCTRestart.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTRestart.a; sourceTree = "<group>"; };
|
AB636AA0286D45CE9B23B2C3 /* libRCTRestart.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTRestart.a; sourceTree = "<group>"; };
|
||||||
CD8C8B91E0A747B3883A0D56 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
CD8C8B91E0A747B3883A0D56 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||||
D211D71BE5A8436A978770A9 /* libRNDocumentPicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNDocumentPicker.a; sourceTree = "<group>"; };
|
D211D71BE5A8436A978770A9 /* libRNDocumentPicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNDocumentPicker.a; sourceTree = "<group>"; };
|
||||||
89C6BE57DB24E9ADA2F236DE /* Pods-drip-dripTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-drip-dripTests.release.xcconfig"; path = "Target Support Files/Pods-drip-dripTests/Pods-drip-dripTests.release.xcconfig"; sourceTree = "<group>"; };
|
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||||
5B7EB9410499542E8C5724F5 /* Pods-drip-dripTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-drip-dripTests.debug.xcconfig"; path = "Target Support Files/Pods-drip-dripTests/Pods-drip-dripTests.debug.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
19F6CBCC0A4E27FBF8BF4A61 /* libPods-drip-dripTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-drip-dripTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
5DCACB8F33CDC322A6C60F78 /* libPods-drip.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-drip.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
F5039D0A572B4BBCB7995891 /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = "<group>"; };
|
F5039D0A572B4BBCB7995891 /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = "<group>"; };
|
||||||
F710D85E391D4094816E1B62 /* libRealmJS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRealmJS.a; sourceTree = "<group>"; };
|
F710D85E391D4094816E1B62 /* libRealmJS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRealmJS.a; sourceTree = "<group>"; };
|
||||||
F79F72C5390646E0A06AAE68 /* RealmJSTests.xctest */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = RealmJSTests.xctest; sourceTree = "<group>"; };
|
F79F72C5390646E0A06AAE68 /* RealmJSTests.xctest */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = RealmJSTests.xctest; sourceTree = "<group>"; };
|
||||||
@@ -118,7 +110,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
7699B88040F8A987B510C191 /* libPods-drip-dripTests.a in Frameworks */,
|
DFCB30DF40F45C00CFBBE07E /* libPods-drip-dripTests.a in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -126,7 +118,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
54E1D49923E7588F003FA37B /* JavaScriptCore.framework in Frameworks */,
|
54E1D49923E7588F003FA37B /* BuildFile in Frameworks */,
|
||||||
62F2A4645AC84CDC9506FF27 /* libc++.tbd in Frameworks */,
|
62F2A4645AC84CDC9506FF27 /* libc++.tbd in Frameworks */,
|
||||||
D91133DCE120440893E2FD2E /* libz.tbd in Frameworks */,
|
D91133DCE120440893E2FD2E /* libz.tbd in Frameworks */,
|
||||||
BD7041F2826E4A2CBE6CB87D /* RealmJSTests.xctest in Frameworks */,
|
BD7041F2826E4A2CBE6CB87D /* RealmJSTests.xctest in Frameworks */,
|
||||||
@@ -176,9 +168,7 @@
|
|||||||
13B07FAE1A68108700A75B9A /* drip */ = {
|
13B07FAE1A68108700A75B9A /* drip */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5488D8D628ABF478008DD66D /* LaunchScreen.storyboard */,
|
|
||||||
5C649EDC281151BC005FED46 /* dripRelease.entitlements */,
|
5C649EDC281151BC005FED46 /* dripRelease.entitlements */,
|
||||||
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
|
|
||||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
|
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
|
||||||
13B07FB01A68108700A75B9A /* AppDelegate.mm */,
|
13B07FB01A68108700A75B9A /* AppDelegate.mm */,
|
||||||
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
||||||
@@ -215,30 +205,16 @@
|
|||||||
90224CB4571D41C4969E9722 /* libGCDWebServers.a */,
|
90224CB4571D41C4969E9722 /* libGCDWebServers.a */,
|
||||||
F710D85E391D4094816E1B62 /* libRealmJS.a */,
|
F710D85E391D4094816E1B62 /* libRealmJS.a */,
|
||||||
F79F72C5390646E0A06AAE68 /* RealmJSTests.xctest */,
|
F79F72C5390646E0A06AAE68 /* RealmJSTests.xctest */,
|
||||||
|
540918A325AB725F00086AE1 /* OpenSans-Light.ttf */,
|
||||||
|
540918A925AB726000086AE1 /* OpenSans-SemiBold.ttf */,
|
||||||
|
540918A725AB726000086AE1 /* Jost-400-Book.otf */,
|
||||||
|
540918A525AB725F00086AE1 /* Menu.ttf */,
|
||||||
|
540918A625AB726000086AE1 /* drip-home-icons.ttf */,
|
||||||
|
540918A425AB725F00086AE1 /* Jost-700-Bold.otf */,
|
||||||
);
|
);
|
||||||
name = "Recovered References";
|
name = "Recovered References";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
6817ABC38854EEB6D3EE933A /* Pods */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
540918A625AB726000086AE1 /* drip-home-icons.ttf */,
|
|
||||||
540918A825AB726000086AE1 /* drip-icon-font.ttf */,
|
|
||||||
540918A725AB726000086AE1 /* Jost-400-Book.otf */,
|
|
||||||
540918A425AB725F00086AE1 /* Jost-700-Bold.otf */,
|
|
||||||
540918A525AB725F00086AE1 /* Menu.ttf */,
|
|
||||||
540918A325AB725F00086AE1 /* OpenSans-Light.ttf */,
|
|
||||||
5409189625AB725F00086AE1 /* OpenSans-LightItalic.ttf */,
|
|
||||||
540918A925AB726000086AE1 /* OpenSans-SemiBold.ttf */,
|
|
||||||
540918A225AB725F00086AE1 /* Prompt-ExtraLight.ttf */,
|
|
||||||
9C2B39F53B3E9590D7F199B8 /* Pods-drip.debug.xcconfig */,
|
|
||||||
2C52A2D4C769AF39D11D7017 /* Pods-drip.release.xcconfig */,
|
|
||||||
3BFD860D9B7CFC35432CDE5C /* Pods-drip-dripTests.debug.xcconfig */,
|
|
||||||
DCE7F65AA04F4A0851ED5A7A /* Pods-drip-dripTests.release.xcconfig */,
|
|
||||||
);
|
|
||||||
path = Pods;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -335,7 +311,7 @@
|
|||||||
83CBB9F71A601CBA00E9B192 /* Project object */ = {
|
83CBB9F71A601CBA00E9B192 /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 1210;
|
LastUpgradeCheck = 1430;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
00E356ED1AD99517003FC87E = {
|
00E356ED1AD99517003FC87E = {
|
||||||
@@ -343,7 +319,6 @@
|
|||||||
TestTargetID = 13B07F861A680F5B00A75B9A;
|
TestTargetID = 13B07F861A680F5B00A75B9A;
|
||||||
};
|
};
|
||||||
13B07F861A680F5B00A75B9A = {
|
13B07F861A680F5B00A75B9A = {
|
||||||
DevelopmentTeam = 6AD72X6W26;
|
|
||||||
LastSwiftMigration = 1120;
|
LastSwiftMigration = 1120;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -416,6 +391,8 @@
|
|||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputPaths = (
|
inputPaths = (
|
||||||
|
"$(SRCROOT)/.xcode.env.local",
|
||||||
|
"$(SRCROOT)/.xcode.env",
|
||||||
);
|
);
|
||||||
name = "Bundle React Native code and images";
|
name = "Bundle React Native code and images";
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
@@ -590,13 +567,14 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-drip-dripTests.debug.xcconfig */;
|
baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-drip-dripTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = dripTests/Info.plist;
|
INFOPLIST_FILE = dripTests/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -617,10 +595,11 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-drip-dripTests.release.xcconfig */;
|
baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-drip-dripTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
INFOPLIST_FILE = dripTests/Info.plist;
|
INFOPLIST_FILE = dripTests/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -644,6 +623,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = 6AD72X6W26;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = drip/Info.plist;
|
INFOPLIST_FILE = drip/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -670,6 +650,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = 6AD72X6W26;
|
||||||
INFOPLIST_FILE = drip/Info.plist;
|
INFOPLIST_FILE = drip/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -680,7 +661,7 @@
|
|||||||
"-ObjC",
|
"-ObjC",
|
||||||
"-lc++",
|
"-lc++",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
PRODUCT_BUNDLE_IDENTIFIER = org.heartofcode.drip.cycle.tracking;
|
||||||
PRODUCT_NAME = drip;
|
PRODUCT_NAME = drip;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
@@ -736,7 +717,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
/usr/lib/swift,
|
/usr/lib/swift,
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -800,7 +781,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
/usr/lib/swift,
|
/usr/lib/swift,
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1210"
|
LastUpgradeVersion = "1430"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
@@ -1,46 +1,55 @@
|
|||||||
{
|
{
|
||||||
"images": [
|
"images": [
|
||||||
{
|
{
|
||||||
|
"filename": "40 1.png",
|
||||||
"idiom": "iphone",
|
"idiom": "iphone",
|
||||||
"scale": "2x",
|
"scale": "2x",
|
||||||
"size": "20x20"
|
"size": "20x20"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename": "60 1.png",
|
||||||
"idiom": "iphone",
|
"idiom": "iphone",
|
||||||
"scale": "3x",
|
"scale": "3x",
|
||||||
"size": "20x20"
|
"size": "20x20"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename": "58 1.png",
|
||||||
"idiom": "iphone",
|
"idiom": "iphone",
|
||||||
"scale": "2x",
|
"scale": "2x",
|
||||||
"size": "29x29"
|
"size": "29x29"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename": "87 1.png",
|
||||||
"idiom": "iphone",
|
"idiom": "iphone",
|
||||||
"scale": "3x",
|
"scale": "3x",
|
||||||
"size": "29x29"
|
"size": "29x29"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename": "80 1.png",
|
||||||
"idiom": "iphone",
|
"idiom": "iphone",
|
||||||
"scale": "2x",
|
"scale": "2x",
|
||||||
"size": "40x40"
|
"size": "40x40"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename": "120 2.png",
|
||||||
"idiom": "iphone",
|
"idiom": "iphone",
|
||||||
"scale": "3x",
|
"scale": "3x",
|
||||||
"size": "40x40"
|
"size": "40x40"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename": "120 1.png",
|
||||||
"idiom": "iphone",
|
"idiom": "iphone",
|
||||||
"scale": "2x",
|
"scale": "2x",
|
||||||
"size": "60x60"
|
"size": "60x60"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename": "180 1.png",
|
||||||
"idiom": "iphone",
|
"idiom": "iphone",
|
||||||
"scale": "3x",
|
"scale": "3x",
|
||||||
"size": "60x60"
|
"size": "60x60"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename": "appstore 1.png",
|
||||||
"idiom": "ios-marketing",
|
"idiom": "ios-marketing",
|
||||||
"scale": "1x",
|
"scale": "1x",
|
||||||
"size": "1024x1024"
|
"size": "1024x1024"
|
||||||
|
|||||||
|
After Width: | Height: | Size: 43 KiB |
@@ -8,8 +8,10 @@
|
|||||||
<string>drip.</string>
|
<string>drip.</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>AppIcon</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
<string>org.heartofcode.drip.cycle.tracking</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
@@ -17,7 +19,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>drip. menstrual cycle & fertility tracking</string>
|
<string>1.2403.19</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export default function getSensiplanMucus(feeling, texture) {
|
export default function getNfpMucus(feeling, texture) {
|
||||||
if (typeof feeling != 'number' || typeof texture != 'number') return null
|
if (typeof feeling != 'number' || typeof texture != 'number') return null
|
||||||
|
|
||||||
const feelingMapping = {
|
const feelingMapping = {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -92,6 +99,38 @@ export async function setChartFlag() {
|
|||||||
await AsyncStorage.setItem('isFirstChartView', JSON.stringify(false))
|
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) {
|
||||||
|
// if temperature tracking is turned off, the temperature reminder gets disabled
|
||||||
|
const tempReminderResult = await AsyncStorage.getItem('tempReminder')
|
||||||
|
if (tempReminderResult && JSON.parse(tempReminderResult).enabled) {
|
||||||
|
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)
|
||||||
|
|
||||||
@@ -132,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
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "drip.",
|
"name": "drip.",
|
||||||
"version": "1.2311.14",
|
"version": "1.2403.19",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"Julia Friesel <julia.friesel@gmail.com>",
|
"Julia Friesel <julia.friesel@gmail.com>",
|
||||||
"Marie Kochsiek",
|
"Marie Kochsiek",
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"start": "react-native start",
|
"start": "react-native start",
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
"ios": "react-native run-ios --simulator=\"iPhone 8 Plus\"",
|
"ios": "react-native run-ios --simulator=\"iPhone 8 Plus\"",
|
||||||
"ios14": "react-native run-ios --simulator=\"iPhone 14 Plus\"",
|
"ios15": "react-native run-ios --simulator=\"iPhone 15 Plus\"",
|
||||||
"log": "react-native log-android",
|
"log": "react-native log-android",
|
||||||
"test": "jest test && yarn lint",
|
"test": "jest test && yarn lint",
|
||||||
"test-watch": "jest --watch test",
|
"test-watch": "jest --watch test",
|
||||||
@@ -34,9 +34,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@js-joda/core": "^5.3.0",
|
"@js-joda/core": "^5.3.0",
|
||||||
"@ptomasroos/react-native-multi-slider": "^2.2.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/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",
|
"@react-native-community/push-notification-ios": "^1.11.0",
|
||||||
"csvtojson": "^2.0.8",
|
"csvtojson": "^2.0.8",
|
||||||
"i18next": "^22.0.2",
|
"i18next": "^22.0.2",
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { scale } from 'react-native-size-matters'
|
import { scale } from 'react-native-size-matters'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
zero: '0%',
|
||||||
tiny: scale(4),
|
tiny: scale(4),
|
||||||
small: scale(10),
|
small: scale(10),
|
||||||
base: scale(16),
|
base: scale(16),
|
||||||
large: scale(20),
|
large: scale(20),
|
||||||
symptomTileWidth: '48%',
|
symptomTileWidth: '48%',
|
||||||
textWidth: '70%'
|
textWidth: '70%',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import getNfpMucus from '../lib/nfp-mucus'
|
||||||
|
|
||||||
|
describe('getNfpMucus', () => {
|
||||||
|
test('returns null if there is no value for feeling or texture', () => {
|
||||||
|
expect(getNfpMucus()).toBeNull()
|
||||||
|
expect(getNfpMucus(undefined, 3)).toBeNull()
|
||||||
|
expect(getNfpMucus(2, undefined)).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('results in t for:', () => {
|
||||||
|
test('dry feeling and no texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(0, 0)
|
||||||
|
expect(nfpValue).toEqual(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('results in Ø for:', () => {
|
||||||
|
test('no feeling and no texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(1, 0)
|
||||||
|
expect(nfpValue).toEqual(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('results in f for:', () => {
|
||||||
|
test('wet feeling and no texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(2, 0)
|
||||||
|
expect(nfpValue).toEqual(2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('results in S for:', () => {
|
||||||
|
test('dry feeling and creamy texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(0, 1)
|
||||||
|
expect(nfpValue).toEqual(3)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('no feeling and creamy texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(1, 1)
|
||||||
|
expect(nfpValue).toEqual(3)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('wet feeling and creamy texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(2, 1)
|
||||||
|
expect(nfpValue).toEqual(3)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('results in +S for:', () => {
|
||||||
|
test('dry feeling and egg white texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(0, 2)
|
||||||
|
expect(nfpValue).toEqual(4)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('no feeling and egg white texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(1, 2)
|
||||||
|
expect(nfpValue).toEqual(4)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('wet feeling and egg white texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(2, 2)
|
||||||
|
expect(nfpValue).toEqual(4)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('slippery feeling and egg white texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(3, 2)
|
||||||
|
expect(nfpValue).toEqual(4)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('slippery feeling and creamy texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(3, 1)
|
||||||
|
expect(nfpValue).toEqual(4)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('slippery feeling and no texture', function () {
|
||||||
|
const nfpValue = getNfpMucus(3, 0)
|
||||||
|
expect(nfpValue).toEqual(4)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import getSensiplanMucus from '../lib/nfp-mucus'
|
|
||||||
|
|
||||||
describe('getSensiplanMucus', () => {
|
|
||||||
test('returns null if there is no value for feeling or texture', () => {
|
|
||||||
expect(getSensiplanMucus()).toBeNull()
|
|
||||||
expect(getSensiplanMucus(undefined, 3)).toBeNull()
|
|
||||||
expect(getSensiplanMucus(2, undefined)).toBeNull()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('results in t for:', () => {
|
|
||||||
test('dry feeling and no texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(0, 0)
|
|
||||||
expect(sensiplanValue).toEqual(0)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('results in Ø for:', () => {
|
|
||||||
test('no feeling and no texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(1, 0)
|
|
||||||
expect(sensiplanValue).toEqual(1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('results in f for:', () => {
|
|
||||||
test('wet feeling and no texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(2, 0)
|
|
||||||
expect(sensiplanValue).toEqual(2)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('results in S for:', () => {
|
|
||||||
test('dry feeling and creamy texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(0, 1)
|
|
||||||
expect(sensiplanValue).toEqual(3)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('no feeling and creamy texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(1, 1)
|
|
||||||
expect(sensiplanValue).toEqual(3)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('wet feeling and creamy texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(2, 1)
|
|
||||||
expect(sensiplanValue).toEqual(3)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('results in +S for:', () => {
|
|
||||||
test('dry feeling and egg white texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(0, 2)
|
|
||||||
expect(sensiplanValue).toEqual(4)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('no feeling and egg white texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(1, 2)
|
|
||||||
expect(sensiplanValue).toEqual(4)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('wet feeling and egg white texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(2, 2)
|
|
||||||
expect(sensiplanValue).toEqual(4)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('slippery feeling and egg white texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(3, 2)
|
|
||||||
expect(sensiplanValue).toEqual(4)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('slippery feeling and creamy texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(3, 1)
|
|
||||||
expect(sensiplanValue).toEqual(4)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('slippery feeling and no texture', function () {
|
|
||||||
const sensiplanValue = getSensiplanMucus(3, 0)
|
|
||||||
expect(sensiplanValue).toEqual(4)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1320,10 +1320,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@ptomasroos/react-native-multi-slider/-/react-native-multi-slider-2.2.2.tgz#35a97fb8c355627c6a2ded010b360ac5728b44ad"
|
resolved "https://registry.yarnpkg.com/@ptomasroos/react-native-multi-slider/-/react-native-multi-slider-2.2.2.tgz#35a97fb8c355627c6a2ded010b360ac5728b44ad"
|
||||||
integrity sha512-HWyCnRD3Z3SbHK2FLWYmBBqd1B4iXipeKv1+AK0FoY/CElEDTEixHE8hN60TsqxalPrznn798LE2Q4tHuCiyaA==
|
integrity sha512-HWyCnRD3Z3SbHK2FLWYmBBqd1B4iXipeKv1+AK0FoY/CElEDTEixHE8hN60TsqxalPrznn798LE2Q4tHuCiyaA==
|
||||||
|
|
||||||
"@react-native-async-storage/async-storage@^1.17.9":
|
"@react-native-async-storage/async-storage@^1.18.2":
|
||||||
version "1.19.3"
|
version "1.18.2"
|
||||||
resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.19.3.tgz#ad5fe3ed0a82d4624aa4500321c1e09c02daeb46"
|
resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.18.2.tgz#ec8fd487a0b6c9500b43ece4b8779d1561f12e91"
|
||||||
integrity sha512-CwGfoHCWdPOTPS+2fW6YRE1fFBpT9++ahLEroX5hkgwyoQ+TkmjOaUxixdEIoVua9Pz5EF2pGOIJzqOTMWfBlA==
|
integrity sha512-dM8AfdoeIxlh+zqgr0o5+vCTPQ0Ru1mrPzONZMsr7ufp5h+6WgNxQNza7t0r5qQ6b04AJqTlBNixTWZxqP649Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
merge-options "^3.0.4"
|
merge-options "^3.0.4"
|
||||||
|
|
||||||
@@ -1505,10 +1505,10 @@
|
|||||||
sudo-prompt "^9.0.0"
|
sudo-prompt "^9.0.0"
|
||||||
wcwidth "^1.0.1"
|
wcwidth "^1.0.1"
|
||||||
|
|
||||||
"@react-native-community/datetimepicker@^6.3.1":
|
"@react-native-community/datetimepicker@^7.2.0":
|
||||||
version "6.7.5"
|
version "7.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-6.7.5.tgz#214796f2d131b6af9cb9d4dea69d4a1981fa2236"
|
resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-7.2.0.tgz#db8c03dbf49bf3c24b06b617a8467d8b05511f62"
|
||||||
integrity sha512-E2Zh6mwvZ6CFEMKP++rdxxjJiB45fYPpdZhJwdZ2vUVwqovqu1cQRDLZmz4XrcHSyuacgR4WUnkYFf0F2nnNIg==
|
integrity sha512-dO1sQy83M/EvnHE2egto05iwXZX7EYn5f/VDMp6afZFRFXRiRo7CzB3VFg4B55gJRJMNBv06NYMLPM3SlpnEGQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
invariant "^2.2.4"
|
invariant "^2.2.4"
|
||||||
|
|
||||||
|
|||||||