♻️ (timer) break into more pieces the hook useTimer

This commit is contained in:
2020-07-04 10:50:58 +02:00
parent b0e28ae209
commit fe674c73df
5 changed files with 150 additions and 110 deletions

View File

@@ -0,0 +1,34 @@
<template>
<div class="chilled-music">
<youtube-video
v-show="false"
src="https://www.youtube-nocookie.com/embed/5qap5aO4i9A"
/>
</div>
</template>
<script lang="ts">
import 'youtube-video-js'
import { defineComponent, onMounted, watchEffect } from '@vue/composition-api'
export default defineComponent({
name: 'ChilledMusic',
props: {
play: {
type: Boolean,
required: true
}
},
setup(props) {
let chilledcow: HTMLVideoElement | null = null
onMounted(() => {
chilledcow = document.querySelector('youtube-video')
})
watchEffect(() => {
props.play ? chilledcow?.play() : chilledcow?.pause()
})
}
})
</script>

79
src/hooks/useTimer.ts Normal file
View File

@@ -0,0 +1,79 @@
import { ref, computed, watch } from '@vue/composition-api'
import { StopwatchState } from '@/types/StopwatchState'
import { notify } from '@/utils/notification'
const format = (num: number) => {
return num.toString().padStart(2, '0')
}
const formatSeconds = (seconds: number) => {
const minutes = Math.floor(seconds / 60)
const secs = seconds % 60
return `${format(minutes)}:${format(secs)}`
}
export const useTimer = () => {
const timeState = ref<StopwatchState>('stopped')
const seconds = ref(0)
const interval = ref(5)
const sessionSeconds = ref(interval.value * 60)
const isProgrammer1Turn = ref(true)
const time = computed(() => formatSeconds(seconds.value))
const session = computed(() => formatSeconds(sessionSeconds.value))
const intervalSeconds = computed(() => interval.value * 60)
let stopwatchId: number | null = null
let stopWatchSessionId: number | null = null
watch(interval, () => {
sessionSeconds.value = interval.value * 60
})
const start = () => {
timeState.value = 'started'
notify('Session started!')
stopwatchId = setInterval(() => {
seconds.value++
if (seconds.value % intervalSeconds.value === 0) {
sessionSeconds.value = intervalSeconds.value
isProgrammer1Turn.value = !isProgrammer1Turn.value
const programmer = isProgrammer1Turn.value
? 'Programmer 1'
: 'Programmer 2'
notify('Time to change', { body: `${programmer}, your turn!` })
}
}, 1000)
stopWatchSessionId = setInterval(() => {
sessionSeconds.value--
}, 1000)
}
const clear = () => {
timeState.value = 'stopped'
if (stopwatchId) {
clearInterval(stopwatchId)
}
if (stopWatchSessionId) {
clearInterval(stopWatchSessionId)
}
seconds.value = 0
sessionSeconds.value = intervalSeconds.value
isProgrammer1Turn.value = true
}
return {
interval,
start,
clear,
timeState,
time,
session,
isProgrammer1Turn
}
}

View File

