Merge pull request #459 from benonymity/hapticFeedback

Add haptic feedback
This commit is contained in:
advplyr 2022-12-09 17:08:17 -06:00 committed by GitHub
commit 99217fee48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 113 additions and 65 deletions

View file

@ -335,15 +335,18 @@ export default {
this.showFullscreen = false this.showFullscreen = false
} }
}, },
touchstartTrack(e) { async touchstartTrack(e) {
await this.$hapticsImpactMedium()
if (!e || !e.touches || !this.$refs.track || !this.showFullscreen || this.lockUi) return if (!e || !e.touches || !this.$refs.track || !this.showFullscreen || this.lockUi) return
this.touchTrackStart = true this.touchTrackStart = true
}, },
selectChapter(chapter) { async selectChapter(chapter) {
await this.$hapticsImpactMedium()
this.seek(chapter.start) this.seek(chapter.start)
this.showChapterModal = false this.showChapterModal = false
}, },
castClick() { async castClick() {
await this.$hapticsImpactMedium()
if (this.isLocalPlayMethod) { if (this.isLocalPlayMethod) {
this.$eventBus.$emit('cast-local-item') this.$eventBus.$emit('cast-local-item')
return return
@ -362,12 +365,14 @@ export default {
this.showFullscreen = false this.showFullscreen = false
this.forceCloseDropdownMenu() this.forceCloseDropdownMenu()
}, },
jumpNextChapter() { async jumpNextChapter() {
await this.$hapticsImpactMedium()
if (this.isLoading) return if (this.isLoading) return
if (!this.nextChapter) return if (!this.nextChapter) return
this.seek(this.nextChapter.start) this.seek(this.nextChapter.start)
}, },
jumpChapterStart() { async jumpChapterStart() {
await this.$hapticsImpactMedium()
if (this.isLoading) return if (this.isLoading) return
if (!this.currentChapter) { if (!this.currentChapter) {
return this.restart() return this.restart()
@ -387,7 +392,8 @@ export default {
showSleepTimerModal() { showSleepTimerModal() {
this.$emit('showSleepTimer') this.$emit('showSleepTimer')
}, },
setPlaybackSpeed(speed) { async setPlaybackSpeed(speed) {
await this.$hapticsImpactMedium()
console.log(`[AudioPlayer] Set Playback Rate: ${speed}`) console.log(`[AudioPlayer] Set Playback Rate: ${speed}`)
this.currentPlaybackRate = speed this.currentPlaybackRate = speed
AbsAudioPlayer.setPlaybackSpeed({ value: speed }) AbsAudioPlayer.setPlaybackSpeed({ value: speed })
@ -395,11 +401,13 @@ export default {
restart() { restart() {
this.seek(0) this.seek(0)
}, },
jumpBackwards() { async jumpBackwards() {
await this.$hapticsImpactMedium()
if (this.isLoading) return if (this.isLoading) return
AbsAudioPlayer.seekBackward({ value: this.jumpBackwardsTime }) AbsAudioPlayer.seekBackward({ value: this.jumpBackwardsTime })
}, },
jumpForward() { async jumpForward() {
await this.$hapticsImpactMedium()
if (this.isLoading) return if (this.isLoading) return
AbsAudioPlayer.seekForward({ value: this.jumpForwardTime }) AbsAudioPlayer.seekForward({ value: this.jumpForwardTime })
}, },
@ -539,6 +547,7 @@ export default {
this.seek(time) this.seek(time)
}, },
async playPauseClick() { async playPauseClick() {
await this.$hapticsImpactMedium()
if (this.isLoading) return if (this.isLoading) return
this.isPlaying = !!((await AbsAudioPlayer.playPause()) || {}).playing this.isPlaying = !!((await AbsAudioPlayer.playPause()) || {}).playing
@ -641,7 +650,8 @@ export default {
ts.innerText = currTimeStr ts.innerText = currTimeStr
} }
}, },
clickMenuAction(action) { async clickMenuAction(action) {
await this.$hapticsImpactMedium()
this.showMoreMenuDialog = false this.showMoreMenuDialog = false
this.$nextTick(() => { this.$nextTick(() => {
if (action === 'lock') { if (action === 'lock') {
@ -969,4 +979,4 @@ export default {
.fullscreen #playerControls .play-btn .material-icons { .fullscreen #playerControls .play-btn .material-icons {
font-size: 2.1rem; font-size: 2.1rem;
} }
</style> </style>

View file

@ -137,6 +137,7 @@ export default {
this.show = false this.show = false
}, },
async logout() { async logout() {
await this.$hapticsImpactMedium()
if (this.user) { if (this.user) {
await this.$axios.$post('/logout').catch((error) => { await this.$axios.$post('/logout').catch((error) => {
console.error(error) console.error(error)

View file

@ -401,12 +401,13 @@ export default {
// Server books may have a local library item // Server books may have a local library item
this.localLibraryItem = localLibraryItem this.localLibraryItem = localLibraryItem
}, },
clickCard(e) { async clickCard(e) {
if (this.isSelectionMode) { if (this.isSelectionMode) {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
this.selectBtnClick() this.selectBtnClick()
} else if (this.recentEpisode) { } else if (this.recentEpisode) {
await this.$hapticsImpactMedium()
var eventBus = this.$eventBus || this.$nuxt.$eventBus var eventBus = this.$eventBus || this.$nuxt.$eventBus
if (this.streamIsPlaying) { if (this.streamIsPlaying) {
eventBus.$emit('pause-item') eventBus.$emit('pause-item')

View file

@ -132,6 +132,7 @@ export default {
} }
}, },
async connectToServer(config) { async connectToServer(config) {
await this.$hapticsImpactMedium()
console.log('[ServerConnectForm] connectToServer', config.address) console.log('[ServerConnectForm] connectToServer', config.address)
this.processing = true this.processing = true
this.serverConfig = { this.serverConfig = {
@ -159,6 +160,7 @@ export default {
}, },
async removeServerConfigClick() { async removeServerConfigClick() {
if (!this.serverConfig.id) return if (!this.serverConfig.id) return
await this.$hapticsImpactMedium()
const { value } = await Dialog.confirm({ const { value } = await Dialog.confirm({
title: 'Confirm', title: 'Confirm',
@ -189,7 +191,8 @@ export default {
this.showForm = true this.showForm = true
this.showAuth = true this.showAuth = true
}, },
newServerConfigClick() { async newServerConfigClick() {
await this.$hapticsImpactMedium()
this.serverConfig = { this.serverConfig = {
address: '', address: '',
userId: '', userId: '',
@ -348,4 +351,4 @@ export default {
this.init() this.init()
} }
} }
</script> </script>

View file

@ -8,7 +8,7 @@
<p v-show="!selectedSeriesName" class="font-book pt-1">{{ totalEntities }} {{ entityTitle }}</p> <p v-show="!selectedSeriesName" class="font-book pt-1">{{ totalEntities }} {{ entityTitle }}</p>
<p v-show="selectedSeriesName" class="ml-2 font-book pt-1">{{ selectedSeriesName }} ({{ totalEntities }})</p> <p v-show="selectedSeriesName" class="ml-2 font-book pt-1">{{ selectedSeriesName }} ({{ totalEntities }})</p>
<div class="flex-grow" /> <div class="flex-grow" />
<span v-if="page == 'library' || seriesBookPage" class="material-icons px-2" @click="bookshelfListView = !bookshelfListView">{{ !bookshelfListView ? 'view_list' : 'grid_view' }}</span> <span v-if="page == 'library' || seriesBookPage" class="material-icons px-2" @click="changeView">{{ !bookshelfListView ? 'view_list' : 'grid_view' }}</span>
<template v-if="page === 'library'"> <template v-if="page === 'library'">
<div class="relative flex items-center px-2"> <div class="relative flex items-center px-2">
<span class="material-icons" @click="showFilterModal = true">filter_alt</span> <span class="material-icons" @click="showFilterModal = true">filter_alt</span>
@ -102,6 +102,10 @@ export default {
}, },
setTotalEntities(total) { setTotalEntities(total) {
this.totalEntities = total this.totalEntities = total
},
async changeView() {
this.bookshelfListView = !this.bookshelfListView
await this.$hapticsImpactMedium()
} }
}, },
mounted() { mounted() {
@ -120,4 +124,4 @@ export default {
#bookshelf-toolbar { #bookshelf-toolbar {
box-shadow: 0px 5px 5px #11111155; box-shadow: 0px 5px 5px #11111155;
} }
</style> </style>

View file

@ -46,6 +46,7 @@
<script> <script>
import { Dialog } from '@capacitor/dialog' import { Dialog } from '@capacitor/dialog'
export default { export default {
props: { props: {
value: Boolean, value: Boolean,
@ -94,6 +95,7 @@ export default {
this.showBookmarkTitleInput = true this.showBookmarkTitleInput = true
}, },
async deleteBookmark(bm) { async deleteBookmark(bm) {
await this.$hapticsImpactMedium()
const { value } = await Dialog.confirm({ const { value } = await Dialog.confirm({
title: 'Remove Bookmark', title: 'Remove Bookmark',
message: `Are you sure you want to remove bookmark?` message: `Are you sure you want to remove bookmark?`
@ -111,7 +113,8 @@ export default {
}) })
this.show = false this.show = false
}, },
clickBookmark(bm) { async clickBookmark(bm) {
await this.$hapticsImpactMedium()
this.$emit('select', bm) this.$emit('select', bm)
}, },
submitUpdateBookmark(updatedBookmark) { submitUpdateBookmark(updatedBookmark) {
@ -155,7 +158,8 @@ export default {
this.newBookmarkTitle = this.$formatDate(Date.now(), 'MMM dd, yyyy HH:mm') this.newBookmarkTitle = this.$formatDate(Date.now(), 'MMM dd, yyyy HH:mm')
this.showBookmarkTitleInput = true this.showBookmarkTitleInput = true
}, },
submitBookmark() { async submitBookmark() {
await this.$hapticsImpactMedium()
if (this.selectedBookmark) { if (this.selectedBookmark) {
var updatePayload = { var updatePayload = {
...this.selectedBookmark, ...this.selectedBookmark,

View file

@ -212,7 +212,8 @@ export default {
} }
}, },
methods: { methods: {
clearSelected() { async clearSelected() {
await this.$hapticsImpactMedium()
this.selected = 'all' this.selected = 'all'
this.show = false this.show = false
this.$nextTick(() => this.$emit('change', 'all')) this.$nextTick(() => this.$emit('change', 'all'))
@ -220,7 +221,7 @@ export default {
clickedSublistOption(item) { clickedSublistOption(item) {
this.clickedOption({ value: `${this.sublist}.${item}` }) this.clickedOption({ value: `${this.sublist}.${item}` })
}, },
clickedOption(option) { async clickedOption(option) {
if (option.sublist) { if (option.sublist) {
this.sublist = option.value this.sublist = option.value
return return
@ -231,6 +232,7 @@ export default {
this.show = false this.show = false
return return
} }
await this.$hapticsImpactMedium()
this.selected = val this.selected = val
this.show = false this.show = false
this.$nextTick(() => this.$emit('change', val)) this.$nextTick(() => this.$emit('change', val))
@ -244,4 +246,4 @@ export default {
.filter-modal-wrapper { .filter-modal-wrapper {
max-height: calc(100% - 320px); max-height: calc(100% - 320px);
} }
</style> </style>

View file

@ -49,6 +49,7 @@ export default {
}, },
methods: { methods: {
async clickedOption(lib) { async clickedOption(lib) {
await this.$hapticsImpactMedium()
this.show = false this.show = false
if (lib.id === this.currentLibraryId) return if (lib.id === this.currentLibraryId) return
await this.$store.dispatch('libraries/fetch', lib.id) await this.$store.dispatch('libraries/fetch', lib.id)

View file

@ -126,7 +126,8 @@ export default {
} }
}, },
methods: { methods: {
clickedOption(val) { async clickedOption(val) {
await this.$hapticsImpactMedium()
if (this.selected === val) { if (this.selected === val) {
this.selectedDesc = !this.selectedDesc this.selectedDesc = !this.selectedDesc
} else { } else {
@ -139,4 +140,4 @@ export default {
}, },
mounted() {} mounted() {}
} }
</script> </script>

View file

@ -89,30 +89,37 @@ export default {
} }
}, },
methods: { methods: {
clickedChapterOption() { async clickedChapterOption() {
await this.$hapticsImpactMedium()
this.show = false this.show = false
this.$nextTick(() => this.$emit('change', { time: this.currentEndOfChapterTime * 1000, isChapterTime: true })) this.$nextTick(() => this.$emit('change', { time: this.currentEndOfChapterTime * 1000, isChapterTime: true }))
}, },
clickedOption(timeoutMin) { async clickedOption(timeoutMin) {
await this.$hapticsImpactMedium()
var timeout = timeoutMin * 1000 * 60 var timeout = timeoutMin * 1000 * 60
this.show = false this.show = false
this.manualTimerModal = false this.manualTimerModal = false
this.$nextTick(() => this.$emit('change', { time: timeout, isChapterTime: false })) this.$nextTick(() => this.$emit('change', { time: timeout, isChapterTime: false }))
}, },
cancelSleepTimer() { async cancelSleepTimer() {
await this.$hapticsImpactMedium()
this.$emit('cancel') this.$emit('cancel')
this.show = false this.show = false
}, },
increaseSleepTime() { async increaseSleepTime() {
await this.$hapticsImpactMedium()
this.$emit('increase') this.$emit('increase')
}, },
decreaseSleepTime() { async decreaseSleepTime() {
await this.$hapticsImpactMedium()
this.$emit('decrease') this.$emit('decrease')
}, },
increaseManualTimeout() { async increaseManualTimeout() {
await this.$hapticsImpactMedium()
this.manualTimeoutMin++ this.manualTimeoutMin++
}, },
decreaseManualTimeout() { async decreaseManualTimeout() {
await this.$hapticsImpactMedium()
if (this.manualTimeoutMin > 1) this.manualTimeoutMin-- if (this.manualTimeoutMin > 1) this.manualTimeoutMin--
} }
}, },

View file

@ -114,7 +114,8 @@ export default {
this.loading = false this.loading = false
}) })
}, },
clickPlaylist(playlist) { async clickPlaylist(playlist) {
await this.$hapticsImpactMedium()
if (playlist.isItemIncluded) { if (playlist.isItemIncluded) {
this.removeFromPlaylist(playlist) this.removeFromPlaylist(playlist)
} else { } else {
@ -163,7 +164,8 @@ export default {
this.newPlaylistName = '' this.newPlaylistName = ''
this.showPlaylistNameInput = true this.showPlaylistNameInput = true
}, },
submitCreatePlaylist() { async submitCreatePlaylist() {
await this.$hapticsImpactMedium()
if (!this.newPlaylistName || !this.selectedPlaylistItems.length) { if (!this.newPlaylistName || !this.selectedPlaylistItems.length) {
return return
} }

View file

@ -148,8 +148,9 @@ export default {
} }
return folderObj return folderObj
}, },
downloadClick() { async downloadClick() {
if (this.downloadItem) return if (this.downloadItem) return
await this.$hapticsImpactMedium()
if (this.isIos) { if (this.isIos) {
// no local folders on iOS // no local folders on iOS
this.startDownload() this.startDownload()
@ -209,7 +210,8 @@ export default {
this.$toast.error(errorMsg) this.$toast.error(errorMsg)
} }
}, },
playClick() { async playClick() {
await this.$hapticsImpactMedium()
if (this.streamIsPlaying) { if (this.streamIsPlaying) {
this.$eventBus.$emit('pause-item') this.$eventBus.$emit('pause-item')
} else { } else {
@ -231,6 +233,7 @@ export default {
} }
}, },
async toggleFinished() { async toggleFinished() {
await this.$hapticsImpactMedium()
this.isProcessingReadUpdate = true this.isProcessingReadUpdate = true
if (this.isLocal || this.localEpisode) { if (this.isLocal || this.localEpisode) {
var isFinished = !this.userIsFinished var isFinished = !this.userIsFinished
@ -278,4 +281,4 @@ export default {
} }
} }
} }
</script> </script>

View file

@ -53,6 +53,7 @@ export default {
}, },
methods: { methods: {
async logout() { async logout() {
await this.$hapticsImpactMedium()
if (this.user) { if (this.user) {
await this.$axios.$post('/logout').catch((error) => { await this.$axios.$post('/logout').catch((error) => {
console.error(error) console.error(error)
@ -68,4 +69,4 @@ export default {
}, },
mounted() {} mounted() {}
} }
</script> </script>

View file

@ -143,6 +143,7 @@
import { Dialog } from '@capacitor/dialog' import { Dialog } from '@capacitor/dialog'
import { AbsFileSystem, AbsDownloader } from '@/plugins/capacitor' import { AbsFileSystem, AbsDownloader } from '@/plugins/capacitor'
export default { export default {
async asyncData({ store, params, redirect, app }) { async asyncData({ store, params, redirect, app }) {
var libraryItemId = params.id var libraryItemId = params.id
@ -406,8 +407,9 @@ export default {
readBook() { readBook() {
this.$store.commit('openReader', this.libraryItem) this.$store.commit('openReader', this.libraryItem)
}, },
playClick() { async playClick() {
var episodeId = null var episodeId = null
await this.$hapticsImpactMedium()
if (this.isPodcast) { if (this.isPodcast) {
this.episodes.sort((a, b) => { this.episodes.sort((a, b) => {
@ -461,6 +463,7 @@ export default {
this.$eventBus.$emit('play-item', { libraryItemId: this.libraryItemId, episodeId }) this.$eventBus.$emit('play-item', { libraryItemId: this.libraryItemId, episodeId })
}, },
async clearProgressClick() { async clearProgressClick() {
await this.$hapticsImpactMedium()
const { value } = await Dialog.confirm({ const { value } = await Dialog.confirm({
title: 'Confirm', title: 'Confirm',
message: 'Are you sure you want to reset your progress?' message: 'Are you sure you want to reset your progress?'
@ -506,13 +509,14 @@ export default {
this.showSelectLocalFolder = false this.showSelectLocalFolder = false
this.download(localFolder) this.download(localFolder)
}, },
downloadClick() { async downloadClick() {
if (this.downloadItem) { if (this.downloadItem) {
return return
} }
if (!this.numTracks) { if (!this.numTracks) {
return return
} }
await this.$hapticsImpactMedium()
if (this.isIos) { if (this.isIos) {
// no local folders on iOS // no local folders on iOS
this.startDownload() this.startDownload()
@ -580,6 +584,7 @@ export default {
} }
}, },
async toggleFinished() { async toggleFinished() {
await this.$hapticsImpactMedium()
this.isProcessingReadUpdate = true this.isProcessingReadUpdate = true
if (this.isLocal) { if (this.isLocal) {
var isFinished = !this.userIsFinished var isFinished = !this.userIsFinished
@ -647,4 +652,4 @@ export default {
width: calc(100% - 64px); width: calc(100% - 64px);
max-width: calc(100% - 64px); max-width: calc(100% - 64px);
} }
</style> </style>

View file

@ -255,14 +255,16 @@ export default {
} }
this.showDialog = true this.showDialog = true
}, },
play() { async play() {
await this.$hapticsImpactMedium()
this.$eventBus.$emit('play-item', { libraryItemId: this.localLibraryItemId }) this.$eventBus.$emit('play-item', { libraryItemId: this.localLibraryItemId })
}, },
getCapImageSrc(contentUrl) { getCapImageSrc(contentUrl) {
return Capacitor.convertFileSrc(contentUrl) return Capacitor.convertFileSrc(contentUrl)
}, },
dialogAction(action) { async dialogAction(action) {
console.log('Dialog action', action) console.log('Dialog action', action)
await this.$hapticsImpactMedium()
if (action == 'scan') { if (action == 'scan') {
this.scanItem() this.scanItem()
} else if (action == 'rescan') { } else if (action == 'rescan') {
@ -405,4 +407,4 @@ export default {
.dragtrack-leave-active { .dragtrack-leave-active {
position: absolute; position: absolute;
} }
</style> </style>

View file

@ -149,6 +149,7 @@ export default {
this.saveSettings() this.saveSettings()
}, },
async saveSettings() { async saveSettings() {
await this.$hapticsImpactMedium()
const updatedDeviceData = await this.$db.updateDeviceSettings({ ...this.settings }) const updatedDeviceData = await this.$db.updateDeviceSettings({ ...this.settings })
console.log('Saved device data', updatedDeviceData) console.log('Saved device data', updatedDeviceData)
if (updatedDeviceData) { if (updatedDeviceData) {
@ -176,4 +177,4 @@ export default {
this.init() this.init()
} }
} }
</script> </script>

View file

@ -1,52 +1,52 @@
import Vue from 'vue' import Vue from "vue";
import { Haptics, ImpactStyle, NotificationType } from '@capacitor/haptics' import { Haptics, ImpactStyle, NotificationType } from "@capacitor/haptics"
const hapticsImpactHeavy = async () => { const hapticsImpactHeavy = async () => {
await Haptics.impact({ style: ImpactStyle.Heavy }); await Haptics.impact({ style: ImpactStyle.Heavy })
} }
Vue.prototype.$hapticsImpactHeavy = hapticsImpactHeavy Vue.prototype.$hapticsImpactHeavy = hapticsImpactHeavy;
const hapticsImpactMedium = async () => { const hapticsImpactMedium = async () => {
await Haptics.impact({ style: ImpactStyle.Medium }); await Haptics.impact({ style: ImpactStyle.Medium })
} }
Vue.prototype.$hapticsImpactMedium = hapticsImpactMedium Vue.prototype.$hapticsImpactMedium = hapticsImpactMedium
const hapticsImpactLight = async () => { const hapticsImpactLight = async () => {
await Haptics.impact({ style: ImpactStyle.Light }); await Haptics.impact({ style: ImpactStyle.Light })
}; }
Vue.prototype.$hapticsImpactLight = hapticsImpactLight Vue.prototype.$hapticsImpactLight = hapticsImpactLight
const hapticsVibrate = async () => { const hapticsVibrate = async () => {
await Haptics.vibrate(); await Haptics.vibrate()
}; }
Vue.prototype.$hapticsVibrate = hapticsVibrate Vue.prototype.$hapticsVibrate = hapticsVibrate;
const hapticsNotificationSuccess = async () => { const hapticsNotificationSuccess = async () => {
await Haptics.notification({ type: NotificationType.Success }); await Haptics.notification({ type: NotificationType.Success })
}; }
Vue.prototype.$hapticsNotificationSuccess = hapticsNotificationSuccess Vue.prototype.$hapticsNotificationSuccess = hapticsNotificationSuccess
const hapticsNotificationWarning = async () => { const hapticsNotificationWarning = async () => {
await Haptics.notification({ type: NotificationType.Warning }); await Haptics.notification({ type: NotificationType.Warning })
}; }
Vue.prototype.$hapticsNotificationWarning = hapticsNotificationWarning Vue.prototype.$hapticsNotificationWarning = hapticsNotificationWarning
const hapticsNotificationError = async () => { const hapticsNotificationError = async () => {
await Haptics.notification({ type: NotificationType.Error }); await Haptics.notification({ type: NotificationType.Error })
}; }
Vue.prototype.$hapticsNotificationError = hapticsNotificationError Vue.prototype.$hapticsNotificationError = hapticsNotificationError
const hapticsSelectionStart = async () => { const hapticsSelectionStart = async () => {
await Haptics.selectionStart(); await Haptics.selectionStart()
}; }
Vue.prototype.$hapticsSelectionStart = hapticsSelectionStart Vue.prototype.$hapticsSelectionStart = hapticsSelectionStart
const hapticsSelectionChanged = async () => { const hapticsSelectionChanged = async () => {
await Haptics.selectionChanged(); await Haptics.selectionChanged()
}; }
Vue.prototype.$hapticsSelectionChanged = hapticsSelectionChanged Vue.prototype.$hapticsSelectionChanged = hapticsSelectionChanged
const hapticsSelectionEnd = async () => { const hapticsSelectionEnd = async () => {
await Haptics.selectionEnd(); await Haptics.selectionEnd()
}; }
Vue.prototype.$hapticsSelectionEnd = hapticsSelectionEnd Vue.prototype.$hapticsSelectionEnd = hapticsSelectionEnd