mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-11-05 18:30:59 +01:00
Fixes to v1.0.7 (#1953)
## Description Collection of minor bug fixes for `v1.0.7` - Fixes a possible race condition crash when navigating to the search page - Uses friendlier error message when login fails due to parental restrictions (based on [`jellyfin-web`](https://github.com/jellyfin/jellyfin-web/blob/v10.11.11/src/controllers/session/login/index.js#L38-L41)) - Don't re-sort search results by name, just by relevance scoring - Consume the key event when dim is active (ie if the screen is dimmed, pressing a key will un-dim and not perform another action) ### Related issues Fixes #1922 Fixes #1951 Related to #1848 (search sorting) ### Testing Emulator & nvidia shield ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
6486bd19ed
commit
616565f671
6 changed files with 70 additions and 28 deletions
|
|
@ -288,7 +288,7 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
if (screensaverService.state.value.show) {
|
||||
if (screensaverService.state.value.run { show || showDim }) {
|
||||
screensaverService.stop(false)
|
||||
screensaverService.pulse()
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -418,12 +418,16 @@ fun SearchPage(
|
|||
itemsIndexed(state.includedSearchableTypes) { index, type ->
|
||||
val rowIndex = RESULTS_START + index
|
||||
val result = state.results.getOrDefault(type, SearchResult.Searching)
|
||||
val focusRequester =
|
||||
remember(state.includedSearchableTypes.size) {
|
||||
focusRequesters.getOrNull(rowIndex) ?: FocusRequester()
|
||||
}
|
||||
SearchRowResult(
|
||||
title = type.titleStringRes,
|
||||
result = result,
|
||||
rowIndex = rowIndex,
|
||||
position = position,
|
||||
focusRequester = focusRequesters[rowIndex],
|
||||
focusRequester = focusRequester,
|
||||
onClickItem = onClickItem,
|
||||
onLongClickItem = { index, item ->
|
||||
onLongClickItem(rowIndex, index, item)
|
||||
|
|
|
|||
|
|
@ -273,8 +273,7 @@ class SearchViewModel
|
|||
}
|
||||
val sorted =
|
||||
items.sortedWith(
|
||||
compareBy<BaseItem> { SearchRelevance.score(it, query) }
|
||||
.thenBy { it.sortName },
|
||||
compareBy<BaseItem> { SearchRelevance.score(it, query) },
|
||||
)
|
||||
Timber.v("Search finished for %s, %s results", type, sorted.size)
|
||||
_state.value.results[type] = SearchResult.Success(sorted)
|
||||
|
|
@ -307,8 +306,7 @@ class SearchViewModel
|
|||
}
|
||||
val sorted =
|
||||
items.sortedWith(
|
||||
compareBy<BaseItem> { SearchRelevance.score(it, query) }
|
||||
.thenBy { it.name ?: "" },
|
||||
compareBy<BaseItem> { SearchRelevance.score(it, query) },
|
||||
)
|
||||
Timber.v("searchCombined complete %s results", sorted.size)
|
||||
_state.update { it.copy(combinedResults = SearchResult.Success(sorted)) }
|
||||
|
|
|
|||
|
|
@ -86,6 +86,24 @@ fun SwitchUserContent(
|
|||
showAddUser = false
|
||||
}
|
||||
|
||||
fun trySwitchUser(user: JellyfinUser) {
|
||||
val result = viewModel.trySwitchUser(user)
|
||||
scope.launch {
|
||||
when (val r = result.await()) {
|
||||
is SwitchUserResult.Error -> {
|
||||
Toast.makeText(context, r.errorMessage, Toast.LENGTH_LONG).show()
|
||||
if (r.showLogin) {
|
||||
showAddUserDialog(user)
|
||||
}
|
||||
}
|
||||
|
||||
SwitchUserResult.Success -> {
|
||||
// no-op, view model will navigate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(state.switchUserState) {
|
||||
if (!showAddUser) {
|
||||
when (val s = state.switchUserState) {
|
||||
|
|
@ -148,13 +166,7 @@ fun SwitchUserContent(
|
|||
} else if (user.hasPin) {
|
||||
switchUserWithPin = user
|
||||
} else {
|
||||
val result = viewModel.trySwitchUser(user)
|
||||
scope.launch {
|
||||
result.await()?.let {
|
||||
Toast.makeText(context, it, Toast.LENGTH_LONG).show()
|
||||
showAddUserDialog(user)
|
||||
}
|
||||
}
|
||||
trySwitchUser(user)
|
||||
}
|
||||
},
|
||||
onAddUser = {
|
||||
|
|
@ -396,14 +408,7 @@ fun SwitchUserContent(
|
|||
},
|
||||
onTextChange = {
|
||||
if (it == user.pin) {
|
||||
val result = viewModel.trySwitchUser(user)
|
||||
scope.launch {
|
||||
result.await()?.let {
|
||||
Toast.makeText(context, it, Toast.LENGTH_LONG).show()
|
||||
showAddUserDialog(user)
|
||||
switchUserWithPin = null
|
||||
}
|
||||
}
|
||||
trySwitchUser(user)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.github.damontecres.wholphin.ui.setup
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.WholphinApplication
|
||||
import com.github.damontecres.wholphin.data.JellyfinServerDao
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
|
|
@ -19,6 +21,7 @@ import dagger.assisted.Assisted
|
|||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -46,6 +49,7 @@ import kotlin.time.Duration.Companion.seconds
|
|||
class SwitchUserViewModel
|
||||
@AssistedInject
|
||||
constructor(
|
||||
@param:ApplicationContext private val context: Context,
|
||||
val jellyfin: Jellyfin,
|
||||
val serverRepository: ServerRepository,
|
||||
val serverDao: JellyfinServerDao,
|
||||
|
|
@ -124,21 +128,38 @@ class SwitchUserViewModel
|
|||
}
|
||||
}
|
||||
|
||||
fun trySwitchUser(user: JellyfinUser): Deferred<String?> =
|
||||
fun trySwitchUser(user: JellyfinUser): Deferred<SwitchUserResult> =
|
||||
viewModelScope.async(WholphinDispatchers.IO) {
|
||||
try {
|
||||
val current = serverRepository.changeUser(server, user)
|
||||
setupNavigationManager.navigateTo(SetupDestination.AppContent(current))
|
||||
null
|
||||
SwitchUserResult.Success
|
||||
} catch (ex: InvalidStatusException) {
|
||||
if (ex.status == 401) {
|
||||
"Credentials expired, please login in again"
|
||||
} else {
|
||||
ex.localizedMessage
|
||||
when (ex.status) {
|
||||
401 -> {
|
||||
Timber.w(ex, "Error switching user 401")
|
||||
SwitchUserResult.Error(
|
||||
context.getString(R.string.login_credentials_expired),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
403 -> {
|
||||
Timber.w(ex, "Error switching user 403")
|
||||
SwitchUserResult.Error(
|
||||
context.getString(R.string.login_not_authorized),
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
Timber.e(ex, "Error switching user")
|
||||
SwitchUserResult.Error(ex.localizedMessage, true)
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex, "Error switching user")
|
||||
ex.localizedMessage
|
||||
SwitchUserResult.Error(ex.localizedMessage, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -322,3 +343,15 @@ data class SwitchUserState(
|
|||
val serverVersion: String? = null,
|
||||
val serverVersionSupported: ServerVersionSupported = ServerVersionSupported.UNKNOWN,
|
||||
)
|
||||
|
||||
/**
|
||||
* Result of trying to switch users via [SwitchUserViewModel.trySwitchUser]
|
||||
*/
|
||||
sealed interface SwitchUserResult {
|
||||
data object Success : SwitchUserResult
|
||||
|
||||
data class Error(
|
||||
val errorMessage: String?,
|
||||
val showLogin: Boolean,
|
||||
) : SwitchUserResult
|
||||
}
|
||||
|
|
|
|||
|
|
@ -923,4 +923,6 @@
|
|||
<string name="photo_albums">Photo albums</string>
|
||||
<string name="no_favorites_found">No favorites found!</string>
|
||||
<string name="remove_from_playlist">Remove from playlist</string>
|
||||
<string name="login_credentials_expired">Credentials expired, please login in again</string>
|
||||
<string name="login_not_authorized">You are not authorized to access the server at this time</string>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue