feat: Add preview screen before encoding

This commit is contained in:
Tixie 2019-04-05 22:14:27 +02:00
parent da154ef249
commit 318c4ef7e1
7 changed files with 159 additions and 36 deletions

View file

@ -56,6 +56,45 @@
background: var(--btn-primary); background: var(--btn-primary);
} }
/* Loading state
-------------------------------------------------------------- */
.btn--loading,
.btn--loading:link,
.btn--loading:visited {
position: relative;
color: transparent;
pointer-events: none;
}
.btn--loading svg {
display: none;
}
.btn--loading::after {
position: absolute;
top: calc(50% - (2em / 2));
left: calc(50% - (2em / 2));
display: block;
width: 2em;
height: 2em;
border: .2rem solid transparent;
border-color: transparent transparent #fff #fff;
border-radius: 42rem;
content: "";
animation: spinAround 500ms infinite linear;
}
@keyframes spinAround {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
/* size /* size
-------------------------------------------------------------- */ -------------------------------------------------------------- */

View file

@ -6,6 +6,7 @@
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
z-index: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;

View file

@ -47,6 +47,7 @@
flex-direction: row; flex-direction: row;
margin-top: auto; margin-top: auto;
margin-bottom: auto; margin-bottom: auto;
padding-left: 2rem;
} }
.capture-progress { .capture-progress {
@ -105,12 +106,13 @@
.download { .download {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding-right: 2rem;
} }
.download-btn, .download-btn,
.download-btn:visited { .download-btn:visited {
margin: auto 0; margin: auto 0;
margin-right: 2rem; margin-right: auto;
margin-left: auto; margin-left: auto;
width: auto; width: auto;
} }

View file

@ -3,6 +3,7 @@ import VueRouter from 'vue-router'
import Welcome from '/views/screens/welcome' import Welcome from '/views/screens/welcome'
import Capture from '/views/screens/capture' import Capture from '/views/screens/capture'
import Preview from '/views/screens/preview'
import Download from '/views/screens/download' import Download from '/views/screens/download'
Vue.use(VueRouter) Vue.use(VueRouter)
@ -12,6 +13,7 @@ export default new VueRouter({
routes: [ routes: [
{ name: 'home', path: '/', component: Welcome }, { name: 'home', path: '/', component: Welcome },
{ name: 'capture', path: '/capture', component: Capture }, { name: 'capture', path: '/capture', component: Capture },
{ name: 'preview', path: '/preview', component: Preview },
{ name: 'download', path: '/download', component: Download } { name: 'download', path: '/download', component: Download }
] ]
}) })

View file

