Compare commits

..

6 Commits

Author SHA1 Message Date
bl00dymarie 60010f9760 Allow more lines for "other" under mood, pain, sex 2024-02-15 18:22:12 +01:00
bl00dymarie 2ee08c9769 Limit lines to 3 for symptom day boxes 2024-02-15 18:20:10 +01:00
bl00dymarie 3020967ed2 Add multiline to notes in edit view 2024-02-15 18:19:47 +01:00
bl00dymarie dc2f867c2c Update version to 1.2402.15 2024-02-15 18:07:22 +01:00
bl00dymarie 90ad1cb12f Add KeyboardAvoidingView for visible TextInput 2024-02-15 17:38:08 +01:00
bl00dymarie 010cabcefb Allow scrolling in note text field 2024-02-15 17:37:15 +01:00
29 changed files with 226 additions and 523 deletions
+1 -2
View File
@@ -59,9 +59,8 @@ buck-out/
# Bundle artifact
*.jsbundle
# Ruby / CocoaPods
# CocoaPods
/ios/Pods/
/vendor/bundle/
# RN android release
android/app/bin/
+2 -2
View File
@@ -134,8 +134,8 @@ android {
applicationId "com.drip"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 29
versionName "1.2402.23"
versionCode 27
versionName "1.2402.15"
ndk {
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
+1 -1
View File
@@ -8,6 +8,6 @@
android:usesCleartextTraffic="true"
tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" />
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>
@@ -1,10 +1,10 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.drip;
package com.rndiffapp;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
import com.facebook.flipper.android.utils.FlipperUtils;
@@ -18,7 +18,6 @@ import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceEventListener;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
@@ -47,7 +46,7 @@ public class ReactNativeFlipper {
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceEventListener() {
new ReactInstanceManager.ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);
+3 -3
View File
@@ -57,12 +57,12 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="sensorPortrait"
android:exported="true">
android:screenOrientation="sensorPortrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -1,8 +1,6 @@
package com.drip;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
public class MainActivity extends ReactActivity {
@@ -14,27 +12,4 @@ public class MainActivity extends ReactActivity {
protected String getMainComponentName() {
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,7 +8,6 @@ import com.facebook.react.ReactInstanceManager;
import cl.json.ShareApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
@@ -63,7 +62,7 @@ public class MainApplication extends Application implements ReactApplication, Sh
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.drip.ReactNativeFlipper");
Class<?> aClass = Class.forName("com.rndiffapp.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
+3 -13
View File
@@ -1,5 +1,3 @@
import org.apache.tools.ant.taskdefs.condition.Os
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
@@ -9,9 +7,8 @@ buildscript {
}
ext.kotlinVersion = '1.3.40'
dependencies {
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")
classpath('com.android.tools.build:gradle:7.0.3')
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
@@ -53,12 +50,5 @@ ext {
minSdkVersion = 21
compileSdkVersion = 33
targetSdkVersion = 33
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"
}
ndkVersion = "21.4.7075529"
}
+5 -14
View File
@@ -9,8 +9,8 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
# Default value: -Xmx1024m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
@@ -25,16 +25,7 @@ android.useAndroidX=true
android.enableJetifier=true
# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.125.0
FLIPPER_VERSION=0.99.0
# Use this property to specify which architecture you want to build.
# 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
# https://github.com/facebook/react-native/issues/30729
org.gradle.jvmargs=-Xmx4g
Binary file not shown.
+2 -1
View File
@@ -1,5 +1,6 @@
#Wed Oct 11 14:45:21 CEST 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
+114 -162
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#!/usr/bin/env bash
#
# Copyright © 2015-2021 the original authors.
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,103 +17,70 @@
#
##############################################################################
#
# 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/.
#
##
## Gradle start up script for UN*X
##
##############################################################################
# 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.
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.
MAX_FD=maximum
MAX_FD="maximum"
warn () {
warn ( ) {
echo "$*"
} >&2
}
die () {
die ( ) {
echo
echo "$*"
echo
exit 1
} >&2
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
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
@@ -121,9 +88,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD=$JAVA_HOME/bin/java
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -132,7 +99,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
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.
Please set the JAVA_HOME variable in your environment to match the
@@ -140,95 +107,80 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# 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" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=$( cygpath --unix "$JAVACMD" )
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
# 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
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.
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
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' ' '
)" '"$@"'
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"
-7
View File
@@ -3,10 +3,3 @@ rootProject.name = 'drip'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
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')
}
+3 -7
View File
@@ -14,10 +14,7 @@ import {
determinePredictionText,
formatWithOrdinalSuffix,
} from './helpers/home'
import {
fertilityTrackingObservable,
periodPredictionObservable,
} from '../local-storage'
import { periodPredictionObservable } from '../local-storage'
import { Colors, Fonts, Sizes, Spacing } from '../styles'
import { LocalDate } from '@js-joda/core'
@@ -31,12 +28,11 @@ const Home = ({ navigate, setDate }) => {
navigate('CycleDay')
}
const isFertilityTrackingEnabled = fertilityTrackingObservable.value
const todayDateString = LocalDate.now().toString()
const { getCycleDayNumber, getPredictedMenses } = cycleModule()
const cycleDayNumber = getCycleDayNumber(todayDateString)
const { status, phase, statusText } =
isFertilityTrackingEnabled && getFertilityStatusForDay(todayDateString)
getFertilityStatusForDay(todayDateString)
const isPeriodPredictionEnabled = periodPredictionObservable.value
const prediction = determinePredictionText(getPredictedMenses(), t)
@@ -59,7 +55,7 @@ const Home = ({ navigate, setDate }) => {
</AppText>
</View>
)}
{isFertilityTrackingEnabled && phase && (
{phase && (
<View style={styles.line}>
<AppText style={styles.whiteSubtitle}>
{formatWithOrdinalSuffix(phase)}
-6
View File
@@ -22,8 +22,6 @@ import {
painTrackingCategoryObservable,
sexTrackingCategoryObservable,
temperatureTrackingCategoryObservable,
mucusTrackingCategoryObservable,
cervixTrackingCategoryObservable,
} from '../../local-storage'
import { makeColumnInfo } from '../helpers/chart'
@@ -74,10 +72,6 @@ const CycleChart = ({ navigate, setDate }) => {
const symptomRowEnabledSymptoms = symptomRowSymptoms.filter((symptom) => {
if (symptom === 'sex') {
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') {
return desireTrackingCategoryObservable.value ? symptom : null
} else if (symptom === 'pain') {
+14 -6
View File
@@ -1,6 +1,7 @@
import React from 'react'
import {
Dimensions,
KeyboardAvoidingView,
Modal,
StyleSheet,
TouchableOpacity,
@@ -19,13 +20,15 @@ const AppModal = ({ children, onClose }) => (
transparent={true}
visible={true}
>
<TouchableOpacity onPress={onClose} style={styles.blackBackground} />
<View style={styles.modalWindow}>
<View style={styles.headerContainer}>
<CloseIcon onClose={onClose} />
<KeyboardAvoidingView behavior={'padding'} style={styles.safeAreaView}>
<TouchableOpacity onPress={onClose} style={styles.blackBackground} />
<View style={styles.modalWindow}>
<View style={styles.headerContainer}>
<CloseIcon onClose={onClose} />
</View>
{children}
</View>
{children}
</View>
</KeyboardAvoidingView>
</Modal>
)
@@ -62,6 +65,11 @@ const styles = StyleSheet.create({
elevation: 2, // works on android
minWidth: '80%',
},
safeAreaView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
})
export default AppModal
+4 -9
View File
@@ -1,13 +1,12 @@
import React from 'react'
import { Platform, StyleSheet, Switch, View } from 'react-native'
import { StyleSheet, Switch, View } from 'react-native'
import PropTypes from 'prop-types'
import AppText from './app-text'
import { Colors, Containers, Spacing } from '../../styles'
import { Containers } from '../../styles'
const AppSwitch = ({ onToggle, text, value, disabled }) => {
const trackColor = { true: Colors.turquoiseDark }
const AppSwitch = ({ onToggle, text, value, trackColor, disabled }) => {
return (
<View style={styles.container}>
<View style={styles.textContainer}>
@@ -28,20 +27,16 @@ AppSwitch.propTypes = {
onToggle: PropTypes.func.isRequired,
text: PropTypes.string,
value: PropTypes.bool,
trackColor: PropTypes.string,
disabled: PropTypes.bool,
}
const styles = StyleSheet.create({
container: {
...Containers.rowContainer,
marginTop: Spacing.tiny,
},
switch: {
flex: 1,
transform:
Platform.OS === 'ios'
? [{ scaleX: 0.8 }, { scaleY: 0.8 }]
: [{ scaleX: 1 }, { scaleY: 1 }],
},
textContainer: {
flex: 4,
@@ -16,8 +16,6 @@ import {
painTrackingCategoryObservable,
sexTrackingCategoryObservable,
temperatureTrackingCategoryObservable,
mucusTrackingCategoryObservable,
cervixTrackingCategoryObservable,
} from '../../local-storage'
import { Spacing } from '../../styles'
import { SYMPTOMS } from '../../config'
@@ -42,10 +40,6 @@ const CycleDayOverView = ({ date, setDate, isTemperatureEditView }) => {
return temperatureTrackingCategoryObservable.value ? symptom : null
} else if (symptom === 'sex') {
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') {
return desireTrackingCategoryObservable.value ? symptom : null
} else if (symptom === 'pain') {
+3 -27
View File
@@ -5,29 +5,14 @@ import { StyleSheet, TouchableOpacity, View } from 'react-native'
import AppText from '../common/app-text'
import { Colors, Containers } from '../../styles'
import labels from '../../i18n/en/settings'
export default function SelectTabGroup({ activeButton, buttons, onSelect }) {
const oneTimeTransformIntoNumber =
typeof activeButton === 'boolean' && Number(activeButton)
const isSecondarySymptomSwitch =
buttons[0]['label'] === labels.secondarySymptom.mucus
return (
<View style={styles.container}>
{buttons.map(({ label, value }, i) => {
const isActive =
value === activeButton || value === oneTimeTransformIntoNumber
const boxStyle = [
styles.box,
isActive && styles.boxActive,
isSecondarySymptomSwitch && styles.purpleBox,
isSecondarySymptomSwitch && isActive && styles.activePurpleBox,
]
const textStyle = [
styles.text,
isSecondarySymptomSwitch && styles.purpleText,
isActive && styles.textActive,
]
const isActive = value === activeButton
const boxStyle = [styles.box, isActive && styles.boxActive]
const textStyle = [styles.text, isActive && styles.textActive]
return (
<TouchableOpacity
@@ -65,13 +50,4 @@ const styles = StyleSheet.create({
textActive: {
color: 'white',
},
purpleBox: {
borderColor: Colors.purple,
},
activePurpleBox: {
backgroundColor: Colors.purple,
},
purpleText: {
color: Colors.purple,
},
})
+1 -1
View File
@@ -64,7 +64,7 @@ const SymptomBox = ({
<View style={styles.textContainer}>
<AppText style={symptomNameStyle}>{t(symptom)}</AppText>
{symptomDataToDisplay && (
<AppText style={textStyle} numberOfLines={4}>
<AppText style={textStyle} numberOfLines={3}>
{symptomDataToDisplay}
</AppText>
)}
+3 -3
View File
@@ -109,8 +109,8 @@ const SymptomEditView = ({ date, onClose, symptom, symptomData }) => {
const noteText = symptom === 'note' ? data.value : data.note
const inputProps = {
multiline: true,
numberOfLines: 3,
scrollEnabled: false,
numberOfLines: 4,
scrollEnabled: true,
style: styles.input,
textAlignVertical: 'top',
}
@@ -180,7 +180,7 @@ const SymptomEditView = ({ date, onClose, symptom, symptomData }) => {
<Segment style={styles.segmentBorder}>
<AppText>{symtomPage[symptom].note}</AppText>
<AppTextInput
{...inputProps}
multiline={true}
onChangeText={onEditNote}
placeholder={sharedLabels.enter}
testID="noteInput"
+2 -7
View File
@@ -1,10 +1,6 @@
import { LocalDate } from '@js-joda/core'
import {
fertilityTrackingObservable,
scaleObservable,
unitObservable,
} from '../../local-storage'
import { scaleObservable, unitObservable } from '../../local-storage'
import { getCycleStatusForDay } from '../../lib/sympto-adapter'
import { getCycleDay, getAmountOfCycleDays } from '../../db'
@@ -274,8 +270,7 @@ export function nfpLines() {
if (dateString < cycle.startDate) updateCurrentCycle(dateString)
if (cycle.noMoreCycles) return ret
const tempShift =
fertilityTrackingObservable.value && cycle.status.temperatureShift
const tempShift = cycle.status.temperatureShift
if (tempShift) {
if (tempShift.firstHighMeasurementDay.date === dateString) {
+46 -142
View File
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React, { useState } from 'react'
import { Alert, Pressable } from 'react-native'
import AppPage from '../../common/app-page'
@@ -6,38 +6,33 @@ import AppSwitch from '../../common/app-switch'
import AppText from '../../common/app-text'
import TemperatureSlider from './temperature-slider'
import Segment from '../../common/segment'
import SelectTabGroup from '../../cycle-day/select-tab-group'
import {
desireTrackingCategoryObservable,
fertilityTrackingObservable,
moodTrackingCategoryObservable,
noteTrackingCategoryObservable,
painTrackingCategoryObservable,
sexTrackingCategoryObservable,
temperatureTrackingCategoryObservable,
mucusTrackingCategoryObservable,
cervixTrackingCategoryObservable,
saveDesireTrackingCategory,
saveFertilityTrackingEnabled,
saveMoodTrackingCategory,
saveNoteTrackingCategory,
savePainTrackingCategory,
saveMucusTrackingCategory,
saveCervixTrackingCategory,
savePeriodPrediction,
saveSexTrackingCategory,
saveTemperatureTrackingCategory,
saveUseCervixAsSecondarySymptom,
saveUseCervix,
periodPredictionObservable,
useCervixAsSecondarySymptomObservable,
useCervixObservable,
} from '../../../local-storage'
import { Colors } from '../../../styles'
import labels from '../../../i18n/en/settings'
import { SYMPTOMS } from '../../../config'
const Settings = () => {
const [useCervixAsSecondarySymptom, setUseCervixAsSecondarySymptom] =
useState(useCervixAsSecondarySymptomObservable.value)
const [shouldUseCervix, setShouldUseCervix] = useState(
useCervixObservable.value
)
const [isPeriodPredictionEnabled, setPeriodPrediction] = useState(
periodPredictionObservable.value
@@ -46,14 +41,6 @@ const Settings = () => {
const [isTemperatureTrackingCategoryEnabled, setTemperatureTrackingCategory] =
useState(temperatureTrackingCategoryObservable.value)
const [isMucusTrackingCategoryEnabled, setMucusTrackingCategory] = useState(
mucusTrackingCategoryObservable.value
)
const [isCervixTrackingCategoryEnabled, setCervixTrackingCategory] = useState(
cervixTrackingCategoryObservable.value
)
const [isSexTrackingCategoryEnabled, setSexTrackingCategory] = useState(
sexTrackingCategoryObservable.value
)
@@ -74,32 +61,19 @@ const Settings = () => {
noteTrackingCategoryObservable.value
)
const [isFertilityTrackingEnabled, setFertilityTrackingEnabled] = useState(
fertilityTrackingObservable.value
)
const fertilityTrackingToggle = (value) => {
setFertilityTrackingEnabled(value)
saveFertilityTrackingEnabled(value)
}
const [isEnabled, setIsEnabled] = useState(false)
const toggleSwitch = () => setIsEnabled((previousState) => !previousState)
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) => {
setSexTrackingCategory(value)
saveSexTrackingCategory(value)
}
const desireTrackingCategoryToggle = (value) => {
setDesireTrackingCategory(value)
saveDesireTrackingCategory(value)
@@ -116,83 +90,30 @@ const Settings = () => {
setNoteTrackingCategory(value)
saveNoteTrackingCategory(value)
}
const onPeriodPredictionToggle = (value) => {
setPeriodPrediction(value)
savePeriodPrediction(value)
}
const fertilityTrackingText = isFertilityTrackingEnabled
? labels.fertilityTracking.on
: labels.fertilityTracking.off
const periodPredictionText = isPeriodPredictionEnabled
? labels.periodPrediction.on
: labels.periodPrediction.off
const secondarySymptomButtons = [
{
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 onCervixToggle = (value) => {
setShouldUseCervix(value)
saveUseCervix(value)
}
// is needed so secondary symptom is set correct on load
useEffect(() => {
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 (!isMucusTrackingCategoryEnabled == isCervixTrackingCategoryEnabled) {
Alert.alert(
labels.secondarySymptom.disabled.title,
labels.secondarySymptom.disabled.noSecondaryEnabled
)
}
}
const cervixText = useCervixAsSecondarySymptom
? labels.secondarySymptom.cervixModeOn
: labels.secondarySymptom.cervixModeOff
const cervixText = shouldUseCervix
? labels.useCervix.cervixModeOn
: labels.useCervix.cervixModeOff
const sliderDisabledPrompt = () => {
if (!isTemperatureTrackingCategoryEnabled) {
Alert.alert(labels.disabled.title, labels.disabled.message)
}
}
return (
<AppPage title={'Customization'}>
<Segment title={'Tracking categories'}>
@@ -200,65 +121,48 @@ const Settings = () => {
onToggle={temperatureTrackingCategoryToggle}
text={SYMPTOMS[1]}
value={isTemperatureTrackingCategoryEnabled}
/>
<AppSwitch
onToggle={(enabled) => {
mucusTrackingCategoryToggle(enabled)
}}
text={SYMPTOMS[2]}
value={isMucusTrackingCategoryEnabled}
/>
<AppSwitch
onToggle={(enabled) => {
cervixTrackingCategoryToggle(enabled)
}}
text={SYMPTOMS[3]}
value={isCervixTrackingCategoryEnabled}
trackColor={{ true: Colors.turquoiseDark }}
/>
<AppSwitch
onToggle={sexTrackingCategoryToggle}
text={SYMPTOMS[4]}
value={isSexTrackingCategoryEnabled}
trackColor={{ true: Colors.turquoiseDark }}
/>
<AppSwitch
onToggle={desireTrackingCategoryToggle}
text={SYMPTOMS[5]}
value={isDesireTrackingCategoryEnabled}
trackColor={{ true: Colors.turquoiseDark }}
/>
<AppSwitch
onToggle={painTrackingCategoryToggle}
text={SYMPTOMS[6]}
value={isPainTrackingCategoryEnabled}
trackColor={{ true: Colors.turquoiseDark }}
/>
<AppSwitch
onToggle={moodTrackingCategoryToggle}
text={SYMPTOMS[7]}
value={isMoodTrackingCategoryEnabled}
trackColor={{ true: Colors.turquoiseDark }}
/>
<AppSwitch
onToggle={noteTrackingCategoryToggle}
text={SYMPTOMS[8]}
value={isNoteTrackingCategoryEnabled}
trackColor={{ true: Colors.turquoiseDark }}
/>
</Segment>
<Segment title={'Fertility feature'}>
<AppSwitch
onToggle={toggleSwitch}
text={'If turned on ...'}
value={isEnabled}
trackColor={{ true: Colors.turquoiseDark }}
/>
</Segment>
<Pressable onPress={sliderDisabledPrompt}>
<Segment title={labels.fertilityTracking.title}>
{isTemperatureTrackingCategoryEnabled &&
(isMucusTrackingCategoryEnabled ||
isCervixTrackingCategoryEnabled) ? (
<>
<AppText>{labels.fertilityTracking.message}</AppText>
<AppSwitch
onToggle={fertilityTrackingToggle}
text={fertilityTrackingText}
value={isFertilityTrackingEnabled}
/>
</>
) : (
<AppText>{labels.disabled.message}</AppText>
)}
</Segment>
</Pressable>
<Pressable onPress={sliderDisabledPrompt}>
<Segment title={labels.tempScale.segmentTitle}>
@@ -274,19 +178,18 @@ const Settings = () => {
</Segment>
</Pressable>
<Pressable onPress={secondarySymptomDisabledPrompt}>
<Segment title={labels.secondarySymptom.title}>
{!isFertilityTrackingEnabled ? (
<AppText>{labels.secondarySymptom.disabled.message}</AppText>
) : (
<>
<AppText>{cervixText}</AppText>
<SelectTabGroup
activeButton={useCervixAsSecondarySymptom}
buttons={secondarySymptomButtons}
onSelect={(value) => onSelectTab(value)}
/>
</>
<Pressable onPress={sliderDisabledPrompt}>
<Segment title={labels.useCervix.title}>
{isTemperatureTrackingCategoryEnabled && (
<AppSwitch
onToggle={onCervixToggle}
text={cervixText}
value={shouldUseCervix}
trackColor={{ true: Colors.turquoiseDark }}
/>
)}
{!isTemperatureTrackingCategoryEnabled && (
<AppText>{labels.disabled.message}</AppText>
)}
</Segment>
</Pressable>
@@ -296,6 +199,7 @@ const Settings = () => {
onToggle={onPeriodPredictionToggle}
text={periodPredictionText}
value={isPeriodPredictionEnabled}
trackColor={{ true: Colors.turquoiseDark }}
/>
</Segment>
</AppPage>
+1 -1
View File
@@ -4,7 +4,7 @@ import { scale, verticalScale } from 'react-native-size-matters'
export const SYMPTOMS = [
'bleeding',
'temperature',
'cervical mucus',
'mucus',
'cervix',
'sex',
'desire',
+3 -19
View File
@@ -41,7 +41,7 @@ export default {
disabled: {
title: 'This feature is turned off',
message:
'To use the temperature scale please first enable the temperature tracking category above.',
'Please first enable the temperature tracking category in the customization settings.',
},
tempReminder: {
title: 'Temperature reminder',
@@ -66,32 +66,16 @@ export default {
'To use the period reminder please first enable period predictions in the customization settings.',
},
},
fertilityTracking: {
title: 'Fertility phases calculation',
message:
'If you enter menstrual bleeding, temperature and cervical mucus or cervix data according to the sympto-thermal rules, drip will calculate cycle phases with the provided data.',
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: {
useCervix: {
title: 'Secondary symptom',
cervixModeOn:
'Cervix values are being used for symptothermal fertility detection. You can switch here to use cervical mucus values for symptothermal fertility detection',
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',
disabled: {
title: 'Disabled',
message:
'To set a secondary symptom please first enable the temperature, cervical mucus or cervix tracking category as well as the fertility feature above.',
noSecondaryEnabled:
'To switch the secondary symptom both cervical mucus and cervix need to be enabled above.',
},
mucus: 'cervical mucus',
cervix: 'cervix',
},
periodPrediction: {
title: 'Period predictions',
on: 'drip predicts your 3 next menstrual bleedings based on statistics if you previously tracked at least 3 complete cycles.',
on: 'drip predicts your 3 next menstrual bleedings based on the statistics of your previously tracked cycles, min 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.',
},
passwordSettings: {
+1 -1
View File
@@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2402.23</string>
<string>1.2402.15</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
+2 -12
View File
@@ -1,15 +1,9 @@
import getFertilityStatus from 'sympto'
import cycleModule from './cycle'
import { fertilityTrackingObservable, useCervixAsSecondarySymptomObservable } from '../local-storage'
import { useCervixObservable } from '../local-storage'
import { fertilityStatus as labels } from '../i18n/en/labels'
const isFertilityTrackingEnabled = fertilityTrackingObservable.value
export function getFertilityStatusForDay(dateString) {
if (!isFertilityTrackingEnabled) {
return
}
const status = getCycleStatusForDay(dateString)
if (!status) return {
status: labels.fertile,
@@ -40,10 +34,6 @@ export function getFertilityStatusForDay(dateString) {
}
export function getCycleStatusForDay(dateString, opts = {}) {
if (!isFertilityTrackingEnabled) {
return
}
const {
getCycleForDay,
getCyclesBefore,
@@ -67,7 +57,7 @@ export function getCycleStatusForDay(dateString, opts = {}) {
}
}
cycleInfo.secondarySymptom = useCervixAsSecondarySymptomObservable.value ? 'cervix' : 'mucus'
cycleInfo.secondarySymptom = useCervixObservable.value ? 'cervix' : 'mucus'
return getFertilityStatus(cycleInfo)
}
+7 -39
View File
@@ -59,19 +59,12 @@ export async function savePeriodPrediction(bool) {
}
}
export const useCervixAsSecondarySymptomObservable = Observable()
setObvWithInitValue(
'useCervixAsSecondarySymptom',
useCervixAsSecondarySymptomObservable,
0
)
export const useCervixObservable = Observable()
setObvWithInitValue('useCervix', useCervixObservable, false)
export async function saveUseCervixAsSecondarySymptom(value) {
await AsyncStorage.setItem(
'useCervixAsSecondarySymptom',
JSON.stringify(value)
)
useCervixAsSecondarySymptomObservable.set(value)
export async function saveUseCervix(bool) {
await AsyncStorage.setItem('useCervix', JSON.stringify(bool))
useCervixObservable.set(bool)
}
export const hasEncryptionObservable = Observable()
@@ -107,30 +100,13 @@ export async function saveTemperatureTrackingCategory(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) {
const result = await AsyncStorage.getItem('tempReminder')
if (JSON.parse(result).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()
setObvWithInitValue('sex', sexTrackingCategoryObservable, true)
@@ -171,14 +147,6 @@ export async function saveNoteTrackingCategory(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) {
const result = await AsyncStorage.getItem(key)
let value
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "drip.",
"version": "1.2402.23",
"version": "1.2402.15",
"contributors": [
"Julia Friesel <julia.friesel@gmail.com>",
"Marie Kochsiek",