Update:Audio player drag cursor to seek #457

This commit is contained in:
advplyr
2023-03-04 16:26:37 -06:00
parent f8ce0b8355
commit 317f00e1b8
2 changed files with 65 additions and 95 deletions
+62 -95
View File
@@ -15,7 +15,7 @@
<p class="top-4 absolute left-0 right-0 mx-auto text-center uppercase tracking-widest text-opacity-75" style="font-size: 10px" :class="{ 'text-success': isLocalPlayMethod, 'text-accent': !isLocalPlayMethod }">{{ isDirectPlayMethod ? 'Direct' : isLocalPlayMethod ? 'Local' : 'Transcode' }}</p> <p class="top-4 absolute left-0 right-0 mx-auto text-center uppercase tracking-widest text-opacity-75" style="font-size: 10px" :class="{ 'text-success': isLocalPlayMethod, 'text-accent': !isLocalPlayMethod }">{{ isDirectPlayMethod ? 'Direct' : isLocalPlayMethod ? 'Local' : 'Transcode' }}</p>
</div> </div>
<div v-if="useChapterTrack && useTotalTrack && showFullscreen" class="absolute total-track w-full z-30" :class="showFullscreen ? 'px-6' : 'px-3'"> <div v-if="useChapterTrack && useTotalTrack && showFullscreen" class="absolute total-track w-full z-30 px-6">
<div class="flex"> <div class="flex">
<p class="font-mono text-white text-opacity-90" style="font-size: 0.8rem">{{ currentTimePretty }}</p> <p class="font-mono text-white text-opacity-90" style="font-size: 0.8rem">{{ currentTimePretty }}</p>
<div class="flex-grow" /> <div class="flex-grow" />
@@ -80,18 +80,17 @@
</div> </div>
</div> </div>
<div id="playerTrack" class="absolute left-0 w-full" :class="showFullscreen ? 'px-6' : 'px-3'"> <div id="playerTrack" class="absolute left-0 w-full px-6">
<div class="flex pb-0.5"> <div class="flex">
<p class="font-mono text-white text-opacity-90" style="font-size: 0.8rem" ref="currentTimestamp">0:00</p> <p class="font-mono text-white text-opacity-90" style="font-size: 0.8rem" ref="currentTimestamp">0:00</p>
<div class="flex-grow" /> <div class="flex-grow" />
<p class="font-mono text-white text-opacity-90" style="font-size: 0.8rem">{{ timeRemainingPretty }}</p> <p class="font-mono text-white text-opacity-90" style="font-size: 0.8rem">{{ timeRemainingPretty }}</p>
</div> </div>
<div ref="track" class="h-1.5 w-full bg-gray-500 bg-opacity-50 relative rounded-full" :class="{ 'animate-pulse': isLoading }" @touchstart="touchstartTrack" @click="clickTrack"> <div ref="track" class="h-1.5 w-full bg-gray-500 bg-opacity-50 relative rounded-full" :class="{ 'animate-pulse': isLoading }" @click.stop>
<div ref="readyTrack" class="h-full bg-gray-600 absolute top-0 left-0 pointer-events-none rounded-full" /> <div ref="readyTrack" class="h-full bg-gray-600 absolute top-0 left-0 rounded-full pointer-events-none" />
<div ref="bufferedTrack" class="h-full bg-gray-500 absolute top-0 left-0 pointer-events-none rounded-full" /> <div ref="bufferedTrack" class="h-full bg-gray-500 absolute top-0 left-0 rounded-full pointer-events-none" />
<div ref="playedTrack" class="h-full bg-gray-200 absolute top-0 left-0 pointer-events-none rounded-full" /> <div ref="playedTrack" class="h-full bg-gray-200 absolute top-0 left-0 rounded-full pointer-events-none" />
<div ref="draggingTrack" class="h-full bg-warning bg-opacity-25 absolute top-0 left-0 pointer-events-none rounded-full" /> <div ref="trackCursor" class="rounded-full bg-gray-200 absolute pointer-events-auto" :class="{ 'opacity-0': lockUi || !showFullscreen, 'h-3.5 w-3.5 -top-1': isDraggingCursor, 'h-3 w-3 -top-0.75': !isDraggingCursor }" @touchstart="touchstartCursor" />
<div ref="trackCursor" class="h-3.5 w-3.5 rounded-full bg-gray-200 absolute -top-1 pointer-events-none" :class="{ 'opacity-0': lockUi || !showFullscreen }" />
</div> </div>
</div> </div>
</div> </div>
@@ -149,8 +148,10 @@ export default {
useTotalTrack: true, useTotalTrack: true,
lockUi: false, lockUi: false,
isLoading: false, isLoading: false,
touchTrackStart: false, isDraggingCursor: false,
dragPercent: 0, draggingTouchStartX: 0,
draggingTouchStartTime: 0,
draggingCurrentTime: 0,
syncStatus: 0, syncStatus: 0,
showMoreMenuDialog: false, showMoreMenuDialog: false,
coverRgb: 'rgb(55, 56, 56)', coverRgb: 'rgb(55, 56, 56)',
@@ -317,17 +318,20 @@ export default {
return this.$secondsToTimestamp(this.totalDuration) return this.$secondsToTimestamp(this.totalDuration)
}, },
currentTimePretty() { currentTimePretty() {
return this.$secondsToTimestamp(this.currentTime / this.currentPlaybackRate) let currentTimeToUse = this.isDraggingCursor ? this.draggingCurrentTime : this.currentTime
return this.$secondsToTimestamp(currentTimeToUse / this.currentPlaybackRate)
}, },
timeRemaining() { timeRemaining() {
let currentTimeToUse = this.isDraggingCursor ? this.draggingCurrentTime : this.currentTime
if (this.useChapterTrack && this.currentChapter) { if (this.useChapterTrack && this.currentChapter) {
var currChapTime = this.currentTime - this.currentChapter.start var currChapTime = currentTimeToUse - this.currentChapter.start
return (this.currentChapterDuration - currChapTime) / this.currentPlaybackRate return (this.currentChapterDuration - currChapTime) / this.currentPlaybackRate
} }
return this.totalTimeRemaining return this.totalTimeRemaining
}, },
totalTimeRemaining() { totalTimeRemaining() {
return (this.totalDuration - this.currentTime) / this.currentPlaybackRate let currentTimeToUse = this.isDraggingCursor ? this.draggingCurrentTime : this.currentTime
return (this.totalDuration - currentTimeToUse) / this.currentPlaybackRate
}, },
totalTimeRemainingPretty() { totalTimeRemainingPretty() {
if (this.totalTimeRemaining < 0) { if (this.totalTimeRemaining < 0) {
@@ -341,10 +345,6 @@ export default {
} }
return '-' + this.$secondsToTimestamp(this.timeRemaining) return '-' + this.$secondsToTimestamp(this.timeRemaining)
}, },
timeLeftInChapter() {
if (!this.currentChapter) return 0
return this.currentChapter.end - this.currentTime
},
sleepTimeRemainingPretty() { sleepTimeRemainingPretty() {
if (!this.sleepTimeRemaining) return '0s' if (!this.sleepTimeRemaining) return '0s'
var secondsRemaining = Math.round(this.sleepTimeRemaining) var secondsRemaining = Math.round(this.sleepTimeRemaining)
@@ -391,11 +391,6 @@ export default {
this.showFullscreen = false this.showFullscreen = false
} }
}, },
async touchstartTrack(e) {
await this.$hapticsImpact()
if (!e || !e.touches || !this.$refs.track || !this.showFullscreen || this.lockUi) return
this.touchTrackStart = true
},
async selectChapter(chapter) { async selectChapter(chapter) {
await this.$hapticsImpact() await this.$hapticsImpact()
this.seek(chapter.start) this.seek(chapter.start)
@@ -507,12 +502,13 @@ export default {
console.error('No timestamp el') console.error('No timestamp el')
return return
} }
let currentTime = this.currentTime / this.currentPlaybackRate
let currentTime = this.isDraggingCursor ? this.draggingCurrentTime : this.currentTime
if (this.useChapterTrack && this.currentChapter) { if (this.useChapterTrack && this.currentChapter) {
const currChapTime = Math.max(0, this.currentTime - this.currentChapter.start) currentTime = Math.max(0, currentTime - this.currentChapter.start)
currentTime = currChapTime / this.currentPlaybackRate
} }
ts.innerText = this.$secondsToTimestamp(currentTime)
ts.innerText = this.$secondsToTimestamp(currentTime / this.currentPlaybackRate)
}, },
timeupdate() { timeupdate() {
if (!this.$refs.playedTrack) { if (!this.$refs.playedTrack) {
@@ -534,22 +530,25 @@ export default {
}, },
updateTrack() { updateTrack() {
// Update progress track UI // Update progress track UI
let percentDone = this.currentTime / this.totalDuration let currentTimeToUse = this.isDraggingCursor ? this.draggingCurrentTime : this.currentTime
let percentDone = currentTimeToUse / this.totalDuration
const totalPercentDone = percentDone const totalPercentDone = percentDone
let bufferedPercent = this.bufferedTime / this.totalDuration let bufferedPercent = this.bufferedTime / this.totalDuration
const totalBufferedPercent = bufferedPercent const totalBufferedPercent = bufferedPercent
if (this.useChapterTrack && this.currentChapter) { if (this.useChapterTrack && this.currentChapter) {
const currChapTime = this.currentTime - this.currentChapter.start const currChapTime = currentTimeToUse - this.currentChapter.start
percentDone = currChapTime / this.currentChapterDuration percentDone = currChapTime / this.currentChapterDuration
bufferedPercent = Math.max(0, Math.min(1, (this.bufferedTime - this.currentChapter.start) / this.currentChapterDuration)) bufferedPercent = Math.max(0, Math.min(1, (this.bufferedTime - this.currentChapter.start) / this.currentChapterDuration))
} }
const ptWidth = Math.round(percentDone * this.trackWidth) const ptWidth = Math.round(percentDone * this.trackWidth)
this.$refs.playedTrack.style.width = ptWidth + 'px' this.$refs.playedTrack.style.width = ptWidth + 'px'
this.$refs.bufferedTrack.style.width = Math.round(bufferedPercent * this.trackWidth) + 'px' this.$refs.bufferedTrack.style.width = Math.round(bufferedPercent * this.trackWidth) + 'px'
if (this.$refs.trackCursor) { if (this.$refs.trackCursor) {
this.$refs.trackCursor.style.left = ptWidth - 8 + 'px' const cursorShift = this.isDraggingCursor ? 7 : 6
this.$refs.trackCursor.style.left = ptWidth - cursorShift + 'px'
} }
if (this.useChapterTrack) { if (this.useChapterTrack) {
@@ -578,27 +577,14 @@ export default {
this.$refs.playedTrack.classList.add('bg-yellow-300') this.$refs.playedTrack.classList.add('bg-yellow-300')
} }
}, },
clickTrack(e) { async touchstartCursor(e) {
if (this.isLoading || this.lockUi) return if (!e || !e.touches || !this.$refs.track || !this.showFullscreen || this.lockUi) return
if (!this.showFullscreen) { await this.$hapticsImpact()
// Track not clickable on mini-player this.isDraggingCursor = true
return this.draggingTouchStartX = e.touches[0].pageX
} this.draggingTouchStartTime = this.currentTime
if (e) e.stopPropagation() this.draggingCurrentTime = this.currentTime
this.updateTrack()
var offsetX = e.offsetX
var perc = offsetX / this.trackWidth
var time = 0
if (this.useChapterTrack && this.currentChapter) {
time = perc * this.currentChapterDuration + this.currentChapter.start
} else {
time = perc * this.totalDuration
}
if (isNaN(time) || time === null) {
console.error('Invalid time', perc, time)
return
}
this.seek(time)
}, },
async playPauseClick() { async playPauseClick() {
await this.$hapticsImpact() await this.$hapticsImpact()
@@ -651,24 +637,11 @@ export default {
touchend(e) { touchend(e) {
if (!e.changedTouches) return if (!e.changedTouches) return
if (this.touchTrackStart) { if (this.isDraggingCursor) {
var touch = e.changedTouches[0] if (this.draggingCurrentTime !== this.currentTime) {
const touchOnTrackPos = touch.pageX - 12 this.seek(this.draggingCurrentTime)
const dragPercent = Math.max(0, Math.min(1, touchOnTrackPos / this.trackWidth))
var seekToTime = 0
if (this.useChapterTrack && this.currentChapter) {
const currChapTime = dragPercent * this.currentChapterDuration
seekToTime = this.currentChapter.start + currChapTime
} else {
seekToTime = dragPercent * this.totalDuration
} }
this.seek(seekToTime) this.isDraggingCursor = false
if (this.$refs.draggingTrack) {
this.$refs.draggingTrack.style.width = '0px'
}
this.touchTrackStart = false
} else if (this.showFullscreen) { } else if (this.showFullscreen) {
this.touchEndY = e.changedTouches[0].screenY this.touchEndY = e.changedTouches[0].screenY
var touchDuration = Date.now() - this.touchStartTime var touchDuration = Date.now() - this.touchStartTime
@@ -680,29 +653,24 @@ export default {
} }
}, },
touchmove(e) { touchmove(e) {
if (!this.touchTrackStart) return if (!this.isDraggingCursor || !e.touches) return
var touch = e.touches[0] const distanceMoved = e.touches[0].pageX - this.draggingTouchStartX
const touchOnTrackPos = touch.pageX - 12 let duration = this.totalDuration
const dragPercent = Math.max(0, Math.min(1, touchOnTrackPos / this.trackWidth)) let minTime = 0
this.dragPercent = dragPercent let maxTime = duration
if (this.useChapterTrack && this.currentChapter) {
if (this.$refs.draggingTrack) { duration = this.currentChapterDuration
this.$refs.draggingTrack.style.width = this.dragPercent * this.trackWidth + 'px' minTime = this.currentChapter.start
maxTime = minTime + duration
} }
var ts = this.$refs.currentTimestamp const timePerPixel = duration / this.trackWidth
if (ts) { const newTime = this.draggingTouchStartTime + timePerPixel * distanceMoved
var currTimeStr = '' this.draggingCurrentTime = Math.min(maxTime, Math.max(minTime, newTime))
if (this.useChapterTrack && this.currentChapter) {
const currChapTime = dragPercent * this.currentChapterDuration this.updateTimestamp()
currTimeStr = this.$secondsToTimestamp(currChapTime) this.updateTrack()
} else {
const dragTime = dragPercent * this.totalDuration
currTimeStr = this.$secondsToTimestamp(dragTime)
}
ts.innerText = currTimeStr
}
}, },
async clickMenuAction(action) { async clickMenuAction(action) {
await this.$hapticsImpact() await this.$hapticsImpact()
@@ -848,7 +816,7 @@ export default {
document.documentElement.style.setProperty('--cover-image-height', coverHeight + 'px') document.documentElement.style.setProperty('--cover-image-height', coverHeight + 'px')
document.documentElement.style.setProperty('--cover-image-width-collapsed', coverImageWidthCollapsed + 'px') document.documentElement.style.setProperty('--cover-image-width-collapsed', coverImageWidthCollapsed + 'px')
document.documentElement.style.setProperty('--cover-image-height-collapsed', 46 + 'px') document.documentElement.style.setProperty('--cover-image-height-collapsed', 46 + 'px')
document.documentElement.style.setProperty('--title-author-left-offset-collapsed', 24 + coverImageWidthCollapsed + 'px') document.documentElement.style.setProperty('--title-author-left-offset-collapsed', 30 + coverImageWidthCollapsed + 'px')
}, },
minimizePlayerEvt() { minimizePlayerEvt() {
this.collapseFullscreen() this.collapseFullscreen()
@@ -915,7 +883,7 @@ export default {
--cover-image-height: 0px; --cover-image-height: 0px;
--cover-image-width-collapsed: 46px; --cover-image-width-collapsed: 46px;
--cover-image-height-collapsed: 46px; --cover-image-height-collapsed: 46px;
--title-author-left-offset-collapsed: 70px; --title-author-left-offset-collapsed: 80px;
} }
.playerContainer { .playerContainer {
@@ -942,7 +910,7 @@ export default {
.cover-wrapper { .cover-wrapper {
bottom: 68px; bottom: 68px;
left: 12px; left: 24px;
height: var(--cover-image-height-collapsed); height: var(--cover-image-height-collapsed);
width: var(--cover-image-width-collapsed); width: var(--cover-image-width-collapsed);
transition: all 0.25s cubic-bezier(0.39, 0.575, 0.565, 1); transition: all 0.25s cubic-bezier(0.39, 0.575, 0.565, 1);
@@ -999,9 +967,8 @@ export default {
#playerControls { #playerControls {
transition: all 0.15s cubic-bezier(0.39, 0.575, 0.565, 1); transition: all 0.15s cubic-bezier(0.39, 0.575, 0.565, 1);
transition-property: width, bottom; transition-property: width, bottom;
width: 140px; width: 128px;
padding-left: 12px; padding-right: 24px;
padding-right: 12px;
bottom: 70px; bottom: 70px;
} }
#playerControls .jump-icon { #playerControls .jump-icon {
@@ -1019,7 +986,7 @@ export default {
width: 40px; width: 40px;
min-width: 40px; min-width: 40px;
min-height: 40px; min-height: 40px;
margin: 0px 14px; margin: 0px 7px;
} }
#playerControls .play-btn .material-icons { #playerControls .play-btn .material-icons {
transition: all 0.15s cubic-bezier(0.39, 0.575, 0.565, 1); transition: all 0.15s cubic-bezier(0.39, 0.575, 0.565, 1);
+3
View File
@@ -50,6 +50,9 @@ module.exports = {
}, },
minHeight: { minHeight: {
'12': '3rem' '12': '3rem'
},
spacing: {
'0.75': '0.1875rem'
} }
} }
}, },