Move UserSwitchListener to its own file & add docs

This commit is contained in:
Damontecres 2026-05-16 17:00:33 -04:00
parent 4dc40f2c3c
commit 093b5f0970
No known key found for this signature in database
2 changed files with 10 additions and 101 deletions

View file

@ -1,12 +1,5 @@
package com.github.damontecres.wholphin.services package com.github.damontecres.wholphin.services
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import androidx.lifecycle.asFlow
import androidx.lifecycle.lifecycleScope
import com.github.damontecres.wholphin.BuildConfig
import com.github.damontecres.wholphin.api.seerr.SeerrApiClient import com.github.damontecres.wholphin.api.seerr.SeerrApiClient
import com.github.damontecres.wholphin.api.seerr.model.AuthJellyfinPostRequest import com.github.damontecres.wholphin.api.seerr.model.AuthJellyfinPostRequest
import com.github.damontecres.wholphin.api.seerr.model.AuthLocalPostRequest import com.github.damontecres.wholphin.api.seerr.model.AuthLocalPostRequest
@ -14,28 +7,22 @@ import com.github.damontecres.wholphin.api.seerr.model.PublicSettings
import com.github.damontecres.wholphin.api.seerr.model.User import com.github.damontecres.wholphin.api.seerr.model.User
import com.github.damontecres.wholphin.data.SeerrServerDao import com.github.damontecres.wholphin.data.SeerrServerDao
import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.data.model.JellyfinUser
import com.github.damontecres.wholphin.data.model.SeerrAuthMethod import com.github.damontecres.wholphin.data.model.SeerrAuthMethod
import com.github.damontecres.wholphin.data.model.SeerrPermission import com.github.damontecres.wholphin.data.model.SeerrPermission
import com.github.damontecres.wholphin.data.model.SeerrServer import com.github.damontecres.wholphin.data.model.SeerrServer
import com.github.damontecres.wholphin.data.model.SeerrUser import com.github.damontecres.wholphin.data.model.SeerrUser
import com.github.damontecres.wholphin.data.model.hasPermission import com.github.damontecres.wholphin.data.model.hasPermission
import com.github.damontecres.wholphin.services.hilt.StandardOkHttpClient import com.github.damontecres.wholphin.services.hilt.StandardOkHttpClient
import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.setup.seerr.createSeerrApiUrl import com.github.damontecres.wholphin.ui.setup.seerr.createSeerrApiUrl
import com.github.damontecres.wholphin.util.LoadingState import com.github.damontecres.wholphin.util.LoadingState
import dagger.hilt.android.qualifiers.ActivityContext
import dagger.hilt.android.scopes.ActivityScoped
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.supervisorScope
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.jellyfin.sdk.model.api.ImageType import org.jellyfin.sdk.model.api.ImageType
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
@ -142,7 +129,7 @@ class SeerrServerRepository
serverRepository.currentUser.value?.let { jellyfinUser -> serverRepository.currentUser.value?.let { jellyfinUser ->
// TODO Need to update server early so that cookies are saved // TODO Need to update server early so that cookies are saved
seerrApi.update(server.url, null) seerrApi.update(server.url, null)
val userConfig = login(seerrApi.api, authMethod, username, password) val userConfig = seerrLogin(seerrApi.api, authMethod, username, password)
val user = val user =
SeerrUser( SeerrUser(
@ -176,7 +163,7 @@ class SeerrServerRepository
.readTimeout(6.seconds) .readTimeout(6.seconds)
.build(), .build(),
) )
login(api, authMethod, username, passwordOrApiKey) seerrLogin(api, authMethod, username, passwordOrApiKey)
return LoadingState.Success return LoadingState.Success
} }
@ -229,7 +216,7 @@ data class CurrentSeerr(
config.hasPermission(SeerrPermission.REQUEST_4K_TV) config.hasPermission(SeerrPermission.REQUEST_4K_TV)
} }
private suspend fun login( suspend fun seerrLogin(
client: SeerrApiClient, client: SeerrApiClient,
authMethod: SeerrAuthMethod, authMethod: SeerrAuthMethod,
username: String?, username: String?,
@ -261,91 +248,6 @@ private suspend fun login(
} }
} }
/**
* Listens for JF user switching in the app to also switch the Seerr user/server
*/
@ActivityScoped
class UserSwitchListener
@Inject
constructor(
@param:ActivityContext private val context: Context,
private val serverRepository: ServerRepository,
private val seerrServerRepository: SeerrServerRepository,
private val seerrServerDao: SeerrServerDao,
private val seerrApi: SeerrApi,
private val homeSettingsService: HomeSettingsService,
) {
init {
context as AppCompatActivity
context.lifecycleScope.launchIO {
serverRepository.currentUser.asFlow().collect { user ->
Timber.d("New user")
seerrServerRepository.clear()
homeSettingsService.currentSettings.update { HomePageResolvedSettings.EMPTY }
if (user != null) {
switchUser(user)
}
}
}
}
private suspend fun switchUser(user: JellyfinUser) =
supervisorScope {
val uiLanguage = user.uiLanguage
val localeList =
user.uiLanguage?.let { LocaleListCompat.forLanguageTags(uiLanguage) }
?: LocaleListCompat.getEmptyLocaleList()
Timber.i("Switch locale to %s", localeList)
AppCompatDelegate.setApplicationLocales(localeList)
// Check for home settings
launchIO {
homeSettingsService.loadCurrentSettings(user.id)
}
if (BuildConfig.DISCOVER_ENABLED) {
// Check for seerr server
launchIO {
seerrServerDao
.getUsersByJellyfinUser(user.rowId)
.lastOrNull()
?.let { seerrUser ->
val server =
seerrServerDao.getServer(seerrUser.serverId)?.server
if (server != null) {
Timber.i("Found a seerr user & server")
try {
seerrApi.update(server.url, seerrUser.credential)
val userConfig =
if (seerrUser.authMethod != SeerrAuthMethod.API_KEY) {
login(
seerrApi.api,
seerrUser.authMethod,
seerrUser.username,
seerrUser.password,
)
} else {
seerrApi.api.usersApi.authMeGet()
}
seerrServerRepository.set(
server,
seerrUser,
userConfig,
)
} catch (ex: Exception) {
Timber.w(
ex,
"Error logging into %s",
server.url,
)
seerrServerRepository.error(server, seerrUser, ex)
}
}
}
}
}
}
}
fun CurrentSeerr?.imageUrlBuilder( fun CurrentSeerr?.imageUrlBuilder(
imageType: ImageType, imageType: ImageType,
path: String?, path: String?,

View file

@ -80,6 +80,11 @@ class LocaleChoiceViewModel
} }
} }
/**
* Get the available locales that can be used.
*
* Defaults to `context.assets.locales` (all locales) if can't find app specific ones
*/
private fun extractAvailableLocales(): List<Locale> { private fun extractAvailableLocales(): List<Locale> {
val id = val id =
context.resources.getIdentifier( context.resources.getIdentifier(
@ -90,6 +95,8 @@ class LocaleChoiceViewModel
return if (id != 0) { return if (id != 0) {
try { try {
val locales = mutableListOf<Locale>() val locales = mutableListOf<Locale>()
// This is kind of a hack, the generated locale config is not available,
// programmatically, so this code parses the raw XML
context.resources.getXml(id).use { parser -> context.resources.getXml(id).use { parser ->
var eventType: Int = parser.eventType var eventType: Int = parser.eventType
while (eventType != XmlResourceParser.END_DOCUMENT) { while (eventType != XmlResourceParser.END_DOCUMENT) {