Skip to content

Commit

Permalink
Add 'Be happy' msg after countdown finishes
Browse files Browse the repository at this point in the history
  • Loading branch information
dsernst committed Jan 12, 2020
1 parent 9d25319 commit c0c0c42
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 127 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ module.exports = {
'sort-imports': ['warn', { ignoreDeclarationSort: true }],
'typescript-sort-keys/interface': 2,
'typescript-sort-keys/string-enum': 2,
'react-native/no-inline-styles': ['off'],
},
}
78 changes: 42 additions & 36 deletions App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import React, { Component } from 'react'
import { StatusBar, StyleSheet, Text, View } from 'react-native'
import { StatusBar, Text, View } from 'react-native'
import _ from 'lodash'
import InitScreen from './InitScreen'
import CountdownScreen from './CountdownScreen'
import { Sound, clips as c } from './clips'

// Shared vars
const bodyTextColor = '#f1f1f1'

type State = {
duration: string
finished: boolean
hasChanting: boolean
hasExtendedMetta: boolean
isEnoughTime: boolean
Expand All @@ -19,6 +23,7 @@ let timeouts: ReturnType<typeof setTimeout>[] = []
class App extends Component {
state: State = {
duration: '60',
finished: false,
hasChanting: false,
hasExtendedMetta: false,
isEnoughTime: true,
Expand Down Expand Up @@ -53,23 +58,23 @@ class App extends Component {
}

checkIfDurationIsEnough() {
type getDurationable = { getDuration: () => number }
const delay = (seconds: number) => ({ getDuration: () => seconds })
const tryingToPlay: getDurationable[] = [c.introInstructions, c.closingMetta]
const queue: { getDuration: () => number }[] = [c.introInstructions, c.closingMetta]
if (this.state.hasChanting) {
tryingToPlay.push(c.introChanting, delay(5), c.closingChanting, delay(2))
queue.push(c.introChanting, delay(5), c.closingChanting, delay(2))
}
if (this.state.hasExtendedMetta) {
tryingToPlay.push(c.mettaIntro, delay(3 * 60))
queue.push(c.mettaIntro, delay(3 * 60))
}
const durations = tryingToPlay.map(clip => clip.getDuration())
const durations = queue.map(clip => clip.getDuration())
this.setState({ isEnoughTime: _.sum(durations) < Number(this.state.duration) * 60 })
}

enqueueOpening() {
pressStart() {
this.setState({ started: true })

if (this.state.hasChanting) {
// Begin introChanting
this.setState({ latestTrack: c.introChanting })

// Setup a timeout to begin introInstructions a few
Expand All @@ -82,9 +87,8 @@ class App extends Component {
} else {
this.setState({ latestTrack: c.introInstructions })
}
}

enqueueClosing() {
// Calculate closing time
const closingMettaTime =
(Number(this.state.duration) * 60 - Math.floor(c.closingMetta.getDuration())) * 1000

Expand Down Expand Up @@ -117,12 +121,35 @@ class App extends Component {
)
}

toggle(key: string) {
return () => {
this.setState({ [key]: !this.state[key] })
}
}

render() {
return (
<>
<StatusBar barStyle="light-content" />
<View style={s.app}>
<Text style={s.title}>Goenka Meditation Timer</Text>
<View
style={{
backgroundColor: '#001709',
flex: 1,
paddingHorizontal: 24,
paddingTop: 18,
}}
>
<Text
style={{
alignSelf: 'center',
color: bodyTextColor,
fontSize: 24,
fontWeight: '600',
marginVertical: 40,
}}
>
Goenka Meditation Timer
</Text>
{this.state.started ? (
<CountdownScreen
{...this.state}
Expand All @@ -140,18 +167,16 @@ class App extends Component {
}

// Go back to InitScreen
this.setState({ latestTrack: null, started: false })
this.setState({ finished: false, latestTrack: null, started: false })
}}
toggle={this.toggle.bind(this)}
/>
) : (
<InitScreen
{...this.state}
pressStart={() => {
this.enqueueOpening()
this.enqueueClosing()
}}
pressStart={this.pressStart.bind(this)}
setDuration={(duration: string) => this.setState({ duration })}
toggle={(key: string) => () => this.setState({ [key]: !this.state[key] })}
toggle={this.toggle.bind(this)}
/>
)}
</View>
Expand All @@ -160,23 +185,4 @@ class App extends Component {
}
}

// Shared vars
const bodyTextColor = '#f1f1f1'

const s = StyleSheet.create({
app: {
backgroundColor: '#001709',
flex: 1,
paddingHorizontal: 24,
paddingTop: 18,
},
title: {
alignSelf: 'center',
color: bodyTextColor,
fontSize: 24,
fontWeight: '600',
marginVertical: 40,
},
})

export default App
40 changes: 40 additions & 0 deletions BeHappyText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useState } from 'react'
import { Animated } from 'react-native'

const bodyTextColor = '#f1f1f1'

export default () => {
const [fadeAnim] = useState(new Animated.Value(0))

React.useEffect(() => {
Animated.loop(
Animated.sequence([
Animated.timing(fadeAnim, {
duration: 4000,
toValue: 0.8,
}),
Animated.timing(fadeAnim, {
duration: 3000,
toValue: 0,
}),
]),
).start()
}, [fadeAnim])

return (
<Animated.Text
style={{
alignSelf: 'center',
color: bodyTextColor,
fontFamily: 'Palatino',
fontSize: 30,
fontStyle: 'italic',
fontWeight: '400',
marginTop: 45,
opacity: fadeAnim,
}}
>
Be happy
</Animated.Text>
)
}
83 changes: 42 additions & 41 deletions CountdownScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,64 @@
/* eslint-disable react-native/no-inline-styles */
import React from 'react'
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import { Text, TouchableOpacity, View } from 'react-native'
import KeepAwake from 'react-native-keep-awake'
import CountdownCircle from './react-native-countdown-circle'
import BeHappyText from './BeHappyText'

// Shared vars
const bodyTextColor = '#f1f1f1'
const btnSize = 80

type CountdownScreenProps = {
duration: string
finished: boolean
pressStop: () => void
toggle: (key: string) => () => void
}

const CountdownScreen = ({ duration, pressStop }: CountdownScreenProps) => (
const CountdownScreen = ({ duration, pressStop, toggle, finished }: CountdownScreenProps) => (
<>
<KeepAwake />
<View style={{ alignItems: 'center', marginTop: 80 }}>
<CountdownCircle
bgColor="#001709"
borderWidth={4}
color="#0a2013"
duration={Number(duration)}
labelStyle={{ color: bodyTextColor, fontSize: 18, opacity: 0.2 }}
minutes
onTimeElapsed={() => console.log('Elapsed!')}
radius={80}
shadowColor="#001709"
textStyle={{ color: bodyTextColor, fontSize: 40 }}
/>
{!finished ? (
<CountdownCircle
bgColor="#001709"
borderWidth={4}
color="#0a2013"
duration={Number(duration)}
labelStyle={{ color: bodyTextColor, fontSize: 18, opacity: 0.2 }}
minutes
onTimeElapsed={toggle('finished')}
radius={80}
shadowColor="#001709"
textStyle={{ color: bodyTextColor, fontSize: 40 }}
/>
) : (
<BeHappyText />
)}
</View>
<TouchableOpacity onPress={pressStop} style={s.stopBtn}>
<Text style={s.stopText}>Stop</Text>
<TouchableOpacity
onPress={pressStop}
style={{
alignItems: 'center',
alignSelf: 'center',
height: btnSize,
justifyContent: 'center',
marginBottom: 30,
marginTop: 'auto',
width: btnSize,
}}
>
<Text
style={{
color: bodyTextColor,
fontSize: 18,
opacity: 0.2,
}}
>
Stop
</Text>
</TouchableOpacity>
</>
)

const s = StyleSheet.create({
stopBtn: {
alignItems: 'center',
alignSelf: 'center',
height: btnSize,
justifyContent: 'center',
marginBottom: 30,
marginTop: 'auto',
width: btnSize,
},
stopText: {
color: bodyTextColor,
fontSize: 18,
opacity: 0.2,
},
text: {
alignSelf: 'center',
color: bodyTextColor,
fontSize: 48,
fontWeight: '400',
marginTop: 40,
},
})

export default CountdownScreen
Loading

0 comments on commit c0c0c42

Please sign in to comment.