Merge pull request #1767 from FreedomBen/add-more-backwards-forward-options

Expand time interval options for jump controls
This commit is contained in:
advplyr
2026-01-29 17:38:42 -06:00
committed by GitHub
5 changed files with 96 additions and 86 deletions
+17 -6
View File
@@ -70,14 +70,20 @@
<div id="playerControls" class="absolute right-0 bottom-0 mx-auto" style="max-width: 414px">
<div class="flex items-center max-w-full" :class="playerSettings.lockUi ? 'justify-center' : 'justify-between'">
<span v-show="showFullscreen && !playerSettings.lockUi" class="material-symbols next-icon text-fg cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpChapterStart">first_page</span>
<span v-show="!playerSettings.lockUi" class="material-symbols jump-icon text-fg cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpBackwards">{{ jumpBackwardsIcon }}</span>
<div v-show="!playerSettings.lockUi" class="jump-icon text-fg cursor-pointer flex flex-col items-center" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpBackwards">
<span class="material-symbols text-3xl leading-none">replay</span>
<span v-if="showFullscreen" class="jump-label text-[10px] font-semibold leading-tight">{{ jumpBackwardsLabel }}</span>
</div>
<div class="play-btn cursor-pointer shadow-sm flex items-center justify-center rounded-full text-primary mx-4 relative overflow-hidden" :style="{ backgroundColor: coverRgb }" :class="{ 'animate-spin': seekLoading }" @mousedown.prevent @mouseup.prevent @click.stop="playPauseClick">
<div v-if="!coverBgIsLight" class="absolute top-0 left-0 w-full h-full bg-white bg-opacity-20 pointer-events-none" />
<span v-if="!isLoading" class="material-symbols fill" :class="{ 'text-white': coverRgb && !coverBgIsLight }">{{ seekLoading ? 'autorenew' : !isPlaying ? 'play_arrow' : 'pause' }}</span>
<widgets-spinner-icon v-else class="h-8 w-8" />
</div>
<span v-show="!playerSettings.lockUi" class="material-symbols jump-icon text-fg cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpForward">{{ jumpForwardIcon }}</span>
<div v-show="!playerSettings.lockUi" class="jump-icon text-fg cursor-pointer flex flex-col items-center" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpForward">
<span class="material-symbols text-3xl leading-none">forward_media</span>
<span v-if="showFullscreen" class="jump-label text-[10px] font-semibold leading-tight">{{ jumpForwardLabel }}</span>
</div>
<span v-show="showFullscreen && !playerSettings.lockUi" class="material-symbols next-icon text-fg cursor-pointer" :class="nextChapter && !isLoading ? 'text-opacity-75' : 'text-opacity-10'" @click.stop="jumpNextChapter">last_page</span>
</div>
</div>
@@ -110,6 +116,7 @@ import { AbsAudioPlayer } from '@/plugins/capacitor'
import { Dialog } from '@capacitor/dialog'
import { FastAverageColor } from 'fast-average-color'
import WrappingMarquee from '@/assets/WrappingMarquee.js'
import jumpLabelMixin from '@/mixins/jumpLabel'
export default {
props: {
@@ -121,6 +128,7 @@ export default {
sleepTimeRemaining: Number,
serverLibraryItemId: String
},
mixins: [jumpLabelMixin],
data() {
return {
windowHeight: 0,
@@ -221,11 +229,11 @@ export default {
return items
},
jumpForwardIcon() {
return this.$store.getters['globals/getJumpForwardIcon'](this.jumpForwardTime)
jumpForwardLabel() {
return this.getJumpLabel(this.jumpForwardTime)
},
jumpBackwardsIcon() {
return this.$store.getters['globals/getJumpBackwardsIcon'](this.jumpBackwardsTime)
jumpBackwardsLabel() {
return this.getJumpLabel(this.jumpBackwardsTime)
},
jumpForwardTime() {
return this.$store.getters['getJumpForwardTime']
@@ -1091,6 +1099,9 @@ export default {
margin: 0px 0px;
font-size: 1.6rem;
}
#playerControls .jump-label {
margin-top: 2px;
}
#playerControls .play-btn {
transition: all 0.15s cubic-bezier(0.39, 0.575, 0.565, 1);
transition-property: padding, margin, height, width, min-width, min-height;
+12
View File
@@ -0,0 +1,12 @@
export default {
methods: {
getJumpLabel(seconds) {
const val = Number(seconds)
if (isNaN(val)) return ''
const useMinutes = val >= 120 // keep 60s as seconds
const key = useMinutes ? 'UnitMinutesShort' : 'UnitSecondsShort'
const unitValue = useMinutes ? val / 60 : val
return this.$getString(key, [this.$formatNumber(unitValue)])
}
}
}
+61 -42
View File
@@ -36,24 +36,24 @@
<!-- Playback settings -->
<p class="uppercase text-xs font-semibold text-fg-muted mb-2 mt-10">{{ $strings.HeaderPlaybackSettings }}</p>
<div class="py-3 flex items-center">
<p class="pr-4 w-36">{{ $strings.LabelJumpBackwardsTime }}</p>
<div @click.stop="showJumpBackwardsOptions">
<ui-text-input :value="jumpBackwardsOption" readonly append-icon="expand_more" style="width: 145px; max-width: 145px" />
</div>
</div>
<div class="py-3 flex items-center">
<p class="pr-4 w-36">{{ $strings.LabelJumpForwardsTime }}</p>
<div @click.stop="showJumpForwardOptions">
<ui-text-input :value="jumpForwardOption" readonly append-icon="expand_more" style="width: 145px; max-width: 145px" />
</div>
</div>
<div class="flex items-center py-3">
<div class="w-10 flex justify-center" @click="toggleDisableAutoRewind">
<ui-toggle-switch v-model="settings.disableAutoRewind" @input="saveSettings" />
</div>
<p class="pl-4">{{ $strings.LabelDisableAutoRewind }}</p>
</div>
<div class="flex items-center py-3">
<div class="w-10 flex justify-center" @click="toggleJumpBackwards">
<span class="material-symbols text-4xl">{{ currentJumpBackwardsTimeIcon }}</span>
</div>
<p class="pl-4">{{ $strings.LabelJumpBackwardsTime }}</p>
</div>
<div class="flex items-center py-3">
<div class="w-10 flex justify-center" @click="toggleJumpForward">
<span class="material-symbols text-4xl">{{ currentJumpForwardTimeIcon }}</span>
</div>
<p class="pl-4">{{ $strings.LabelJumpForwardsTime }}</p>
</div>
<div v-if="!isiOS" class="flex items-center py-3">
<div class="w-10 flex justify-center" @click="toggleEnableMp3IndexSeeking">
<ui-toggle-switch v-model="settings.enableMp3IndexSeeking" @input="saveSettings" />
@@ -179,7 +179,7 @@
<ui-loading-indicator />
</div>
<modals-dialog v-model="showMoreMenuDialog" :items="moreMenuItems" @action="clickMenuAction" />
<modals-dialog v-model="showMoreMenuDialog" :items="moreMenuItems" :selected="moreMenuSelected" @action="clickMenuAction" />
<modals-sleep-timer-length-modal v-model="showSleepTimerLengthModal" @change="sleepTimerLengthModalSelection" />
<modals-auto-sleep-timer-rewind-length-modal v-model="showAutoSleepTimerRewindLengthModal" @change="showAutoSleepTimerRewindLengthModalSelection" />
</div>
@@ -187,8 +187,10 @@
<script>
import { Dialog } from '@capacitor/dialog'
import jumpLabelMixin from '@/mixins/jumpLabel'
export default {
mixins: [jumpLabelMixin],
data() {
return {
loading: false,
@@ -352,15 +354,21 @@ export default {
isiOS() {
return this.$platform === 'ios'
},
jumpForwardItems() {
return this.$store.state.globals.jumpForwardItems || []
jumpForwardSecondsOptions() {
return this.$store.state.globals.jumpForwardSecondsOptions || []
},
jumpBackwardsItems() {
return this.$store.state.globals.jumpBackwardsItems || []
jumpBackwardsSecondsOptions() {
return this.$store.state.globals.jumpBackwardsSecondsOptions || []
},
languageOptionItems() {
return this.$languageCodeOptions || []
},
jumpForwardOption() {
return this.getJumpLabel(this.settings.jumpForwardTime)
},
jumpBackwardsOption() {
return this.getJumpLabel(this.settings.jumpBackwardsTime)
},
themeOptionItems() {
return [
{
@@ -377,20 +385,6 @@ export default {
}
]
},
currentJumpForwardTimeIcon() {
return this.jumpForwardItems[this.currentJumpForwardTimeIndex].icon
},
currentJumpForwardTimeIndex() {
var index = this.jumpForwardItems.findIndex((jfi) => jfi.value === this.settings.jumpForwardTime)
return index >= 0 ? index : 1
},
currentJumpBackwardsTimeIcon() {
return this.jumpBackwardsItems[this.currentJumpBackwardsTimeIndex].icon
},
currentJumpBackwardsTimeIndex() {
var index = this.jumpBackwardsItems.findIndex((jfi) => jfi.value === this.settings.jumpBackwardsTime)
return index >= 0 ? index : 1
},
shakeSensitivityOption() {
const item = this.shakeSensitivityItems.find((i) => i.value === this.settings.shakeSensitivity)
return item?.text || 'Error'
@@ -434,7 +428,29 @@ export default {
else if (this.moreMenuSetting === 'downloadUsingCellular') return this.downloadUsingCellularItems
else if (this.moreMenuSetting === 'streamingUsingCellular') return this.streamingUsingCellularItems
else if (this.moreMenuSetting === 'androidAutoBrowseSeriesSequenceOrder') return this.androidAutoBrowseSeriesSequenceOrderItems
else if (this.moreMenuSetting === 'jumpForward')
return this.jumpForwardSecondsOptions.map((value) => ({
text: this.getJumpLabel(value),
value: value
}))
else if (this.moreMenuSetting === 'jumpBackwards')
return this.jumpBackwardsSecondsOptions.map((value) => ({
text: this.getJumpLabel(value),
value: value
}))
return []
},
moreMenuSelected() {
if (this.moreMenuSetting === 'jumpForward') return this.settings.jumpForwardTime
if (this.moreMenuSetting === 'jumpBackwards') return this.settings.jumpBackwardsTime
if (this.moreMenuSetting === 'language') return this.settings.languageCode
if (this.moreMenuSetting === 'theme') return this.theme
if (this.moreMenuSetting === 'downloadUsingCellular') return this.settings.downloadUsingCellular
if (this.moreMenuSetting === 'streamingUsingCellular') return this.settings.streamingUsingCellular
if (this.moreMenuSetting === 'androidAutoBrowseSeriesSequenceOrder') return this.settings.androidAutoBrowseSeriesSequenceOrder
if (this.moreMenuSetting === 'shakeSensitivity') return this.settings.shakeSensitivity
if (this.moreMenuSetting === 'hapticFeedback') return this.settings.hapticFeedback
return null
}
},
methods: {
@@ -468,6 +484,14 @@ export default {
this.moreMenuSetting = 'theme'
this.showMoreMenuDialog = true
},
showJumpForwardOptions() {
this.moreMenuSetting = 'jumpForward'
this.showMoreMenuDialog = true
},
showJumpBackwardsOptions() {
this.moreMenuSetting = 'jumpBackwards'
this.showMoreMenuDialog = true
},
showDownloadUsingCellularOptions() {
this.moreMenuSetting = 'downloadUsingCellular'
this.showMoreMenuDialog = true
@@ -503,6 +527,12 @@ export default {
} else if (this.moreMenuSetting === 'androidAutoBrowseSeriesSequenceOrder') {
this.settings.androidAutoBrowseSeriesSequenceOrder = action
this.saveSettings()
} else if (this.moreMenuSetting === 'jumpForward') {
this.settings.jumpForwardTime = action
this.saveSettings()
} else if (this.moreMenuSetting === 'jumpBackwards') {
this.settings.jumpBackwardsTime = action
this.saveSettings()
}
},
saveTheme(theme) {
@@ -598,17 +628,6 @@ export default {
this.$setOrientationLock(this.settings.lockOrientation)
this.saveSettings()
},
toggleJumpForward() {
var next = (this.currentJumpForwardTimeIndex + 1) % 3
this.settings.jumpForwardTime = this.jumpForwardItems[next].value
this.saveSettings()
},
toggleJumpBackwards() {
var next = (this.currentJumpBackwardsTimeIndex + 4) % 3
if (next > 2) return
this.settings.jumpBackwardsTime = this.jumpBackwardsItems[next].value
this.saveSettings()
},
async saveSettings() {
await this.$hapticsImpact()
const updatedDeviceData = await this.$db.updateDeviceSettings({ ...this.settings })
+3 -37
View File
@@ -5,34 +5,8 @@ export const state = () => ({
series: null,
localMediaProgress: [],
lastSearch: null,
jumpForwardItems: [
{
icon: 'forward_5',
value: 5
},
{
icon: 'forward_10',
value: 10
},
{
icon: 'forward_30',
value: 30
}
],
jumpBackwardsItems: [
{
icon: 'replay_5',
value: 5
},
{
icon: 'replay_10',
value: 10
},
{
icon: 'replay_30',
value: 30
}
],
jumpForwardSecondsOptions: [5, 10, 15, 30, 60, 120, 300],
jumpBackwardsSecondsOptions: [5, 10, 15, 30, 60, 120, 300],
libraryIcons: ['database', 'audiobookshelf', 'books-1', 'books-2', 'book-1', 'microphone-1', 'microphone-3', 'radio', 'podcast', 'rss', 'headphones', 'music', 'file-picture', 'rocket', 'power', 'star', 'heart'],
selectedPlaylistItems: [],
showPlaylistsAddCreateModal: false,
@@ -111,15 +85,7 @@ export const getters = {
if (episodeId != null && lmp.episodeId != episodeId) return false
return lmp.libraryItemId == libraryItemId
})
},
getJumpForwardIcon: (state) => (jumpForwardTime) => {
const item = state.jumpForwardItems.find((i) => i.value == jumpForwardTime)
return item ? item.icon : 'forward_10'
},
getJumpBackwardsIcon: (state) => (jumpBackwardsTime) => {
const item = state.jumpBackwardsItems.find((i) => i.value == jumpBackwardsTime)
return item ? item.icon : 'replay_10'
}
}
}
export const actions = {
+3 -1
View File
@@ -359,5 +359,7 @@
"ToastPodcastCreateSuccess": "Podcast created successfully",
"ToastRSSFeedCloseFailed": "Failed to close RSS feed",
"ToastRSSFeedCloseSuccess": "RSS feed closed",
"ToastStreamingNotAllowedOnCellular": "Streaming is not allowed on cellular data"
"ToastStreamingNotAllowedOnCellular": "Streaming is not allowed on cellular data",
"UnitMinutesShort": "{0}m",
"UnitSecondsShort": "{0}s"
}