@ -9,18 +9,14 @@
<video ref="preview" class="preview-visual" :class="{ 'preview--flip': shouldFlip }" preload="yes" autoplay muted playsinline webkit-playsinline></video> <video ref="preview" class="preview-visual" :class="{ 'preview--flip': shouldFlip }" preload="yes" autoplay muted playsinline webkit-playsinline></video>
</div> </div>
<button class="capture-btn" :class="{ 'capture-btn--capturing': capturing }" :disabled="!camera || encoding" @click.prevent="startCapturing">Capture</button> <button class="capture-btn" :class="{ 'capture-btn--capturing': capturing }" :disabled="!camera" @click.prevent="startCapturing">Capture</button>
<encoding-overlay v-if="encoding" :value="encodingProgress"></encoding-overlay>
</div> </div>
</template> </template>
<script> <script>
import captureOptions from '/views/components/capture-options' import captureOptions from '/views/components/capture-options'
import captureProgress from '/views/components/capture-progress' import captureProgress from '/views/components/capture-progress'
import encodingOverlay from '/views/components/encoding'
import { capture } from '/services/capture.js' import { capture } from '/services/capture.js'
import { encode } from '/services/encode.js'
import 'objectFitPolyfill' import 'objectFitPolyfill'
@ -30,14 +26,11 @@ export default {
name: 'capture', name: 'capture',
components: { components: {
captureOptions, captureOptions,
captureProgress, captureProgress
encodingOverlay
}, },
data: () => ({ data: () => ({
capturing: false, capturing: false,
capturingProgress: 0, capturingProgress: 0
encoding: false,
encodingProgress: 0
}), }),
computed: { computed: {
...mapState([ ...mapState([
@ -82,28 +75,8 @@ export default {
this.capturing = false this.capturing = false
this.capturingProgress = 0 this.capturingProgress = 0
this.$store.commit('updateCapture', captureData) this.$store.commit('updateCapture', captureData)
this.startEncoding() this.$router.push({ name: 'preview' })
}) // this.startEncoding()
},
startEncoding () {
this.encoding = true
const encoding = encode(this.capture)
encoding.once('error', error => {
console.error(error)
this.encoding = false
this.encodingProgress = 0
})
encoding.on('progress', value => {
this.encodingProgress = value
})
encoding.once('done', gif => {
this.encoding = false
this.encodingProgress = 0
this.$store.commit('updateGif', gif)
this.$router.push({ name: 'download' })
}) })
}, },
async ensureCamera () { async ensureCamera () {

View file

@ -26,8 +26,11 @@ export default {
'gif' 'gif'
]), ]),
timestamp () { timestamp () {
if (this.gif) {
return this.gif.createdAt.getTime() return this.gif.createdAt.getTime()
} }
return null
}
}, },
methods: { methods: {
back () { back () {
@ -37,9 +40,9 @@ export default {
created () { created () {
if (!this.gif) { if (!this.gif) {
this.$router.push({ name: 'home' }) this.$router.push({ name: 'home' })
} } else {
this.objectUrl = URL.createObjectURL(this.gif.blob) this.objectUrl = URL.createObjectURL(this.gif.blob)
}
}, },
destroyed () { destroyed () {
URL.revokeObjectURL(this.objectUrl) URL.revokeObjectURL(this.objectUrl)

View file

@ -0,0 +1,103 @@
<template lang="html">
<div class="download">
<div class="options">
<span></span>
<button class="options__btn" @click="back"> back</button>
</div>
<div class="preview">
<canvas ref="previewCanvas" class="preview-visual"></canvas>
</div>
<button class="download-btn btn btn--primary w100" :class="{ 'btn--loading': encoding }" :disabled="encoding" @click="startEncoding">Generate GIF</button>
<encoding-overlay v-if="encoding" :value="encodingProgress"></encoding-overlay>
</div>
</template>
<script>
import { encode } from '/services/encode.js'
import encodingOverlay from '/views/components/encoding'
import { mapState } from 'vuex'
export default {
name: 'preview',
components: {
encodingOverlay
},
data: () => ({
encoding: false,
encodingProgress: 0,
previewTimeout: null
}),
computed: {
...mapState([
'camera',
'capture'
])
},
methods: {
back () {
this.$router.push({ name: 'capture' })
},
backHome () {
this.$router.push({ name: 'home' })
},
printPreview (context, frameNumber) {
this.previewTimeout = setTimeout(() => {
// Looper
frameNumber < (this.capture.imageDataList.length - 1) ? frameNumber++ : frameNumber = 0
// Printer
const image = this.capture.imageDataList[frameNumber]
context.putImageData(image, 0, 0)
this.printPreview(context, frameNumber)
}, this.capture.delayTime)
},
startPreview () {
if (!this.capture) {
this.backHome()
} else {
const canvas = this.$refs.previewCanvas
canvas.width = this.capture.imageWidth
canvas.height = this.capture.imageHeight
const canvasContext = canvas.getContext('2d')
this.printPreview(canvasContext, 0)
}
},
startEncoding () {
this.encoding = true
const encoding = encode(this.capture)
encoding.once('error', error => {
console.error(error)
this.encoding = false
this.encodingProgress = 0
})
encoding.on('progress', value => {
this.encodingProgress = value
})
encoding.once('done', gif => {
this.encoding = false
this.encodingProgress = 0
this.$store.commit('updateGif', gif)
this.$router.push({ name: 'download' })
})
}
},
created () {
if (!this.capture) {
this.backHome()
}
},
mounted () {
this.startPreview()
},
destroyed () {
window.clearTimeout(this.previewTimeout)
}
}
</script>