From 0b3881d81d4d9434a0a09ebe3f4b5378b0842f3b Mon Sep 17 00:00:00 2001 From: Sasikanth Miriyampalli Date: Sat, 4 May 2024 08:55:55 +0530 Subject: [PATCH] Show confirmation dialog when deleting selected sources --- .../resources/strings/DeTwineStrings.kt | 4 +- .../resources/strings/EnTwineStrings.kt | 4 +- .../resources/strings/TrTwineStrings.kt | 4 +- .../reader/resources/strings/TwineStrings.kt | 2 + .../sasikanth/rss/reader/feeds/FeedsEvent.kt | 6 +- .../rss/reader/feeds/FeedsPresenter.kt | 30 ++++++---- .../sasikanth/rss/reader/feeds/FeedsState.kt | 4 +- .../ui/expanded/BottomSheetExpandedContent.kt | 59 ++++++++++++++++++- 8 files changed, 97 insertions(+), 16 deletions(-) diff --git a/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/DeTwineStrings.kt b/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/DeTwineStrings.kt index 389d37d19..741bf1f97 100644 --- a/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/DeTwineStrings.kt +++ b/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/DeTwineStrings.kt @@ -158,5 +158,7 @@ val DeTwineStrings = groupAddNew = "Add new", appBarAllFeeds = "All feeds", edit = "Edit", - buttonAddToGroup = "Add to group..." + buttonAddToGroup = "Add to group...", + removeSources = "Delete sources", + removeSourcesDesc = "Do you want to delete selected sources?", ) diff --git a/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/EnTwineStrings.kt b/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/EnTwineStrings.kt index 90ecdb24e..999e6c4c3 100644 --- a/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/EnTwineStrings.kt +++ b/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/EnTwineStrings.kt @@ -165,5 +165,7 @@ val EnTwineStrings = groupAddNew = "Add new", appBarAllFeeds = "All feeds", edit = "Edit", - buttonAddToGroup = "Add to group..." + buttonAddToGroup = "Add to group...", + removeSources = "Delete sources", + removeSourcesDesc = "Do you want to delete selected sources?", ) diff --git a/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/TrTwineStrings.kt b/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/TrTwineStrings.kt index 2b0dae866..58ccfe39b 100644 --- a/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/TrTwineStrings.kt +++ b/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/TrTwineStrings.kt @@ -154,5 +154,7 @@ val TrTwineStrings = groupAddNew = "Add new", appBarAllFeeds = "All feeds", edit = "Edit", - buttonAddToGroup = "Add to group..." + buttonAddToGroup = "Add to group...", + removeSources = "Delete sources", + removeSourcesDesc = "Do you want to delete selected sources?", ) diff --git a/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/TwineStrings.kt b/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/TwineStrings.kt index 147d94fdc..77bc26951 100644 --- a/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/TwineStrings.kt +++ b/resources/strings/src/commonMain/kotlin/dev/sasikanth/rss/reader/resources/strings/TwineStrings.kt @@ -146,6 +146,8 @@ data class TwineStrings( val appBarAllFeeds: String, val edit: String, val buttonAddToGroup: String, + val removeSources: String, + val removeSourcesDesc: String, ) object Locales { diff --git a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsEvent.kt b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsEvent.kt index 6de369a1d..c5bb2fc2c 100644 --- a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsEvent.kt +++ b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsEvent.kt @@ -54,7 +54,7 @@ sealed interface FeedsEvent { data object UnPinSelectedSources : FeedsEvent - data object DeleteSelectedSources : FeedsEvent + data object DeleteSelectedSourcesClicked : FeedsEvent data class OnCreateGroup(val name: String) : FeedsEvent @@ -65,4 +65,8 @@ sealed interface FeedsEvent { data object OnAddToGroupClicked : FeedsEvent data object OnNewFeedClicked : FeedsEvent + + data object DismissDeleteConfirmation : FeedsEvent + + data object DeleteSelectedSources : FeedsEvent } diff --git a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsPresenter.kt b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsPresenter.kt index a06fe5590..1a6c21041 100644 --- a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsPresenter.kt +++ b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsPresenter.kt @@ -163,7 +163,7 @@ class FeedsPresenter( FeedsEvent.OnChangeFeedsViewModeClick -> onChangeFeedsViewModeClick() is FeedsEvent.OnHomeSelected -> onHomeSelected() FeedsEvent.CancelSourcesSelection -> onCancelSourcesSelection() - FeedsEvent.DeleteSelectedSources -> onDeleteSelectedSources() + FeedsEvent.DeleteSelectedSourcesClicked -> onDeleteSelectedSourcesClicked() FeedsEvent.PinSelectedSources -> onPinSelectedSources() FeedsEvent.UnPinSelectedSources -> onUnpinSelectedSources() is FeedsEvent.OnCreateGroup -> onCreateGroup(event.name) @@ -177,9 +177,26 @@ class FeedsPresenter( FeedsEvent.OnNewFeedClicked -> { // no-op } + FeedsEvent.DeleteSelectedSources -> deleteSelectedSources() + FeedsEvent.DismissDeleteConfirmation -> dismissDeleteConfirmation() } } + private fun dismissDeleteConfirmation() { + _state.update { it.copy(showDeleteConfirmation = false) } + } + + private fun deleteSelectedSources() { + coroutineScope + .launch { rssRepository.deleteSources(_state.value.selectedSources) } + .invokeOnCompletion { + if (_state.value.selectedSources.any { it.id == _state.value.activeSource?.id }) { + observableActiveSource.clearSelection() + } + dispatch(FeedsEvent.CancelSourcesSelection) + } + } + private fun onGroupsSelected(groupIds: Set) { coroutineScope.launch { rssRepository.addFeedIdsToGroups( @@ -217,15 +234,8 @@ class FeedsPresenter( .invokeOnCompletion { dispatch(FeedsEvent.CancelSourcesSelection) } } - private fun onDeleteSelectedSources() { - coroutineScope - .launch { rssRepository.deleteSources(_state.value.selectedSources) } - .invokeOnCompletion { - if (_state.value.selectedSources.any { it.id == _state.value.activeSource?.id }) { - observableActiveSource.clearSelection() - } - dispatch(FeedsEvent.CancelSourcesSelection) - } + private fun onDeleteSelectedSourcesClicked() { + _state.update { it.copy(showDeleteConfirmation = true) } } private fun onCancelSourcesSelection() { diff --git a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsState.kt b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsState.kt index e03124296..6cd0994d5 100644 --- a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsState.kt +++ b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsState.kt @@ -37,6 +37,7 @@ internal data class FeedsState( val selectedSources: Set, val numberOfFeeds: Int, val numberOfFeedGroups: Int, + val showDeleteConfirmation: Boolean, ) { val isInMultiSelectMode: Boolean @@ -56,7 +57,8 @@ internal data class FeedsState( isPinnedSectionExpanded = true, selectedSources = emptySet(), numberOfFeeds = 0, - numberOfFeedGroups = 0 + numberOfFeedGroups = 0, + showDeleteConfirmation = false ) } } diff --git a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/ui/expanded/BottomSheetExpandedContent.kt b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/ui/expanded/BottomSheetExpandedContent.kt index 29b11389f..ef0185076 100644 --- a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/ui/expanded/BottomSheetExpandedContent.kt +++ b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/ui/expanded/BottomSheetExpandedContent.kt @@ -43,6 +43,7 @@ import androidx.compose.material.icons.filled.GridView import androidx.compose.material.icons.outlined.ViewAgenda import androidx.compose.material.icons.rounded.Close import androidx.compose.material.icons.rounded.Search +import androidx.compose.material3.AlertDialog import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -50,6 +51,7 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.darkColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -95,6 +97,13 @@ internal fun BottomSheetExpandedContent( var showNewGroupDialog by remember { mutableStateOf(false) } + if (state.showDeleteConfirmation) { + DeleteConfirmationDialog( + onDelete = { feedsPresenter.dispatch(FeedsEvent.DeleteSelectedSources) }, + dismiss = { feedsPresenter.dispatch(FeedsEvent.DismissDeleteConfirmation) } + ) + } + Scaffold( modifier = Modifier.fillMaxSize().consumeWindowInsets(WindowInsets.statusBars).then(modifier), topBar = { @@ -169,7 +178,7 @@ internal fun BottomSheetExpandedContent( modifier = Modifier.weight(1f), icon = TwineIcons.Delete, label = LocalStrings.current.actionDelete, - onClick = { feedsPresenter.dispatch(FeedsEvent.DeleteSelectedSources) } + onClick = { feedsPresenter.dispatch(FeedsEvent.DeleteSelectedSourcesClicked) } ) if (state.selectedSources.size == 1) { @@ -358,3 +367,51 @@ private fun SearchBar( Spacer(Modifier.requiredWidth(20.dp)) } } + +@Composable +fun DeleteConfirmationDialog( + onDelete: () -> Unit, + dismiss: () -> Unit, + modifier: Modifier = Modifier +) { + AlertDialog( + modifier = modifier, + onDismissRequest = dismiss, + confirmButton = { + TextButton( + onClick = { + onDelete() + dismiss() + }, + shape = MaterialTheme.shapes.large + ) { + Text( + text = LocalStrings.current.delete, + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.error + ) + } + }, + dismissButton = { + TextButton(onClick = dismiss, shape = MaterialTheme.shapes.large) { + Text( + text = LocalStrings.current.buttonCancel, + style = MaterialTheme.typography.labelLarge, + color = AppTheme.colorScheme.textEmphasisMed + ) + } + }, + title = { + Text(text = LocalStrings.current.removeSources, color = AppTheme.colorScheme.textEmphasisMed) + }, + text = { + Text( + text = LocalStrings.current.removeSourcesDesc, + color = AppTheme.colorScheme.textEmphasisMed + ) + }, + containerColor = AppTheme.colorScheme.tintedSurface, + titleContentColor = AppTheme.colorScheme.onSurface, + textContentColor = AppTheme.colorScheme.onSurface, + ) +}