Compare commits

...
10 changed files with 191 additions and 51 deletions
@@ -236,32 +236,37 @@ class MediaManager(var apiHandler: ApiHandler, var ctx: Context) {
serverConfigIdUsed = DeviceManager.serverConnectionConfigId serverConfigIdUsed = DeviceManager.serverConnectionConfigId
loadLibraries { libraries -> loadLibraries { libraries ->
val library = libraries[0] if (libraries.isEmpty()) {
Log.d(tag, "Loading categories for library ${library.name} - ${library.id} - ${library.mediaType}") Log.w(tag, "No libraries returned from server request")
cb(cats) // Return download category only
} else {
val library = libraries[0]
Log.d(tag, "Loading categories for library ${library.name} - ${library.id} - ${library.mediaType}")
loadLibraryCategories(library.id) { libraryCategories -> loadLibraryCategories(library.id) { libraryCategories ->
// Only using book or podcast library categories for now // Only using book or podcast library categories for now
libraryCategories.forEach { libraryCategories.forEach {
// Add items in continue listening to serverLibraryItems // Add items in continue listening to serverLibraryItems
if (it.id == "continue-listening") { if (it.id == "continue-listening") {
it.entities.forEach { libraryItemWrapper -> it.entities.forEach { libraryItemWrapper ->
val libraryItem = libraryItemWrapper as LibraryItem val libraryItem = libraryItemWrapper as LibraryItem
if (serverLibraryItems.find { li -> li.id == libraryItem.id } == null) { if (serverLibraryItems.find { li -> li.id == libraryItem.id } == null) {
serverLibraryItems.add(libraryItem) serverLibraryItems.add(libraryItem)
}
} }
} }
// Log.d(tag, "Found library category ${it.label} with type ${it.type}")
if (it.type == library.mediaType) {
// Log.d(tag, "Using library category ${it.id}")
cats.add(it)
}
} }
// Log.d(tag, "Found library category ${it.label} with type ${it.type}") cb(cats)
if (it.type == library.mediaType) {
// Log.d(tag, "Using library category ${it.id}")
cats.add(it)
}
} }
cb(cats)
} }
} }
} else { // Not connected/no internet sent downloaded cats only } else { // Not connected/no internet sent downloaded cats only
@@ -19,6 +19,7 @@ data class MediaProgressSyncData(
class MediaProgressSyncer(val playerNotificationService:PlayerNotificationService, private val apiHandler: ApiHandler) { class MediaProgressSyncer(val playerNotificationService:PlayerNotificationService, private val apiHandler: ApiHandler) {
private val tag = "MediaProgressSync" private val tag = "MediaProgressSync"
private val METERED_CONNECTION_SYNC_INTERVAL = 60000
private var listeningTimerTask: TimerTask? = null private var listeningTimerTask: TimerTask? = null
var listeningTimerRunning:Boolean = false var listeningTimerRunning:Boolean = false
@@ -46,7 +47,10 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
} else { } else {
return return
} }
} else if (playerNotificationService.getCurrentPlaybackSessionId() != currentSessionId) {
currentLocalMediaProgress = null
} }
listeningTimerRunning = true listeningTimerRunning = true
lastSyncTime = System.currentTimeMillis() lastSyncTime = System.currentTimeMillis()
currentPlaybackSession = playerNotificationService.getCurrentPlaybackSessionCopy() currentPlaybackSession = playerNotificationService.getCurrentPlaybackSessionCopy()
@@ -54,8 +58,11 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
listeningTimerTask = Timer("ListeningTimer", false).schedule(0L, 5000L) { listeningTimerTask = Timer("ListeningTimer", false).schedule(0L, 5000L) {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
if (playerNotificationService.currentPlayer.isPlaying) { if (playerNotificationService.currentPlayer.isPlaying) {
// Only sync with server on unmetered connection every 5s OR sync with server if last sync time is >= 60s
val shouldSyncServer = PlayerNotificationService.isUnmeteredNetwork || System.currentTimeMillis() - lastSyncTime >= METERED_CONNECTION_SYNC_INTERVAL
val currentTime = playerNotificationService.getCurrentTimeSeconds() val currentTime = playerNotificationService.getCurrentTimeSeconds()
sync(currentTime) { sync(shouldSyncServer, currentTime) {
Log.d(tag, "Sync complete") Log.d(tag, "Sync complete")
} }
} }
@@ -63,13 +70,30 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
} }
} }
fun stop() { fun stop(cb: () -> Unit) {
if (!listeningTimerRunning) return if (!listeningTimerRunning) return
Log.d(tag, "stop: Stopping listening for $currentDisplayTitle") Log.d(tag, "stop: Stopping listening for $currentDisplayTitle")
val currentTime = playerNotificationService.getCurrentTimeSeconds() val currentTime = playerNotificationService.getCurrentTimeSeconds()
sync(currentTime) { sync(true, currentTime) {
reset() reset()
cb()
}
}
fun pause(cb: () -> Unit) {
if (!listeningTimerRunning) return
Log.d(tag, "pause: Pausing progress syncer for $currentDisplayTitle")
val currentTime = playerNotificationService.getCurrentTimeSeconds()
sync(true, currentTime) {
listeningTimerTask?.cancel()
listeningTimerTask = null
listeningTimerRunning = false
lastSyncTime = 0L
failedSyncs = 0
cb()
} }
} }
@@ -77,19 +101,17 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
currentPlaybackSession?.let { currentPlaybackSession?.let {
it.updatedAt = mediaProgress.lastUpdate it.updatedAt = mediaProgress.lastUpdate
it.currentTime = mediaProgress.currentTime it.currentTime = mediaProgress.currentTime
DeviceManager.dbManager.saveLocalPlaybackSession(it) DeviceManager.dbManager.saveLocalPlaybackSession(it)
saveLocalProgress(it) saveLocalProgress(it)
} }
} }
fun sync(currentTime:Double, cb: () -> Unit) { fun sync(shouldSyncServer:Boolean, currentTime:Double, cb: () -> Unit) {
val diffSinceLastSync = System.currentTimeMillis() - lastSyncTime val diffSinceLastSync = System.currentTimeMillis() - lastSyncTime
if (diffSinceLastSync < 1000L) { if (diffSinceLastSync < 1000L) {
return cb() return cb()
} }
val listeningTimeToAdd = diffSinceLastSync / 1000L val listeningTimeToAdd = diffSinceLastSync / 1000L
lastSyncTime = System.currentTimeMillis()
val syncData = MediaProgressSyncData(listeningTimeToAdd,currentPlaybackDuration,currentTime) val syncData = MediaProgressSyncData(listeningTimeToAdd,currentPlaybackDuration,currentTime)
@@ -105,10 +127,11 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
currentPlaybackSession?.let { currentPlaybackSession?.let {
DeviceManager.dbManager.saveLocalPlaybackSession(it) DeviceManager.dbManager.saveLocalPlaybackSession(it)
saveLocalProgress(it) saveLocalProgress(it)
lastSyncTime = System.currentTimeMillis()
// Local library item is linked to a server library item // Local library item is linked to a server library item
// Send sync to server also if connected to this server and local item belongs to this server // Send sync to server also if connected to this server and local item belongs to this server
if (!it.libraryItemId.isNullOrEmpty() && it.serverConnectionConfigId != null && DeviceManager.serverConnectionConfig?.id == it.serverConnectionConfigId) { if (shouldSyncServer && !it.libraryItemId.isNullOrEmpty() && it.serverConnectionConfigId != null && DeviceManager.serverConnectionConfig?.id == it.serverConnectionConfigId) {
apiHandler.sendLocalProgressSync(it) { syncSuccess -> apiHandler.sendLocalProgressSync(it) { syncSuccess ->
Log.d( Log.d(
tag, tag,
@@ -132,12 +155,13 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
cb() cb()
} }
} }
} else { } else if (shouldSyncServer) {
apiHandler.sendProgressSync(currentSessionId, syncData) { apiHandler.sendProgressSync(currentSessionId, syncData) {
if (it) { if (it) {
Log.d(tag, "Progress sync data sent to server $currentDisplayTitle for time $currentTime") Log.d(tag, "Progress sync data sent to server $currentDisplayTitle for time $currentTime")
failedSyncs = 0 failedSyncs = 0
playerNotificationService.alertSyncSuccess() playerNotificationService.alertSyncSuccess()
lastSyncTime = System.currentTimeMillis()
} else { } else {
failedSyncs++ failedSyncs++
if (failedSyncs == 2) { if (failedSyncs == 2) {
@@ -148,6 +172,8 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
} }
cb() cb()
} }
} else {
cb()
} }
} }
@@ -71,32 +71,36 @@ class PlayerListener(var playerNotificationService:PlayerNotificationService) :
if (player.isPlaying) { if (player.isPlaying) {
Log.d(tag, "SeekBackTime: Player is playing") Log.d(tag, "SeekBackTime: Player is playing")
if (lastPauseTime > 0 && DeviceManager.deviceData.deviceSettings?.disableAutoRewind != true) { if (lastPauseTime > 0 && DeviceManager.deviceData.deviceSettings?.disableAutoRewind != true) {
var seekBackTime = 0L
if (onSeekBack) onSeekBack = false if (onSeekBack) onSeekBack = false
else { else {
Log.d(tag, "SeekBackTime: playing started now set seek back time $lastPauseTime") Log.d(tag, "SeekBackTime: playing started now set seek back time $lastPauseTime")
var backTime = calcPauseSeekBackTime() seekBackTime = calcPauseSeekBackTime()
if (backTime > 0) { if (seekBackTime > 0) {
// Current chapter is used so that seek back does not go back to the previous chapter // Current chapter is used so that seek back does not go back to the previous chapter
val currentChapter = playerNotificationService.getCurrentBookChapter() val currentChapter = playerNotificationService.getCurrentBookChapter()
val minSeekBackTime = currentChapter?.startMs ?: 0 val minSeekBackTime = currentChapter?.startMs ?: 0
val currentTime = playerNotificationService.getCurrentTime() val currentTime = playerNotificationService.getCurrentTime()
val newTime = currentTime - backTime val newTime = currentTime - seekBackTime
if (newTime < minSeekBackTime) { if (newTime < minSeekBackTime) {
backTime = currentTime - minSeekBackTime seekBackTime = currentTime - minSeekBackTime
} }
Log.d(tag, "SeekBackTime $backTime") Log.d(tag, "SeekBackTime $seekBackTime")
onSeekBack = true onSeekBack = true
playerNotificationService.seekBackward(backTime)
} }
} }
// Check if playback session still exists or sync media progress if updated // Check if playback session still exists or sync media progress if updated
val pauseLength: Long = System.currentTimeMillis() - lastPauseTime val pauseLength: Long = System.currentTimeMillis() - lastPauseTime
if (pauseLength > PAUSE_LEN_BEFORE_RECHECK) { if (pauseLength > PAUSE_LEN_BEFORE_RECHECK) {
val shouldCarryOn = playerNotificationService.checkCurrentSessionProgress() val shouldCarryOn = playerNotificationService.checkCurrentSessionProgress(seekBackTime)
if (!shouldCarryOn) return if (!shouldCarryOn) return
} }
if (seekBackTime > 0L) {
playerNotificationService.seekBackward(seekBackTime)
}
} }
} else { } else {
Log.d(tag, "SeekBackTime: Player not playing set last pause time") Log.d(tag, "SeekBackTime: Player not playing set last pause time")
@@ -104,12 +108,13 @@ class PlayerListener(var playerNotificationService:PlayerNotificationService) :
} }
// Start/stop progress sync interval // Start/stop progress sync interval
Log.d(tag, "Playing ${playerNotificationService.getCurrentBookTitle()}")
if (player.isPlaying) { if (player.isPlaying) {
player.volume = 1F // Volume on sleep timer might have decreased this player.volume = 1F // Volume on sleep timer might have decreased this
playerNotificationService.mediaProgressSyncer.start() playerNotificationService.mediaProgressSyncer.start()
} else { } else {
playerNotificationService.mediaProgressSyncer.stop() playerNotificationService.mediaProgressSyncer.pause {
Log.d(tag, "Media Progress Syncer paused and synced")
}
} }
playerNotificationService.clientEventEmitter?.onPlayingUpdate(player.isPlaying) playerNotificationService.clientEventEmitter?.onPlayingUpdate(player.isPlaying)
@@ -6,6 +6,10 @@ import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.hardware.Sensor import android.hardware.Sensor
import android.hardware.SensorManager import android.hardware.SensorManager
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.* import android.os.*
import android.support.v4.media.MediaBrowserCompat import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaDescriptionCompat import android.support.v4.media.MediaDescriptionCompat
@@ -45,6 +49,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
companion object { companion object {
var isStarted = false var isStarted = false
var isClosed = false var isClosed = false
var isUnmeteredNetwork = false
} }
interface ClientEventEmitter { interface ClientEventEmitter {
@@ -59,6 +64,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
fun onMediaPlayerChanged(mediaPlayer:String) fun onMediaPlayerChanged(mediaPlayer:String)
fun onProgressSyncFailing() fun onProgressSyncFailing()
fun onProgressSyncSuccess() fun onProgressSyncSuccess()
fun onNetworkMeteredChanged(isUnmetered:Boolean)
} }
private val tag = "PlayerService" private val tag = "PlayerService"
@@ -164,6 +170,15 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
super.onCreate() super.onCreate()
ctx = this ctx = this
// To listen for network change from metered to unmetered
val networkRequest = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build()
val connectivityManager = getSystemService(ConnectivityManager::class.java) as ConnectivityManager
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
DbManager.initialize(ctx) DbManager.initialize(ctx)
// Initialize API // Initialize API
@@ -550,10 +565,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
// Called from PlayerListener play event // Called from PlayerListener play event
// check with server if progress has updated since last play and sync progress update // check with server if progress has updated since last play and sync progress update
fun checkCurrentSessionProgress():Boolean { fun checkCurrentSessionProgress(seekBackTime:Long):Boolean {
if (currentPlaybackSession == null) return true if (currentPlaybackSession == null) return true
currentPlaybackSession?.let { playbackSession -> mediaProgressSyncer.currentPlaybackSession?.let { playbackSession ->
if (!apiHandler.isOnline() || playbackSession.isLocalLibraryItemOnly) { if (!apiHandler.isOnline() || playbackSession.isLocalLibraryItemOnly) {
return true // carry on return true // carry on
} }
@@ -575,16 +590,28 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
Log.d(tag, "checkCurrentSessionProgress: Media progress was updated since last play time updating from ${playbackSession.currentTime} to ${mediaProgress.currentTime}") Log.d(tag, "checkCurrentSessionProgress: Media progress was updated since last play time updating from ${playbackSession.currentTime} to ${mediaProgress.currentTime}")
mediaProgressSyncer.syncFromServerProgress(mediaProgress) mediaProgressSyncer.syncFromServerProgress(mediaProgress)
// Update current playback session stored in PNS since MediaProgressSyncer version is a copy
mediaProgressSyncer.currentPlaybackSession?.let { updatedPlaybackSession ->
currentPlaybackSession = updatedPlaybackSession
}
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
seekPlayer(playbackSession.currentTimeMs) seekPlayer(playbackSession.currentTimeMs)
// Should already be playing
currentPlayer.volume = 1F // Volume on sleep timer might have decreased this
mediaProgressSyncer.start()
clientEventEmitter?.onPlayingUpdate(true)
}
} else {
Handler(Looper.getMainLooper()).post {
if (seekBackTime > 0L) {
seekBackward(seekBackTime)
}
// Should already be playing
currentPlayer.volume = 1F // Volume on sleep timer might have decreased this
mediaProgressSyncer.start()
clientEventEmitter?.onPlayingUpdate(true)
} }
}
Handler(Looper.getMainLooper()).post {
// Should already be playing
currentPlayer.volume = 1F // Volume on sleep timer might have decreased this
mediaProgressSyncer.start()
clientEventEmitter?.onPlayingUpdate(true)
} }
} }
} else { } else {
@@ -607,6 +634,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
} else { } else {
Log.d(tag, "checkCurrentSessionProgress: Playback session still available on server") Log.d(tag, "checkCurrentSessionProgress: Playback session still available on server")
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
if (seekBackTime > 0L) {
seekBackward(seekBackTime)
}
currentPlayer.volume = 1F // Volume on sleep timer might have decreased this currentPlayer.volume = 1F // Volume on sleep timer might have decreased this
mediaProgressSyncer.start() mediaProgressSyncer.start()
clientEventEmitter?.onPlayingUpdate(true) clientEventEmitter?.onPlayingUpdate(true)
@@ -673,7 +704,9 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
Log.d(tag, "closePlayback") Log.d(tag, "closePlayback")
if (mediaProgressSyncer.listeningTimerRunning) { if (mediaProgressSyncer.listeningTimerRunning) {
Log.i(tag, "About to close playback so stopping media progress syncer first") Log.i(tag, "About to close playback so stopping media progress syncer first")
mediaProgressSyncer.stop() mediaProgressSyncer.stop {
Log.d(tag, "Media Progress syncer stopped and synced")
}
} }
try { try {
@@ -896,5 +929,19 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
} }
} }
} }
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
// Network capabilities have changed for the network
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
val unmetered = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
Log.i(tag, "Network capabilities changed is unmetered = $unmetered")
isUnmeteredNetwork = unmetered
clientEventEmitter?.onNetworkMeteredChanged(unmetered)
}
}
} }
@@ -84,6 +84,10 @@ class AbsAudioPlayer : Plugin() {
override fun onProgressSyncSuccess() { override fun onProgressSyncSuccess() {
emit("onProgressSyncSuccess", "") emit("onProgressSyncSuccess", "")
} }
override fun onNetworkMeteredChanged(isUnmetered:Boolean) {
emit("onNetworkMeteredChanged", isUnmetered)
}
}) })
} }
mainActivity.pluginCallback = foregroundServiceReady mainActivity.pluginCallback = foregroundServiceReady
@@ -177,7 +181,21 @@ class AbsAudioPlayer : Plugin() {
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
Log.d(tag, "prepareLibraryItem: Preparing Local Media item ${jacksonMapper.writeValueAsString(it)}") Log.d(tag, "prepareLibraryItem: Preparing Local Media item ${jacksonMapper.writeValueAsString(it)}")
val playbackSession = it.getPlaybackSession(episode) val playbackSession = it.getPlaybackSession(episode)
playerNotificationService.preparePlayer(playbackSession, playWhenReady, playbackRate)
if (playerNotificationService.mediaProgressSyncer.listeningTimerRunning) { // If progress syncing then first stop before preparing next
playerNotificationService.mediaProgressSyncer.stop {
Log.d(tag, "Media progress syncer was already syncing - stopped")
Handler(Looper.getMainLooper()).post { // TODO: This was needed again which is probably a design a flaw
playerNotificationService.preparePlayer(
playbackSession,
playWhenReady,
playbackRate
)
}
}
} else {
playerNotificationService.preparePlayer(playbackSession, playWhenReady, playbackRate)
}
} }
return call.resolve(JSObject()) return call.resolve(JSObject())
} }
@@ -188,9 +206,20 @@ class AbsAudioPlayer : Plugin() {
if (it == null) { if (it == null) {
call.resolve(JSObject("{\"error\":\"Server play request failed\"}")) call.resolve(JSObject("{\"error\":\"Server play request failed\"}"))
} else { } else {
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
Log.d(tag, "Preparing Player TEST ${jacksonMapper.writeValueAsString(it)}") Log.d(tag, "Preparing Player playback session ${jacksonMapper.writeValueAsString(it)}")
playerNotificationService.preparePlayer(it, playWhenReady, playbackRate)
if (playerNotificationService.mediaProgressSyncer.listeningTimerRunning) { // If progress syncing then first stop before preparing next
playerNotificationService.mediaProgressSyncer.stop {
Log.d(tag, "Media progress syncer was already syncing - stopped")
Handler(Looper.getMainLooper()).post { // TODO: This was needed again which is probably a design a flaw
playerNotificationService.preparePlayer(it, playWhenReady, playbackRate)
}
}
} else {
playerNotificationService.preparePlayer(it, playWhenReady, playbackRate)
}
} }
call.resolve(JSObject(jacksonMapper.writeValueAsString(it))) call.resolve(JSObject(jacksonMapper.writeValueAsString(it)))
@@ -79,6 +79,12 @@ class ApiHandler(var ctx:Context) {
return false return false
} }
fun isUsingCellularData(): Boolean {
val connectivityManager = ctx.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
return capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true
}
fun makeRequest(request:Request, httpClient:OkHttpClient?, cb: (JSObject) -> Unit) { fun makeRequest(request:Request, httpClient:OkHttpClient?, cb: (JSObject) -> Unit) {
val client = httpClient ?: defaultClient val client = httpClient ?: defaultClient
client.newCall(request).enqueue(object : Callback { client.newCall(request).enqueue(object : Callback {
+7 -2
View File
@@ -24,6 +24,9 @@ export default {
networkConnectionType() { networkConnectionType() {
return this.$store.state.networkConnectionType return this.$store.state.networkConnectionType
}, },
isNetworkUnmetered() {
return this.$store.state.isNetworkUnmetered
},
isCellular() { isCellular() {
return this.networkConnectionType === 'cellular' return this.networkConnectionType === 'cellular'
}, },
@@ -43,6 +46,7 @@ export default {
iconClass() { iconClass() {
if (!this.networkConnected) return 'text-error' if (!this.networkConnected) return 'text-error'
else if (!this.socketConnected) return 'text-warning' else if (!this.socketConnected) return 'text-warning'
else if (!this.isNetworkUnmetered) return 'text-yellow-400'
else if (this.isCellular) return 'text-gray-200' else if (this.isCellular) return 'text-gray-200'
else return 'text-success' else return 'text-success'
} }
@@ -50,14 +54,15 @@ export default {
methods: { methods: {
showAlertDialog() { showAlertDialog() {
var msg = '' var msg = ''
var meteredString = this.isNetworkUnmetered ? 'unmetered' : 'metered'
if (!this.networkConnected) { if (!this.networkConnected) {
msg = 'No internet' msg = 'No internet'
} else if (!this.socketConnected) { } else if (!this.socketConnected) {
msg = 'Socket not connected' msg = 'Socket not connected'
} else if (this.isCellular) { } else if (this.isCellular) {
msg = 'Socket connected over cellular' msg = `Socket connected over ${meteredString} cellular`
} else { } else {
msg = 'Socket connected over wifi' msg = `Socket connected over ${meteredString} wifi`
} }
Dialog.alert({ Dialog.alert({
title: 'Connection Status', title: 'Connection Status',
+1 -1
View File
@@ -17,7 +17,7 @@
<div v-else class="w-full media-item-container overflow-y-auto"> <div v-else class="w-full media-item-container overflow-y-auto">
<template v-for="mediaItem in localLibraryItems"> <template v-for="mediaItem in localLibraryItems">
<nuxt-link :to="`/localMedia/item/${mediaItem.id}`" :key="mediaItem.id" class="flex my-1"> <nuxt-link :to="`/localMedia/item/${mediaItem.id}`" :key="mediaItem.id" class="flex my-1">
<div class="w-12 h-12 bg-primary"> <div class="w-12 h-12 min-w-12 min-h-12 bg-primary">
<img v-if="mediaItem.coverPathSrc" :src="mediaItem.coverPathSrc" class="w-full h-full object-contain" /> <img v-if="mediaItem.coverPathSrc" :src="mediaItem.coverPathSrc" class="w-full h-full object-contain" />
</div> </div>
<div class="flex-grow px-2"> <div class="flex-grow px-2">
+11
View File
@@ -1,4 +1,5 @@
import { Network } from '@capacitor/network' import { Network } from '@capacitor/network'
import { AbsAudioPlayer } from '@/plugins/capacitor'
export const state = () => ({ export const state = () => ({
deviceData: null, deviceData: null,
@@ -12,6 +13,7 @@ export const state = () => ({
socketConnected: false, socketConnected: false,
networkConnected: false, networkConnected: false,
networkConnectionType: null, networkConnectionType: null,
isNetworkUnmetered: true,
isFirstLoad: true, isFirstLoad: true,
hasStoragePermission: false, hasStoragePermission: false,
selectedLibraryItem: null, selectedLibraryItem: null,
@@ -62,6 +64,12 @@ export const actions = {
console.log('Network status changed', status.connected, status.connectionType) console.log('Network status changed', status.connected, status.connectionType)
commit('setNetworkStatus', status) commit('setNetworkStatus', status)
}) })
AbsAudioPlayer.addListener('onNetworkMeteredChanged', (payload) => {
const isUnmetered = payload.value
console.log('On network metered changed', isUnmetered)
commit('setIsNetworkUnmetered', isUnmetered)
})
} }
} }
@@ -114,6 +122,9 @@ export const mutations = {
state.networkConnected = val.connected state.networkConnected = val.connected
state.networkConnectionType = val.connectionType state.networkConnectionType = val.connectionType
}, },
setIsNetworkUnmetered(state, val) {
state.isNetworkUnmetered = val
},
openReader(state, libraryItem) { openReader(state, libraryItem) {
state.selectedLibraryItem = libraryItem state.selectedLibraryItem = libraryItem
state.showReader = true state.showReader = true
+6
View File
@@ -39,6 +39,12 @@ module.exports = {
}, },
maxWidth: { maxWidth: {
'24': '6rem' '24': '6rem'
},
minWidth: {
'12': '3rem'
},
minHeight: {
'12': '3rem'
} }
} }
}, },