feat(tracking): expose manual provider refresh

This commit is contained in:
tapframe 2026-07-22 14:12:42 +05:30
parent adcc829a1a
commit 32449a7a15
3 changed files with 57 additions and 3 deletions

View file

@ -1138,6 +1138,7 @@
<string name="settings_simkl_invalid_callback">Simkl did not accept the sign-in callback. Please try again.</string>
<string name="settings_simkl_authorization_expired">The Simkl sign-in request expired. Start again.</string>
<string name="settings_simkl_sign_in_failed">Could not complete Simkl sign in. Please try again.</string>
<string name="settings_simkl_sync_now">Sync now</string>
<string name="settings_simkl_authorization_revoked">Simkl authorization expired or was revoked. Connect again.</string>
<string name="tracking_source_simkl">Simkl</string>
<string name="tracking_library_source_simkl_selected">Simkl watchlist selected</string>
@ -1651,6 +1652,7 @@
<string name="library_filter_type">Select type</string>
<string name="library_layout_show_horizontal">Show horizontal shelves</string>
<string name="library_layout_show_vertical">Show vertical grid</string>
<string name="library_refresh">Refresh library</string>
<string name="library_load_failed">Couldn't load library</string>
<string name="library_other">Other</string>
<string name="library_sort_added_asc">Oldest added</string>

View file

@ -84,6 +84,7 @@ import com.nuvio.app.features.home.components.HomePosterCard
import com.nuvio.app.features.home.components.HomeSkeletonRow
import com.nuvio.app.features.home.components.posterGridColumnCountForWidth
import com.nuvio.app.features.profiles.ProfileRepository
import com.nuvio.app.features.tracking.TrackingRefreshIntent
import com.nuvio.app.features.watched.WatchedRepository
import com.nuvio.app.features.watching.application.WatchingState
import kotlinx.coroutines.flow.Flow
@ -170,7 +171,10 @@ fun LibraryScreen(
val retryLibraryLoad: () -> Unit = {
NetworkStatusRepository.requestRefresh(force = true)
coroutineScope.launch {
LibraryRepository.pullFromServer(ProfileRepository.activeProfileId)
LibraryRepository.pullFromServer(
profileId = ProfileRepository.activeProfileId,
refreshIntent = TrackingRefreshIntent.USER_INITIATED,
)
}
}
@ -256,6 +260,18 @@ fun LibraryScreen(
modifier = Modifier.padding(horizontal = 16.dp),
actions = {
if (sourceMode == LibraryViewMode.Saved) {
if (isRemoteSource) {
IconButton(
onClick = retryLibraryLoad,
enabled = !uiState.isLoading,
) {
Icon(
imageVector = Icons.Rounded.Refresh,
contentDescription = stringResource(Res.string.library_refresh),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
val targetLayout = if (displaySettings.layoutMode == LibraryLayoutMode.HORIZONTAL) {
LibraryLayoutMode.VERTICAL
} else {

View file

@ -28,6 +28,7 @@ import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
@ -38,18 +39,21 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.nuvio.app.features.library.LibrarySourceMode
import com.nuvio.app.features.profiles.ProfileRepository
import com.nuvio.app.features.simkl.SimklAuthError
import com.nuvio.app.features.simkl.SimklAuthRepository
import com.nuvio.app.features.simkl.SimklAuthUiState
import com.nuvio.app.features.simkl.SimklConnectionMode
import com.nuvio.app.features.simkl.SimklSyncRepository
import com.nuvio.app.features.trakt.TraktAuthRepository
import com.nuvio.app.features.trakt.TraktAuthUiState
import com.nuvio.app.features.trakt.TraktConnectionMode
import com.nuvio.app.features.trakt.TraktContinueWatchingDaysOptions
import com.nuvio.app.features.trakt.MoreLikeThisSourcePreference
import com.nuvio.app.features.tracking.TrackingProviderId
import com.nuvio.app.features.tracking.TrackingRefreshIntent
import com.nuvio.app.features.tracking.TrackingSettingsRepository
import com.nuvio.app.features.tracking.TrackingSettingsUiState
import com.nuvio.app.features.tracking.WatchProgressSource
@ -94,6 +98,7 @@ import nuvio.composeapp.generated.resources.settings_simkl_missing_credentials
import nuvio.composeapp.generated.resources.settings_simkl_open_login
import nuvio.composeapp.generated.resources.settings_simkl_sign_in_description
import nuvio.composeapp.generated.resources.settings_simkl_sign_in_failed
import nuvio.composeapp.generated.resources.settings_simkl_sync_now
import nuvio.composeapp.generated.resources.settings_simkl_visit
import nuvio.composeapp.generated.resources.tracking_library_source_simkl_selected
import nuvio.composeapp.generated.resources.tracking_source_simkl
@ -781,6 +786,12 @@ private fun SimklConnectionCard(
isTablet: Boolean,
uiState: SimklAuthUiState,
) {
val syncState by remember {
SimklSyncRepository.ensureLoaded()
SimklSyncRepository.state
}.collectAsStateWithLifecycle()
val scope = rememberCoroutineScope()
ProviderConnectionCard(
isTablet = isTablet,
mode = when (uiState.mode) {
@ -801,8 +812,10 @@ private fun SimklConnectionCard(
connectLabel = stringResource(Res.string.settings_simkl_connect),
openLoginLabel = stringResource(Res.string.settings_simkl_open_login),
disconnectLabel = stringResource(Res.string.settings_simkl_disconnect),
syncLabel = stringResource(Res.string.settings_simkl_sync_now),
isSyncing = syncState.isLoading,
missingCredentialsMessage = stringResource(Res.string.settings_simkl_missing_credentials),
errorMessage = simklErrorMessage(uiState.error),
errorMessage = simklErrorMessage(uiState.error) ?: syncState.errorMessage,
websiteLabel = stringResource(Res.string.settings_simkl_visit),
websiteUrl = SIMKL_WEBSITE_URL,
onConnectRequested = SimklAuthRepository::onConnectRequested,
@ -811,6 +824,11 @@ private fun SimklConnectionCard(
?: SimklAuthRepository.onConnectRequested()
},
onCancelAuthorization = SimklAuthRepository::onCancelAuthorization,
onSyncRequested = {
scope.launch {
SimklSyncRepository.refresh(TrackingRefreshIntent.USER_INITIATED)
}
},
onDisconnect = SimklAuthRepository::onDisconnectRequested,
)
}
@ -829,6 +847,8 @@ private fun ProviderConnectionCard(
connectLabel: String,
openLoginLabel: String,
disconnectLabel: String,
syncLabel: String? = null,
isSyncing: Boolean = false,
missingCredentialsMessage: String,
statusMessage: String? = null,
errorMessage: String? = null,
@ -837,6 +857,7 @@ private fun ProviderConnectionCard(
onConnectRequested: () -> String?,
onResumeAuthorization: () -> String?,
onCancelAuthorization: () -> Unit,
onSyncRequested: (() -> Unit)? = null,
onDisconnect: () -> Unit,
) {
val uriHandler = LocalUriHandler.current
@ -871,9 +892,24 @@ private fun ProviderConnectionCard(
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
if (syncLabel != null && onSyncRequested != null) {
Button(
onClick = onSyncRequested,
enabled = !isLoading && !isSyncing,
) {
if (isSyncing) {
NuvioLoadingIndicator(
color = MaterialTheme.colorScheme.onPrimary,
modifier = Modifier.size(18.dp),
)
} else {
Text(syncLabel)
}
}
}
Button(
onClick = onDisconnect,
enabled = !isLoading,
enabled = !isLoading && !isSyncing,
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant,
contentColor = MaterialTheme.colorScheme.onSurface,