Better Jellyseerr connection error handling (#933)
## Description Show Jellyseerr connection errors in settings. If an error occurred trying to login, in setting it will show "Server error" and clicking gives more error info and option to remove the server. ### Related issues Fixes #907 ### Testing Emulator with simulated errors ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
dfd9acf561
commit
4f8f69c438
6 changed files with 120 additions and 63 deletions
|
|
@ -408,12 +408,13 @@ fun ConfirmDialog(
|
|||
onConfirm: () -> Unit,
|
||||
properties: DialogProperties = DialogProperties(),
|
||||
elevation: Dp = 8.dp,
|
||||
bodyColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) = BasicDialog(
|
||||
onDismissRequest = onCancel,
|
||||
properties = properties,
|
||||
elevation = elevation,
|
||||
content = {
|
||||
ConfirmDialogContent(title, body, onCancel, onConfirm, Modifier)
|
||||
ConfirmDialogContent(title, body, onCancel, onConfirm, Modifier, bodyColor)
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -427,6 +428,7 @@ fun ConfirmDialogContent(
|
|||
onCancel: () -> Unit,
|
||||
onConfirm: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
bodyColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
|
|
@ -446,7 +448,7 @@ fun ConfirmDialogContent(
|
|||
item {
|
||||
Text(
|
||||
text = body,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
color = bodyColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,8 @@ class DiscoverMovieViewModel
|
|||
val canCancelRequest = MutableStateFlow(false)
|
||||
|
||||
val userConfig = seerrServerRepository.current.map { it?.config }
|
||||
val request4kEnabled = seerrServerRepository.current.map { it?.request4kMovieEnabled ?: false }
|
||||
val request4kEnabled =
|
||||
seerrServerRepository.current.map { it?.request4kMovieEnabled ?: false }
|
||||
|
||||
init {
|
||||
init()
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class SeerrRequestsViewModel
|
|||
viewModelScope.launchIO {
|
||||
backdropService.clearBackdrop()
|
||||
}
|
||||
seerrServerRepository.current
|
||||
seerrServerRepository.connection
|
||||
.onEach { user ->
|
||||
state.update { it.copy(requests = DataLoadingState.Loading) }
|
||||
if (user != null) {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import com.github.damontecres.wholphin.preferences.PlayerBackend
|
|||
import com.github.damontecres.wholphin.preferences.advancedPreferences
|
||||
import com.github.damontecres.wholphin.preferences.basicPreferences
|
||||
import com.github.damontecres.wholphin.preferences.updatePlaybackPreferences
|
||||
import com.github.damontecres.wholphin.services.SeerrConnectionStatus
|
||||
import com.github.damontecres.wholphin.services.UpdateChecker
|
||||
import com.github.damontecres.wholphin.ui.components.ConfirmDialog
|
||||
import com.github.damontecres.wholphin.ui.ifElse
|
||||
|
|
@ -90,7 +91,7 @@ fun PreferencesContent(
|
|||
var showPinFlow by remember { mutableStateOf(false) }
|
||||
|
||||
var cacheUsage by remember { mutableStateOf(CacheUsage(0, 0, 0)) }
|
||||
val seerrIntegrationEnabled by viewModel.seerrEnabled.collectAsState(false)
|
||||
val seerrConnection by viewModel.seerrConnection.collectAsState()
|
||||
var seerrDialogMode by remember { mutableStateOf<SeerrDialogMode>(SeerrDialogMode.None) }
|
||||
var showQuickConnectDialog by remember { mutableStateOf(false) }
|
||||
|
||||
|
|
@ -385,19 +386,29 @@ fun PreferencesContent(
|
|||
ClickPreference(
|
||||
title = stringResource(pref.title),
|
||||
onClick = {
|
||||
if (seerrIntegrationEnabled) {
|
||||
seerrDialogMode = SeerrDialogMode.Remove
|
||||
} else {
|
||||
seerrVm.resetStatus()
|
||||
seerrDialogMode = SeerrDialogMode.Add
|
||||
}
|
||||
seerrDialogMode =
|
||||
when (val conn = seerrConnection) {
|
||||
is SeerrConnectionStatus.Error -> {
|
||||
SeerrDialogMode.Error(conn.serverUrl, conn.ex)
|
||||
}
|
||||
|
||||
SeerrConnectionStatus.NotConfigured -> {
|
||||
SeerrDialogMode.Add
|
||||
}
|
||||
|
||||
is SeerrConnectionStatus.Success -> {
|
||||
SeerrDialogMode.Remove(
|
||||
conn.current.server.url,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier,
|
||||
summary =
|
||||
if (seerrIntegrationEnabled) {
|
||||
stringResource(R.string.enabled)
|
||||
} else {
|
||||
null
|
||||
when (seerrConnection) {
|
||||
is SeerrConnectionStatus.Error -> stringResource(R.string.voice_error_server)
|
||||
SeerrConnectionStatus.NotConfigured -> stringResource(R.string.add_server)
|
||||
is SeerrConnectionStatus.Success -> stringResource(R.string.enabled)
|
||||
},
|
||||
onLongClick = {},
|
||||
interactionSource = interactionSource,
|
||||
|
|
@ -479,11 +490,11 @@ fun PreferencesContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
when (seerrDialogMode) {
|
||||
SeerrDialogMode.Remove -> {
|
||||
when (val mode = seerrDialogMode) {
|
||||
is SeerrDialogMode.Remove -> {
|
||||
ConfirmDialog(
|
||||
title = stringResource(R.string.remove_seerr_server),
|
||||
body = currentServer?.url ?: "",
|
||||
body = mode.serverUrl,
|
||||
onCancel = { seerrDialogMode = SeerrDialogMode.None },
|
||||
onConfirm = {
|
||||
seerrVm.removeServer()
|
||||
|
|
@ -510,6 +521,28 @@ fun PreferencesContent(
|
|||
)
|
||||
}
|
||||
|
||||
is SeerrDialogMode.Error -> {
|
||||
val errorStr = stringResource(R.string.voice_error_server)
|
||||
val body =
|
||||
remember(mode) {
|
||||
"""
|
||||
${mode.serverUrl}
|
||||
|
||||
$errorStr: ${mode.ex.localizedMessage}
|
||||
""".trimIndent()
|
||||
}
|
||||
ConfirmDialog(
|
||||
title = stringResource(R.string.remove_seerr_server),
|
||||
body = body,
|
||||
onCancel = { seerrDialogMode = SeerrDialogMode.None },
|
||||
onConfirm = {
|
||||
seerrVm.removeServer()
|
||||
seerrDialogMode = SeerrDialogMode.None
|
||||
},
|
||||
bodyColor = MaterialTheme.colorScheme.error,
|
||||
)
|
||||
}
|
||||
|
||||
SeerrDialogMode.None -> {}
|
||||
}
|
||||
}
|
||||
|
|
@ -580,10 +613,17 @@ data class CacheUsage(
|
|||
val imageDiskUsed: Long,
|
||||
)
|
||||
|
||||
private sealed class SeerrDialogMode {
|
||||
data object None : SeerrDialogMode()
|
||||
private sealed interface SeerrDialogMode {
|
||||
data object None : SeerrDialogMode
|
||||
|
||||
data object Add : SeerrDialogMode()
|
||||
data object Add : SeerrDialogMode
|
||||
|
||||
data object Remove : SeerrDialogMode()
|
||||
data class Remove(
|
||||
val serverUrl: String,
|
||||
) : SeerrDialogMode
|
||||
|
||||
data class Error(
|
||||
val serverUrl: String,
|
||||
val ex: Exception,
|
||||
) : SeerrDialogMode
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.github.damontecres.wholphin.ui.preferences
|
|||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.data.model.JellyfinUser
|
||||
|
|
@ -22,7 +21,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.model.ClientInfo
|
||||
import org.jellyfin.sdk.model.DeviceInfo
|
||||
|
|
@ -46,10 +44,7 @@ class PreferencesViewModel
|
|||
RememberTabManager by rememberTabManager {
|
||||
val currentUser get() = serverRepository.currentUser
|
||||
|
||||
val seerrEnabled =
|
||||
seerrServerRepository.currentUser.combine(currentUser.asFlow()) { seerrUser, jellyfinUser ->
|
||||
seerrUser != null && jellyfinUser != null && seerrUser.jellyfinUserRowId == jellyfinUser.rowId
|
||||
}
|
||||
val seerrConnection = seerrServerRepository.connection
|
||||
|
||||
private val _quickConnectStatus = MutableStateFlow<LoadingState>(LoadingState.Pending)
|
||||
val quickConnectStatus: StateFlow<LoadingState> = _quickConnectStatus
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue