Add:Haptic feedback device setting off/light/medium/heavy #472

This commit is contained in:
advplyr 2023-01-08 15:32:15 -06:00
parent 89041c4141
commit d59f3ae0b6
25 changed files with 133 additions and 73 deletions

View file

@ -11,6 +11,10 @@ enum class LockOrientationSetting {
NONE, PORTRAIT, LANDSCAPE
}
enum class HapticFeedbackSetting {
OFF, LIGHT, MEDIUM, HEAVY
}
data class ServerConnectionConfig(
var id:String,
var index:Int,
@ -28,7 +32,8 @@ data class DeviceSettings(
var jumpBackwardsTime:Int,
var jumpForwardTime:Int,
var disableShakeToResetSleepTimer:Boolean,
var lockOrientation:LockOrientationSetting
var lockOrientation:LockOrientationSetting,
var hapticFeedback: HapticFeedbackSetting
) {
companion object {
// Static method to get default device settings
@ -39,7 +44,8 @@ data class DeviceSettings(
jumpBackwardsTime = 10,
jumpForwardTime = 10,
disableShakeToResetSleepTimer = false,
lockOrientation = LockOrientationSetting.NONE
lockOrientation = LockOrientationSetting.NONE,
hapticFeedback = HapticFeedbackSetting.LIGHT
)
}
}

View file

@ -352,17 +352,17 @@ export default {
}
},
async touchstartTrack(e) {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (!e || !e.touches || !this.$refs.track || !this.showFullscreen || this.lockUi) return
this.touchTrackStart = true
},
async selectChapter(chapter) {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
this.seek(chapter.start)
this.showChapterModal = false
},
async castClick() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.isLocalPlayMethod) {
this.$eventBus.$emit('cast-local-item')
return
@ -382,13 +382,13 @@ export default {
this.forceCloseDropdownMenu()
},
async jumpNextChapter() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.isLoading) return
if (!this.nextChapter) return
this.seek(this.nextChapter.start)
},
async jumpChapterStart() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.isLoading) return
if (!this.currentChapter) {
return this.restart()
@ -409,7 +409,7 @@ export default {
this.$emit('showSleepTimer')
},
async setPlaybackSpeed(speed) {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
console.log(`[AudioPlayer] Set Playback Rate: ${speed}`)
this.currentPlaybackRate = speed
AbsAudioPlayer.setPlaybackSpeed({ value: speed })
@ -418,12 +418,12 @@ export default {
this.seek(0)
},
async jumpBackwards() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.isLoading) return
AbsAudioPlayer.seekBackward({ value: this.jumpBackwardsTime })
},
async jumpForward() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.isLoading) return
AbsAudioPlayer.seekForward({ value: this.jumpForwardTime })
},
@ -563,7 +563,7 @@ export default {
this.seek(time)
},
async playPauseClick() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.isLoading) return
this.isPlaying = !!((await AbsAudioPlayer.playPause()) || {}).playing
@ -667,7 +667,7 @@ export default {
}
},
async clickMenuAction(action) {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
this.showMoreMenuDialog = false
this.$nextTick(() => {
if (action === 'lock') {

View file

@ -115,10 +115,10 @@ export default {
})
} else {
items.push({
icon: 'download',
iconOutlined: false,
text: 'Downloads',
to: '/downloads'
icon: 'download',
iconOutlined: false,
text: 'Downloads',
to: '/downloads'
})
}
items.push({
@ -137,7 +137,7 @@ export default {
this.show = false
},
async logout() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.user) {
await this.$axios.$post('/logout').catch((error) => {
console.error(error)

View file

@ -407,7 +407,7 @@ export default {
e.preventDefault()
this.selectBtnClick()
} else if (this.recentEpisode) {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
var eventBus = this.$eventBus || this.$nuxt.$eventBus
if (this.streamIsPlaying) {
eventBus.$emit('pause-item')

View file

@ -132,7 +132,7 @@ export default {
}
},
async connectToServer(config) {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
console.log('[ServerConnectForm] connectToServer', config.address)
this.processing = true
this.serverConfig = {
@ -160,7 +160,7 @@ export default {
},
async removeServerConfigClick() {
if (!this.serverConfig.id) return
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
const { value } = await Dialog.confirm({
title: 'Confirm',
@ -192,7 +192,7 @@ export default {
this.showAuth = true
},
async newServerConfigClick() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
this.serverConfig = {
address: '',
userId: '',

View file

@ -104,7 +104,7 @@ export default {
},
async changeView() {
this.bookshelfListView = !this.bookshelfListView
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
}
},
mounted() {

View file

@ -95,7 +95,7 @@ export default {
this.showBookmarkTitleInput = true
},
async deleteBookmark(bm) {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
const { value } = await Dialog.confirm({
title: 'Remove Bookmark',
message: `Are you sure you want to remove bookmark?`
@ -114,7 +114,7 @@ export default {
this.show = false
},
async clickBookmark(bm) {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
this.$emit('select', bm)
},
submitUpdateBookmark(updatedBookmark) {
@ -159,7 +159,7 @@ export default {
this.showBookmarkTitleInput = true
},
async submitBookmark() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.selectedBookmark) {
var updatePayload = {
...this.selectedBookmark,

View file

@ -213,7 +213,7 @@ export default {
},
methods: {
async clearSelected() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
this.selected = 'all'
this.show = false
this.$nextTick(() => this.$emit('change', 'all'))
@ -232,7 +232,7 @@ export default {
this.show = false
return
}
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
this.selected = val
this.show = false
this.$nextTick(() => this.$emit('change', val))

View file

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

View file

@ -127,7 +127,7 @@ export default {
},
methods: {
async clickedOption(val) {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.selected === val) {
this.selectedDesc = !this.selectedDesc
} else {

View file

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

View file

@ -115,7 +115,7 @@ export default {
})
},
async clickPlaylist(playlist) {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (playlist.isItemIncluded) {
this.removeFromPlaylist(playlist)
} else {
@ -165,7 +165,7 @@ export default {
this.showPlaylistNameInput = true
},
async submitCreatePlaylist() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (!this.newPlaylistName || !this.selectedPlaylistItems.length) {
return
}

View file

@ -187,7 +187,7 @@ export default {
},
async downloadClick() {
if (this.downloadItem) return
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.isIos) {
// no local folders on iOS
this.startDownload()
@ -248,7 +248,7 @@ export default {
}
},
async playClick() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.streamIsPlaying) {
this.$eventBus.$emit('pause-item')
} else {
@ -270,7 +270,7 @@ export default {
}
},
async toggleFinished() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
this.isProcessingReadUpdate = true
if (this.isLocal || this.localEpisode) {
var isFinished = !this.userIsFinished

View file

@ -61,7 +61,7 @@ export default {
return this.selectedItem ? this.selectedItem.text : ''
},
buttonClass() {
var classes = []
const classes = []
if (this.small) classes.push('h-9')
else classes.push('h-10')

View file

@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// Override point for customization after application launch.
let configuration = Realm.Configuration(
schemaVersion: 5,
schemaVersion: 6,
migrationBlock: { [weak self] migration, oldSchemaVersion in
if (oldSchemaVersion < 1) {
self?.logger.log("Realm schema version was \(oldSchemaVersion)")
@ -36,6 +36,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
newObject?["lockOrientation"] = "NONE"
}
}
if (oldSchemaVersion < 6) {
self?.logger.log("Realm schema version was \(oldSchemaVersion)... Adding hapticFeedback setting")
migration.enumerateObjects(ofType: DeviceSettings.className()) { oldObject, newObject in
newObject?["hapticFeedback"] = "LIGHT"
}
}
}
)
Realm.Configuration.defaultConfiguration = configuration

View file

@ -237,12 +237,14 @@ public class AbsDatabase: CAPPlugin {
let jumpBackwardsTime = call.getInt("jumpBackwardsTime") ?? 10
let jumpForwardTime = call.getInt("jumpForwardTime") ?? 10
let lockOrientation = call.getString("lockOrientation") ?? "NONE"
let hapticFeedback = call.getString("hapticFeedback") ?? "LIGHT"
let settings = DeviceSettings()
settings.disableAutoRewind = disableAutoRewind
settings.enableAltView = enableAltView
settings.jumpBackwardsTime = jumpBackwardsTime
settings.jumpForwardTime = jumpForwardTime
settings.lockOrientation = lockOrientation
settings.hapticFeedback = hapticFeedback
Database.shared.setDeviceSettings(deviceSettings: settings)

View file

@ -14,6 +14,7 @@ class DeviceSettings: Object {
@Persisted var jumpBackwardsTime: Int = 10
@Persisted var jumpForwardTime: Int = 10
@Persisted var lockOrientation: String = "NONE"
@Persisted var hapticFeedback: String = "LIGHT"
}
func getDefaultDeviceSettings() -> DeviceSettings {
@ -26,6 +27,7 @@ func deviceSettingsToJSON(settings: DeviceSettings) -> Dictionary<String, Any> {
"enableAltView": settings.enableAltView,
"jumpBackwardsTime": settings.jumpBackwardsTime,
"jumpForwardTime": settings.jumpForwardTime,
"lockOrientation": settings.lockOrientation
"lockOrientation": settings.lockOrientation,
"hapticFeedback": settings.hapticFeedback
]
}

View file

@ -94,11 +94,16 @@ export default {
}
this.attemptingConnection = true
var deviceData = await this.$db.getDeviceData()
var serverConfig = null
if (deviceData && deviceData.lastServerConnectionConfigId && deviceData.serverConnectionConfigs.length) {
serverConfig = deviceData.serverConnectionConfigs.find((scc) => scc.id == deviceData.lastServerConnectionConfigId)
const deviceData = await this.$db.getDeviceData()
let serverConfig = null
if (deviceData) {
this.$store.commit('globals/setHapticFeedback', deviceData.hapticFeedback)
if (deviceData.lastServerConnectionConfigId && deviceData.serverConnectionConfigs.length) {
serverConfig = deviceData.serverConnectionConfigs.find((scc) => scc.id == deviceData.lastServerConnectionConfigId)
}
}
if (!serverConfig) {
// No last server config set
this.attemptingConnection = false
@ -107,9 +112,9 @@ export default {
console.log(`[default] Got server config, attempt authorize ${serverConfig.address}`)
var authRes = await this.$axios.$post(`${serverConfig.address}/api/authorize`, null, { headers: { Authorization: `Bearer ${serverConfig.token}` }, timeout: 3000 }).catch((error) => {
const authRes = await this.$axios.$post(`${serverConfig.address}/api/authorize`, null, { headers: { Authorization: `Bearer ${serverConfig.token}` }, timeout: 3000 }).catch((error) => {
console.error('[Server] Server auth failed', error)
var errorMsg = error.response ? error.response.data || 'Unknown Error' : 'Unknown Error'
const errorMsg = error.response ? error.response.data || 'Unknown Error' : 'Unknown Error'
this.error = errorMsg
return false
})
@ -122,13 +127,13 @@ export default {
this.$store.commit('setServerSettings', serverSettings)
// Set library - Use last library if set and available fallback to default user library
var lastLibraryId = await this.$localStore.getLastLibraryId()
const lastLibraryId = await this.$localStore.getLastLibraryId()
if (lastLibraryId && (!user.librariesAccessible.length || user.librariesAccessible.includes(lastLibraryId))) {
this.$store.commit('libraries/setCurrentLibrary', lastLibraryId)
} else if (userDefaultLibraryId) {
this.$store.commit('libraries/setCurrentLibrary', userDefaultLibraryId)
}
var serverConnectionConfig = await this.$db.setServerConnectionConfig(serverConfig)
const serverConnectionConfig = await this.$db.setServerConnectionConfig(serverConfig)
this.$store.commit('user/setUser', user)
this.$store.commit('user/setServerConnectionConfig', serverConnectionConfig)

View file

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

View file

@ -402,7 +402,7 @@ export default {
},
async playClick() {
let episodeId = null
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.isPodcast) {
this.episodes.sort((a, b) => {
@ -456,7 +456,7 @@ export default {
this.$eventBus.$emit('play-item', { libraryItemId: this.libraryItemId, episodeId })
},
async clearProgressClick() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
const { value } = await Dialog.confirm({
title: 'Confirm',
message: 'Are you sure you want to reset your progress?'
@ -509,7 +509,7 @@ export default {
if (!this.numTracks) {
return
}
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (this.isIos) {
// no local folders on iOS
this.startDownload()
@ -577,7 +577,7 @@ export default {
}
},
async toggleFinished() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
this.isProcessingReadUpdate = true
if (this.isLocal) {
var isFinished = !this.userIsFinished

View file

@ -256,7 +256,7 @@ export default {
this.showDialog = true
},
async play() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
this.$eventBus.$emit('play-item', { libraryItemId: this.localLibraryItemId })
},
getCapImageSrc(contentUrl) {
@ -264,7 +264,7 @@ export default {
},
async dialogAction(action) {
console.log('Dialog action', action)
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
if (action == 'scan') {
this.scanItem()
} else if (action == 'rescan') {

View file

@ -1,6 +1,7 @@
<template>
<div class="w-full h-full p-8">
<p class="uppercase text-xs font-semibold text-gray-300 mb-2">Display Settings</p>
<!-- Display settings -->
<p class="uppercase text-xs font-semibold text-gray-300 mb-2">User Interface Settings</p>
<div class="flex items-center py-3" @click="toggleEnableAltView">
<div class="w-10 flex justify-center">
<ui-toggle-switch v-model="settings.enableAltView" @input="saveSettings" />
@ -13,7 +14,12 @@
</div>
<p class="pl-4">Lock orientation</p>
</div>
<div class="py-3 flex items-center">
<p class="pr-4">Haptic feedback</p>
<ui-dropdown v-model="settings.hapticFeedback" :items="hapticFeedbackItems" style="max-width: 105px" @input="hapticFeedbackUpdated" />
</div>
<!-- Playback settings -->
<p class="uppercase text-xs font-semibold text-gray-300 mb-2 mt-6">Playback Settings</p>
<div v-if="!isiOS" class="flex items-center py-3" @click="toggleDisableAutoRewind">
<div class="w-10 flex justify-center">
@ -34,6 +40,7 @@
<p class="pl-4">Jump forwards time</p>
</div>
<!-- Sleep timer settings -->
<p v-if="!isiOS" class="uppercase text-xs font-semibold text-gray-300 mb-2 mt-6">Sleep Timer Settings</p>
<div v-if="!isiOS" class="flex items-center py-3" @click="toggleDisableShakeToResetSleepTimer">
<div class="w-10 flex justify-center">
@ -58,7 +65,8 @@ export default {
jumpForwardTime: 10,
jumpBackwardsTime: 10,
disableShakeToResetSleepTimer: false,
lockOrientation: 0
lockOrientation: 0,
hapticFeedback: 'LIGHT'
},
settingInfo: {
disableShakeToResetSleepTimer: {
@ -66,7 +74,25 @@ export default {
message: 'The sleep timer will start fading out when 30s is remaining. Shaking your device will reset the timer if it is within 30s OR has finished less than 2 mintues ago. Enable this setting to disable that feature.'
}
},
lockCurrentOrientation: false
lockCurrentOrientation: false,
hapticFeedbackItems: [
{
text: 'Off',
value: 'OFF'
},
{
text: 'Light',
value: 'LIGHT'
},
{
text: 'Medium',
value: 'MEDIUM'
},
{
text: 'Heavy',
value: 'HEAVY'
}
]
}
},
computed: {
@ -95,6 +121,10 @@ export default {
}
},
methods: {
hapticFeedbackUpdated(val) {
this.$store.commit('globals/setHapticFeedback', val)
this.saveSettings()
},
showInfo(setting) {
if (this.settingInfo[setting]) {
Dialog.alert({
@ -124,17 +154,13 @@ export default {
return 'PORTRAIT' // default
},
toggleLockOrientation() {
console.log('TOGGLE LOCK ORIENTATION', this.lockCurrentOrientation)
this.lockCurrentOrientation = !this.lockCurrentOrientation
if (this.lockCurrentOrientation) {
console.log('CURRENT ORIENTATION=', this.getCurrentOrientation())
this.settings.lockOrientation = this.getCurrentOrientation()
} else {
console.log('SETTING CURRENT ORIENTATION TO NONE')
this.settings.lockOrientation = 'NONE'
}
this.$setOrientationLock(this.settings.lockOrientation)
console.log('NOW SAVING SETTINGS', this.settings.lockOrientation)
this.saveSettings()
},
toggleJumpForward() {
@ -149,7 +175,7 @@ export default {
this.saveSettings()
},
async saveSettings() {
await this.$hapticsImpactMedium()
await this.$hapticsImpact()
const updatedDeviceData = await this.$db.updateDeviceSettings({ ...this.settings })
console.log('Saved device data', updatedDeviceData)
if (updatedDeviceData) {
@ -168,9 +194,8 @@ export default {
this.settings.jumpBackwardsTime = deviceSettings.jumpBackwardsTime || 10
this.settings.disableShakeToResetSleepTimer = !!deviceSettings.disableShakeToResetSleepTimer
this.settings.lockOrientation = deviceSettings.lockOrientation || 'NONE'
console.log('INIT SETTINGS LOCK ORIENTATION=', this.settings.lockOrientation)
this.lockCurrentOrientation = this.settings.lockOrientation !== 'NONE'
this.settings.hapticFeedback = deviceSettings.hapticFeedback || 'LIGHT'
}
},
mounted() {

View file

@ -212,7 +212,7 @@ class AbsDatabaseWeb extends WebPlugin {
}
async updateDeviceSettings(payload) {
var deviceData = await this.getDeviceData()
const deviceData = await this.getDeviceData()
deviceData.deviceSettings = payload
localStorage.setItem('device', JSON.stringify(deviceData))
return deviceData

View file

@ -4,7 +4,7 @@ import { Haptics, ImpactStyle, NotificationType } from "@capacitor/haptics"
const hapticsImpactHeavy = async () => {
await Haptics.impact({ style: ImpactStyle.Heavy })
}
Vue.prototype.$hapticsImpactHeavy = hapticsImpactHeavy;
Vue.prototype.$hapticsImpactHeavy = hapticsImpactHeavy
const hapticsImpactMedium = async () => {
await Haptics.impact({ style: ImpactStyle.Medium })
@ -19,7 +19,7 @@ Vue.prototype.$hapticsImpactLight = hapticsImpactLight
const hapticsVibrate = async () => {
await Haptics.vibrate()
}
Vue.prototype.$hapticsVibrate = hapticsVibrate;
Vue.prototype.$hapticsVibrate = hapticsVibrate
const hapticsNotificationSuccess = async () => {
await Haptics.notification({ type: NotificationType.Success })
@ -50,3 +50,13 @@ const hapticsSelectionEnd = async () => {
await Haptics.selectionEnd()
}
Vue.prototype.$hapticsSelectionEnd = hapticsSelectionEnd
export default ({ store }, inject) => {
inject('hapticsImpact', () => {
const hapticFeedback = store.state.globals.hapticFeedback
if (hapticFeedback === 'OFF') return
if (hapticFeedback === 'LIGHT') return hapticsImpactLight()
if (hapticFeedback === 'MEDIUM') return hapticsImpactMedium()
return hapticsImpactHeavy()
})
}

View file

@ -35,7 +35,8 @@ export const state = () => ({
],
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
showPlaylistsAddCreateModal: false,
hapticFeedback: 'LIGHT'
})
export const getters = {
@ -144,5 +145,8 @@ export const mutations = {
},
setShowPlaylistsAddCreateModal(state, val) {
state.showPlaylistsAddCreateModal = val
},
setHapticFeedback(state, val) {
state.hapticFeedback = val || 'LIGHT'
}
}