Introduces NFP section redesign, upgrades slider version
This commit is contained in:
@@ -65,6 +65,7 @@ android/app/.project
|
|||||||
|
|
||||||
ios/Podfile.lock
|
ios/Podfile.lock
|
||||||
android/app/src/main/res/drawable-*
|
android/app/src/main/res/drawable-*
|
||||||
|
android/app/src/main/assets/*
|
||||||
|
|
||||||
# nodejs-mobile creates these with every npm install
|
# nodejs-mobile creates these with every npm install
|
||||||
nodejs-assets/nodejs-project/sample-*
|
nodejs-assets/nodejs-project/sample-*
|
||||||
|
|||||||
@@ -3,15 +3,21 @@ import PropTypes from 'prop-types'
|
|||||||
import { StyleSheet, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
|
|
||||||
import AppText from './app-text'
|
import AppText from './app-text'
|
||||||
|
import AppIcon from './app-icon'
|
||||||
|
|
||||||
import { Colors, Spacing, Typography } from '../../styles/redesign'
|
import { Colors, Containers, Spacing, Typography } from '../../styles/redesign'
|
||||||
|
|
||||||
const Segment = ({ children, last, title }) => {
|
const Segment = ({ children, icon, last, title }) => {
|
||||||
const containerStyle = last ? styles.containerLast : styles.container
|
const containerStyle = last ? styles.containerLast : styles.container
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={containerStyle}>
|
<View style={containerStyle}>
|
||||||
{title && <AppText style={styles.title}>{title}</AppText>}
|
{title &&
|
||||||
|
<View style={styles.line}>
|
||||||
|
{icon && <AppIcon name={icon} color={Colors.purple} />}
|
||||||
|
<AppText style={styles.title}>{title}</AppText>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
{children}
|
{children}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
@@ -19,6 +25,7 @@ const Segment = ({ children, last, title }) => {
|
|||||||
|
|
||||||
Segment.propTypes = {
|
Segment.propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
|
icon: PropTypes.string,
|
||||||
last: PropTypes.bool,
|
last: PropTypes.bool,
|
||||||
title: PropTypes.string
|
title: PropTypes.string
|
||||||
}
|
}
|
||||||
@@ -39,6 +46,10 @@ const styles = StyleSheet.create({
|
|||||||
containerLast: {
|
containerLast: {
|
||||||
...segmentContainer
|
...segmentContainer
|
||||||
},
|
},
|
||||||
|
line: {
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
title: {
|
title: {
|
||||||
...Typography.subtitle
|
...Typography.subtitle
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,114 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import {
|
import { StyleSheet, View } from 'react-native'
|
||||||
ScrollView, View
|
import Slider from '@ptomasroos/react-native-multi-slider'
|
||||||
} from 'react-native'
|
|
||||||
import styles from '../../../styles'
|
import alertError from '../shared/alert-error'
|
||||||
import labels from '../../../i18n/en/settings'
|
import AppPage from '../../common/app-page'
|
||||||
|
import AppSwitch from '../../common/app-switch'
|
||||||
import AppText from '../../common/app-text'
|
import AppText from '../../common/app-text'
|
||||||
|
import Label from './label'
|
||||||
import Segment from '../../common/segment'
|
import Segment from '../../common/segment'
|
||||||
import TempSlider from './temp-slider'
|
|
||||||
import UseCervixSetting from './use-cervix'
|
import { useCervixObservable,
|
||||||
import Icon from 'react-native-vector-icons/Entypo'
|
saveUseCervix,
|
||||||
|
scaleObservable,
|
||||||
|
saveTempScale
|
||||||
|
} from '../../../local-storage'
|
||||||
|
import { Colors, Sizes } from '../../../styles/redesign'
|
||||||
|
import labels from '../../../i18n/en/settings'
|
||||||
|
import config from '../../../config'
|
||||||
|
|
||||||
export default class Settings extends Component {
|
export default class Settings extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {}
|
|
||||||
|
this.state = {
|
||||||
|
useCervix: useCervixObservable.value,
|
||||||
|
temperatureScale: { ...scaleObservable.value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCervixToggle = (value) => {
|
||||||
|
this.setState({ useCervix: value })
|
||||||
|
saveUseCervix(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
onSliderChange = (values) => {
|
||||||
|
this.setState({ min: values[0], max: values[1] })
|
||||||
|
}
|
||||||
|
|
||||||
|
onSliderChangeFinish = (values) => {
|
||||||
|
this.setState({ min: values[0], max: values[1] })
|
||||||
|
|
||||||
|
try {
|
||||||
|
saveTempScale({ min: values[0], max: values[1] })
|
||||||
|
} catch(err) {
|
||||||
|
alertError(labels.tempScale.saveError)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { useCervix } = this.state
|
||||||
|
const cervixText = useCervix ?
|
||||||
|
labels.useCervix.cervixModeOn : labels.useCervix.cervixModeOff
|
||||||
|
const { min, max } = this.state.temperatureScale
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<AppPage>
|
||||||
<Segment title={labels.useCervix.title}>
|
<Segment title={labels.useCervix.title}>
|
||||||
<UseCervixSetting/>
|
<AppSwitch
|
||||||
|
onToggle={this.onCervixToggle}
|
||||||
|
text={cervixText}
|
||||||
|
value={useCervix}
|
||||||
|
/>
|
||||||
</Segment>
|
</Segment>
|
||||||
<Segment title={labels.tempScale.segmentTitle}>
|
<Segment title={labels.tempScale.segmentTitle}>
|
||||||
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
<AppText>{labels.tempScale.segmentExplainer}</AppText>
|
||||||
<TempSlider/>
|
<View style={styles.container}>
|
||||||
</Segment>
|
<Slider
|
||||||
<Segment style={styles.framedSegmentLast} >
|
customLabel={Label}
|
||||||
<View style={{flexDirection: 'row', alignItems: 'center'}}>
|
enableLabel={true}
|
||||||
<Icon name="info-with-circle"/>
|
markerStyle={styles.marker}
|
||||||
<AppText style={styles.framedSegmentTitle}>{` ${labels.preOvu.title} `}</AppText>
|
markerOffsetY={Sizes.tiny}
|
||||||
|
max={config.temperatureScale.max}
|
||||||
|
min={config.temperatureScale.min}
|
||||||
|
onValuesChange={this.onSliderChange}
|
||||||
|
onValuesChangeFinish={this.onSliderChangeFinish}
|
||||||
|
selectedStyle={styles.sliderAccentBackground}
|
||||||
|
step={config.temperatureScale.step}
|
||||||
|
trackStyle={styles.slider}
|
||||||
|
unselectedStyle={styles.sliderBackground}
|
||||||
|
values={[min, max]}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
</Segment>
|
||||||
|
<Segment icon="info-with-circle" last title={labels.preOvu.title}>
|
||||||
<AppText>{labels.preOvu.note}</AppText>
|
<AppText>{labels.preOvu.note}</AppText>
|
||||||
</Segment>
|
</Segment>
|
||||||
</ScrollView>
|
</AppPage>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingTop: Sizes.base
|
||||||
|
},
|
||||||
|
marker: {
|
||||||
|
backgroundColor: Colors.tourquiseDark,
|
||||||
|
borderRadius: 50,
|
||||||
|
elevation: 4,
|
||||||
|
height: Sizes.subtitle,
|
||||||
|
width: Sizes.subtitle
|
||||||
|
},
|
||||||
|
slider: {
|
||||||
|
borderRadius: 25,
|
||||||
|
height: Sizes.small
|
||||||
|
},
|
||||||
|
sliderAccentBackground: {
|
||||||
|
backgroundColor: Colors.tourquiseDark
|
||||||
|
},
|
||||||
|
sliderBackground: {
|
||||||
|
backgroundColor: Colors.tourquise
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { StyleSheet } from 'react-native'
|
||||||
|
|
||||||
|
import AppText from '../../common/app-text'
|
||||||
|
|
||||||
|
import { Sizes } from '../../../styles/redesign'
|
||||||
|
|
||||||
|
const sliderRadius = 5
|
||||||
|
const width = 50
|
||||||
|
|
||||||
|
export default class Label extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
oneMarkerValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
twoMarkerValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
oneMarkerLeftPosition: PropTypes.number,
|
||||||
|
twoMarkerLeftPosition: PropTypes.number,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
oneMarkerValue,
|
||||||
|
twoMarkerValue,
|
||||||
|
oneMarkerLeftPosition,
|
||||||
|
twoMarkerLeftPosition,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
const minCoordinate = oneMarkerLeftPosition - width / 2 + sliderRadius
|
||||||
|
const maxCoordinate = twoMarkerLeftPosition - width / 2 + sliderRadius
|
||||||
|
const isMinNumber = Number.isFinite(oneMarkerLeftPosition) &&
|
||||||
|
Number.isFinite(oneMarkerValue)
|
||||||
|
const isMaxNumber = Number.isFinite(twoMarkerLeftPosition) &&
|
||||||
|
Number.isFinite(twoMarkerValue)
|
||||||
|
const minStyle = [styles.label, { left: minCoordinate }]
|
||||||
|
const maxStyle = [styles.label, { left: maxCoordinate }]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{isMinNumber && <AppText style={minStyle}>{oneMarkerValue}</AppText>}
|
||||||
|
{isMaxNumber && <AppText style={maxStyle}>{twoMarkerValue}</AppText>}
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
label: {
|
||||||
|
position: 'absolute',
|
||||||
|
marginTop: (-1) * Sizes.base
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
import React, { Component } from 'react'
|
|
||||||
import { View } from 'react-native'
|
|
||||||
import Slider from '@ptomasroos/react-native-multi-slider'
|
|
||||||
import AppText from '../../common/app-text'
|
|
||||||
import {
|
|
||||||
scaleObservable,
|
|
||||||
saveTempScale,
|
|
||||||
} from '../../../local-storage'
|
|
||||||
import { secondaryColor } from '../../../styles/index'
|
|
||||||
import labels from '../../../i18n/en/settings'
|
|
||||||
import config from '../../../config'
|
|
||||||
import alertError from '../shared/alert-error'
|
|
||||||
|
|
||||||
export default class TempSlider extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props)
|
|
||||||
this.state = Object.assign({}, scaleObservable.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
onValuesChange = (values) => {
|
|
||||||
this.setState({
|
|
||||||
min: values[0],
|
|
||||||
max: values[1]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onValuesChangeFinish = (values) => {
|
|
||||||
this.setState({
|
|
||||||
min: values[0],
|
|
||||||
max: values[1]
|
|
||||||
})
|
|
||||||
try {
|
|
||||||
saveTempScale(this.state)
|
|
||||||
} catch(err) {
|
|
||||||
alertError(labels.tempScale.saveError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<View style={{ alignItems: 'center' }}>
|
|
||||||
<AppText>{`${labels.tempScale.min} ${this.state.min.toFixed(1)}`}</AppText>
|
|
||||||
<AppText>{`${labels.tempScale.max} ${this.state.max.toFixed(1)}`}</AppText>
|
|
||||||
<Slider
|
|
||||||
values={[this.state.min, this.state.max]}
|
|
||||||
min={config.temperatureScale.min}
|
|
||||||
max={config.temperatureScale.max}
|
|
||||||
step={0.5}
|
|
||||||
onValuesChange={this.onValuesChange}
|
|
||||||
onValuesChangeFinish={this.onValuesChangeFinish}
|
|
||||||
selectedStyle={{
|
|
||||||
backgroundColor: 'darkgrey',
|
|
||||||
}}
|
|
||||||
unselectedStyle={{
|
|
||||||
backgroundColor: 'silver',
|
|
||||||
}}
|
|
||||||
trackStyle={{
|
|
||||||
height: 10,
|
|
||||||
}}
|
|
||||||
markerStyle={{
|
|
||||||
backgroundColor: secondaryColor,
|
|
||||||
height: 20,
|
|
||||||
width: 20,
|
|
||||||
borderRadius: 100,
|
|
||||||
marginTop: 10
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import React, { Component } from 'react'
|
|
||||||
import {
|
|
||||||
View,
|
|
||||||
Switch
|
|
||||||
} from 'react-native'
|
|
||||||
import AppText from '../../common/app-text'
|
|
||||||
import {
|
|
||||||
useCervixObservable,
|
|
||||||
saveUseCervix
|
|
||||||
} from '../../../local-storage'
|
|
||||||
import labels from '../../../i18n/en/settings'
|
|
||||||
|
|
||||||
export default class UseCervixSetting extends Component {
|
|
||||||
constructor() {
|
|
||||||
super()
|
|
||||||
this.state = {useCervix: useCervixObservable.value}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
||||||
<View style={{ flex: 1 }}>
|
|
||||||
{this.state.useCervix ?
|
|
||||||
<AppText>{labels.useCervix.cervixModeOn}</AppText>
|
|
||||||
:
|
|
||||||
<AppText>{labels.useCervix.cervixModeOff}</AppText>
|
|
||||||
}
|
|
||||||
</View>
|
|
||||||
<Switch
|
|
||||||
value={this.state.useCervix}
|
|
||||||
onValueChange={bool => {
|
|
||||||
this.setState({ useCervix: bool })
|
|
||||||
saveUseCervix(bool)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,6 +9,7 @@ const config = {
|
|||||||
defaultHigh: 38,
|
defaultHigh: 38,
|
||||||
min: 34,
|
min: 34,
|
||||||
max: 40,
|
max: 40,
|
||||||
|
step: 0.5,
|
||||||
units: 0.1,
|
units: 0.1,
|
||||||
verticalPadding: 0.03
|
verticalPadding: 0.03
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+4113
-5531
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -27,7 +27,7 @@
|
|||||||
"postinstall": "npx jetify"
|
"postinstall": "npx jetify"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ptomasroos/react-native-multi-slider": "^1.0.0",
|
"@ptomasroos/react-native-multi-slider": "^2.2.0",
|
||||||
"ajv": "^5.5.2",
|
"ajv": "^5.5.2",
|
||||||
"assert": "^1.4.1",
|
"assert": "^1.4.1",
|
||||||
"csvtojson": "^2.0.8",
|
"csvtojson": "^2.0.8",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export const fonts = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const sizes = {
|
export const sizes = {
|
||||||
|
tiny: 7,
|
||||||
small: 14,
|
small: 14,
|
||||||
base: 18,
|
base: 18,
|
||||||
subtitle: 22,
|
subtitle: 22,
|
||||||
|
|||||||
Reference in New Issue
Block a user