Refactoring switching server or user (#205)

Now when initiating a user or server switch, you can't back out of it
and must select a user/server. This will be useful when PIN code are
implemented down the road.

The app will now disconnect the web socket when backgrounded.

Also lots of internal refactoring
This commit is contained in:
damontecres 2025-11-12 17:44:16 -05:00 committed by GitHub
parent 2e3e4e3f5f
commit 58395e9adf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 442 additions and 277 deletions

View file

@ -2,13 +2,17 @@ package com.github.damontecres.wholphin.util
import android.content.Context
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.github.damontecres.wholphin.data.ServerRepository
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 dagger.hilt.android.qualifiers.ActivityContext
import dagger.hilt.android.scopes.ActivityScoped
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@ -20,24 +24,36 @@ import org.jellyfin.sdk.model.api.GeneralCommandType
import org.jellyfin.sdk.model.api.MediaType
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
@ActivityScoped
class ServerEventListener
@Inject
constructor(
@param:ApplicationContext private val context: Context,
@param:ActivityContext private val context: Context,
private val api: ApiClient,
@param:IoCoroutineScope private val scope: CoroutineScope,
) {
private val serverRepository: ServerRepository,
) : DefaultLifecycleObserver {
private val activity = (context as AppCompatActivity)
private var listenJob: Job? = null
init {
activity.lifecycle.addObserver(this)
serverRepository.current.observe(activity) {
Timber.d("New user/server: %s", it)
listenJob?.cancel()
if (it != null) {
init(it.server, it.user)
}
}
}
fun init(
server: JellyfinServer?,
user: JellyfinUser?,
) {
if (server != null && user != null && api.baseUrl != null && api.accessToken != null) {
scope.launchIO {
(context as AppCompatActivity).lifecycleScope.launchIO {
api.sessionApi.postCapabilities(
playableMediaTypes = listOf(MediaType.VIDEO),
supportedCommands =
@ -53,6 +69,7 @@ class ServerEventListener
}
fun setupListeners() {
serverRepository.currentUser
Timber.v("Subscribing to WebSocket")
listenJob?.cancel()
listenJob =
@ -73,6 +90,20 @@ class ServerEventListener
.joinToString("\n")
showToast(context, toast, Toast.LENGTH_LONG)
}
}.launchIn(scope)
}.launchIn(activity.lifecycleScope)
}
override fun onResume(owner: LifecycleOwner) {
serverRepository.current.value?.let { init(it.server, it.user) }
}
override fun onPause(owner: LifecycleOwner) {
Timber.v("Cancelling WebSocket")
listenJob?.cancel()
}
override fun onStop(owner: LifecycleOwner) {
Timber.v("Cancelling WebSocket")
listenJob?.cancel()
}
}