Add:iOS device settings for jump forward/backward

This commit is contained in:
advplyr 2022-07-02 18:29:41 -05:00
parent 39b137c7f1
commit b5c6acc2bc
11 changed files with 108 additions and 31 deletions

View file

@ -687,7 +687,6 @@ export default {
}) })
}, },
onPlaybackClosed() { onPlaybackClosed() {
console.log('Received onPlaybackClosed evt')
this.endPlayback() this.endPlayback()
}, },
onPlaybackFailed(data) { onPlaybackFailed(data) {
@ -717,14 +716,18 @@ export default {
}, },
mounted() { mounted() {
this.updateScreenSize() this.updateScreenSize()
screen.orientation.addEventListener('change', this.screenOrientationChange) if (screen.orientation) {
screen.orientation.addEventListener('change', this.screenOrientationChange)
}
document.body.addEventListener('touchstart', this.touchstart) document.body.addEventListener('touchstart', this.touchstart)
document.body.addEventListener('touchend', this.touchend) document.body.addEventListener('touchend', this.touchend)
document.body.addEventListener('touchmove', this.touchmove) document.body.addEventListener('touchmove', this.touchmove)
this.$nextTick(this.init) this.$nextTick(this.init)
}, },
beforeDestroy() { beforeDestroy() {
screen.orientation.removeEventListener('change', this.screenOrientationChange) if (screen.orientation) {
screen.orientation.removeEventListener('change', this.screenOrientationChange)
}
if (this.playbackSession) { if (this.playbackSession) {
console.log('[AudioPlayer] Before destroy closing playback') console.log('[AudioPlayer] Before destroy closing playback')
@ -752,7 +755,6 @@ export default {
--cover-image-height: 0px; --cover-image-height: 0px;
--cover-image-width-collapsed: 60px; --cover-image-width-collapsed: 60px;
--cover-image-height-collapsed: 60px; --cover-image-height-collapsed: 60px;
--test-var: 100px;
} }
.bookCoverWrapper { .bookCoverWrapper {
box-shadow: 3px -2px 5px #00000066; box-shadow: 3px -2px 5px #00000066;

View file

@ -108,12 +108,12 @@ export default {
text: 'Local Media', text: 'Local Media',
to: '/localMedia/folders' to: '/localMedia/folders'
}) })
items.push({
icon: 'settings',
text: 'Settings',
to: '/settings'
})
} }
items.push({
icon: 'settings',
text: 'Settings',
to: '/settings'
})
return items return items
}, },
currentRoutePath() { currentRoutePath() {

View file

@ -27,6 +27,7 @@
4D66B954282EE87C008272D4 /* AbsDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D66B953282EE87C008272D4 /* AbsDownloader.swift */; }; 4D66B954282EE87C008272D4 /* AbsDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D66B953282EE87C008272D4 /* AbsDownloader.swift */; };
4D66B956282EE951008272D4 /* AbsFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D66B955282EE951008272D4 /* AbsFileSystem.m */; }; 4D66B956282EE951008272D4 /* AbsFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D66B955282EE951008272D4 /* AbsFileSystem.m */; };
4D66B958282EEA14008272D4 /* AbsFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D66B957282EEA14008272D4 /* AbsFileSystem.swift */; }; 4D66B958282EEA14008272D4 /* AbsFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D66B957282EEA14008272D4 /* AbsFileSystem.swift */; };
4DF74912287105C600AC7814 /* DeviceSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DF74911287105C600AC7814 /* DeviceSettings.swift */; };
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; }; 50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; }; 504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; }; 504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
@ -59,6 +60,7 @@
4D66B955282EE951008272D4 /* AbsFileSystem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AbsFileSystem.m; sourceTree = "<group>"; }; 4D66B955282EE951008272D4 /* AbsFileSystem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AbsFileSystem.m; sourceTree = "<group>"; };
4D66B957282EEA14008272D4 /* AbsFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbsFileSystem.swift; sourceTree = "<group>"; }; 4D66B957282EEA14008272D4 /* AbsFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbsFileSystem.swift; sourceTree = "<group>"; };
4D8D412C26E187E400BA5F0D /* App-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "App-Bridging-Header.h"; sourceTree = "<group>"; }; 4D8D412C26E187E400BA5F0D /* App-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "App-Bridging-Header.h"; sourceTree = "<group>"; };
4DF74911287105C600AC7814 /* DeviceSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceSettings.swift; sourceTree = "<group>"; };
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; }; 50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; }; 504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@ -134,6 +136,7 @@
3ABF580828059BAE005DFBE5 /* PlaybackSession.swift */, 3ABF580828059BAE005DFBE5 /* PlaybackSession.swift */,
C4D0677428106D0C00B8F875 /* DataClasses.swift */, C4D0677428106D0C00B8F875 /* DataClasses.swift */,
3A90295E280968E700E1D427 /* PlaybackReport.swift */, 3A90295E280968E700E1D427 /* PlaybackReport.swift */,
4DF74911287105C600AC7814 /* DeviceSettings.swift */,
); );
path = models; path = models;
sourceTree = "<group>"; sourceTree = "<group>";
@ -325,6 +328,7 @@
3AD4FCEB280443DD006DB301 /* Database.swift in Sources */, 3AD4FCEB280443DD006DB301 /* Database.swift in Sources */,
3AD4FCE528043E50006DB301 /* AbsDatabase.swift in Sources */, 3AD4FCE528043E50006DB301 /* AbsDatabase.swift in Sources */,
4D66B952282EE822008272D4 /* AbsDownloader.m in Sources */, 4D66B952282EE822008272D4 /* AbsDownloader.m in Sources */,
4DF74912287105C600AC7814 /* DeviceSettings.swift in Sources */,
3AF197102806E3DC0096F747 /* AbsAudioPlayer.m in Sources */, 3AF197102806E3DC0096F747 /* AbsAudioPlayer.m in Sources */,
3AF1970C2806E2590096F747 /* ApiClient.swift in Sources */, 3AF1970C2806E2590096F747 /* ApiClient.swift in Sources */,
C4D0677528106D0C00B8F875 /* DataClasses.swift in Sources */, C4D0677528106D0C00B8F875 /* DataClasses.swift in Sources */,

View file

@ -43,10 +43,10 @@ public class AbsAudioPlayer: CAPPlugin {
initialPlayWhenReady = playWhenReady initialPlayWhenReady = playWhenReady
initialPlaybackRate = playbackRate initialPlaybackRate = playbackRate
PlayerHandler.stopPlayback()
sendPrepareMetadataEvent(itemId: libraryItemId!, playWhenReady: playWhenReady) sendPrepareMetadataEvent(itemId: libraryItemId!, playWhenReady: playWhenReady)
ApiClient.startPlaybackSession(libraryItemId: libraryItemId!, episodeId: episodeId, forceTranscode: false) { session in ApiClient.startPlaybackSession(libraryItemId: libraryItemId!, episodeId: episodeId, forceTranscode: false) { session in
PlayerHandler.startPlayback(session: session, playWhenReady: playWhenReady, playbackRate: playbackRate)
do { do {
self.sendPlaybackSession(session: try session.asDictionary()) self.sendPlaybackSession(session: try session.asDictionary())
call.resolve(try session.asDictionary()) call.resolve(try session.asDictionary())
@ -56,6 +56,8 @@ public class AbsAudioPlayer: CAPPlugin {
call.resolve([:]) call.resolve([:])
} }
PlayerHandler.startPlayback(session: session, playWhenReady: playWhenReady, playbackRate: playbackRate)
self.sendMetadata() self.sendMetadata()
} }
} }
@ -173,7 +175,7 @@ public class AbsAudioPlayer: CAPPlugin {
let playbackSession = PlayerHandler.getPlaybackSession() let playbackSession = PlayerHandler.getPlaybackSession()
let libraryItemId = playbackSession?.libraryItemId ?? "" let libraryItemId = playbackSession?.libraryItemId ?? ""
let episodeId = playbackSession?.episodeId ?? nil let episodeId = playbackSession?.episodeId ?? nil
NSLog("TEST: Forcing Transcode") NSLog("Forcing Transcode")
// If direct playing then fallback to transcode // If direct playing then fallback to transcode
ApiClient.startPlaybackSession(libraryItemId: libraryItemId, episodeId: episodeId, forceTranscode: true) { session in ApiClient.startPlaybackSession(libraryItemId: libraryItemId, episodeId: episodeId, forceTranscode: true) { session in

View file

@ -19,5 +19,6 @@ CAP_PLUGIN(AbsDatabase, "AbsDatabase",
CAP_PLUGIN_METHOD(getLocalLibraryItem, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getLocalLibraryItem, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(getLocalLibraryItemByLLId, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getLocalLibraryItemByLLId, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(getLocalLibraryItemsInFolder, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getLocalLibraryItemsInFolder, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(updateDeviceSettings, CAPPluginReturnPromise);
) )

View file

@ -65,11 +65,12 @@ public class AbsDatabase: CAPPlugin {
@objc func getDeviceData(_ call: CAPPluginCall) { @objc func getDeviceData(_ call: CAPPluginCall) {
let configs = Database.shared.getServerConnectionConfigs() let configs = Database.shared.getServerConnectionConfigs()
let index = Database.shared.getLastActiveConfigIndex() let index = Database.shared.getLastActiveConfigIndex()
let settings = Database.shared.getDeviceSettings()
call.resolve([ call.resolve([
"serverConnectionConfigs": configs.map { config in convertServerConnectionConfigToJSON(config: config) }, "serverConnectionConfigs": configs.map { config in convertServerConnectionConfigToJSON(config: config) },
"lastServerConnectionConfigId": configs.first { config in config.index == index }?.id as Any, "lastServerConnectionConfigId": configs.first { config in config.index == index }?.id as Any,
// "currentLocalPlaybackSession": nil, "deviceSettings": deviceSettingsToJSON(settings: settings)
]) ])
} }
@ -85,4 +86,18 @@ public class AbsDatabase: CAPPlugin {
@objc func getLocalLibraryItemsInFolder(_ call: CAPPluginCall) { @objc func getLocalLibraryItemsInFolder(_ call: CAPPluginCall) {
call.resolve([ "value": [] ]) call.resolve([ "value": [] ])
} }
@objc func updateDeviceSettings(_ call: CAPPluginCall) {
let disableAutoRewind = call.getBool("disableAutoRewind") ?? false
let jumpBackwardsTime = call.getInt("jumpBackwardsTime") ?? 10
let jumpForwardTime = call.getInt("jumpForwardTime") ?? 10
let settings = DeviceSettings()
settings.disableAutoRewind = disableAutoRewind
settings.jumpBackwardsTime = jumpBackwardsTime
settings.jumpForwardTime = jumpForwardTime
Database.shared.setDeviceSettings(deviceSettings: settings)
// call.resolve([ "value": [] ])
getDeviceData(call)
}
} }

View file

@ -9,12 +9,12 @@ install! 'cocoapods', :disable_input_output_paths => true
def capacitor_pods def capacitor_pods
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorApp', :path => '..\..\node_modules\@capacitor\app' pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
pod 'CapacitorDialog', :path => '..\..\node_modules\@capacitor\dialog' pod 'CapacitorDialog', :path => '../../node_modules/@capacitor/dialog'
pod 'CapacitorHaptics', :path => '..\..\node_modules\@capacitor\haptics' pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
pod 'CapacitorNetwork', :path => '..\..\node_modules\@capacitor\network' pod 'CapacitorNetwork', :path => '../../node_modules/@capacitor/network'
pod 'CapacitorStatusBar', :path => '..\..\node_modules\@capacitor\status-bar' pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
pod 'CapacitorStorage', :path => '..\..\node_modules\@capacitor\storage' pod 'CapacitorStorage', :path => '../../node_modules/@capacitor/storage'
end end
target 'App' do target 'App' do

View file

@ -0,0 +1,33 @@
//
// DeviceSettings.swift
// App
//
// Created by advplyr on 7/2/22.
//
import Foundation
import RealmSwift
class DeviceSettings: Object {
@Persisted var disableAutoRewind: Bool
@Persisted var jumpBackwardsTime: Int
@Persisted var jumpForwardTime: Int
}
func getDefaultDeviceSettings() -> DeviceSettings {
let settings = DeviceSettings()
settings.disableAutoRewind = false
settings.jumpForwardTime = 10
settings.jumpBackwardsTime = 10
return settings
}
func deviceSettingsToJSON(settings: DeviceSettings) -> Dictionary<String, Any> {
return Database.realmQueue.sync {
return [
"disableAutoRewind": settings.disableAutoRewind,
"jumpBackwardsTime": settings.jumpBackwardsTime,
"jumpForwardTime": settings.jumpForwardTime
]
}
}

View file

@ -66,10 +66,10 @@ class AudioPlayer: NSObject {
} }
self.currentTrackIndex = getItemIndexForTime(time: playbackSession.currentTime) self.currentTrackIndex = getItemIndexForTime(time: playbackSession.currentTime)
NSLog("TEST: Starting track index \(self.currentTrackIndex) for start time \(playbackSession.currentTime)") NSLog("Starting track index \(self.currentTrackIndex) for start time \(playbackSession.currentTime)")
let playerItems = self.allPlayerItems[self.currentTrackIndex..<self.allPlayerItems.count] let playerItems = self.allPlayerItems[self.currentTrackIndex..<self.allPlayerItems.count]
NSLog("TEST: Setting player items \(playerItems.count)") NSLog("Setting player items \(playerItems.count)")
for item in Array(playerItems) { for item in Array(playerItems) {
self.audioPlayer.insert(item, after:self.audioPlayer.items().last) self.audioPlayer.insert(item, after:self.audioPlayer.items().last)
@ -123,7 +123,7 @@ class AudioPlayer: NSObject {
self.audioPlayer.currentItem.map { item in self.audioPlayer.currentItem.map { item in
self.currentTrackIndex = self.allPlayerItems.firstIndex(of:item) ?? 0 self.currentTrackIndex = self.allPlayerItems.firstIndex(of:item) ?? 0
if (self.currentTrackIndex != prevTrackIndex) { if (self.currentTrackIndex != prevTrackIndex) {
NSLog("TEST: New Current track index \(self.currentTrackIndex)") NSLog("New Current track index \(self.currentTrackIndex)")
} }
} }
} }
@ -133,7 +133,7 @@ class AudioPlayer: NSObject {
self.queueItemStatusObserver?.invalidate() self.queueItemStatusObserver?.invalidate()
self.queueItemStatusObserver = self.audioPlayer.currentItem?.observe(\.status, options: [.new, .old], changeHandler: { (playerItem, change) in self.queueItemStatusObserver = self.audioPlayer.currentItem?.observe(\.status, options: [.new, .old], changeHandler: { (playerItem, change) in
if (playerItem.status == .readyToPlay) { if (playerItem.status == .readyToPlay) {
NSLog("TEST: queueStatusObserver: Current Item Ready to play. PlayWhenReady: \(self.playWhenReady)") NSLog("queueStatusObserver: Current Item Ready to play. PlayWhenReady: \(self.playWhenReady)")
self.updateNowPlaying() self.updateNowPlaying()
let firstReady = self.status < 0 let firstReady = self.status < 0
@ -146,7 +146,7 @@ class AudioPlayer: NSObject {
self.seek(self.playbackSession.currentTime, from: "queueItemStatusObserver") self.seek(self.playbackSession.currentTime, from: "queueItemStatusObserver")
} }
} else if (playerItem.status == .failed) { } else if (playerItem.status == .failed) {
NSLog("TEST: queueStatusObserver: FAILED \(playerItem.error?.localizedDescription ?? "")") NSLog("queueStatusObserver: FAILED \(playerItem.error?.localizedDescription ?? "")")
NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.failed.rawValue), object: nil) NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.failed.rawValue), object: nil)
} }
@ -203,16 +203,16 @@ class AudioPlayer: NSObject {
pause() pause()
NSLog("TEST: Seek to \(to) from \(from)") NSLog("Seek to \(to) from \(from)")
let currentTrack = self.playbackSession.audioTracks[self.currentTrackIndex] let currentTrack = self.playbackSession.audioTracks[self.currentTrackIndex]
let ctso = currentTrack.startOffset ?? 0.0 let ctso = currentTrack.startOffset ?? 0.0
let trackEnd = ctso + currentTrack.duration let trackEnd = ctso + currentTrack.duration
NSLog("TEST: Seek current track END = \(trackEnd)") NSLog("Seek current track END = \(trackEnd)")
let indexOfSeek = getItemIndexForTime(time: to) let indexOfSeek = getItemIndexForTime(time: to)
NSLog("TEST: Seek to index \(indexOfSeek) | Current index \(self.currentTrackIndex)") NSLog("Seek to index \(indexOfSeek) | Current index \(self.currentTrackIndex)")
// Reconstruct queue if seeking to a different track // Reconstruct queue if seeking to a different track
if (self.currentTrackIndex != indexOfSeek) { if (self.currentTrackIndex != indexOfSeek) {
@ -231,7 +231,7 @@ class AudioPlayer: NSObject {
setupQueueItemStatusObserver() setupQueueItemStatusObserver()
} else { } else {
NSLog("TEST: Seeking in current item \(to)") NSLog("Seeking in current item \(to)")
let currentTrackStartOffset = self.playbackSession.audioTracks[self.currentTrackIndex].startOffset ?? 0.0 let currentTrackStartOffset = self.playbackSession.audioTracks[self.currentTrackIndex].startOffset ?? 0.0
let seekTime = to - currentTrackStartOffset let seekTime = to - currentTrackStartOffset
@ -250,7 +250,7 @@ class AudioPlayer: NSObject {
public func setPlaybackRate(_ rate: Float, observed: Bool = false) { public func setPlaybackRate(_ rate: Float, observed: Bool = false) {
if self.audioPlayer.rate != rate { if self.audioPlayer.rate != rate {
NSLog("TEST: setPlaybakRate rate changed from \(self.audioPlayer.rate) to \(rate)") NSLog("setPlaybakRate rate changed from \(self.audioPlayer.rate) to \(rate)")
self.audioPlayer.rate = rate self.audioPlayer.rate = rate
} }
if rate > 0.0 && !(observed && rate == 1) { if rate > 0.0 && !(observed && rate == 1) {
@ -373,7 +373,7 @@ class AudioPlayer: NSObject {
public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &playerContext { if context == &playerContext {
if keyPath == #keyPath(AVPlayer.rate) { if keyPath == #keyPath(AVPlayer.rate) {
NSLog("TEST: playerContext observer player rate") NSLog("playerContext observer player rate")
self.setPlaybackRate(change?[.newKey] as? Float ?? 1.0, observed: true) self.setPlaybackRate(change?[.newKey] as? Float ?? 1.0, observed: true)
} else if keyPath == #keyPath(AVPlayer.currentItem) { } else if keyPath == #keyPath(AVPlayer.currentItem) {
NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.update.rawValue), object: nil) NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.update.rawValue), object: nil)

View file

@ -128,4 +128,24 @@ class Database {
return instance.objects(ServerConnectionConfigActiveIndex.self).first?.index ?? nil return instance.objects(ServerConnectionConfigActiveIndex.self).first?.index ?? nil
} }
} }
public func setDeviceSettings(deviceSettings: DeviceSettings) {
Database.realmQueue.sync {
let existing = instance.objects(DeviceSettings.self)
do {
try instance.write {
instance.delete(existing)
instance.add(deviceSettings)
}
} catch(let exception) {
NSLog("failed to save device settings")
debugPrint(exception)
}
}
}
public func getDeviceSettings() -> DeviceSettings {
return Database.realmQueue.sync {
return instance.objects(DeviceSettings.self).first ?? getDefaultDeviceSettings()
}
}
} }

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="w-full h-full p-8"> <div class="w-full h-full p-8">
<div class="flex items-center py-3" @click="toggleDisableAutoRewind"> <div v-if="$platform !== 'ios'" class="flex items-center py-3" @click="toggleDisableAutoRewind">
<div class="w-10 flex justify-center"> <div class="w-10 flex justify-center">
<ui-toggle-switch v-model="settings.disableAutoRewind" @input="saveSettings" /> <ui-toggle-switch v-model="settings.disableAutoRewind" @input="saveSettings" />
</div> </div>