diff --git a/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/PlaylistConfigurationScreen.kt b/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/PlaylistConfigurationScreen.kt index adc522d9e..c6f3896d5 100644 --- a/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/PlaylistConfigurationScreen.kt +++ b/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/PlaylistConfigurationScreen.kt @@ -80,7 +80,7 @@ internal fun PlaylistConfigurationRoute( val playlist by viewModel.playlist.collectAsStateWithLifecycle() val manifest by viewModel.manifest.collectAsStateWithLifecycle() - val subscribingOrRefreshing by viewModel.subscribingOrRefreshing.collectAsStateWithLifecycle() + val subscribingOrRefreshingWorkInfo by viewModel.subscribingOrRefreshingWorkInfo.collectAsStateWithLifecycle() val expired by viewModel.expired.collectAsStateWithLifecycle() val xtreamUserInfo by viewModel.xtreamUserInfo.collectAsStateWithLifecycle() @@ -96,7 +96,7 @@ internal fun PlaylistConfigurationRoute( PlaylistConfigurationScreen( playlist = it, manifest = manifest, - subscribingOrRefreshing = subscribingOrRefreshing, + subscribingOrRefreshing = subscribingOrRefreshingWorkInfo != null, expired = expired, xtreamUserInfo = xtreamUserInfo, onUpdatePlaylistTitle = viewModel::onUpdatePlaylistTitle, @@ -124,6 +124,7 @@ internal fun PlaylistConfigurationRoute( } ) }, + onCancelSyncProgrammes = viewModel::onCancelSyncProgrammes, modifier = modifier, contentPadding = contentPadding ) @@ -142,6 +143,7 @@ private fun PlaylistConfigurationScreen( onUpdateEpgPlaylist: (PlaylistRepository.UpdateEpgPlaylistUseCase) -> Unit, onUpdatePlaylistAutoRefreshProgrammes: () -> Unit, onSyncProgrammes: () -> Unit, + onCancelSyncProgrammes: () -> Unit, modifier: Modifier = Modifier, contentPadding: PaddingValues = PaddingValues() ) { @@ -190,7 +192,8 @@ private fun PlaylistConfigurationScreen( SyncProgrammesButton( subscribingOrRefreshing = subscribingOrRefreshing, expired = expired, - onSyncProgrammes = onSyncProgrammes + onSyncProgrammes = onSyncProgrammes, + onCancelSyncProgrammes = onCancelSyncProgrammes ) AutoSyncProgrammesButton( checked = playlist.autoRefreshProgrammes, diff --git a/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/PlaylistConfigurationViewModel.kt b/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/PlaylistConfigurationViewModel.kt index 2d67ac426..f3a14c0d0 100644 --- a/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/PlaylistConfigurationViewModel.kt +++ b/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/PlaylistConfigurationViewModel.kt @@ -99,7 +99,7 @@ class PlaylistConfigurationViewModel @Inject constructor( started = SharingStarted.Lazily, initialValue = emptyMap() ) - internal val subscribingOrRefreshing: StateFlow = workManager + internal val subscribingOrRefreshingWorkInfo: StateFlow = workManager .getWorkInfosFlow( WorkQuery.fromStates( WorkInfo.State.RUNNING, @@ -107,13 +107,13 @@ class PlaylistConfigurationViewModel @Inject constructor( ) ) .combine(playlistUrl) { infos, playlistUrl -> - infos.any { info -> + infos.find { info -> var isCorrectedWorker = false var isCurrentPlaylist = false info.tags.forEach { tag -> if (SubscriptionWorker.TAG == tag) isCorrectedWorker = true if (playlistUrl == tag) isCurrentPlaylist = true - if (isCorrectedWorker && isCurrentPlaylist) return@any true + if (isCorrectedWorker && isCurrentPlaylist) return@find true } false } @@ -121,8 +121,8 @@ class PlaylistConfigurationViewModel @Inject constructor( .flowOn(ioDispatcher) .stateIn( scope = viewModelScope, - initialValue = false, - started = SharingStarted.WhileSubscribed(5000) + initialValue = null, + started = SharingStarted.WhileSubscribed(5_000L) ) internal val expired: StateFlow = playlistUrl @@ -173,4 +173,9 @@ class PlaylistConfigurationViewModel @Inject constructor( val playlistUrl = playlistUrl.value SubscriptionWorker.epg(workManager, playlistUrl, true) } + + internal fun onCancelSyncProgrammes() { + val workInfo = subscribingOrRefreshingWorkInfo.value + workInfo?.id?.let { workManager.cancelWorkById(it) } + } } \ No newline at end of file diff --git a/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/components/SyncProgrammesButton.kt b/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/components/SyncProgrammesButton.kt index 83695d0f7..5504f3e4e 100644 --- a/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/components/SyncProgrammesButton.kt +++ b/feature/playlist-configuration/src/main/java/com/m3u/feature/playlist/configuration/components/SyncProgrammesButton.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.ListItem import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -21,6 +22,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.m3u.core.util.basic.title import com.m3u.i18n.R.string +import com.m3u.material.components.CircularProgressIndicator import com.m3u.material.components.SelectionsDefaults import com.m3u.material.model.LocalSpacing import com.m3u.material.shape.AbsoluteSmoothCornerShape @@ -31,13 +33,16 @@ internal fun SyncProgrammesButton( subscribingOrRefreshing: Boolean, expired: LocalDateTime?, onSyncProgrammes: () -> Unit, + onCancelSyncProgrammes: () -> Unit, modifier: Modifier = Modifier ) { val spacing = LocalSpacing.current + val colorScheme = MaterialTheme.colorScheme ListItem( headlineContent = { Text( - text = stringResource(string.feat_playlist_configuration_sync_programmes).title(), + text = if (!subscribingOrRefreshing) stringResource(string.feat_playlist_configuration_sync_programmes).title() + else stringResource(string.feat_playlist_configuration_cancel_sync_programmes).title(), maxLines = 1, overflow = TextOverflow.Ellipsis, ) @@ -64,22 +69,30 @@ internal fun SyncProgrammesButton( } } }, + trailingContent = { + if (subscribingOrRefreshing) { + CircularProgressIndicator() + } + }, colors = ListItemDefaults.colors( - headlineColor = LocalContentColor.current.copy( - if (subscribingOrRefreshing) 0.38f else 1f - ), - supportingColor = LocalContentColor.current.copy(0.38f) + headlineColor = if (!subscribingOrRefreshing) LocalContentColor.current + else colorScheme.onTertiaryContainer, + supportingColor = if (!subscribingOrRefreshing) LocalContentColor.current.copy(0.38f) + else colorScheme.onTertiaryContainer.copy(0.38f), + containerColor = if (!subscribingOrRefreshing) colorScheme.surface + else colorScheme.tertiaryContainer ), modifier = Modifier .border( 1.dp, - LocalContentColor.current.copy(0.38f), + if (subscribingOrRefreshing) colorScheme.tertiaryContainer + else LocalContentColor.current.copy(0.38f), SelectionsDefaults.Shape ) .clip(AbsoluteSmoothCornerShape(spacing.medium, 65)) .clickable( - onClick = onSyncProgrammes, - enabled = !subscribingOrRefreshing + onClick = if (subscribingOrRefreshing) onCancelSyncProgrammes + else onSyncProgrammes, ) .then(modifier) ) diff --git a/i18n/src/main/res/values/feat_playlist_configuration.xml b/i18n/src/main/res/values/feat_playlist_configuration.xml index d66ddc0a8..164e7f6cc 100644 --- a/i18n/src/main/res/values/feat_playlist_configuration.xml +++ b/i18n/src/main/res/values/feat_playlist_configuration.xml @@ -4,6 +4,7 @@ user agent enabled EPGs sync programmes + cancel sync programmes Expire: %s Cached programmes are out of date Auto Refresh Programmes