@@ -33,4 +33,6 @@ button:active {
input { input {
padding: 0.5rem; padding: 0.5rem;
text-align: center;
border-radius: 0.5rem;
} }

View File

@@ -0,0 +1 @@
export type StopwatchState = 'started' | 'stopped'

View File

@@ -1,11 +1,24 @@
<template> <template>
<div class="home"> <div class="home">
<section class="brogrammers"> <section class="developers">
<DreamMaker <DreamMaker
position="1" position="1"
:is-turn="isProgrammer1Turn" :is-turn="isProgrammer1Turn"
:session="session" :session="session"
/> />
<div v-if="timeState === 'stopped'">
<label for="interval">intervale : </label>
<input
id="interval"
name="interval"
v-model.number="interval"
type="number"
step="1"
min="1"
@keypress.enter="start"
/>
minutes
</div>
<DreamMaker <DreamMaker
position="2" position="2"
:is-turn="!isProgrammer1Turn" :is-turn="!isProgrammer1Turn"
@@ -13,132 +26,43 @@
/> />
</section> </section>
<div class="global-time">{{ time }}</div> <div class="global-time">{{ time }}</div>
<div v-if="timeState === 'stopped'">
<label for="interval">Interval: </label>
<input
id="interval"
name="interval"
v-model.number="interval"
type="number"
step="1"
/>
</div>
<div class="actions"> <div class="actions">
<button v-if="timeState === 'stopped'" @click="start">play</button> <button v-show="timeState === 'stopped'" @click="start">commencer</button>
<button v-if="timeState === 'started'" @click="stop">stop</button> <button v-show="timeState === 'started'" @click="clear">arrêter</button>
</div> </div>
<youtube-video <ChilledMusic :play="timeState === 'started'" />
v-show="false"
src="https://www.youtube-nocookie.com/embed/5qap5aO4i9A"
/>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import 'youtube-video-js' import { defineComponent, onUnmounted } from '@vue/composition-api'
import { import { useTimer } from '@/hooks/useTimer'
ref,
watchEffect,
defineComponent,
onMounted,
computed,
onUnmounted
} from '@vue/composition-api'
import DreamMaker from '@/components/DreamMaker.vue' import DreamMaker from '@/components/DreamMaker.vue'
import { notify } from '@/utils/notification' import ChilledMusic from '@/components/ChilledMusic.vue'
type Stopwatch = 'stopped' | 'started'
export default defineComponent({ export default defineComponent({
name: 'Home', name: 'Home',
components: { components: {
DreamMaker DreamMaker,
ChilledMusic
}, },
setup() { setup() {
let chilledcow: HTMLVideoElement | null = null const {
const interval = ref(5) interval,
const intervalSeconds = computed(() => { start,
return interval.value * 60 clear,
}) timeState,
let stopwatchId: number | null = null time,
const isProgrammer1Turn = ref(true) session,
let stopWatchSessionId: number | null = null isProgrammer1Turn
const seconds = ref(0) } = useTimer()
const time = computed(() => {
const m = Math.floor(seconds.value / 60)
const s = seconds.value % 60
return `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
})
const sessionSeconds = ref(interval.value * 60)
const session = computed(() => {
const m = Math.floor(sessionSeconds.value / 60)
const s = sessionSeconds.value % 60
return `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
})
const timeState = ref<Stopwatch>('stopped')
const start = () => {
timeState.value = 'started'
notify('Session started!')
stopwatchId = setInterval(() => {
seconds.value++
if (seconds.value % intervalSeconds.value === 0) {
sessionSeconds.value = intervalSeconds.value
isProgrammer1Turn.value = !isProgrammer1Turn.value
const programmer = isProgrammer1Turn.value
? 'Programmer 1'
: 'Programmer 2'
notify('Time to change', { body: `${programmer}, your turn!` })
}
}, 1000)
stopWatchSessionId = setInterval(() => {
sessionSeconds.value--
}, 1000)
}
const stop = () => {
timeState.value = 'stopped'
}
onMounted(() => {
chilledcow = document.querySelector('youtube-video')
})
const clear = () => {
if (stopwatchId) {
clearInterval(stopwatchId)
}
if (stopWatchSessionId) {
clearInterval(stopWatchSessionId)
}
seconds.value = 0
sessionSeconds.value = intervalSeconds.value
}
onUnmounted(clear) onUnmounted(clear)
watchEffect(() => {
switch (timeState.value) {
case 'started':
if (chilledcow) {
chilledcow.play()
}
break
case 'stopped':
if (chilledcow) {
chilledcow.pause()
}
clear()
}
})
return { return {
interval, interval,
start, start,
stop, clear,
timeState, timeState,
time, time,
session, session,
@@ -155,7 +79,8 @@ export default defineComponent({
flex-direction: column; flex-direction: column;
justify-content: space-around; justify-content: space-around;
} }
.brogrammers {
.developers {
display: flex; display: flex;
justify-content: space-around; justify-content: space-around;
flex-wrap: wrap; flex-wrap: wrap;
@@ -163,6 +88,5 @@ export default defineComponent({
.global-time { .global-time {
font-size: calc(3em + 10vw); font-size: calc(3em + 10vw);
padding: 1rem;
} }
</style> </style>