Introduces Stats page redesign

This commit is contained in:
mashazyu
2020-04-22 21:41:25 +02:00
committed by Sofiya Tepikin
parent fe5f734cff
commit 9d6c0aa65c
5 changed files with 235 additions and 80 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+79
View File
@@ -0,0 +1,79 @@
import React from 'react'
import { StyleSheet, View } from 'react-native'
import PropTypes from 'prop-types'
import AppText from './app-text'
import { Spacing, Typography } from '../../styles/redesign'
const Table = ({ tableContent }) => {
return (
tableContent.map((rowContent, i) => <Row key={i} rowContent={rowContent} />)
)
}
Table.propTypes = {
tableContent: PropTypes.array.isRequired
}
const Row = ({ rowContent }) => {
return(
<View style={styles.row}>
<Cell content={rowContent[0]} isLeft />
<Cell content={rowContent[1]} />
</View>
)
}
Row.propTypes = {
rowContent: PropTypes.array.isRequired
}
const Cell = ({ content, isLeft }) => {
const styleContainer = isLeft ? styles.cellLeft : styles.cellRight
const styleText = isLeft ? styles.accentPurpleBig : styles.accentOrange
const numberOfLines = isLeft ? 1 : 2
const ellipsizeMode = isLeft ? 'clip' : 'tail'
return(
<View style={styleContainer}>
<AppText
numberOfLines={numberOfLines}
ellipsizeMode={ellipsizeMode}
style={styleText}
>
{content}
</AppText>
</View>
)
}
Cell.propTypes = {
content: PropTypes.node.isRequired,
isLeft: PropTypes.bool
}
const styles = StyleSheet.create({
accentOrange: {
...Typography.accentOrange
},
accentPurpleBig: {
...Typography.accentPurpleBig,
marginRight: Spacing.base
},
cellLeft: {
alignItems: 'flex-end',
flex: 5,
justifyContent: 'center'
},
cellRight: {
flex: 6,
justifyContent: 'center'
},
row: {
flexDirection: 'row',
marginBottom: Spacing.tiny
}
})
export default Table
+106 -69
View File
@@ -1,77 +1,114 @@
import React, { Component } from 'react'
import {
View,
ScrollView
} from 'react-native'
import React from 'react'
import { ImageBackground, StyleSheet, View } from 'react-native'
import AppPage from './common/app-page'
import AppText from './common/app-text'
import Segment from './common/segment'
import Table from './common/table'
import styles from '../styles/index'
import cycleModule from '../lib/cycle'
import {getCycleLengthStats as getCycleInfo} from '../lib/cycle-length'
import {stats as labels} from '../i18n/en/labels'
import AppText from './common/app-text'
import Segment from './common/segment'
export default class Stats extends Component {
render() {
const cycleLengths = cycleModule().getAllCycleLengths()
const atLeastOneCycle = cycleLengths.length >= 1
let numberOfCycles
let cycleInfo
if (atLeastOneCycle) {
numberOfCycles = cycleLengths.length
if (numberOfCycles > 1) {
cycleInfo = getCycleInfo(cycleLengths)
}
}
return (
<ScrollView>
<Segment
style={styles.framedSegmentLast}
title={labels.cycleLengthTitle}
>
<AppText style={styles.paragraph}>
{labels.cycleLengthExplainer}
</AppText>
import { Sizes, Spacing, Typography } from '../styles/redesign'
{!atLeastOneCycle &&
<AppText>{labels.emptyStats}</AppText>
}
{atLeastOneCycle && numberOfCycles === 1 &&
<View style={[styles.statsRow, styles.paragraph]}>
<AppText>{labels.oneCycleStats}</AppText>
<AppText style={styles.emphasis}> {cycleLengths[0]} </AppText>
<AppText>{labels.daysLabel}.</AppText>
</View>
}
{atLeastOneCycle && numberOfCycles > 1 && <View>
<View style={styles.paragraph}>
<AppText style={styles.emphasis}>
{labels.averageLabel}: {cycleInfo.mean} {labels.daysLabel}
</AppText>
</View>
<View>
<AppText>
{labels.minLabel}: {cycleInfo.minimum} {labels.daysLabel}
</AppText>
</View>
<View>
<AppText>
{labels.maxLabel}: {cycleInfo.maximum} {labels.daysLabel}
</AppText>
</View>
<View style={styles.paragraph}>
<AppText>
{labels.stdLabel}: {cycleInfo.stdDeviation} {labels.daysLabel}
</AppText>
</View>
<View style={styles.statsRow}>
<AppText>{labels.basisOfStatsBeginning}</AppText>
<AppText style={styles.emphasis}> {numberOfCycles} </AppText>
<AppText>{labels.basisOfStatsEnd}</AppText>
</View>
</View>}
</Segment>
</ScrollView>
)
const image = require('../assets/cycle-icon.png')
const Stats = () => {
const cycleLengths = cycleModule().getAllCycleLengths()
const atLeastOneCycle = cycleLengths.length >= 1
const numberOfCycles = cycleLengths.length
let cycleData
if (atLeastOneCycle) {
cycleData = getCycleInfo(cycleLengths)
}
const statsData = [
[atLeastOneCycle ? cycleData.minimum : 0, labels.minLabel],
[atLeastOneCycle ? cycleData.maximum : 0, labels.maxLabel],
[atLeastOneCycle && cycleData.stdDeviation ? cycleData.stdDeviation : '—', labels.stdLabel],
[numberOfCycles, labels.basisOfStatsEnd]
]
return (
<AppPage>
<Segment last style={styles.pageContainer}>
<AppText>{labels.cycleLengthExplainer}</AppText>
{!atLeastOneCycle && <AppText>{labels.emptyStats}</AppText>}
{atLeastOneCycle &&
<View style={styles.container}>
<View style={styles.columnLeft}>
<ImageBackground
source={image}
imageStyle={styles.image}
style={styles.imageContainter}
>
<AppText
numberOfLines={1}
ellipsizeMode="clip"
style={styles.accentPurpleGiant}
>
{cycleData.mean}
</AppText>
<AppText style={styles.accentPurpleHuge}>
{labels.daysLabel}
</AppText>
</ImageBackground>
<AppText style={styles.accentOrange}>
{labels.averageLabel}
</AppText>
</View>
<View style={styles.columnRight}>
<Table tableContent={statsData} />
</View>
</View>
}
</Segment>
</AppPage>
)
}
const column = {
flexDirection: 'column'
}
const styles = StyleSheet.create({
accentOrange: {
...Typography.accentOrange
},
accentPurpleGiant: {
...Typography.accentPurpleGiant,
marginVertical: Sizes.giant * (-0.5)
},
accentPurpleHuge: {
...Typography.accentPurpleHuge,
marginRight: Spacing.base
},
container: {
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
},
columnLeft: {
...column,
flex: 4
},
columnRight: {
...column,
flex: 5
},
image: {
height: Sizes.huge * 3,
marginLeft: Sizes.huge / 2,
resizeMode: 'contain',
width: Sizes.huge * 3
},
imageContainter: {
paddingTop: Sizes.huge,
marginBottom: Sizes.huge / 4
},
pageContainer: {
marginVertical: Spacing.large
}
})
export default Stats
+5 -10
View File
@@ -61,19 +61,14 @@ export const menuTitles = {
}
export const stats = {
cycleLengthTitle: 'Cycle length',
cycleLengthExplainer: 'Basic statistics about the length of your cycles.',
emptyStats: 'At least one completed cycle is needed to display stats.',
//oneCycleStats: (number) => `You have documented one cycle of ${number} days.`,
oneCycleStats: 'You have documented one cycle of',
daysLabel: 'days',
//getBasisOfStats: (numberOfCycles) => `Stats are based on ${numberOfCycles} completed cycles.`,
basisOfStatsBeginning: 'Stats are based on',
basisOfStatsEnd: 'completed cycles.',
averageLabel: 'Average cycle length',
minLabel: 'Shortest cycle',
maxLabel: 'Longest cycle',
stdLabel: 'Standard deviation'
basisOfStatsEnd: 'completed\ncycles',
averageLabel: 'Average cycle',
minLabel: `Shortest`,
maxLabel: `Longest`,
stdLabel: `Standard\ndeviation`
}
export const bleedingPrediction = {
+45 -1
View File
@@ -12,7 +12,9 @@ export const sizes = {
base: 18,
subtitle: 22,
title: 24,
huge: 40
big: 30,
huge: 40,
giant: 50
}
const title = {
@@ -20,7 +22,49 @@ const title = {
marginVertical: Spacing.large
}
const accentText = {
fontFamily: fonts.bold,
textAlignVertical: 'center',
textTransform: 'uppercase'
}
const accentTextBig = {
...accentText,
fontSize: sizes.big,
}
const accentTextGiant = {
...accentText,
fontSize: sizes.giant,
}
const accentTextHuge = {
...accentText,
fontSize: sizes.huge,
}
const accentTextSmall = {
...accentText,
fontSize: sizes.small
}
export default {
accentOrange: {
...accentTextSmall,
color: Colors.orange
},
accentPurpleBig: {
...accentTextBig,
color: Colors.purple
},
accentPurpleGiant: {
...accentTextGiant,
color: Colors.purple
},
accentPurpleHuge: {
...accentTextHuge,
color: Colors.purple
},
mainText: {
fontFamily: fonts.main,
fontSize: sizes.base