Commit 2481761d by Jonathan Thomas

Improved editClip to scroll to edited clip (up or down). Refactored how…

Improved editClip to scroll to edited clip (up or down). Refactored how scrolling to clips work. Wait for thumbnail to load first. Reset position when selecting new files. Don't regenerate thumbnail when editing clip. Loop playback. Pause video when trimming clip. Clear errors when editing project.
parent 9b9351d0
...@@ -24,11 +24,9 @@ ...@@ -24,11 +24,9 @@
{{ (clip.end - clip.start).toFixed(1) }} Seconds {{ (clip.end - clip.start).toFixed(1) }} Seconds
</div> </div>
<img @click="toggleSelection(clip)" :class="getSelectedClass(clip)" class="img-fluid img-thumbnail clip-thumbnail" :title="clip.name" :src="clip.thumbnail"/> <img @click="toggleSelection(clip)" :class="getSelectedClass(clip)" class="img-fluid img-thumbnail clip-thumbnail" @load="thumbnailLoaded($event, clip)" :title="clip.name" :src="clip.thumbnail"/>
</div> </div>
</div> </div>
<div ref="bottom"></div>
</div> </div>
</div> </div>
</template> </template>
...@@ -53,8 +51,11 @@ export default { ...@@ -53,8 +51,11 @@ export default {
let pos = 0.0 let pos = 0.0
for (let clip of reordered_clips) { for (let clip of reordered_clips) {
clip.position = pos clip.position = pos
this.editClip(clip) let payload = { data: clip, latest: false, thumbnail: false }
if (clip.id == clipObj.id) {
payload.latest = true
}
this.editClip(payload)
pos += (clip.end - clip.start) pos += (clip.end - clip.start)
} }
}, },
...@@ -82,14 +83,24 @@ export default { ...@@ -82,14 +83,24 @@ export default {
} }
}, },
getSelectedClass(clipObj) { getSelectedClass(clipObj) {
let class_value = ''
if (this.preview.clip && clipObj.id == this.preview.clip.id) { if (this.preview.clip && clipObj.id == this.preview.clip.id) {
return 'selected' class_value = ' selected'
} else { }
return '' if (this.scrollToClip == clipObj) {
class_value += ' scroll-to-me'
}
return class_value
},
thumbnailLoaded(e, clipObj) {
let el = e.target
if (clipObj == this.scrollToClip) {
el.scrollIntoView({behavior: 'smooth', block: 'end'})
this.setScrollToClip(null)
} }
}, },
...mapActions(['loadClips', 'createClip', 'deleteClip', 'editClip']), ...mapActions(['loadClips', 'createClip', 'deleteClip', 'editClip']),
...mapMutations((['setPreviewClip', 'setClips'])) ...mapMutations((['setPreviewClip', 'setClips', 'setScrollToClip']))
}, },
computed: { computed: {
thumbnailedClips() { thumbnailedClips() {
...@@ -100,10 +111,16 @@ export default { ...@@ -100,10 +111,16 @@ export default {
}, },
watch: { watch: {
scrollToClip() { scrollToClip() {
if (this.scrollToClip) {
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.bottom.scrollIntoView({behavior: 'smooth', block: 'end'}) if (document.querySelector(".scroll-to-me").complete) {
// Scroll if image is already loaded
document.querySelector(".scroll-to-me").scrollIntoView({behavior: 'smooth', block: 'end'})
this.setScrollToClip(null)
}
}) })
} }
}
}, },
async mounted() { async mounted() {
this.setClips([]) this.setClips([])
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<video ref="video" v-if="!isImage && hasPreviewFile" @timeupdate="videoTimeUpdate" @pause="togglePause" @play="togglePause" preload="" poster="" class="video-responsive"> <video ref="video" v-if="!isImage && hasPreviewFile" @loadeddata="videoLoaded" @timeupdate="videoTimeUpdate" @pause="togglePause" @play="togglePause" loop preload="" poster="" class="video-responsive">
<source :type="previewFormat" :src="preview.file.media"> <source :type="previewFormat" :src="preview.file.media">
</video> </video>
<img v-if="isImage && hasPreviewFile" :src="preview.file.media" class="img-fluid img-thumbnail" /> <img v-if="isImage && hasPreviewFile" :src="preview.file.media" class="img-fluid img-thumbnail" />
...@@ -109,15 +109,29 @@ export default { ...@@ -109,15 +109,29 @@ export default {
}, },
videoTimeUpdate() { videoTimeUpdate() {
if (this.$refs.video) { if (this.$refs.video) {
let playback_percent = (this.$refs.video.currentTime / this.$refs.video.duration) let playback_percent = this.$refs.video.currentTime / this.$refs.video.duration;
if (!this.$refs.video.paused && playback_percent >= this.preview.end) {
// Exceeded end of clip
this.$refs.video.currentTime = this.preview.start * this.$refs.video.duration
}
// Update playback %, because it might have changed
playback_percent = (this.$refs.video.currentTime / this.$refs.video.duration)
this.setPreviewPosition(playback_percent) this.setPreviewPosition(playback_percent)
} }
}, },
videoLoaded() {
if (this.$refs.video && this.preview.clip) {
this.$refs.video.currentTime = this.preview.clip.start
}
},
startDrag(e, marker) { startDrag(e, marker) {
if (e) { if (e) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
} }
if (this.$refs.video) {
this.$refs.video.pause()
}
this.dragging_marker = marker this.dragging_marker = marker
}, },
endDrag() { endDrag() {
......
...@@ -99,6 +99,7 @@ export default { ...@@ -99,6 +99,7 @@ export default {
}, },
methods: { methods: {
editProject(project) { editProject(project) {
this.clearErrors()
this.$router.push(`/projects/${project.id}`) this.$router.push(`/projects/${project.id}`)
}, },
showNewProjectModal() { showNewProjectModal() {
...@@ -134,7 +135,7 @@ export default { ...@@ -134,7 +135,7 @@ export default {
this.deletedProject = null this.deletedProject = null
}, },
...mapActions(['loadProjects', 'createProject', 'deleteProject']), ...mapActions(['loadProjects', 'createProject', 'deleteProject']),
...mapMutations(['setProject']) ...mapMutations(['setProject', 'clearErrors'])
}, },
computed: { computed: {
...mapState(['projects']) ...mapState(['projects'])
......
...@@ -44,6 +44,9 @@ export default createStore({ ...@@ -44,6 +44,9 @@ export default createStore({
clearErrors(state) { clearErrors(state) {
state.errors = [] state.errors = []
}, },
setScrollToClip(state, clipObj) {
state.scrollToClip = clipObj
},
setUser(state, user) { setUser(state, user) {
state.user = user state.user = user
}, },
...@@ -116,6 +119,7 @@ export default createStore({ ...@@ -116,6 +119,7 @@ export default createStore({
state.preview.clip = null state.preview.clip = null
state.preview.start = 0.0 state.preview.start = 0.0
state.preview.end = 1.0 state.preview.end = 1.0
state.preview.position = 0.0
if (state.preview.file) { if (state.preview.file) {
state.preview.length = (state.preview.end - state.preview.start) * state.preview.length = (state.preview.end - state.preview.start) *
fixImageDuration(state.preview.file.json.duration) fixImageDuration(state.preview.file.json.duration)
...@@ -134,6 +138,7 @@ export default createStore({ ...@@ -134,6 +138,7 @@ export default createStore({
state.preview.file = null state.preview.file = null
state.preview.start = 0.0 state.preview.start = 0.0
state.preview.end = 1.0 state.preview.end = 1.0
state.preview.position = 0.0
} }
if (state.preview.file) { if (state.preview.file) {
...@@ -256,13 +261,17 @@ export default createStore({ ...@@ -256,13 +261,17 @@ export default createStore({
commit('addError', err.response.data) commit('addError', err.response.data)
} }
}, },
async editClip({dispatch, commit}, clipObj) { async editClip({dispatch, commit}, payload) {
try { try {
await instance.patch(`${clipObj.url}`, clipObj) await instance.patch(`${payload.data.url}`, payload.data)
commit('setClip', clipObj) commit('setClip', payload.data)
let fps = clipObj.json.reader.fps.num / clipObj.json.reader.fps.den let fps = payload.data.json.reader.fps.num / payload.data.json.reader.fps.den
let thumbnail_payload = { obj: clipObj, frame: clipObj.start * fps, latest: true } let thumbnail_payload = { obj: payload.data, frame: payload.data.start * fps, latest: payload.latest }
dispatch('attachThumbnail', thumbnail_payload) if (payload.thumbnail) {
dispatch('attachThumbnail', thumbnail_payload)
} else if (payload.latest) {
commit('setScrollToClip', payload.data)
}
} catch(err) { } catch(err) {
commit('addError', err.response.data) commit('addError', err.response.data)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment