Better restoration for auto sign in (#566)

## Description
Improves how the app restores state when auto sign in is enabled. If
auto sign in is enabled, the app will restore back to the last page.

#538 altered the app start up logic. This caused the app to reset state
more often when it goes into the background.

### Related issues
Related to #552
This commit is contained in:
Ray 2025-12-24 16:44:41 -05:00 committed by GitHub
parent bcc7e660ea
commit b671e14826
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 61 additions and 23 deletions

View file

@ -32,7 +32,6 @@ import androidx.tv.material3.Surface
import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.preferences.AppPreference
import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.preferences.DefaultUserConfiguration
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.services.AppUpgradeHandler
import com.github.damontecres.wholphin.services.BackdropService
@ -102,7 +101,7 @@ class MainActivity : AppCompatActivity() {
@OptIn(ExperimentalTvMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Timber.i("MainActivity.onCreate")
Timber.i("MainActivity.onCreate: savedInstanceState is null=${savedInstanceState == null}")
lifecycle.addObserver(playbackLifecycleObserver)
if (savedInstanceState == null) {
appUpgradeHandler.copySubfont(false)
@ -209,12 +208,8 @@ class MainActivity : AppCompatActivity() {
appPreferences,
)
val preferences =
remember(appPreferences, current) {
UserPreferences(
appPreferences,
current.userDto.configuration
?: DefaultUserConfiguration,
)
remember(appPreferences) {
UserPreferences(appPreferences)
}
ApplicationContent(
user = current.user,
@ -238,6 +233,7 @@ class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
Timber.i("onResume")
lifecycleScope.launchIO {
appUpgradeHandler.run()
}
@ -256,6 +252,36 @@ class MainActivity : AppCompatActivity() {
// serverRepository.closeSession()
// }
}
// override fun onStop() {
// super.onStop()
// Timber.i("onStop")
// }
//
// override fun onPause() {
// super.onPause()
// Timber.i("onPause")
// }
//
// override fun onStart() {
// super.onStart()
// Timber.i("onStart")
// }
//
// override fun onSaveInstanceState(outState: Bundle) {
// super.onSaveInstanceState(outState)
// Timber.i("onSaveInstanceState")
// }
//
// override fun onRestoreInstanceState(savedInstanceState: Bundle) {
// super.onRestoreInstanceState(savedInstanceState)
// Timber.i("onRestoreInstanceState")
// }
//
// override fun onDestroy() {
// super.onDestroy()
// Timber.i("onDestroy")
// }
}
@HiltViewModel

View file

@ -46,9 +46,11 @@ class ServerRepository
private var _current = EqualityMutableLiveData<CurrentUser?>(null)
val current: LiveData<CurrentUser?> = _current
private var _currentUserDto = EqualityMutableLiveData<UserDto?>(null)
val currentUserDto: LiveData<UserDto?> = _currentUserDto
val currentServer: LiveData<JellyfinServer?> get() = _current.map { it?.server }
val currentUser: LiveData<JellyfinUser?> get() = _current.map { it?.user }
val currentUserDto: LiveData<UserDto?> get() = _current.map { it?.userDto }
/**
* Adds a server to the app database and updated the [ApiClient] to the server's URL
@ -101,7 +103,8 @@ class ServerRepository
}.build()
}
withContext(Dispatchers.Main) {
_current.value = CurrentUser(updatedServer, updatedUser, userDto)
_current.value = CurrentUser(updatedServer, updatedUser)
_currentUserDto.value = userDto
}
sharedPreferences.edit(true) {
putString(SERVER_URL_KEY, updatedServer.url)
@ -128,6 +131,15 @@ class ServerRepository
serverDao.getServer(serverId)
}
if (serverAndUsers != null) {
val current = _current.value
if (current != null && current.server.id == serverId && current.user.id == userId) {
Timber.v("Restoring session for current user, so shortcut")
apiClient.update(
baseUrl = current.server.url,
accessToken = current.user.accessToken,
)
return current
} else {
val user = serverAndUsers.users.firstOrNull { it.id == userId }
if (user != null) {
// TODO pin-related
@ -135,6 +147,7 @@ class ServerRepository
return changeUser(serverAndUsers.server, user)
}
}
}
return null
}
@ -271,5 +284,4 @@ class ServerRepository
data class CurrentUser(
val server: JellyfinServer,
val user: JellyfinUser,
val userDto: UserDto,
)

View file

@ -8,7 +8,6 @@ import org.jellyfin.sdk.model.api.UserConfiguration
*/
data class UserPreferences(
val appPreferences: AppPreferences,
val userConfig: UserConfiguration,
)
val DefaultUserConfiguration =

View file

@ -13,6 +13,7 @@ import org.jellyfin.sdk.model.api.MediaSourceInfo
import org.jellyfin.sdk.model.api.MediaStream
import org.jellyfin.sdk.model.api.MediaStreamType
import org.jellyfin.sdk.model.api.SubtitlePlaybackMode
import org.jellyfin.sdk.model.api.UserConfiguration
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
import timber.log.Timber
import java.util.UUID
@ -26,6 +27,8 @@ class StreamChoiceService
private val serverRepository: ServerRepository,
private val playbackLanguageChoiceDao: PlaybackLanguageChoiceDao,
) {
private val userConfig: UserConfiguration? get() = serverRepository.currentUserDto.value?.configuration
suspend fun updateAudio(
dto: BaseItemDto,
audioLang: String,
@ -117,7 +120,7 @@ class StreamChoiceService
val seriesLang =
playbackLanguageChoice?.audioLanguage?.takeIf { it.isNotNullOrBlank() }
// If the user has chosen a different language for the series, prefer that
val audioLanguage = seriesLang ?: prefs.userConfig.audioLanguagePreference
val audioLanguage = seriesLang ?: userConfig?.audioLanguagePreference
if (audioLanguage.isNotNullOrBlank()) {
val sorted =
@ -174,7 +177,7 @@ class StreamChoiceService
val seriesLang =
playbackLanguageChoice?.subtitleLanguage?.takeIf { it.isNotNullOrBlank() }
val subtitleLanguage =
(seriesLang ?: prefs.userConfig.subtitleLanguagePreference)
(seriesLang ?: userConfig?.subtitleLanguagePreference)
?.takeIf { it.isNotNullOrBlank() }
val subtitleMode =
@ -192,7 +195,7 @@ class StreamChoiceService
else -> {
// Fallback to the user's preference
prefs.userConfig.subtitleMode
userConfig?.subtitleMode ?: SubtitlePlaybackMode.DEFAULT
}
}
return when (subtitleMode) {
@ -213,7 +216,7 @@ class StreamChoiceService
}
SubtitlePlaybackMode.SMART -> {
val audioLanguage = prefs.userConfig.audioLanguagePreference
val audioLanguage = userConfig?.audioLanguagePreference
val audioStreamLang = audioStream?.language
if (audioLanguage.isNotNullOrBlank() && audioStreamLang.isNotNullOrBlank() && audioLanguage != audioStreamLang) {
candidates.firstOrNull { it.language == subtitleLanguage }

View file

@ -3,7 +3,6 @@ package com.github.damontecres.wholphin.services
import androidx.datastore.core.DataStore
import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.preferences.DefaultUserConfiguration
import com.github.damontecres.wholphin.preferences.UserPreferences
import kotlinx.coroutines.flow.firstOrNull
import javax.inject.Inject
@ -21,7 +20,6 @@ class UserPreferencesService
val appPrefs = preferencesDataStore.data.firstOrNull() ?: AppPreferences.getDefaultInstance()
UserPreferences(
appPrefs,
userConfig ?: DefaultUserConfiguration,
)
}
}

View file

@ -302,7 +302,7 @@ fun DebugPage(
color = MaterialTheme.colorScheme.onSurface,
)
Text(
text = "User server settings: ${preferences.userConfig}",
text = "User server settings: ${viewModel.serverRepository.currentUserDto.value?.configuration}",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurface,
)