Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79b268fe4c | |||
| dddb095463 | |||
| 805587302b | |||
| e3f44d7654 | |||
| 590acd0bcb | |||
| 7710e9c9bd | |||
| a434242640 | |||
| 05f28b072a | |||
| 223ac148bd | |||
| e82dcb6cc1 | |||
| bd9c586edb | |||
| d492a27797 | |||
| 22a451d4e6 | |||
| 86bdb8a1f8 | |||
| 4212906917 |
+1
-1
@@ -30,7 +30,7 @@ ios/Index/DataStore
|
||||
build/
|
||||
.idea
|
||||
.gradle
|
||||
local.properties
|
||||
*.properties
|
||||
*.iml
|
||||
*.hprof
|
||||
|
||||
|
||||
@@ -131,15 +131,19 @@ Minimum system requirements to run iOS app are as follows:
|
||||
- MacOS 10.15.7 for Mac users
|
||||
- Xcode 13 (command line tools only might be enough)
|
||||
|
||||
i. Install XCode dependencies by running the following command from the root project directory:
|
||||
i. Install yarn dependencies
|
||||
|
||||
yarn install ..
|
||||
|
||||
ii. Install XCode dependencies by running the following command from the root project directory:
|
||||
|
||||
cd ios && pod install && cd ..
|
||||
|
||||
ii. To run app either open drip workspace ('drip.xcworkspace' file) with XCode and run "Build" or run the following command:
|
||||
iii. To run app either open drip workspace ('drip.xcworkspace' file) with XCode and run "Build" or run the following command:
|
||||
|
||||
yarn ios
|
||||
|
||||
iii. If you are building the app with XCode make sure you are running this as well:
|
||||
iiii. If you are building the app with XCode make sure you are running this as well:
|
||||
|
||||
yarn start
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: "com.android.application"
|
||||
|
||||
import com.android.build.OutputFile
|
||||
import java.util.Properties
|
||||
import java.io.FileInputStream
|
||||
|
||||
/**
|
||||
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
|
||||
@@ -125,6 +127,16 @@ def enableHermes = project.ext.react.get("enableHermes", false);
|
||||
*/
|
||||
def nativeArchitectures = project.getProperties().get("reactNativeDebugArchitectures")
|
||||
|
||||
// Create a variable called keystorePropertiesFile, and initialize it to your
|
||||
// keystore.properties file, in the rootProject folder.
|
||||
def keystorePropertiesFile = rootProject.file("keystore.properties")
|
||||
|
||||
// Initialize a new Properties() object called keystoreProperties.
|
||||
def keystoreProperties = new Properties()
|
||||
|
||||
// Load your keystore.properties file into the keystoreProperties object.
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
|
||||
android {
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
@@ -134,8 +146,8 @@ android {
|
||||
applicationId "com.drip"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 33
|
||||
versionName "1.2403.19"
|
||||
versionCode 38
|
||||
versionName "1.2410.22"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
}
|
||||
@@ -150,6 +162,10 @@ android {
|
||||
keyPassword 'android'
|
||||
}
|
||||
release {
|
||||
storeFile file('drip-release-key.keystore')
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storePassword keystoreProperties['storePassword']
|
||||
if (project.hasProperty('DRIP_RELEASE_STORE_FILE')) {
|
||||
storeFile file(DRIP_RELEASE_STORE_FILE)
|
||||
storePassword DRIP_RELEASE_STORE_PASSWORD
|
||||
|
||||
@@ -53,6 +53,7 @@ ext {
|
||||
minSdkVersion = 21
|
||||
compileSdkVersion = 33
|
||||
targetSdkVersion = 33
|
||||
soLoaderVersion = "0.10.4+"
|
||||
|
||||
if (System.properties['os.arch'] == "aarch64") {
|
||||
// For M1 Users we need to use the NDK 24 which added support for aarch64
|
||||
|
||||
@@ -18,6 +18,10 @@ const AboutSection = () => {
|
||||
<AppPage title={t('title')}>
|
||||
<Segment>
|
||||
<AppText>{t('intro.text')}</AppText>
|
||||
<Button isCTA isSmall onPress={() => Linking.openURL(links.faq.url)}>
|
||||
{t('intro.faq')}
|
||||
</Button>
|
||||
<AppText>{t('intro.contact')}</AppText>
|
||||
<ButtonRow>
|
||||
{[links.email, links.gitlab, links.website].map((link) => (
|
||||
<Button
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import React from 'react'
|
||||
import { View } from 'react-native'
|
||||
import PropTypes from 'prop-types'
|
||||
import Slider from '@ptomasroos/react-native-multi-slider'
|
||||
|
||||
import SliderLabel from './slider-label'
|
||||
import { styles } from './slider-styles'
|
||||
import {
|
||||
ADVANCE_PERIOD_NOTICE_DAYS_MIN,
|
||||
ADVANCE_PERIOD_NOTICE_DAYS_MAX,
|
||||
} from '../../../config'
|
||||
|
||||
const AdvanceNoticeDaysSlider = ({
|
||||
disabled,
|
||||
advanceNoticeDays,
|
||||
onAdvanceNoticeDaysChange,
|
||||
}) => {
|
||||
const sliderAccentBackground = disabled
|
||||
? styles.disabledSliderAccentBackground
|
||||
: styles.sliderAccentBackground
|
||||
|
||||
const sliderBackground = disabled
|
||||
? styles.disabledSliderBackground
|
||||
: styles.sliderBackground
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Slider
|
||||
customLabel={SliderLabel}
|
||||
enableLabel={true}
|
||||
markerStyle={styles.marker}
|
||||
markerOffsetY={styles.markerOffsetY}
|
||||
max={ADVANCE_PERIOD_NOTICE_DAYS_MAX}
|
||||
min={ADVANCE_PERIOD_NOTICE_DAYS_MIN}
|
||||
onValuesChange={onAdvanceNoticeDaysChange}
|
||||
step={1}
|
||||
showSteps={true}
|
||||
snapped={true}
|
||||
trackStyle={styles.slider}
|
||||
values={[advanceNoticeDays]}
|
||||
enabledOne={!disabled}
|
||||
enabledTwo={false}
|
||||
selectedStyle={sliderAccentBackground}
|
||||
unselectedStyle={sliderBackground}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default AdvanceNoticeDaysSlider
|
||||
|
||||
AdvanceNoticeDaysSlider.propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
advanceNoticeDays: PropTypes.number,
|
||||
onAdvanceNoticeDaysChange: PropTypes.func,
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { StyleSheet } from 'react-native'
|
||||
import { Colors, Sizes } from '../../../styles'
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
paddingTop: Sizes.base,
|
||||
},
|
||||
marker: {
|
||||
backgroundColor: Colors.turquoiseDark,
|
||||
borderRadius: 50,
|
||||
elevation: 4,
|
||||
height: Sizes.subtitle,
|
||||
width: Sizes.subtitle,
|
||||
},
|
||||
slider: {
|
||||
borderRadius: 25,
|
||||
height: Sizes.small,
|
||||
paddingTop: Sizes.base,
|
||||
},
|
||||
sliderAccentBackground: {
|
||||
backgroundColor: Colors.turquoiseDark,
|
||||
},
|
||||
disabledSliderAccentBackground: {
|
||||
backgroundColor: Colors.grey,
|
||||
},
|
||||
sliderBackground: {
|
||||
backgroundColor: Colors.turquoise,
|
||||
},
|
||||
disabledSliderBackground: {
|
||||
backgroundColor: Colors.greyLight,
|
||||
},
|
||||
markerOffsetY: Sizes.tiny,
|
||||
})
|
||||
@@ -1,13 +1,12 @@
|
||||
import React, { useState } from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import { View } from 'react-native'
|
||||
import PropTypes from 'prop-types'
|
||||
import Slider from '@ptomasroos/react-native-multi-slider'
|
||||
|
||||
import alertError from '../common/alert-error'
|
||||
import SliderLabel from './slider-label'
|
||||
|
||||
import { styles } from './slider-styles'
|
||||
import alertError from '../common/alert-error'
|
||||
import { scaleObservable, saveTempScale } from '../../../local-storage'
|
||||
import { Colors, Sizes } from '../../../styles'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
import { TEMP_MIN, TEMP_MAX, TEMP_SLIDER_STEP } from '../../../config'
|
||||
|
||||
@@ -40,7 +39,7 @@ const TemperatureSlider = ({ disabled }) => {
|
||||
customLabel={SliderLabel}
|
||||
enableLabel={true}
|
||||
markerStyle={styles.marker}
|
||||
markerOffsetY={Sizes.tiny}
|
||||
markerOffsetY={styles.markerOffsetY}
|
||||
max={TEMP_MAX}
|
||||
min={TEMP_MIN}
|
||||
onValuesChange={onTemperatureSliderChange}
|
||||
@@ -61,34 +60,3 @@ export default TemperatureSlider
|
||||
TemperatureSlider.propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
paddingTop: Sizes.base,
|
||||
},
|
||||
marker: {
|
||||
backgroundColor: Colors.turquoiseDark,
|
||||
|
||||
borderRadius: 50,
|
||||
elevation: 4,
|
||||
height: Sizes.subtitle,
|
||||
width: Sizes.subtitle,
|
||||
},
|
||||
slider: {
|
||||
borderRadius: 25,
|
||||
height: Sizes.small,
|
||||
},
|
||||
sliderAccentBackground: {
|
||||
backgroundColor: Colors.turquoiseDark,
|
||||
},
|
||||
disabledSliderAccentBackground: {
|
||||
backgroundColor: Colors.grey,
|
||||
},
|
||||
sliderBackground: {
|
||||
backgroundColor: Colors.turquoise,
|
||||
},
|
||||
disabledSliderBackground: {
|
||||
backgroundColor: Colors.greyLight,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import React, { useState } from 'react'
|
||||
import AppSwitch from '../../common/app-switch'
|
||||
import AdvanceNoticeDaysSlider from '../customization/advance-notice-days-slider'
|
||||
|
||||
import {
|
||||
periodReminderObservable,
|
||||
savePeriodReminder,
|
||||
periodPredictionObservable,
|
||||
saveAdvanceNoticeDays,
|
||||
advanceNoticeDaysObservable,
|
||||
} from '../../../local-storage'
|
||||
import labels from '../../../i18n/en/settings'
|
||||
|
||||
const PeriodReminder = () => {
|
||||
const isPeriodPredictionDisabled = !periodPredictionObservable.value
|
||||
|
||||
const [isPeriodReminderEnabled, setIsPeriodReminderEnabled] = useState(
|
||||
periodReminderObservable.value.enabled
|
||||
)
|
||||
|
||||
const [advanceNoticeDays, setAdvanceNoticeDays] = useState(
|
||||
advanceNoticeDaysObservable.value
|
||||
)
|
||||
|
||||
const periodReminderToggle = (isEnabled) => {
|
||||
setIsPeriodReminderEnabled(isEnabled)
|
||||
savePeriodReminder({ enabled: isEnabled })
|
||||
}
|
||||
|
||||
const handleAdvanceNoticeDaysChange = (days) => {
|
||||
setAdvanceNoticeDays(days)
|
||||
saveAdvanceNoticeDays(days)
|
||||
}
|
||||
|
||||
const reminderText =
|
||||
advanceNoticeDays == 1
|
||||
? labels.periodReminder.reminderTextSingular
|
||||
: labels.periodReminder.reminderTextPlural(advanceNoticeDays)
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppSwitch
|
||||
onToggle={periodReminderToggle}
|
||||
text={reminderText}
|
||||
value={isPeriodReminderEnabled}
|
||||
disabled={isPeriodPredictionDisabled}
|
||||
/>
|
||||
{isPeriodReminderEnabled && (
|
||||
<AdvanceNoticeDaysSlider
|
||||
disabled={isPeriodPredictionDisabled}
|
||||
advanceNoticeDays={parseInt(advanceNoticeDays)}
|
||||
onAdvanceNoticeDaysChange={handleAdvanceNoticeDaysChange}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PeriodReminder
|
||||
@@ -1,13 +1,11 @@
|
||||
import React, { useState } from 'react'
|
||||
import React from 'react'
|
||||
|
||||
import AppPage from '../../common/app-page'
|
||||
import AppSwitch from '../../common/app-switch'
|
||||
import Segment from '../../common/segment'
|
||||
import TemperatureReminder from './temperature-reminder'
|
||||
import PeriodReminder from './period-reminder'
|
||||
|
||||
import {
|
||||
periodReminderObservable,
|
||||
savePeriodReminder,
|
||||
periodPredictionObservable,
|
||||
temperatureTrackingCategoryObservable,
|
||||
} from '../../../local-storage'
|
||||
@@ -16,17 +14,7 @@ import labels from '../../../i18n/en/settings'
|
||||
import { Alert, Pressable } from 'react-native'
|
||||
|
||||
const Reminders = () => {
|
||||
const isPeriodPredictionDisabled = !periodPredictionObservable.value
|
||||
|
||||
const [isPeriodReminderEnabled, setIsPeriodReminderEnabled] = useState(
|
||||
periodReminderObservable.value.enabled
|
||||
)
|
||||
const periodReminderToggle = (isEnabled) => {
|
||||
setIsPeriodReminderEnabled(isEnabled)
|
||||
savePeriodReminder({ enabled: isEnabled })
|
||||
}
|
||||
|
||||
const reminderDisabledPrompt = () => {
|
||||
const periodReminderDisabledPrompt = () => {
|
||||
if (!periodPredictionObservable.value) {
|
||||
Alert.alert(
|
||||
labels.periodReminder.alertNoPeriodReminder.title,
|
||||
@@ -43,16 +31,12 @@ const Reminders = () => {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<AppPage>
|
||||
<Pressable onPress={reminderDisabledPrompt}>
|
||||
<Pressable onPress={periodReminderDisabledPrompt}>
|
||||
<Segment title={labels.periodReminder.title}>
|
||||
<AppSwitch
|
||||
onToggle={periodReminderToggle}
|
||||
text={labels.periodReminder.reminderText}
|
||||
value={isPeriodReminderEnabled}
|
||||
disabled={isPeriodPredictionDisabled}
|
||||
/>
|
||||
<PeriodReminder />
|
||||
</Segment>
|
||||
</Pressable>
|
||||
<Pressable onPress={tempReminderDisabledPrompt}>
|
||||
|
||||
@@ -33,6 +33,10 @@ export const TEMP_MAX = 39
|
||||
export const TEMP_MIN = 35
|
||||
export const TEMP_SLIDER_STEP = 0.5
|
||||
|
||||
export const ADVANCE_PERIOD_NOTICE_DAYS_MIN = 1
|
||||
export const ADVANCE_PERIOD_NOTICE_DAYS_MAX = 7
|
||||
export const ADVANCE_PERIOD_NOTICE_DAYS_INIT_VALUE = 3
|
||||
|
||||
export const HIT_SLOP = {
|
||||
top: verticalScale(20),
|
||||
bottom: verticalScale(20),
|
||||
|
||||
+3
-1
@@ -45,7 +45,9 @@
|
||||
"text": "The drips are developing this app on a volunteer basis. We are always grateful for support. This could mean condriputing to the code, giving feedback, suggesting improvements or features, testing or donating. It helps and motivates us maintaining this app and developing new features. Thank you for your support!"
|
||||
},
|
||||
"intro": {
|
||||
"text": "Please note that your data is stored locally on your phone and not on a server. This means your data cannot be read by anyone else unless they have access to your phone. We want to ensure that you stay in control of your own data. If you are planning to switch or reset your phone, please remember to export your data before doing so. You can reinstall the app afterwards and import your data.\n\nIf you encounter any technical issues, don't hesitate to contact us via email. You can also contribute to the code base on Gitlab and visit our website."
|
||||
"text": "Please note that your data is stored locally on your phone and not on a server. This means your data cannot be read by anyone else unless they have access to your phone. We want to ensure that you stay in control of your own data. If you are planning to switch or reset your phone, please remember to export your data before doing so. You can reinstall the app afterwards and import your data.\n\nIf you encounter any issues, please take a look at our Frequently Asked Questions page.",
|
||||
"faq": "FAQ",
|
||||
"contact": "\nIf your issue is not listed, don't hesitate to contact us via email. You can also contribute to the code base on Gitlab and visit our website."
|
||||
},
|
||||
"philosophy": {
|
||||
"title": "Remember to think for yourself",
|
||||
|
||||
@@ -39,4 +39,8 @@ export default {
|
||||
url: 'https://www.flaticon.com',
|
||||
text: 'Flaticon',
|
||||
},
|
||||
faq: {
|
||||
url: 'https://dripapp.org/faq',
|
||||
text: 'FAQ',
|
||||
},
|
||||
}
|
||||
|
||||
+6
-4
@@ -60,10 +60,12 @@ export default {
|
||||
},
|
||||
periodReminder: {
|
||||
title: 'Next period reminder',
|
||||
reminderText:
|
||||
'Get a notification 3 days before your next period is likely to start.',
|
||||
notification: (daysToEndOfPrediction) =>
|
||||
`Your next period is likely to start in 3 to ${daysToEndOfPrediction} days.`,
|
||||
reminderTextSingular:
|
||||
'Get a notification 1 day before your next period is likely to start.',
|
||||
reminderTextPlural: (days) =>
|
||||
`Get a notification ${days} days before your next period is likely to start.`,
|
||||
notification: (advanceNoticeDays, daysToEndOfPrediction) =>
|
||||
`Your next period is likely to start in ${advanceNoticeDays} to ${daysToEndOfPrediction} days.`,
|
||||
alertNoPeriodReminder: {
|
||||
title: 'Period predictions turned off',
|
||||
message:
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2403.19</string>
|
||||
<string>1.2410.22</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
+55
-25
@@ -2,6 +2,7 @@ import { Platform } from 'react-native'
|
||||
import {
|
||||
tempReminderObservable,
|
||||
periodReminderObservable,
|
||||
advanceNoticeDaysObservable,
|
||||
} from '../local-storage'
|
||||
import * as PN from 'react-native-push-notification'
|
||||
import { requestNotifications } from 'react-native-permissions'
|
||||
@@ -13,12 +14,19 @@ import { getBleedingDaysSortedByDate } from '../db'
|
||||
import cycleModule from './cycle'
|
||||
import nothingChanged from '../db/db-unchanged'
|
||||
|
||||
const DRIP_CHANNEL_ID = 'drip-channel-id'
|
||||
const TEMPERATURE_REMINDER_ID = '1'
|
||||
const PERIOD_REMINDER_ID = '2'
|
||||
const PushNotification = Platform.OS === 'ios' ? PN : PN.default
|
||||
|
||||
export default function setupNotifications(navigate, setDate) {
|
||||
Platform.OS === 'android' ? requestNotifications() : null
|
||||
const PushNotification = Platform.OS === 'ios' ? PN : PN.default
|
||||
// for Android, this method call is necessary
|
||||
if (Platform.OS === 'android') {
|
||||
requestNotifications()
|
||||
}
|
||||
|
||||
PushNotification.createChannel({
|
||||
channelId: 'drip-channel-id', // (required)
|
||||
channelId: DRIP_CHANNEL_ID, // (required)
|
||||
channelName: 'drip reminder', // (required)
|
||||
playSound: false, // (optional) default: true
|
||||
})
|
||||
@@ -26,7 +34,10 @@ export default function setupNotifications(navigate, setDate) {
|
||||
PushNotification.configure({
|
||||
onNotification: (notification) => {
|
||||
// https://github.com/zo0r/react-native-push-notification/issues/966#issuecomment-479069106
|
||||
if (notification.data?.id === '1' || notification.id === '1') {
|
||||
if (
|
||||
notification.data?.id === TEMPERATURE_REMINDER_ID ||
|
||||
notification.id === TEMPERATURE_REMINDER_ID
|
||||
) {
|
||||
const todayDate = LocalDate.now().toString()
|
||||
setDate(todayDate)
|
||||
navigate('TemperatureEditView')
|
||||
@@ -37,7 +48,7 @@ export default function setupNotifications(navigate, setDate) {
|
||||
})
|
||||
|
||||
tempReminderObservable((reminder) => {
|
||||
PushNotification.cancelLocalNotification({ id: '1' })
|
||||
PushNotification.cancelLocalNotification({ id: TEMPERATURE_REMINDER_ID })
|
||||
if (reminder.enabled) {
|
||||
const [hours, minutes] = reminder.time.split(':')
|
||||
let target = new Moment()
|
||||
@@ -50,56 +61,75 @@ export default function setupNotifications(navigate, setDate) {
|
||||
}
|
||||
|
||||
PushNotification.localNotificationSchedule({
|
||||
id: '1',
|
||||
userInfo: { id: '1' },
|
||||
id: TEMPERATURE_REMINDER_ID,
|
||||
userInfo: { id: TEMPERATURE_REMINDER_ID },
|
||||
message: labels.tempReminder.notification,
|
||||
date: target.toDate(),
|
||||
vibrate: false,
|
||||
repeatType: 'day',
|
||||
channelId: 'drip-channel-id',
|
||||
channelId: DRIP_CHANNEL_ID,
|
||||
allowWhileIdle: true,
|
||||
})
|
||||
}
|
||||
}, false)
|
||||
|
||||
periodReminderObservable((reminder) => {
|
||||
PushNotification.cancelLocalNotification({ id: '2' })
|
||||
if (reminder.enabled) setupPeriodReminder()
|
||||
}, false)
|
||||
periodReminderObservable(() => updatePeriodNotification(), false)
|
||||
advanceNoticeDaysObservable(() => updatePeriodNotification(), false)
|
||||
|
||||
getBleedingDaysSortedByDate().addListener((_, changes) => {
|
||||
// the listener fires on setup, so we check if there were actually any changes
|
||||
if (nothingChanged(changes)) return
|
||||
PushNotification.cancelLocalNotification({ id: '2' })
|
||||
if (periodReminderObservable.value.enabled) setupPeriodReminder()
|
||||
if (nothingChanged(changes)) {
|
||||
return
|
||||
}
|
||||
|
||||
updatePeriodNotification()
|
||||
})
|
||||
}
|
||||
|
||||
function setupPeriodReminder() {
|
||||
const PushNotification = Platform.OS === 'ios' ? PN : PN.default
|
||||
const updatePeriodNotification = () => {
|
||||
// Cancel any existing period reminder
|
||||
PushNotification.cancelLocalNotification({ id: PERIOD_REMINDER_ID })
|
||||
|
||||
// Set up a new period reminder if enabled
|
||||
if (periodReminderObservable.value.enabled) {
|
||||
schedulePeriodNotification()
|
||||
}
|
||||
}
|
||||
|
||||
function schedulePeriodNotification() {
|
||||
const bleedingPrediction = cycleModule().getPredictedMenses()
|
||||
|
||||
if (bleedingPrediction.length > 0) {
|
||||
const predictedBleedingStart = Moment(
|
||||
bleedingPrediction[0][0],
|
||||
'YYYY-MM-DD'
|
||||
)
|
||||
// 3 days before and at 6 am
|
||||
|
||||
const advanceNoticeDays = parseInt(advanceNoticeDaysObservable.value)
|
||||
|
||||
// ${advanceNoticeDays} days before and at 6 am
|
||||
const reminderDate = predictedBleedingStart
|
||||
.subtract(3, 'days')
|
||||
.subtract(advanceNoticeDays, 'days')
|
||||
.hours(6)
|
||||
.minutes(0)
|
||||
.seconds(0)
|
||||
|
||||
if (reminderDate.isAfter()) {
|
||||
// period is likely to start in 3 to 3 + (length of prediction - 1) days
|
||||
const daysToEndOfPrediction = bleedingPrediction[0].length + 2
|
||||
// period is likely to start in advanceNoticeDays to advanceNoticeDays + (length of prediction - 1) days
|
||||
const daysToEndOfPrediction =
|
||||
advanceNoticeDays + bleedingPrediction[0].length - 1
|
||||
|
||||
PushNotification.localNotificationSchedule({
|
||||
id: '2',
|
||||
userInfo: { id: '2' },
|
||||
message: labels.periodReminder.notification(daysToEndOfPrediction),
|
||||
id: PERIOD_REMINDER_ID,
|
||||
userInfo: { id: PERIOD_REMINDER_ID },
|
||||
message: labels.periodReminder.notification(
|
||||
advanceNoticeDays,
|
||||
daysToEndOfPrediction
|
||||
),
|
||||
date: reminderDate.toDate(),
|
||||
vibrate: false,
|
||||
channelId: 'drip-channel-id',
|
||||
channelId: DRIP_CHANNEL_ID,
|
||||
allowWhileIdle: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+15
-1
@@ -2,6 +2,8 @@ import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import Observable from 'obv'
|
||||
import { TEMP_SCALE_MIN, TEMP_SCALE_MAX, TEMP_SCALE_UNITS } from './config'
|
||||
|
||||
import { ADVANCE_PERIOD_NOTICE_DAYS_INIT_VALUE } from './config'
|
||||
|
||||
export const scaleObservable = Observable()
|
||||
setObvWithInitValue('tempScale', scaleObservable, {
|
||||
min: TEMP_SCALE_MIN,
|
||||
@@ -59,6 +61,18 @@ export async function savePeriodPrediction(bool) {
|
||||
}
|
||||
}
|
||||
|
||||
export const advanceNoticeDaysObservable = Observable()
|
||||
setObvWithInitValue(
|
||||
'advanceNoticeDays',
|
||||
advanceNoticeDaysObservable,
|
||||
parseInt(ADVANCE_PERIOD_NOTICE_DAYS_INIT_VALUE)
|
||||
)
|
||||
|
||||
export async function saveAdvanceNoticeDays(days) {
|
||||
await AsyncStorage.setItem('advanceNoticeDays', JSON.stringify(days))
|
||||
advanceNoticeDaysObservable.set(days)
|
||||
}
|
||||
|
||||
export const useCervixAsSecondarySymptomObservable = Observable()
|
||||
setObvWithInitValue(
|
||||
'useCervixAsSecondarySymptom',
|
||||
@@ -109,7 +123,7 @@ export async function saveTemperatureTrackingCategory(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) {
|
||||
if (tempReminderResult && JSON.parse(tempReminderResult).enabled) {
|
||||
tempReminderObservable.set(false)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,13 +1,14 @@
|
||||
{
|
||||
"name": "drip.",
|
||||
"version": "1.2403.19",
|
||||
"version": "1.2410.22",
|
||||
"contributors": [
|
||||
"Julia Friesel <julia.friesel@gmail.com>",
|
||||
"Marie Kochsiek",
|
||||
"Tina Baumann",
|
||||
"Sofiya Tepikin",
|
||||
"Mariya Zadnepryanets",
|
||||
"Lisa Hillebrand"
|
||||
"Lisa Hillebrand",
|
||||
"Martha Dörfler"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "react-native start",
|
||||
@@ -47,7 +48,7 @@
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "17.0.2",
|
||||
"react-i18next": "^12.0.0",
|
||||
"react-native": "0.68.3",
|
||||
"react-native": "0.68.5",
|
||||
"react-native-calendars": "^1.1287.0",
|
||||
"react-native-document-picker": "^8.1.1",
|
||||
"react-native-fs": "^2.20.0",
|
||||
|
||||
@@ -6378,7 +6378,7 @@ promise@^7.1.1:
|
||||
dependencies:
|
||||
asap "~2.0.3"
|
||||
|
||||
promise@^8.0.3:
|
||||
promise@^8.2.0:
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a"
|
||||
integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==
|
||||
@@ -6508,10 +6508,10 @@ react-native-calendars@^1.1287.0:
|
||||
optionalDependencies:
|
||||
moment "^2.29.4"
|
||||
|
||||
react-native-codegen@^0.0.17:
|
||||
version "0.0.17"
|
||||
resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.0.17.tgz#83fb814d94061cbd46667f510d2ddba35ffb50ac"
|
||||
integrity sha512-7GIEUmAemH9uWwB6iYXNNsPoPgH06pxzGRmdBzK98TgFBdYJZ7CBuZFPMe4jmHQTPOkQazKZ/w5O6/71JBixmw==
|
||||
react-native-codegen@^0.0.18:
|
||||
version "0.0.18"
|
||||
resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.0.18.tgz#99d6623d65292e8ce3fdb1d133a358caaa2145e7"
|
||||
integrity sha512-XPI9aVsFy3dvgDZvyGWrFnknNiyb22kg5nHgxa0vjWTH9ENLBgVRZt9A64xHZ8BYihH+gl0p/1JNOCIEUzRPBg==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.14.0"
|
||||
flow-parser "^0.121.0"
|
||||
@@ -6601,10 +6601,10 @@ react-native-version@^3.1.0:
|
||||
resolve-from "^5.0.0"
|
||||
semver "^6.0.0"
|
||||
|
||||
react-native@0.68.3:
|
||||
version "0.68.3"
|
||||
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.68.3.tgz#07ac7374acde9bc5e80f9e473e03d6b730528f1c"
|
||||
integrity sha512-LPgLQ4e96NWCrJPKlXzKfvlg1ddhfUplsEg00/cfBIMFZPJn2inzo9Rym8I/JYjmRORe4GjGY8kOem72hPm0Lw==
|
||||
react-native@0.68.5:
|
||||
version "0.68.5"
|
||||
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.68.5.tgz#8ba7389e00b757c59b6ea23bf38303d52367d155"
|
||||
integrity sha512-t3kiQ/gumFV+0r/NRSIGtYxanjY4da0utFqHgkMcRPJVwXFWC0Fr8YiOeRGYO1dp8EfrSsOjtfWic/inqVYlbQ==
|
||||
dependencies:
|
||||
"@jest/create-cache-key-function" "^27.0.1"
|
||||
"@react-native-community/cli" "^7.0.3"
|
||||
@@ -6626,9 +6626,9 @@ react-native@0.68.3:
|
||||
metro-source-map "0.67.0"
|
||||
nullthrows "^1.1.1"
|
||||
pretty-format "^26.5.2"
|
||||
promise "^8.0.3"
|
||||
promise "^8.2.0"
|
||||
react-devtools-core "^4.23.0"
|
||||
react-native-codegen "^0.0.17"
|
||||
react-native-codegen "^0.0.18"
|
||||
react-native-gradle-plugin "^0.0.6"
|
||||
react-refresh "^0.4.0"
|
||||
react-shallow-renderer "16.14.1"
|
||||
|
||||
Reference in New Issue
Block a user