From 06b9f2333641b14d7066b27c14bb56366b4e2442 Mon Sep 17 00:00:00 2001 From: ashiagr Date: Fri, 10 Feb 2023 18:55:43 +0530 Subject: [PATCH 1/3] Add header with clear all button --- .../search/searchhistory/SearchHistoryPage.kt | 49 +++++++++++++++---- .../searchhistory/SearchHistoryViewModel.kt | 7 +++ .../src/main/res/values/strings.xml | 1 + 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt index dbac0ab1782..9a94cf40b4f 100644 --- a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt +++ b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt @@ -29,15 +29,18 @@ import au.com.shiftyjelly.pocketcasts.compose.AppTheme import au.com.shiftyjelly.pocketcasts.compose.bars.NavigationButton import au.com.shiftyjelly.pocketcasts.compose.components.HorizontalDivider import au.com.shiftyjelly.pocketcasts.compose.components.PodcastImage +import au.com.shiftyjelly.pocketcasts.compose.components.TextH20 +import au.com.shiftyjelly.pocketcasts.compose.components.TextH40 import au.com.shiftyjelly.pocketcasts.compose.components.TextP40 import au.com.shiftyjelly.pocketcasts.compose.components.TextP50 import au.com.shiftyjelly.pocketcasts.compose.folder.FolderImageSmall import au.com.shiftyjelly.pocketcasts.compose.preview.ThemePreviewParameterProvider import au.com.shiftyjelly.pocketcasts.compose.theme -import au.com.shiftyjelly.pocketcasts.localization.R import au.com.shiftyjelly.pocketcasts.models.to.SearchHistoryEntry import au.com.shiftyjelly.pocketcasts.ui.theme.Theme import java.util.UUID +import au.com.shiftyjelly.pocketcasts.images.R as IR +import au.com.shiftyjelly.pocketcasts.localization.R as LR private val IconSize = 64.dp @Composable @@ -47,7 +50,8 @@ internal fun SearchHistoryPage( val state by viewModel.state.collectAsState() SearchHistoryView( state = state, - onCloseClick = { viewModel.remove(it) } + onCloseClick = { viewModel.remove(it) }, + onClearAllClick = { viewModel.clearAll() } ) viewModel.start() } @@ -56,8 +60,34 @@ internal fun SearchHistoryPage( fun SearchHistoryView( state: SearchHistoryViewModel.State, onCloseClick: (SearchHistoryEntry) -> Unit, + onClearAllClick: () -> Unit, + modifier: Modifier = Modifier, ) { - LazyColumn { + LazyColumn( + modifier = modifier.background(color = MaterialTheme.theme.colors.primaryUi01) + ) { + if (state.entries.isNotEmpty()) { + item { + Row( + modifier = modifier + .fillMaxWidth() + .padding(start = 16.dp, top = 8.dp, end = 16.dp, bottom = 4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + TextH20( + text = stringResource(LR.string.search_history_recent_searches), + color = MaterialTheme.theme.colors.primaryText01, + modifier = modifier.weight(1f) + + ) + TextH40( + text = stringResource(LR.string.clear_all).uppercase(), + color = MaterialTheme.theme.colors.support03, + modifier = modifier.clickable { onClearAllClick() } + ) + } + } + } state.entries.forEach { entry -> item { when (entry) { @@ -89,9 +119,7 @@ fun SearchHistoryRow( modifier: Modifier = Modifier, content: @Composable () -> Unit = {}, ) { - Column( - modifier = modifier.background(color = MaterialTheme.theme.colors.primaryUi01) - ) { + Column { Row( verticalAlignment = Alignment.CenterVertically, modifier = modifier @@ -155,10 +183,10 @@ fun SearchHistoryFolderView( modifier = Modifier.padding(bottom = 2.dp) ) val podcastCount = if (entry.podcastIds.size == 1) { - stringResource(R.string.podcasts_singular) + stringResource(LR.string.podcasts_singular) } else { stringResource( - R.string.podcasts_plural, + LR.string.podcasts_plural, entry.podcastIds.size ) } @@ -232,7 +260,7 @@ fun SearchHistoryTermView( contentAlignment = Alignment.Center, ) { Icon( - painter = painterResource(id = au.com.shiftyjelly.pocketcasts.images.R.drawable.ic_search), + painter = painterResource(id = IR.drawable.ic_search), contentDescription = null, tint = MaterialTheme.theme.colors.primaryIcon02 ) @@ -275,7 +303,8 @@ fun SearchHistoryViewPreview( ), ) ), - onCloseClick = {} + onCloseClick = {}, + onClearAllClick = {}, ) } } diff --git a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryViewModel.kt b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryViewModel.kt index e9c714e7705..5b5c547cfa6 100644 --- a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryViewModel.kt +++ b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryViewModel.kt @@ -65,4 +65,11 @@ class SearchHistoryViewModel @Inject constructor( loadSearchHistory() } } + + fun clearAll() { + viewModelScope.launch { + searchHistoryManager.clearAll() + loadSearchHistory() + } + } } diff --git a/modules/services/localization/src/main/res/values/strings.xml b/modules/services/localization/src/main/res/values/strings.xml index d3464ee8341..17ff40a182d 100644 --- a/modules/services/localization/src/main/res/values/strings.xml +++ b/modules/services/localization/src/main/res/values/strings.xml @@ -194,6 +194,7 @@ Try more general or different keywords. Search podcasts Search by podcast name + Recent searches %dh %1$dh %2$dm From 9451d709c1132827ab3322254792ea4322e1c8bb Mon Sep 17 00:00:00 2001 From: ashiagr Date: Fri, 10 Feb 2023 18:50:57 +0530 Subject: [PATCH 2/3] Add search history row click action --- .../pocketcasts/search/SearchFragment.kt | 14 ++++++++++++- .../search/searchhistory/SearchHistoryPage.kt | 20 +++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/SearchFragment.kt b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/SearchFragment.kt index b05b2793faf..de2d47de93c 100644 --- a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/SearchFragment.kt +++ b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/SearchFragment.kt @@ -116,6 +116,15 @@ class SearchFragment : BaseFragment() { viewModel.onFragmentPause(activity?.isChangingConfigurations) } + private fun navigateFromSearchHistoryEntry(entry: SearchHistoryEntry) { + when (entry) { + is SearchHistoryEntry.Episode -> Unit // TODO + is SearchHistoryEntry.Folder -> listener?.onSearchFolderClick(entry.uuid) + is SearchHistoryEntry.Podcast -> listener?.onSearchPodcastClick(entry.uuid) + is SearchHistoryEntry.SearchTerm -> binding?.searchView?.setQuery(entry.term, true) + } + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -219,7 +228,10 @@ class SearchFragment : BaseFragment() { binding.searchHistoryPanel.setContent { AppTheme(theme.activeTheme) { - SearchHistoryPage(searchHistoryViewModel) + SearchHistoryPage( + viewModel = searchHistoryViewModel, + onClick = ::navigateFromSearchHistoryEntry + ) if (viewModel.isFragmentChangingConfigurations && viewModel.showSearchHistory) { binding.searchHistoryPanel.show() } diff --git a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt index 9a94cf40b4f..c8dc35730c9 100644 --- a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt +++ b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt @@ -45,13 +45,15 @@ import au.com.shiftyjelly.pocketcasts.localization.R as LR private val IconSize = 64.dp @Composable internal fun SearchHistoryPage( - viewModel: SearchHistoryViewModel + viewModel: SearchHistoryViewModel, + onClick: (SearchHistoryEntry) -> Unit, ) { val state by viewModel.state.collectAsState() SearchHistoryView( state = state, onCloseClick = { viewModel.remove(it) }, - onClearAllClick = { viewModel.clearAll() } + onClearAllClick = { viewModel.clearAll() }, + onRowClick = onClick, ) viewModel.start() } @@ -61,6 +63,7 @@ fun SearchHistoryView( state: SearchHistoryViewModel.State, onCloseClick: (SearchHistoryEntry) -> Unit, onClearAllClick: () -> Unit, + onRowClick: (SearchHistoryEntry) -> Unit, modifier: Modifier = Modifier, ) { LazyColumn( @@ -95,17 +98,20 @@ fun SearchHistoryView( is SearchHistoryEntry.Folder -> SearchHistoryRow( content = { SearchHistoryFolderView(entry) }, - onCloseClick = { onCloseClick(entry) } + onCloseClick = { onCloseClick(entry) }, + onRowClick = { onRowClick(entry) }, ) is SearchHistoryEntry.Podcast -> SearchHistoryRow( content = { SearchHistoryPodcastView(entry) }, - onCloseClick = { onCloseClick(entry) } + onCloseClick = { onCloseClick(entry) }, + onRowClick = { onRowClick(entry) }, ) is SearchHistoryEntry.SearchTerm -> SearchHistoryRow( content = { SearchHistoryTermView(entry) }, - onCloseClick = { onCloseClick(entry) } + onCloseClick = { onCloseClick(entry) }, + onRowClick = { onRowClick(entry) }, ) } } @@ -116,6 +122,7 @@ fun SearchHistoryView( @Composable fun SearchHistoryRow( onCloseClick: () -> Unit, + onRowClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable () -> Unit = {}, ) { @@ -123,7 +130,7 @@ fun SearchHistoryRow( Row( verticalAlignment = Alignment.CenterVertically, modifier = modifier - .clickable { /*TODO*/ } + .clickable { onRowClick() } .fillMaxWidth() ) { Box(Modifier.weight(weight = 1f, fill = true)) { @@ -305,6 +312,7 @@ fun SearchHistoryViewPreview( ), onCloseClick = {}, onClearAllClick = {}, + onRowClick = {}, ) } } From d3f5f0662c4a8e40e6a297bc25f144f9a428b3f4 Mon Sep 17 00:00:00 2001 From: ashiagr Date: Fri, 10 Feb 2023 18:39:23 +0530 Subject: [PATCH 3/3] Add search history clear all confirmation dialog --- .../pocketcasts/search/SearchFragment.kt | 10 +++++++++- ...SearchHistoryClearAllConfirmationDialog.kt | 19 +++++++++++++++++++ .../search/searchhistory/SearchHistoryPage.kt | 10 +++++++++- .../src/main/res/values/strings.xml | 1 + 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryClearAllConfirmationDialog.kt diff --git a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/SearchFragment.kt b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/SearchFragment.kt index de2d47de93c..e0cf54402c9 100644 --- a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/SearchFragment.kt +++ b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/SearchFragment.kt @@ -20,6 +20,7 @@ import au.com.shiftyjelly.pocketcasts.models.to.SearchHistoryEntry import au.com.shiftyjelly.pocketcasts.search.SearchViewModel.SearchResultType import au.com.shiftyjelly.pocketcasts.search.adapter.PodcastSearchAdapter import au.com.shiftyjelly.pocketcasts.search.databinding.FragmentSearchBinding +import au.com.shiftyjelly.pocketcasts.search.searchhistory.SearchHistoryClearAllConfirmationDialog import au.com.shiftyjelly.pocketcasts.search.searchhistory.SearchHistoryPage import au.com.shiftyjelly.pocketcasts.search.searchhistory.SearchHistoryViewModel import au.com.shiftyjelly.pocketcasts.ui.extensions.getThemeColor @@ -36,6 +37,7 @@ import au.com.shiftyjelly.pocketcasts.ui.R as UR private const val ARG_FLOATING = "arg_floating" private const val ARG_ONLY_SEARCH_REMOTE = "arg_only_search_remote" private const val ARG_SOURCE = "arg_source" +private const val SEARCH_HISTORY_CLEAR_ALL_CONFIRMATION_DIALOG_TAG = "search_history_clear_all_confirmation_dialog" @AndroidEntryPoint class SearchFragment : BaseFragment() { @@ -230,7 +232,13 @@ class SearchFragment : BaseFragment() { AppTheme(theme.activeTheme) { SearchHistoryPage( viewModel = searchHistoryViewModel, - onClick = ::navigateFromSearchHistoryEntry + onClick = ::navigateFromSearchHistoryEntry, + onShowClearAllConfirmation = { + SearchHistoryClearAllConfirmationDialog( + context = this@SearchFragment.requireContext(), + onConfirm = { searchHistoryViewModel.clearAll() } + ).show(parentFragmentManager, SEARCH_HISTORY_CLEAR_ALL_CONFIRMATION_DIALOG_TAG) + } ) if (viewModel.isFragmentChangingConfigurations && viewModel.showSearchHistory) { binding.searchHistoryPanel.show() diff --git a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryClearAllConfirmationDialog.kt b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryClearAllConfirmationDialog.kt new file mode 100644 index 00000000000..33dcf116dce --- /dev/null +++ b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryClearAllConfirmationDialog.kt @@ -0,0 +1,19 @@ +package au.com.shiftyjelly.pocketcasts.search.searchhistory + +import android.content.Context +import au.com.shiftyjelly.pocketcasts.views.dialog.ConfirmationDialog +import au.com.shiftyjelly.pocketcasts.localization.R as LR +import au.com.shiftyjelly.pocketcasts.views.R as VR + +class SearchHistoryClearAllConfirmationDialog( + context: Context, + onConfirm: () -> Unit, +) : ConfirmationDialog() { + init { + setTitle(context.getString(LR.string.clear_all)) + setSummary(context.getString(LR.string.search_history_clear_all_confirmation_message)) + setIconId(VR.drawable.ic_delete) + setButtonType(ButtonType.Danger(context.getString(LR.string.delete))) + setOnConfirm { onConfirm() } + } +} diff --git a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt index c8dc35730c9..4b228794ccd 100644 --- a/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt +++ b/modules/features/search/src/main/java/au/com/shiftyjelly/pocketcasts/search/searchhistory/SearchHistoryPage.kt @@ -43,16 +43,24 @@ import au.com.shiftyjelly.pocketcasts.images.R as IR import au.com.shiftyjelly.pocketcasts.localization.R as LR private val IconSize = 64.dp +private const val CLEAR_ALL_THRESHOLD = 3 @Composable internal fun SearchHistoryPage( viewModel: SearchHistoryViewModel, onClick: (SearchHistoryEntry) -> Unit, + onShowClearAllConfirmation: () -> Unit, ) { val state by viewModel.state.collectAsState() SearchHistoryView( state = state, onCloseClick = { viewModel.remove(it) }, - onClearAllClick = { viewModel.clearAll() }, + onClearAllClick = { + if (state.entries.size > CLEAR_ALL_THRESHOLD) { + onShowClearAllConfirmation() + } else { + viewModel.clearAll() + } + }, onRowClick = onClick, ) viewModel.start() diff --git a/modules/services/localization/src/main/res/values/strings.xml b/modules/services/localization/src/main/res/values/strings.xml index 17ff40a182d..2c369a47eaa 100644 --- a/modules/services/localization/src/main/res/values/strings.xml +++ b/modules/services/localization/src/main/res/values/strings.xml @@ -194,6 +194,7 @@ Try more general or different keywords. Search podcasts Search by podcast name + Are you sure you want to clear all your search history? Recent searches %dh