Don't flash previous app content when resuming app & auto sign-in is off (#585)

## Description
When the app is put into the background with auto sign-in disabled, it
will remove the current page and show a loading indicator. This way when
the app is resumed, the previous content won't flash on screen for a
split second.

The above should technically fix #584 on its own, but as additional safe
guide, this PR also makes sure the `ApiClient` is configured before
trying to create image URLs.

### Related issues
Fixes #584
This commit is contained in:
Ray 2025-12-27 15:13:45 -05:00 committed by GitHub
parent 494ff07b72
commit 639ce0de71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 38 additions and 12 deletions

View file

@ -13,13 +13,16 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.unit.dp
import androidx.datastore.core.DataStore
import androidx.lifecycle.ViewModel
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
@ -208,13 +211,35 @@ class MainActivity : AppCompatActivity() {
remember(appPreferences) {
UserPreferences(appPreferences)
}
ApplicationContent(
user = current.user,
server = current.server,
navigationManager = navigationManager,
preferences = preferences,
modifier = Modifier.fillMaxSize(),
)
var showContent by remember {
mutableStateOf(true)
}
if (!preferences.appPreferences.signInAutomatically) {
LifecycleStartEffect(Unit) {
onStopOrDispose {
showContent = false
}
}
}
if (showContent) {
ApplicationContent(
user = current.user,
server = current.server,
navigationManager = navigationManager,
preferences = preferences,
modifier = Modifier.fillMaxSize(),
)
} else {
Box(
modifier = Modifier.size(200.dp),
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator(
color = MaterialTheme.colorScheme.border,
modifier = Modifier.align(Alignment.Center),
)
}
}
}
}
}

View file

@ -242,7 +242,6 @@ class ServerRepository
}
suspend fun switchServerOrUser() {
apiClient.update(baseUrl = null, accessToken = null)
userPreferencesDataStore.updateData {
it
.toBuilder()

View file

@ -31,7 +31,7 @@ class ImageUrlService
imageType: ImageType,
fillWidth: Int? = null,
fillHeight: Int? = null,
): String =
): String? =
when (imageType) {
ImageType.BACKDROP,
ImageType.LOGO,
@ -124,8 +124,9 @@ class ImageUrlService
backgroundColor: String? = null,
foregroundLayer: String? = null,
imageIndex: Int? = null,
): String =
api.imageApi.getItemImageUrl(
): String? {
if (api.baseUrl.isNullOrBlank()) return null
return api.imageApi.getItemImageUrl(
itemId = itemId,
imageType = imageType,
maxWidth = maxWidth,
@ -144,6 +145,7 @@ class ImageUrlService
foregroundLayer = foregroundLayer,
imageIndex = imageIndex,
)
}
fun getUserImageUrl(userId: UUID) = api.imageApi.getUserImageUrl(userId)

View file

@ -103,7 +103,7 @@ class GenreViewModel
loading.value = LoadingState.Success
}
// val excludeItemIds = mutableSetOf<UUID>()
val genreToUrl = ConcurrentHashMap<UUID, String>()
val genreToUrl = ConcurrentHashMap<UUID, String?>()
val semaphore = Semaphore(4)
genres
.map { genre ->