Initial work

This commit is contained in:
Marcos Carvalho 2024-05-23 22:33:06 +01:00
parent f047f6a23b
commit d788623509
No known key found for this signature in database
9 changed files with 214 additions and 44 deletions

View file

@ -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
) )
} }
} }

View file

@ -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 {

View file

@ -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

View file

@ -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"
}
} }
) )

View file

@ -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 ?? ""]

View file

@ -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
] ]
} }

View file

@ -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

View file

@ -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)
} }
} }

View file

@ -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"
} }