From b671e1482665d0b5a8a3db957ead345499f688c4 Mon Sep 17 00:00:00 2001 From: Ray <154766448+damontecres@users.noreply.github.com> Date: Wed, 24 Dec 2025 16:44:41 -0500 Subject: [PATCH] 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 --- .../damontecres/wholphin/MainActivity.kt | 42 +++++++++++++++---- .../wholphin/data/ServerRepository.kt | 26 ++++++++---- .../wholphin/preferences/UserPreferences.kt | 1 - .../wholphin/services/StreamChoiceService.kt | 11 +++-- .../services/UserPreferencesService.kt | 2 - .../wholphin/ui/detail/DebugPage.kt | 2 +- 6 files changed, 61 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt b/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt index 41d24b3c..2e65a8c7 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt @@ -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 diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/ServerRepository.kt b/app/src/main/java/com/github/damontecres/wholphin/data/ServerRepository.kt index 539c8ac4..a396b873 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/ServerRepository.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/ServerRepository.kt @@ -46,9 +46,11 @@ class ServerRepository private var _current = EqualityMutableLiveData(null) val current: LiveData = _current + private var _currentUserDto = EqualityMutableLiveData(null) + val currentUserDto: LiveData = _currentUserDto + val currentServer: LiveData get() = _current.map { it?.server } val currentUser: LiveData get() = _current.map { it?.user } - val currentUserDto: LiveData 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,11 +131,21 @@ class ServerRepository serverDao.getServer(serverId) } if (serverAndUsers != null) { - val user = serverAndUsers.users.firstOrNull { it.id == userId } - if (user != null) { - // TODO pin-related + 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 // if (user != null && !user.hasPin) { - return changeUser(serverAndUsers.server, user) + 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, ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/preferences/UserPreferences.kt b/app/src/main/java/com/github/damontecres/wholphin/preferences/UserPreferences.kt index 520a12e8..35da376a 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/preferences/UserPreferences.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/preferences/UserPreferences.kt @@ -8,7 +8,6 @@ import org.jellyfin.sdk.model.api.UserConfiguration */ data class UserPreferences( val appPreferences: AppPreferences, - val userConfig: UserConfiguration, ) val DefaultUserConfiguration = diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/StreamChoiceService.kt b/app/src/main/java/com/github/damontecres/wholphin/services/StreamChoiceService.kt index e1490ac0..703821fe 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/StreamChoiceService.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/StreamChoiceService.kt @@ -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 } diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/UserPreferencesService.kt b/app/src/main/java/com/github/damontecres/wholphin/services/UserPreferencesService.kt index a59f287b..90d68e52 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/UserPreferencesService.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/UserPreferencesService.kt @@ -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, ) } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/DebugPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/DebugPage.kt index b65f8624..60ad839e 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/DebugPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/DebugPage.kt @@ -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, )