diff --git a/components/labels.js b/components/labels.js index 5ebae600568e258d6ddb1f19a973c030b7bc5549..5a044273b3abc99944aa8d42fc116f8cb5280dab 100644 --- a/components/labels.js +++ b/components/labels.js @@ -57,6 +57,11 @@ export const settings = { timeSet: time => `Daily reminder set for ${time}`, notification: 'Record your morning temperature' }, + 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.` + }, passwordSettings: { title: 'App password', explainerDisabled: "Encrypt the app's database with a password. You need to enter the password every time the app is started.", diff --git a/components/settings/index.js b/components/settings/index.js index e0828d8042e638cc1cf9818097f4c56e56446d35..1180f240d96b51fb3db10e0ab35384a47a1ec094 100644 --- a/components/settings/index.js +++ b/components/settings/index.js @@ -8,6 +8,7 @@ import styles from '../../styles/index' import { settings as labels } from '../labels' import { AppText } from '../app-text' import TempReminderPicker from './temp-reminder-picker' +import PeriodReminderPicker from './period-reminder' import TempSlider from './temp-slider' import openImportDialogAndImport from './import-dialog' import openShareDialogAndExport from './export-dialog' @@ -30,6 +31,7 @@ export default class Settings extends Component { <AppText>{labels.tempScale.segmentExplainer}</AppText> <TempSlider/> </View> + <PeriodReminderPicker/> <PasswordSetting /> <View style={styles.settingsSegment}> <AppText style={styles.settingsSegmentTitle}> diff --git a/components/settings/period-reminder.js b/components/settings/period-reminder.js new file mode 100644 index 0000000000000000000000000000000000000000..70ec0fcf7bd0c3ac48f0c756212bbe2318de25f6 --- /dev/null +++ b/components/settings/period-reminder.js @@ -0,0 +1,41 @@ +import React, { Component } from 'react' +import { + View, + Switch +} from 'react-native' +import { AppText } from '../app-text' +import { + periodReminderObservable, + savePeriodReminder +} from '../../local-storage' +import styles from '../../styles/index' +import { settings as labels } from '../labels' + +export default class PeriodReminderPicker extends Component { + constructor(props) { + super(props) + this.state = periodReminderObservable.value + } + + render() { + return ( + <View style={styles.settingsSegment}> + <AppText style={styles.settingsSegmentTitle}> + {labels.periodReminder.title} + </AppText> + <View style={{ flexDirection: 'row', alignItems: 'center' }}> + <View style={{ flex: 1 }}> + <AppText>{labels.periodReminder.reminderText}</AppText> + </View> + <Switch + value={this.state.enabled} + onValueChange={switchOn => { + this.setState({ enabled: switchOn }) + savePeriodReminder({enabled: switchOn}) + }} + /> + </View> + </View> + ) + } +} \ No newline at end of file diff --git a/lib/notifications.js b/lib/notifications.js index dc1a7a52ce2c5f792eabca6b8166471566e20fdd..06056427f17bb8ff58f2f68468446f732395dbfc 100644 --- a/lib/notifications.js +++ b/lib/notifications.js @@ -1,21 +1,26 @@ -import {tempReminderObservable} from '../local-storage' +import {tempReminderObservable, periodReminderObservable} from '../local-storage' import Notification from 'react-native-push-notification' import { LocalDate } from 'js-joda' import Moment from 'moment' import { settings as labels } from '../components/labels' -import { getOrCreateCycleDay } from '../db' +import { getOrCreateCycleDay, getBleedingDaysSortedByDate } from '../db' +import cycleModule from './cycle' export default function setupNotifications(navigate) { Notification.configure({ - onNotification: () => { - const todayDateString = LocalDate.now().toString() - const cycleDay = getOrCreateCycleDay(todayDateString) - navigate('TemperatureEditView', { cycleDay }) + onNotification: (notification) => { + if (notification.id === '1') { + const todayDateString = LocalDate.now().toString() + const cycleDay = getOrCreateCycleDay(todayDateString) + navigate('TemperatureEditView', { cycleDay }) + } else { + navigate('Home') + } } }) tempReminderObservable(reminder => { - Notification.cancelAllLocalNotifications() + Notification.cancelLocalNotifications({id: '1'}) if (reminder.enabled) { const [hours, minutes] = reminder.time.split(':') let target = new Moment() @@ -28,6 +33,7 @@ export default function setupNotifications(navigate) { } Notification.localNotificationSchedule({ + id: '1', message: labels.tempReminder.notification, date: target.toDate(), vibrate: false, @@ -35,4 +41,37 @@ export default function setupNotifications(navigate) { }) } }) + + periodReminderObservable(reminder => { + Notification.cancelLocalNotifications({id: '2'}) + if (reminder.enabled) setupPeriodReminder() + }) + + getBleedingDaysSortedByDate().addListener(() => { + Notification.cancelLocalNotifications({id: '2'}) + if (periodReminderObservable.value.enabled) setupPeriodReminder() + }) + +} + +function setupPeriodReminder() { + const bleedingPrediction = cycleModule().getPredictedMenses() + if (bleedingPrediction.length > 0) { + const bleedingStart = Moment(bleedingPrediction[0][0], "YYYY-MM-DD") + // 3 days before and at 6 am + const reminderDate = bleedingStart + .subtract(3, 'days') + .hours(6) + .minutes(0) + .seconds(0) + // period is likely to start in 3 to 3 + (length of prediction - 1) days + const daysToEndOfPrediction = bleedingPrediction[0].length + 2 + + Notification.localNotificationSchedule({ + id: '2', + message: labels.periodReminder.notification(daysToEndOfPrediction), + date: reminderDate.toDate(), + vibrate: false + }) + } } \ No newline at end of file diff --git a/local-storage/index.js b/local-storage/index.js index d41d4d7f23fa8f089f87c7d66fbae7fcc265f5bc..5f4af70e252bc350db736a5729fbb8279b611879 100644 --- a/local-storage/index.js +++ b/local-storage/index.js @@ -34,6 +34,16 @@ export async function saveTempReminder(reminder) { tempReminderObservable.set(reminder) } +export const periodReminderObservable = Observable() +setObvWithInitValue('periodReminder', periodReminderObservable, { + enabled: false +}) + +export async function savePeriodReminder(reminder) { + await AsyncStorage.setItem('periodReminder', JSON.stringify(reminder)) + periodReminderObservable.set(reminder) +} + export const hasEncryptionObservable = Observable() setObvWithInitValue('hasEncryption', hasEncryptionObservable, false)