mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-07-31 08:04:46 +02:00
Initial work
This commit is contained in:
parent
f047f6a23b
commit
d788623509
9 changed files with 214 additions and 44 deletions
|
@ -20,6 +20,14 @@ enum class ShakeSensitivitySetting {
|
||||||
VERY_LOW, LOW, MEDIUM, HIGH, VERY_HIGH
|
VERY_LOW, LOW, MEDIUM, HIGH, VERY_HIGH
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class DownloadUsingCellularSetting {
|
||||||
|
ASK, ALWAYS, NEVER
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class StreamingUsingCellularSetting {
|
||||||
|
ASK, ALWAYS, NEVER
|
||||||
|
}
|
||||||
|
|
||||||
data class ServerConnectionConfig(
|
data class ServerConnectionConfig(
|
||||||
var id:String,
|
var id:String,
|
||||||
var index:Int,
|
var index:Int,
|
||||||
|
@ -123,7 +131,9 @@ data class DeviceSettings(
|
||||||
var sleepTimerLength: Long, // Time in milliseconds
|
var sleepTimerLength: Long, // Time in milliseconds
|
||||||
var disableSleepTimerFadeOut: Boolean,
|
var disableSleepTimerFadeOut: Boolean,
|
||||||
var disableSleepTimerResetFeedback: Boolean,
|
var disableSleepTimerResetFeedback: Boolean,
|
||||||
var languageCode: String
|
var languageCode: String,
|
||||||
|
var downloadUsingCellular: DownloadUsingCellularSetting,
|
||||||
|
var streamingUsingCellular: StreamingUsingCellularSetting
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
// Static method to get default device settings
|
// Static method to get default device settings
|
||||||
|
@ -147,7 +157,9 @@ data class DeviceSettings(
|
||||||
autoSleepTimerAutoRewindTime = 300000L, // 5 minutes
|
autoSleepTimerAutoRewindTime = 300000L, // 5 minutes
|
||||||
disableSleepTimerFadeOut = false,
|
disableSleepTimerFadeOut = false,
|
||||||
disableSleepTimerResetFeedback = false,
|
disableSleepTimerResetFeedback = false,
|
||||||
languageCode = "en-us"
|
languageCode = "en-us",
|
||||||
|
downloadUsingCellular = DownloadUsingCellularSetting.ALWAYS,
|
||||||
|
streamingUsingCellular = StreamingUsingCellularItems.ALWAYS
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,14 @@ object DeviceManager {
|
||||||
if (deviceData.deviceSettings?.languageCode == null) {
|
if (deviceData.deviceSettings?.languageCode == null) {
|
||||||
deviceData.deviceSettings?.languageCode = "en-us"
|
deviceData.deviceSettings?.languageCode = "en-us"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deviceData.deviceSettings?.downloadUsingCellular == null) {
|
||||||
|
deviceData.deviceSettings?.downloadUsingCellular = DownloadUsingCellularSetting.ALWAYS
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceData.deviceSettings?.streamingUsingCellular == null) {
|
||||||
|
deviceData.deviceSettings?.streamingUsingCellular = StreamingUsingCellularSetting.ALWAYS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBase64Id(id:String):String {
|
fun getBase64Id(id:String):String {
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { Dialog } from '@capacitor/dialog'
|
||||||
import { AbsFileSystem, AbsDownloader } from '@/plugins/capacitor'
|
import { AbsFileSystem, AbsDownloader } from '@/plugins/capacitor'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -96,6 +97,15 @@ export default {
|
||||||
userCanDownload() {
|
userCanDownload() {
|
||||||
return this.$store.getters['user/getUserCanDownload']
|
return this.$store.getters['user/getUserCanDownload']
|
||||||
},
|
},
|
||||||
|
canDownloadUsingCellular() {
|
||||||
|
return this.$store.getters['getCanDownloadUsingCellular']
|
||||||
|
},
|
||||||
|
canStreamUsingCellular() {
|
||||||
|
return this.$store.getters['getCanStreamingUsingCellular']
|
||||||
|
},
|
||||||
|
isCellular() {
|
||||||
|
return this.$store.state.networkConnectionType === 'cellular'
|
||||||
|
},
|
||||||
audioFile() {
|
audioFile() {
|
||||||
return this.episode.audioFile
|
return this.episode.audioFile
|
||||||
},
|
},
|
||||||
|
@ -185,8 +195,45 @@ export default {
|
||||||
}
|
}
|
||||||
return folderObj
|
return folderObj
|
||||||
},
|
},
|
||||||
|
async confirmAction(action) {
|
||||||
|
const { value } = await Dialog.confirm({
|
||||||
|
title: 'Confirm',
|
||||||
|
message: `You are about to ${action} using cellular data. Do you want to proceed?`
|
||||||
|
});
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
async checkDownloadPermission() {
|
||||||
|
if (this.isCellular) {
|
||||||
|
const permission = this.canDownloadUsingCellular
|
||||||
|
if (permission === 'NEVER') {
|
||||||
|
this.$toast.error('Downloading is not allowed on cellular data.')
|
||||||
|
return false
|
||||||
|
} else if (permission === 'ASK') {
|
||||||
|
const confirmed = await this.confirmAction('download')
|
||||||
|
return confirmed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
async checkStreamPermission() {
|
||||||
|
if (this.isCellular) {
|
||||||
|
const permission = this.canStreamUsingCellular
|
||||||
|
if (permission === 'NEVER') {
|
||||||
|
this.$toast.error('Streaming is not allowed on cellular data.')
|
||||||
|
return false
|
||||||
|
} else if (permission === 'ASK') {
|
||||||
|
const confirmed = await this.confirmAction('stream')
|
||||||
|
return confirmed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
async downloadClick() {
|
async downloadClick() {
|
||||||
if (this.downloadItem || this.pendingDownload) return
|
if (this.downloadItem || this.pendingDownload) return
|
||||||
|
|
||||||
|
const hasPermission = await this.checkDownloadPermission()
|
||||||
|
if (!hasPermission) return
|
||||||
|
|
||||||
this.pendingDownload = true
|
this.pendingDownload = true
|
||||||
await this.$hapticsImpact()
|
await this.$hapticsImpact()
|
||||||
if (this.isIos) {
|
if (this.isIos) {
|
||||||
|
@ -258,9 +305,8 @@ export default {
|
||||||
if (this.streamIsPlaying) {
|
if (this.streamIsPlaying) {
|
||||||
this.$eventBus.$emit('pause-item')
|
this.$eventBus.$emit('pause-item')
|
||||||
} else {
|
} else {
|
||||||
this.$store.commit('setPlayerIsStartingPlayback', this.episode.id)
|
|
||||||
|
|
||||||
if (this.localEpisode && this.localLibraryItemId) {
|
if (this.localEpisode && this.localLibraryItemId) {
|
||||||
|
this.$store.commit('setPlayerIsStartingPlayback', this.episode.id)
|
||||||
console.log('Play local episode', this.localEpisode.id, this.localLibraryItemId)
|
console.log('Play local episode', this.localEpisode.id, this.localLibraryItemId)
|
||||||
|
|
||||||
this.$eventBus.$emit('play-item', {
|
this.$eventBus.$emit('play-item', {
|
||||||
|
@ -270,6 +316,10 @@ export default {
|
||||||
serverEpisodeId: this.episode.id
|
serverEpisodeId: this.episode.id
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
const hasPermission = await this.checkStreamPermission()
|
||||||
|
if (!hasPermission) return
|
||||||
|
|
||||||
|
this.$store.commit('setPlayerIsStartingPlayback', this.episode.id)
|
||||||
this.$eventBus.$emit('play-item', {
|
this.$eventBus.$emit('play-item', {
|
||||||
libraryItemId: this.libraryItemId,
|
libraryItemId: this.libraryItemId,
|
||||||
episodeId: this.episode.id
|
episodeId: this.episode.id
|
||||||
|
|
|
@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
// Override point for customization after application launch.
|
// Override point for customization after application launch.
|
||||||
|
|
||||||
let configuration = Realm.Configuration(
|
let configuration = Realm.Configuration(
|
||||||
schemaVersion: 17,
|
schemaVersion: 18,
|
||||||
migrationBlock: { [weak self] migration, oldSchemaVersion in
|
migrationBlock: { [weak self] migration, oldSchemaVersion in
|
||||||
if (oldSchemaVersion < 1) {
|
if (oldSchemaVersion < 1) {
|
||||||
self?.logger.log("Realm schema version was \(oldSchemaVersion)")
|
self?.logger.log("Realm schema version was \(oldSchemaVersion)")
|
||||||
|
@ -54,6 +54,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
newObject?["chapterTrack"] = false
|
newObject?["chapterTrack"] = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (oldSchemaVersion < 17) {
|
||||||
|
self?.logger.log("Realm schema version was \(oldSchemaVersion)... Adding downloadUsingCellular and streamingUsingCellular settings")
|
||||||
|
migration.enumerateObjects(ofType: PlayerSettings.className()) { oldObject, newObject in
|
||||||
|
newObject?["downloadUsingCellular"] = "ALWAYS"
|
||||||
|
newObject?["streamingUsingCellular"] = "ALWAYS"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -29,20 +29,20 @@ extension String {
|
||||||
@objc(AbsDatabase)
|
@objc(AbsDatabase)
|
||||||
public class AbsDatabase: CAPPlugin {
|
public class AbsDatabase: CAPPlugin {
|
||||||
private let logger = AppLogger(category: "AbsDatabase")
|
private let logger = AppLogger(category: "AbsDatabase")
|
||||||
|
|
||||||
@objc func setCurrentServerConnectionConfig(_ call: CAPPluginCall) {
|
@objc func setCurrentServerConnectionConfig(_ call: CAPPluginCall) {
|
||||||
var id = call.getString("id")
|
var id = call.getString("id")
|
||||||
let address = call.getString("address", "")
|
let address = call.getString("address", "")
|
||||||
let userId = call.getString("userId", "")
|
let userId = call.getString("userId", "")
|
||||||
let username = call.getString("username", "")
|
let username = call.getString("username", "")
|
||||||
let token = call.getString("token", "")
|
let token = call.getString("token", "")
|
||||||
|
|
||||||
let name = "\(address) (\(username))"
|
let name = "\(address) (\(username))"
|
||||||
|
|
||||||
if id == nil {
|
if id == nil {
|
||||||
id = "\(address)@\(username)".toBase64()
|
id = "\(address)@\(username)".toBase64()
|
||||||
}
|
}
|
||||||
|
|
||||||
let config = ServerConnectionConfig()
|
let config = ServerConnectionConfig()
|
||||||
config.id = id ?? ""
|
config.id = id ?? ""
|
||||||
config.index = 0
|
config.index = 0
|
||||||
|
@ -51,7 +51,7 @@ public class AbsDatabase: CAPPlugin {
|
||||||
config.userId = userId
|
config.userId = userId
|
||||||
config.username = username
|
config.username = username
|
||||||
config.token = token
|
config.token = token
|
||||||
|
|
||||||
Store.serverConfig = config
|
Store.serverConfig = config
|
||||||
let savedConfig = Store.serverConfig // Fetch the latest value
|
let savedConfig = Store.serverConfig // Fetch the latest value
|
||||||
call.resolve(convertServerConnectionConfigToJSON(config: savedConfig!))
|
call.resolve(convertServerConnectionConfigToJSON(config: savedConfig!))
|
||||||
|
@ -59,26 +59,26 @@ public class AbsDatabase: CAPPlugin {
|
||||||
@objc func removeServerConnectionConfig(_ call: CAPPluginCall) {
|
@objc func removeServerConnectionConfig(_ call: CAPPluginCall) {
|
||||||
let id = call.getString("serverConnectionConfigId", "")
|
let id = call.getString("serverConnectionConfigId", "")
|
||||||
Database.shared.deleteServerConnectionConfig(id: id)
|
Database.shared.deleteServerConnectionConfig(id: id)
|
||||||
|
|
||||||
call.resolve()
|
call.resolve()
|
||||||
}
|
}
|
||||||
@objc func logout(_ call: CAPPluginCall) {
|
@objc func logout(_ call: CAPPluginCall) {
|
||||||
Store.serverConfig = nil
|
Store.serverConfig = nil
|
||||||
call.resolve()
|
call.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
@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()
|
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,
|
||||||
"deviceSettings": deviceSettingsToJSON(settings: settings)
|
"deviceSettings": deviceSettingsToJSON(settings: settings)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func getLocalLibraryItems(_ call: CAPPluginCall) {
|
@objc func getLocalLibraryItems(_ call: CAPPluginCall) {
|
||||||
do {
|
do {
|
||||||
let items = Database.shared.getLocalLibraryItems()
|
let items = Database.shared.getLocalLibraryItems()
|
||||||
|
@ -89,7 +89,7 @@ public class AbsDatabase: CAPPlugin {
|
||||||
call.resolve()
|
call.resolve()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func getLocalLibraryItem(_ call: CAPPluginCall) {
|
@objc func getLocalLibraryItem(_ call: CAPPluginCall) {
|
||||||
do {
|
do {
|
||||||
let item = Database.shared.getLocalLibraryItem(localLibraryItemId: call.getString("id") ?? "")
|
let item = Database.shared.getLocalLibraryItem(localLibraryItemId: call.getString("id") ?? "")
|
||||||
|
@ -105,7 +105,7 @@ public class AbsDatabase: CAPPlugin {
|
||||||
call.resolve()
|
call.resolve()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func getLocalLibraryItemByLId(_ call: CAPPluginCall) {
|
@objc func getLocalLibraryItemByLId(_ call: CAPPluginCall) {
|
||||||
do {
|
do {
|
||||||
let item = Database.shared.getLocalLibraryItem(byServerLibraryItemId: call.getString("libraryItemId") ?? "")
|
let item = Database.shared.getLocalLibraryItem(byServerLibraryItemId: call.getString("libraryItemId") ?? "")
|
||||||
|
@ -121,11 +121,11 @@ public class AbsDatabase: CAPPlugin {
|
||||||
call.resolve()
|
call.resolve()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func getLocalLibraryItemsInFolder(_ call: CAPPluginCall) {
|
@objc func getLocalLibraryItemsInFolder(_ call: CAPPluginCall) {
|
||||||
call.resolve([ "value": [] ])
|
call.resolve([ "value": [] ])
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func getAllLocalMediaProgress(_ call: CAPPluginCall) {
|
@objc func getAllLocalMediaProgress(_ call: CAPPluginCall) {
|
||||||
do {
|
do {
|
||||||
call.resolve([ "value": try Database.shared.getAllLocalMediaProgress().asDictionaryArray() ])
|
call.resolve([ "value": try Database.shared.getAllLocalMediaProgress().asDictionaryArray() ])
|
||||||
|
@ -135,7 +135,7 @@ public class AbsDatabase: CAPPlugin {
|
||||||
call.resolve(["value": []])
|
call.resolve(["value": []])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func removeLocalMediaProgress(_ call: CAPPluginCall) {
|
@objc func removeLocalMediaProgress(_ call: CAPPluginCall) {
|
||||||
let localMediaProgressId = call.getString("localMediaProgressId")
|
let localMediaProgressId = call.getString("localMediaProgressId")
|
||||||
guard let localMediaProgressId = localMediaProgressId else {
|
guard let localMediaProgressId = localMediaProgressId else {
|
||||||
|
@ -145,7 +145,7 @@ public class AbsDatabase: CAPPlugin {
|
||||||
try? Database.shared.removeLocalMediaProgress(localMediaProgressId: localMediaProgressId)
|
try? Database.shared.removeLocalMediaProgress(localMediaProgressId: localMediaProgressId)
|
||||||
call.resolve()
|
call.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func syncLocalSessionsWithServer(_ call: CAPPluginCall) {
|
@objc func syncLocalSessionsWithServer(_ call: CAPPluginCall) {
|
||||||
let isFirstSync = call.getBool("isFirstSync", false)
|
let isFirstSync = call.getBool("isFirstSync", false)
|
||||||
logger.log("syncLocalSessionsWithServer: Starting (First sync: \(isFirstSync))")
|
logger.log("syncLocalSessionsWithServer: Starting (First sync: \(isFirstSync))")
|
||||||
|
@ -153,19 +153,19 @@ public class AbsDatabase: CAPPlugin {
|
||||||
call.reject("syncLocalSessionsWithServer not connected to server")
|
call.reject("syncLocalSessionsWithServer not connected to server")
|
||||||
return call.resolve()
|
return call.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
await ApiClient.syncLocalSessionsWithServer(isFirstSync: isFirstSync)
|
await ApiClient.syncLocalSessionsWithServer(isFirstSync: isFirstSync)
|
||||||
call.resolve()
|
call.resolve()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func syncServerMediaProgressWithLocalMediaProgress(_ call: CAPPluginCall) {
|
@objc func syncServerMediaProgressWithLocalMediaProgress(_ call: CAPPluginCall) {
|
||||||
let serverMediaProgress = call.getJson("mediaProgress", type: MediaProgress.self)
|
let serverMediaProgress = call.getJson("mediaProgress", type: MediaProgress.self)
|
||||||
let localLibraryItemId = call.getString("localLibraryItemId")
|
let localLibraryItemId = call.getString("localLibraryItemId")
|
||||||
let localEpisodeId = call.getString("localEpisodeId")
|
let localEpisodeId = call.getString("localEpisodeId")
|
||||||
let localMediaProgressId = call.getString("localMediaProgressId")
|
let localMediaProgressId = call.getString("localMediaProgressId")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
guard let serverMediaProgress = serverMediaProgress else {
|
guard let serverMediaProgress = serverMediaProgress else {
|
||||||
return call.reject("serverMediaProgress not specified")
|
return call.reject("serverMediaProgress not specified")
|
||||||
|
@ -173,35 +173,35 @@ public class AbsDatabase: CAPPlugin {
|
||||||
guard localLibraryItemId != nil || localMediaProgressId != nil else {
|
guard localLibraryItemId != nil || localMediaProgressId != nil else {
|
||||||
return call.reject("localLibraryItemId or localMediaProgressId must be specified")
|
return call.reject("localLibraryItemId or localMediaProgressId must be specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
let localMediaProgress = try LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: localMediaProgressId, localLibraryItemId: localLibraryItemId, localEpisodeId: localEpisodeId)
|
let localMediaProgress = try LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: localMediaProgressId, localLibraryItemId: localLibraryItemId, localEpisodeId: localEpisodeId)
|
||||||
guard let localMediaProgress = localMediaProgress else {
|
guard let localMediaProgress = localMediaProgress else {
|
||||||
call.reject("Local media progress not found or created")
|
call.reject("Local media progress not found or created")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log("syncServerMediaProgressWithLocalMediaProgress: Saving local media progress")
|
logger.log("syncServerMediaProgressWithLocalMediaProgress: Saving local media progress")
|
||||||
try localMediaProgress.updateFromServerMediaProgress(serverMediaProgress)
|
try localMediaProgress.updateFromServerMediaProgress(serverMediaProgress)
|
||||||
|
|
||||||
call.resolve(try localMediaProgress.asDictionary())
|
call.resolve(try localMediaProgress.asDictionary())
|
||||||
} catch {
|
} catch {
|
||||||
call.reject("Failed to sync media progress")
|
call.reject("Failed to sync media progress")
|
||||||
debugPrint(error)
|
debugPrint(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateLocalMediaProgressFinished(_ call: CAPPluginCall) {
|
@objc func updateLocalMediaProgressFinished(_ call: CAPPluginCall) {
|
||||||
let localLibraryItemId = call.getString("localLibraryItemId")
|
let localLibraryItemId = call.getString("localLibraryItemId")
|
||||||
let localEpisodeId = call.getString("localEpisodeId")
|
let localEpisodeId = call.getString("localEpisodeId")
|
||||||
let isFinished = call.getBool("isFinished", false)
|
let isFinished = call.getBool("isFinished", false)
|
||||||
|
|
||||||
var localMediaProgressId = localLibraryItemId ?? ""
|
var localMediaProgressId = localLibraryItemId ?? ""
|
||||||
if localEpisodeId != nil {
|
if localEpisodeId != nil {
|
||||||
localMediaProgressId += "-\(localEpisodeId ?? "")"
|
localMediaProgressId += "-\(localEpisodeId ?? "")"
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log("updateLocalMediaProgressFinished \(localMediaProgressId) | Is Finished: \(isFinished)")
|
logger.log("updateLocalMediaProgressFinished \(localMediaProgressId) | Is Finished: \(isFinished)")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let localMediaProgress = try LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: localMediaProgressId, localLibraryItemId: localLibraryItemId, localEpisodeId: localEpisodeId)
|
let localMediaProgress = try LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: localMediaProgressId, localLibraryItemId: localLibraryItemId, localEpisodeId: localEpisodeId)
|
||||||
guard let localMediaProgress = localMediaProgress else {
|
guard let localMediaProgress = localMediaProgress else {
|
||||||
|
@ -211,11 +211,11 @@ public class AbsDatabase: CAPPlugin {
|
||||||
|
|
||||||
// Update finished status
|
// Update finished status
|
||||||
try localMediaProgress.updateIsFinished(isFinished)
|
try localMediaProgress.updateIsFinished(isFinished)
|
||||||
|
|
||||||
// Build API response
|
// Build API response
|
||||||
let progressDictionary = try? localMediaProgress.asDictionary()
|
let progressDictionary = try? localMediaProgress.asDictionary()
|
||||||
var response: [String: Any] = ["local": true, "server": false, "localMediaProgress": progressDictionary ?? ""]
|
var response: [String: Any] = ["local": true, "server": false, "localMediaProgress": progressDictionary ?? ""]
|
||||||
|
|
||||||
// Send update to the server if logged in
|
// Send update to the server if logged in
|
||||||
let hasLinkedServer = localMediaProgress.serverConnectionConfigId != nil
|
let hasLinkedServer = localMediaProgress.serverConnectionConfigId != nil
|
||||||
let loggedIntoServer = Store.serverConfig?.id == localMediaProgress.serverConnectionConfigId
|
let loggedIntoServer = Store.serverConfig?.id == localMediaProgress.serverConnectionConfigId
|
||||||
|
@ -234,7 +234,7 @@ public class AbsDatabase: CAPPlugin {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateDeviceSettings(_ call: CAPPluginCall) {
|
@objc func updateDeviceSettings(_ call: CAPPluginCall) {
|
||||||
let disableAutoRewind = call.getBool("disableAutoRewind") ?? false
|
let disableAutoRewind = call.getBool("disableAutoRewind") ?? false
|
||||||
let enableAltView = call.getBool("enableAltView") ?? false
|
let enableAltView = call.getBool("enableAltView") ?? false
|
||||||
|
@ -244,6 +244,8 @@ public class AbsDatabase: CAPPlugin {
|
||||||
let lockOrientation = call.getString("lockOrientation") ?? "NONE"
|
let lockOrientation = call.getString("lockOrientation") ?? "NONE"
|
||||||
let hapticFeedback = call.getString("hapticFeedback") ?? "LIGHT"
|
let hapticFeedback = call.getString("hapticFeedback") ?? "LIGHT"
|
||||||
let languageCode = call.getString("languageCode") ?? "en-us"
|
let languageCode = call.getString("languageCode") ?? "en-us"
|
||||||
|
let downloadUsingCellular = call.getString("downloadUsingCellular") ?? "ALWAYS"
|
||||||
|
let streamingUsingCellular = call.getString("downloadUsingCellular") ?? "ALWAYS"
|
||||||
let settings = DeviceSettings()
|
let settings = DeviceSettings()
|
||||||
settings.disableAutoRewind = disableAutoRewind
|
settings.disableAutoRewind = disableAutoRewind
|
||||||
settings.enableAltView = enableAltView
|
settings.enableAltView = enableAltView
|
||||||
|
@ -253,22 +255,24 @@ public class AbsDatabase: CAPPlugin {
|
||||||
settings.lockOrientation = lockOrientation
|
settings.lockOrientation = lockOrientation
|
||||||
settings.hapticFeedback = hapticFeedback
|
settings.hapticFeedback = hapticFeedback
|
||||||
settings.languageCode = languageCode
|
settings.languageCode = languageCode
|
||||||
|
settings.downloadUsingCellular = downloadUsingCellular
|
||||||
|
settings.streamingUsingCellular = streamingUsingCellular
|
||||||
|
|
||||||
Database.shared.setDeviceSettings(deviceSettings: settings)
|
Database.shared.setDeviceSettings(deviceSettings: settings)
|
||||||
|
|
||||||
// Updates the media notification controls (for allowSeekingOnMediaControls setting)
|
// Updates the media notification controls (for allowSeekingOnMediaControls setting)
|
||||||
PlayerHandler.updateRemoteTransportControls()
|
PlayerHandler.updateRemoteTransportControls()
|
||||||
|
|
||||||
getDeviceData(call)
|
getDeviceData(call)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateLocalEbookProgress(_ call: CAPPluginCall) {
|
@objc func updateLocalEbookProgress(_ call: CAPPluginCall) {
|
||||||
let localLibraryItemId = call.getString("localLibraryItemId")
|
let localLibraryItemId = call.getString("localLibraryItemId")
|
||||||
let ebookLocation = call.getString("ebookLocation", "")
|
let ebookLocation = call.getString("ebookLocation", "")
|
||||||
let ebookProgress = call.getDouble("ebookProgress", 0.0)
|
let ebookProgress = call.getDouble("ebookProgress", 0.0)
|
||||||
|
|
||||||
logger.log("updateLocalEbookProgress \(localLibraryItemId ?? "Unknown") | ebookLocation: \(ebookLocation) | ebookProgress: \(ebookProgress)")
|
logger.log("updateLocalEbookProgress \(localLibraryItemId ?? "Unknown") | ebookLocation: \(ebookLocation) | ebookProgress: \(ebookProgress)")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let localMediaProgress = try LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: localLibraryItemId, localLibraryItemId: localLibraryItemId, localEpisodeId: nil)
|
let localMediaProgress = try LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: localLibraryItemId, localLibraryItemId: localLibraryItemId, localEpisodeId: nil)
|
||||||
guard let localMediaProgress = localMediaProgress else {
|
guard let localMediaProgress = localMediaProgress else {
|
||||||
|
@ -278,7 +282,7 @@ public class AbsDatabase: CAPPlugin {
|
||||||
|
|
||||||
// Update finished status
|
// Update finished status
|
||||||
try localMediaProgress.updateEbookProgress(ebookLocation: ebookLocation, ebookProgress: ebookProgress)
|
try localMediaProgress.updateEbookProgress(ebookLocation: ebookLocation, ebookProgress: ebookProgress)
|
||||||
|
|
||||||
// Build API response
|
// Build API response
|
||||||
let progressDictionary = try? localMediaProgress.asDictionary()
|
let progressDictionary = try? localMediaProgress.asDictionary()
|
||||||
let response: [String: Any] = ["localMediaProgress": progressDictionary ?? ""]
|
let response: [String: Any] = ["localMediaProgress": progressDictionary ?? ""]
|
||||||
|
|
|
@ -17,6 +17,8 @@ class DeviceSettings: Object {
|
||||||
@Persisted var lockOrientation: String = "NONE"
|
@Persisted var lockOrientation: String = "NONE"
|
||||||
@Persisted var hapticFeedback: String = "LIGHT"
|
@Persisted var hapticFeedback: String = "LIGHT"
|
||||||
@Persisted var languageCode: String = "en-us"
|
@Persisted var languageCode: String = "en-us"
|
||||||
|
@Persisted var downloadUsingCellular: String = "ALWAYS"
|
||||||
|
@Persisted var streamingUsingCellular: String = "ALWAYS"
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDefaultDeviceSettings() -> DeviceSettings {
|
func getDefaultDeviceSettings() -> DeviceSettings {
|
||||||
|
@ -32,6 +34,8 @@ func deviceSettingsToJSON(settings: DeviceSettings) -> Dictionary<String, Any> {
|
||||||
"jumpForwardTime": settings.jumpForwardTime,
|
"jumpForwardTime": settings.jumpForwardTime,
|
||||||
"lockOrientation": settings.lockOrientation,
|
"lockOrientation": settings.lockOrientation,
|
||||||
"hapticFeedback": settings.hapticFeedback,
|
"hapticFeedback": settings.hapticFeedback,
|
||||||
"languageCode": settings.languageCode
|
"languageCode": settings.languageCode,
|
||||||
|
"downloadUsingCellular": settings.downloadUsingCellular,
|
||||||
|
"streamingUsingCellular": settings.streamingUsingCellular
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,6 +135,21 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Data settings -->
|
||||||
|
<p class="uppercase text-xs font-semibold text-fg-muted mb-2 mt-10">{{ $strings.HeaderDataSettings }}</p>
|
||||||
|
<div class="py-3 flex items-center">
|
||||||
|
<p class="pr-4 w-36">{{ $strings.LabelDownloadUsingCellular }}</p>
|
||||||
|
<div @click.stop="showDownloadUsingCellularOptions">
|
||||||
|
<ui-text-input :value="downloadUsingCellularOption" readonly append-icon="expand_more" style="max-width: 200px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="py-3 flex items-center">
|
||||||
|
<p class="pr-4 w-36">{{ $strings.LabelStreamingUsingCellular }}</p>
|
||||||
|
<div @click.stop="showStreamingUsingCellularOptions">
|
||||||
|
<ui-text-input :value="streamingUsingCellularOption" readonly append-icon="expand_more" style="max-width: 200px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-show="loading" class="w-full h-full absolute top-0 left-0 flex items-center justify-center z-10">
|
<div v-show="loading" class="w-full h-full absolute top-0 left-0 flex items-center justify-center z-10">
|
||||||
<ui-loading-indicator />
|
<ui-loading-indicator />
|
||||||
</div>
|
</div>
|
||||||
|
@ -176,7 +191,9 @@ export default {
|
||||||
disableSleepTimerResetFeedback: false,
|
disableSleepTimerResetFeedback: false,
|
||||||
autoSleepTimerAutoRewind: false,
|
autoSleepTimerAutoRewind: false,
|
||||||
autoSleepTimerAutoRewindTime: 300000, // 5 minutes
|
autoSleepTimerAutoRewindTime: 300000, // 5 minutes
|
||||||
languageCode: 'en-us'
|
languageCode: 'en-us',
|
||||||
|
downloadUsingCellular: 'ALWAYS',
|
||||||
|
streamingUsingCellular: 'ALWAYS'
|
||||||
},
|
},
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
lockCurrentOrientation: false,
|
lockCurrentOrientation: false,
|
||||||
|
@ -245,6 +262,34 @@ export default {
|
||||||
text: this.$strings.LabelVeryHigh,
|
text: this.$strings.LabelVeryHigh,
|
||||||
value: 'VERY_HIGH'
|
value: 'VERY_HIGH'
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
downloadUsingCellularItems: [
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelAskConfirmation,
|
||||||
|
value: 'ASK'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelAlways,
|
||||||
|
value: 'ALWAYS'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelNever,
|
||||||
|
value: 'NEVER'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
streamingUsingCellularItems: [
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelAskConfirmation,
|
||||||
|
value: 'ASK'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelAlways,
|
||||||
|
value: 'ALWAYS'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelNever,
|
||||||
|
value: 'NEVER'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -319,11 +364,21 @@ export default {
|
||||||
const minutes = Number(this.settings.autoSleepTimerAutoRewindTime) / 1000 / 60
|
const minutes = Number(this.settings.autoSleepTimerAutoRewindTime) / 1000 / 60
|
||||||
return `${minutes} min`
|
return `${minutes} min`
|
||||||
},
|
},
|
||||||
|
downloadUsingCellularOption() {
|
||||||
|
const item = this.downloadUsingCellularItems.find((i) => i.value === this.settings.downloadUsingCellular)
|
||||||
|
return item?.text || 'Error'
|
||||||
|
},
|
||||||
|
streamingUsingCellularOption() {
|
||||||
|
const item = this.streamingUsingCellularItems.find((i) => i.value === this.settings.streamingUsingCellular)
|
||||||
|
return item?.text || 'Error'
|
||||||
|
},
|
||||||
moreMenuItems() {
|
moreMenuItems() {
|
||||||
if (this.moreMenuSetting === 'shakeSensitivity') return this.shakeSensitivityItems
|
if (this.moreMenuSetting === 'shakeSensitivity') return this.shakeSensitivityItems
|
||||||
else if (this.moreMenuSetting === 'hapticFeedback') return this.hapticFeedbackItems
|
else if (this.moreMenuSetting === 'hapticFeedback') return this.hapticFeedbackItems
|
||||||
else if (this.moreMenuSetting === 'language') return this.languageOptionItems
|
else if (this.moreMenuSetting === 'language') return this.languageOptionItems
|
||||||
else if (this.moreMenuSetting === 'theme') return this.themeOptionItems
|
else if (this.moreMenuSetting === 'theme') return this.themeOptionItems
|
||||||
|
else if (this.moreMenuSetting === 'downloadUsingCellular') return this.downloadUsingCellularItems
|
||||||
|
else if (this.moreMenuSetting === 'streamingUsingCellular') return this.streamingUsingCellularItems
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -358,6 +413,14 @@ export default {
|
||||||
this.moreMenuSetting = 'theme'
|
this.moreMenuSetting = 'theme'
|
||||||
this.showMoreMenuDialog = true
|
this.showMoreMenuDialog = true
|
||||||
},
|
},
|
||||||
|
showDownloadUsingCellularOptions() {
|
||||||
|
this.moreMenuSetting = 'downloadUsingCellular'
|
||||||
|
this.showMoreMenuDialog = true
|
||||||
|
},
|
||||||
|
showStreamingUsingCellularOptions() {
|
||||||
|
this.moreMenuSetting = 'streamingUsingCellular'
|
||||||
|
this.showMoreMenuDialog = true
|
||||||
|
},
|
||||||
clickMenuAction(action) {
|
clickMenuAction(action) {
|
||||||
this.showMoreMenuDialog = false
|
this.showMoreMenuDialog = false
|
||||||
if (this.moreMenuSetting === 'shakeSensitivity') {
|
if (this.moreMenuSetting === 'shakeSensitivity') {
|
||||||
|
@ -372,6 +435,12 @@ export default {
|
||||||
} else if (this.moreMenuSetting === 'theme') {
|
} else if (this.moreMenuSetting === 'theme') {
|
||||||
this.theme = action
|
this.theme = action
|
||||||
this.saveTheme(action)
|
this.saveTheme(action)
|
||||||
|
} else if (this.moreMenuSetting === 'downloadUsingCellular') {
|
||||||
|
this.settings.downloadUsingCellular = action
|
||||||
|
this.saveSettings()
|
||||||
|
} else if (this.moreMenuSetting === 'streamingUsingCellular') {
|
||||||
|
this.settings.streamingUsingCellular = action
|
||||||
|
this.saveSettings()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveTheme(theme) {
|
saveTheme(theme) {
|
||||||
|
@ -504,6 +573,9 @@ export default {
|
||||||
this.settings.autoSleepTimerAutoRewindTime = !isNaN(deviceSettings.autoSleepTimerAutoRewindTime) ? deviceSettings.autoSleepTimerAutoRewindTime : 300000 // 5 minutes
|
this.settings.autoSleepTimerAutoRewindTime = !isNaN(deviceSettings.autoSleepTimerAutoRewindTime) ? deviceSettings.autoSleepTimerAutoRewindTime : 300000 // 5 minutes
|
||||||
|
|
||||||
this.settings.languageCode = deviceSettings.languageCode || 'en-us'
|
this.settings.languageCode = deviceSettings.languageCode || 'en-us'
|
||||||
|
|
||||||
|
this.settings.downloadUsingCellular = deviceSettings.downloadUsingCellular || 'ALWAYS'
|
||||||
|
this.settings.streamingUsingCellular = deviceSettings.streamingUsingCellular || 'ALWAYS'
|
||||||
},
|
},
|
||||||
async init() {
|
async init() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|
|
@ -77,6 +77,14 @@ export const getters = {
|
||||||
},
|
},
|
||||||
getOrientationLockSetting: state => {
|
getOrientationLockSetting: state => {
|
||||||
return state.deviceData?.deviceSettings?.lockOrientation
|
return state.deviceData?.deviceSettings?.lockOrientation
|
||||||
|
},
|
||||||
|
getCanDownloadUsingCellular: state => {
|
||||||
|
if (!state.deviceData?.deviceSettings?.downloadUsingCellular) return 'ALWAYS'
|
||||||
|
return state.deviceData.deviceSettings.downloadUsingCellular || 'ALWAYS'
|
||||||
|
},
|
||||||
|
getCanStreamingUsingCellular: state => {
|
||||||
|
if (!state.deviceData?.deviceSettings?.streamingUsingCellular) return 'ALWAYS'
|
||||||
|
return state.deviceData.deviceSettings.streamingUsingCellular || 'ALWAYS'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,4 +188,4 @@ export const mutations = {
|
||||||
state.serverSettings = val
|
state.serverSettings = val
|
||||||
this.$localStore.setServerSettings(state.serverSettings)
|
this.$localStore.setServerSettings(state.serverSettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
"HeaderCollection": "Collection",
|
"HeaderCollection": "Collection",
|
||||||
"HeaderCollectionItems": "Collection Items",
|
"HeaderCollectionItems": "Collection Items",
|
||||||
"HeaderConnectionStatus": "Connection Status",
|
"HeaderConnectionStatus": "Connection Status",
|
||||||
|
"HeaderDataSettings": "Data Settings",
|
||||||
"HeaderDetails": "Details",
|
"HeaderDetails": "Details",
|
||||||
"HeaderDownloads": "Downloads",
|
"HeaderDownloads": "Downloads",
|
||||||
"HeaderEbookFiles": "Ebook Files",
|
"HeaderEbookFiles": "Ebook Files",
|
||||||
|
@ -87,6 +88,8 @@
|
||||||
"LabelAddToPlaylist": "Add to Playlist",
|
"LabelAddToPlaylist": "Add to Playlist",
|
||||||
"LabelAll": "All",
|
"LabelAll": "All",
|
||||||
"LabelAllowSeekingOnMediaControls": "Allow position seeking on media notification controls",
|
"LabelAllowSeekingOnMediaControls": "Allow position seeking on media notification controls",
|
||||||
|
"LabelAlways": "Always",
|
||||||
|
"LabelAskConfirmation": "Ask for confirmation",
|
||||||
"LabelAuthor": "Author",
|
"LabelAuthor": "Author",
|
||||||
"LabelAuthorFirstLast": "Author (First Last)",
|
"LabelAuthorFirstLast": "Author (First Last)",
|
||||||
"LabelAuthorLastFirst": "Author (Last, First)",
|
"LabelAuthorLastFirst": "Author (Last, First)",
|
||||||
|
@ -120,6 +123,7 @@
|
||||||
"LabelDiscover": "Discover",
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Download",
|
"LabelDownload": "Download",
|
||||||
"LabelDownloaded": "Downloaded",
|
"LabelDownloaded": "Downloaded",
|
||||||
|
"LabelDownloadUsingCellular": "Download using Cellular",
|
||||||
"LabelDuration": "Duration",
|
"LabelDuration": "Duration",
|
||||||
"LabelEbook": "Ebook",
|
"LabelEbook": "Ebook",
|
||||||
"LabelEbooks": "Ebooks",
|
"LabelEbooks": "Ebooks",
|
||||||
|
@ -170,6 +174,7 @@
|
||||||
"LabelName": "Name",
|
"LabelName": "Name",
|
||||||
"LabelNarrator": "Narrator",
|
"LabelNarrator": "Narrator",
|
||||||
"LabelNarrators": "Narrators",
|
"LabelNarrators": "Narrators",
|
||||||
|
"LabelNever": "Never",
|
||||||
"LabelNewestAuthors": "Newest Authors",
|
"LabelNewestAuthors": "Newest Authors",
|
||||||
"LabelNewestEpisodes": "Newest Episodes",
|
"LabelNewestEpisodes": "Newest Episodes",
|
||||||
"LabelNo": "No",
|
"LabelNo": "No",
|
||||||
|
@ -219,6 +224,7 @@
|
||||||
"LabelStatsMinutes": "minutes",
|
"LabelStatsMinutes": "minutes",
|
||||||
"LabelStatsMinutesListening": "Minutes Listening",
|
"LabelStatsMinutesListening": "Minutes Listening",
|
||||||
"LabelStatsWeekListening": "Week Listening",
|
"LabelStatsWeekListening": "Week Listening",
|
||||||
|
"LabelStreamingUsingCellular": "Streaming using Cellular",
|
||||||
"LabelTag": "Tag",
|
"LabelTag": "Tag",
|
||||||
"LabelTags": "Tags",
|
"LabelTags": "Tags",
|
||||||
"LabelTheme": "Theme",
|
"LabelTheme": "Theme",
|
||||||
|
@ -293,4 +299,4 @@
|
||||||
"ToastPodcastCreateSuccess": "Podcast created successfully",
|
"ToastPodcastCreateSuccess": "Podcast created successfully",
|
||||||
"ToastRSSFeedCloseFailed": "Failed to close RSS feed",
|
"ToastRSSFeedCloseFailed": "Failed to close RSS feed",
|
||||||
"ToastRSSFeedCloseSuccess": "RSS feed closed"
|
"ToastRSSFeedCloseSuccess": "RSS feed closed"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue