UI Updates & Fixes (#114)

Fixes #113 

- Ensures all audio and subtitle options are shown during playback
- Fix home rows not being at top when going back
- Show error message when background home page refresh fails

Also shows more details for login failures and adds a link to the debug
page (with log info) after multiple login failure attempts. Hopefully
this can help diagnose #112 and #18
This commit is contained in:
damontecres 2025-10-30 13:41:46 -04:00 committed by GitHub
parent b1275ae210
commit 3f7c2ac730
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 128 additions and 53 deletions

View file

@ -15,5 +15,8 @@ sealed interface LoadingState {
val exception: Throwable? = null,
) : LoadingState {
constructor(exception: Throwable) : this(null, exception)
val localizedMessage: String =
listOfNotNull(message, exception?.localizedMessage).joinToString(" - ")
}
}

View file

@ -2,11 +2,14 @@ package com.github.damontecres.wholphin.util
import android.content.Context
import android.widget.Toast
import com.github.damontecres.wholphin.data.model.JellyfinServer
import com.github.damontecres.wholphin.data.model.JellyfinUser
import com.github.damontecres.wholphin.hilt.IoCoroutineScope
import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.showToast
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.jellyfin.sdk.api.client.ApiClient
@ -27,43 +30,49 @@ class ServerEventListener
private val api: ApiClient,
@param:IoCoroutineScope private val scope: CoroutineScope,
) {
init {
setupListeners()
}
private var listenJob: Job? = null
fun init() {
scope.launchIO {
api.sessionApi.postCapabilities(
playableMediaTypes = listOf(MediaType.VIDEO),
supportedCommands =
listOf(
GeneralCommandType.DISPLAY_MESSAGE,
GeneralCommandType.SEND_STRING,
),
supportsMediaControl = true,
)
fun init(
server: JellyfinServer?,
user: JellyfinUser?,
) {
if (server != null && user != null && api.baseUrl != null && api.accessToken != null) {
scope.launchIO {
api.sessionApi.postCapabilities(
playableMediaTypes = listOf(MediaType.VIDEO),
supportedCommands =
listOf(
GeneralCommandType.DISPLAY_MESSAGE,
GeneralCommandType.SEND_STRING,
),
supportsMediaControl = true,
)
setupListeners()
}
}
}
fun setupListeners() {
Timber.v("Subscribing to WebSocket")
api.webSocket
.subscribe<GeneralCommandMessage>()
.onEach { message ->
if (message.data?.name in
setOf(
GeneralCommandType.DISPLAY_MESSAGE,
GeneralCommandType.SEND_STRING,
)
) {
val header = message.data?.arguments["Header"]
val text =
message.data?.arguments["Text"] ?: message.data?.arguments["String"]
val toast =
listOfNotNull(header, text)
.joinToString("\n")
showToast(context, toast, Toast.LENGTH_LONG)
}
}.launchIn(scope)
listenJob?.cancel()
listenJob =
api.webSocket
.subscribe<GeneralCommandMessage>()
.onEach { message ->
if (message.data?.name in
setOf(
GeneralCommandType.DISPLAY_MESSAGE,
GeneralCommandType.SEND_STRING,
)
) {
val header = message.data?.arguments["Header"]
val text =
message.data?.arguments["Text"] ?: message.data?.arguments["String"]
val toast =
listOfNotNull(header, text)
.joinToString("\n")
showToast(context, toast, Toast.LENGTH_LONG)
}
}.launchIn(scope)
}
}