Loading app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultsContentTest.kt +2 −47 Original line number Diff line number Diff line Loading @@ -204,51 +204,6 @@ class SearchResultsContentTest { composeRule.onAllNodesWithText("Open App").assertCountEquals(0) } @Test fun refreshError_showsRetry() { val pagingData = PagingData.empty<Application>( sourceLoadStates = loadStates(refresh = LoadState.Error(RuntimeException("boom"))) ) renderSearchResults( tabs = listOf(SearchTabType.OPEN_SOURCE), selectedTab = SearchTabType.OPEN_SOURCE, fossPagingData = pagingData, ) composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) ).assertIsDisplayed() } @Test fun appendError_showsFooterRetryWithResults() { val pagingData = PagingData.from( listOf(sampleApp("Loaded App")), sourceLoadStates = loadStates( refresh = LoadState.NotLoading(endOfPaginationReached = false), append = LoadState.Error(RuntimeException("append boom")) ) ) renderSearchResults( tabs = listOf(SearchTabType.OPEN_SOURCE), selectedTab = SearchTabType.OPEN_SOURCE, fossPagingData = pagingData, ) composeRule.onNodeWithText("Loaded App").assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) ).assertIsDisplayed() } @Test fun emptyResults_showsPlaceholder() { val pagingData = PagingData.empty<Application>( Loading @@ -256,7 +211,7 @@ class SearchResultsContentTest { refresh = LoadState.NotLoading(endOfPaginationReached = true) ) ) val noAppsText = composeRule.activity.getString(R.string.no_apps_found) val noAppsText = composeRule.activity.getString(R.string.search_empty_results_body) renderSearchResults( tabs = listOf(SearchTabType.OPEN_SOURCE), Loading @@ -269,7 +224,7 @@ class SearchResultsContentTest { @Test fun emptyResults_resetOnNewQuery_showsRefreshLoading() { val noAppsText = composeRule.activity.getString(R.string.no_apps_found) val noAppsText = composeRule.activity.getString(R.string.search_empty_results_body) val emptyPagingData = PagingData.empty<Application>( sourceLoadStates = loadStates( refresh = LoadState.NotLoading(endOfPaginationReached = true) Loading app/src/androidTest/java/foundation/e/apps/ui/compose/components/search/SearchErrorStateTest.kt +4 −10 Original line number Diff line number Diff line Loading @@ -41,16 +41,13 @@ class SearchErrorStateTest { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { SearchErrorState(onRetry = {}, fullScreen = true) SearchErrorState(errorTitleStringRes = R.string.search_error_title_opensource, fullScreen = true) } } } composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) composeRule.activity.getString(R.string.search_error_message) ).assertIsDisplayed() } Loading @@ -59,16 +56,13 @@ class SearchErrorStateTest { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { SearchErrorState(onRetry = {}, fullScreen = false) SearchErrorState(errorTitleStringRes = R.string.search_error_title_opensource, fullScreen = false) } } } composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) composeRule.activity.getString(R.string.search_error_message) ).assertIsDisplayed() } } app/src/main/java/foundation/e/apps/ui/compose/components/SearchPlaceholder.kt +18 −18 Original line number Diff line number Diff line Loading @@ -18,22 +18,20 @@ package foundation.e.apps.ui.compose.components import androidx.compose.foundation.Image import androidx.annotation.StringRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign.Companion.Center import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp Loading @@ -41,7 +39,7 @@ import foundation.e.apps.R import foundation.e.apps.ui.compose.theme.AppTheme @Composable fun SearchPlaceholder(modifier: Modifier = Modifier) { fun SearchPlaceholder(@StringRes stringResource: Int, modifier: Modifier = Modifier) { Box( modifier = modifier .fillMaxSize(), Loading @@ -51,21 +49,23 @@ fun SearchPlaceholder(modifier: Modifier = Modifier) { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp), ) { Image( painter = painterResource(id = R.drawable.ic_error_circular), contentDescription = stringResource(id = R.string.menu_search), contentScale = ContentScale.Fit, modifier = Modifier .padding(bottom = 4.dp) .size(96.dp), ) Text( text = stringResource(id = R.string.no_apps_found), text = stringResource(id = stringResource), style = MaterialTheme.typography.bodyMedium.copy( fontSize = 18.sp ), color = colorResource(id = R.color.light_grey), textAlign = androidx.compose.ui.text.style.TextAlign.Center, color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.87f), textAlign = Center, ) Text( text = stringResource(R.string.search_empty_results_body), modifier = Modifier.padding(horizontal = 32.dp), textAlign = Center, style = MaterialTheme.typography.bodyMedium.copy( fontSize = 14.sp, fontWeight = FontWeight.Normal ), color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.38f) ) } } Loading @@ -75,6 +75,6 @@ fun SearchPlaceholder(modifier: Modifier = Modifier) { @Composable private fun SearchPlaceholderPreview() { AppTheme(darkTheme = true) { SearchPlaceholder() SearchPlaceholder(stringResource = R.string.search_empty_results_title_playstore) } } app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt +37 −51 Original line number Diff line number Diff line Loading @@ -187,26 +187,34 @@ private fun SearchTabPage( installButtonStateProvider: (Application) -> InstallButtonState, modifier: Modifier = Modifier, ) { val items: LazyPagingItems<Application>? val emptyResultsStringResource: Int val errorTitleStringResource: Int when (tab) { SearchTabType.COMMON_APPS -> { items = playStoreItems emptyResultsStringResource = R.string.search_empty_results_title_playstore errorTitleStringResource = R.string.search_error_title_playstore } SearchTabType.OPEN_SOURCE -> { PagingSearchResultList( items = fossItems, searchVersion = searchVersion, tab = tab, getScrollPosition = getScrollPosition, onScrollPositionChange = onScrollPositionChange, onItemClick = onResultClick, onPrimaryActionClick = onPrimaryActionClick, onShowMoreClick = onShowMoreClick, onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, modifier = modifier, ) items = fossItems emptyResultsStringResource = R.string.search_empty_results_title_open_source errorTitleStringResource = R.string.search_error_title_opensource } SearchTabType.PWA -> { items = pwaItems emptyResultsStringResource = R.string.search_empty_results_title_pwa errorTitleStringResource = R.string.search_error_title_pwa } } when (tab) { SearchTabType.OPEN_SOURCE, SearchTabType.PWA -> { PagingSearchResultList( items = pwaItems, items = items, searchVersion = searchVersion, tab = tab, getScrollPosition = getScrollPosition, Loading @@ -216,13 +224,15 @@ private fun SearchTabPage( onShowMoreClick = onShowMoreClick, onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, emptyResultsStringResource = emptyResultsStringResource, errorTitleStringResource = errorTitleStringResource, modifier = modifier, ) } SearchTabType.COMMON_APPS -> { PagingPlayStoreResultList( items = playStoreItems, items = items, searchVersion = searchVersion, getScrollPosition = getScrollPosition, onScrollPositionChange = onScrollPositionChange, Loading @@ -231,6 +241,8 @@ private fun SearchTabPage( onShowMoreClick = onShowMoreClick, onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, emptyResultsStringResource = emptyResultsStringResource, errorTitleStringResource = errorTitleStringResource, modifier = modifier, ) } Loading @@ -248,6 +260,8 @@ private fun PagingPlayStoreResultList( onShowMoreClick: (Application) -> Unit, onPrivacyClick: (Application) -> Unit, installButtonStateProvider: (Application) -> InstallButtonState, emptyResultsStringResource: Int, errorTitleStringResource: Int, modifier: Modifier = Modifier, ) { val lazyItems = items ?: return Loading Loading @@ -295,11 +309,7 @@ private fun PagingPlayStoreResultList( } val initialLoadError = refreshError != null && !hasLoadedCurrentQuery.value val showFooterError = hasLoadedCurrentQuery.value && listOf( refreshError, appendError, prependError ).any { it != null } val isEmpty = !isRefreshing && refreshError == null && appendError == null && prependError == null && lazyItems.itemCount == 0 Loading @@ -311,7 +321,7 @@ private fun PagingPlayStoreResultList( initialLoadError -> { SearchErrorState( onRetry = { lazyItems.retry() }, errorTitleStringRes = errorTitleStringResource, modifier = Modifier.fillMaxSize(), fullScreen = true, ) Loading @@ -319,6 +329,7 @@ private fun PagingPlayStoreResultList( isEmpty -> { SearchPlaceholder( stringResource = emptyResultsStringResource, modifier = Modifier .fillMaxWidth() .align(Alignment.Center) Loading Loading @@ -375,18 +386,6 @@ private fun PagingPlayStoreResultList( } } } if (showFooterError) { item(key = "error_footer_play_store") { SearchErrorState( onRetry = { lazyItems.retry() }, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 12.dp), fullScreen = false, ) } } } } } Loading @@ -405,6 +404,8 @@ private fun PagingSearchResultList( onShowMoreClick: (Application) -> Unit, onPrivacyClick: (Application) -> Unit, installButtonStateProvider: (Application) -> InstallButtonState, emptyResultsStringResource: Int, errorTitleStringResource: Int, modifier: Modifier = Modifier, ) { val lazyItems = items ?: return Loading Loading @@ -448,11 +449,7 @@ private fun PagingSearchResultList( } val initialLoadError = refreshError != null && !hasLoadedCurrentQuery.value val showFooterError = hasLoadedCurrentQuery.value && listOf( refreshError, appendError, prependError ).any { it != null } val isEmpty = !isRefreshing && refreshError == null && appendError == null && prependError == null && lazyItems.itemCount == 0 Loading @@ -466,7 +463,7 @@ private fun PagingSearchResultList( initialLoadError -> { SearchErrorState( onRetry = { lazyItems.retry() }, errorTitleStringRes = errorTitleStringResource, modifier = Modifier.fillMaxSize(), fullScreen = true, ) Loading @@ -474,6 +471,7 @@ private fun PagingSearchResultList( isEmpty -> { SearchPlaceholder( stringResource = emptyResultsStringResource, modifier = Modifier .fillMaxWidth() .align(Alignment.Center) Loading Loading @@ -535,18 +533,6 @@ private fun PagingSearchResultList( } } } if (showFooterError) { item(key = "error_footer") { SearchErrorState( onRetry = { lazyItems.retry() }, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 12.dp), fullScreen = false, ) } } } } } Loading app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchErrorState.kt +21 −26 Original line number Diff line number Diff line Loading @@ -18,28 +18,30 @@ package foundation.e.apps.ui.compose.components.search import androidx.annotation.StringRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import foundation.e.apps.R import foundation.e.apps.ui.compose.theme.AppTheme @Composable fun SearchErrorState( onRetry: () -> Unit, @StringRes errorTitleStringRes: Int, modifier: Modifier = Modifier, fullScreen: Boolean = true, ) { Loading @@ -49,31 +51,29 @@ fun SearchErrorState( modifier.fillMaxWidth() } val contentPadding = if (fullScreen) { PaddingValues(all = 24.dp) } else { PaddingValues(horizontal = 16.dp, vertical = 12.dp) } Box( modifier = containerModifier, contentAlignment = Alignment.Center ) { Column( modifier = Modifier .fillMaxWidth() .padding(contentPadding), .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp), ) { Text( text = stringResource(id = R.string.search_error), style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onBackground, text = stringResource(id = errorTitleStringRes), fontSize = 18.sp, fontWeight = FontWeight.Medium, color = MaterialTheme.colorScheme.onPrimary, ) Text( modifier = Modifier.padding(horizontal = 24.dp), textAlign = TextAlign.Center, text = stringResource(id = R.string.search_error_message), fontSize = 15.sp, color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.38F), ) Button(onClick = onRetry) { Text(text = stringResource(id = R.string.retry)) } } } } Loading @@ -82,14 +82,9 @@ fun SearchErrorState( @Composable private fun SearchErrorStateFullScreenPreview() { AppTheme { SearchErrorState(onRetry = {}, fullScreen = true) } } @Preview(showBackground = true) @Composable private fun SearchErrorStateFooterPreview() { AppTheme { SearchErrorState(onRetry = {}, fullScreen = false) SearchErrorState( errorTitleStringRes = R.string.search_error_title_opensource, fullScreen = true ) } } Loading
app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultsContentTest.kt +2 −47 Original line number Diff line number Diff line Loading @@ -204,51 +204,6 @@ class SearchResultsContentTest { composeRule.onAllNodesWithText("Open App").assertCountEquals(0) } @Test fun refreshError_showsRetry() { val pagingData = PagingData.empty<Application>( sourceLoadStates = loadStates(refresh = LoadState.Error(RuntimeException("boom"))) ) renderSearchResults( tabs = listOf(SearchTabType.OPEN_SOURCE), selectedTab = SearchTabType.OPEN_SOURCE, fossPagingData = pagingData, ) composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) ).assertIsDisplayed() } @Test fun appendError_showsFooterRetryWithResults() { val pagingData = PagingData.from( listOf(sampleApp("Loaded App")), sourceLoadStates = loadStates( refresh = LoadState.NotLoading(endOfPaginationReached = false), append = LoadState.Error(RuntimeException("append boom")) ) ) renderSearchResults( tabs = listOf(SearchTabType.OPEN_SOURCE), selectedTab = SearchTabType.OPEN_SOURCE, fossPagingData = pagingData, ) composeRule.onNodeWithText("Loaded App").assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) ).assertIsDisplayed() } @Test fun emptyResults_showsPlaceholder() { val pagingData = PagingData.empty<Application>( Loading @@ -256,7 +211,7 @@ class SearchResultsContentTest { refresh = LoadState.NotLoading(endOfPaginationReached = true) ) ) val noAppsText = composeRule.activity.getString(R.string.no_apps_found) val noAppsText = composeRule.activity.getString(R.string.search_empty_results_body) renderSearchResults( tabs = listOf(SearchTabType.OPEN_SOURCE), Loading @@ -269,7 +224,7 @@ class SearchResultsContentTest { @Test fun emptyResults_resetOnNewQuery_showsRefreshLoading() { val noAppsText = composeRule.activity.getString(R.string.no_apps_found) val noAppsText = composeRule.activity.getString(R.string.search_empty_results_body) val emptyPagingData = PagingData.empty<Application>( sourceLoadStates = loadStates( refresh = LoadState.NotLoading(endOfPaginationReached = true) Loading
app/src/androidTest/java/foundation/e/apps/ui/compose/components/search/SearchErrorStateTest.kt +4 −10 Original line number Diff line number Diff line Loading @@ -41,16 +41,13 @@ class SearchErrorStateTest { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { SearchErrorState(onRetry = {}, fullScreen = true) SearchErrorState(errorTitleStringRes = R.string.search_error_title_opensource, fullScreen = true) } } } composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) composeRule.activity.getString(R.string.search_error_message) ).assertIsDisplayed() } Loading @@ -59,16 +56,13 @@ class SearchErrorStateTest { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { SearchErrorState(onRetry = {}, fullScreen = false) SearchErrorState(errorTitleStringRes = R.string.search_error_title_opensource, fullScreen = false) } } } composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) composeRule.activity.getString(R.string.search_error_message) ).assertIsDisplayed() } }
app/src/main/java/foundation/e/apps/ui/compose/components/SearchPlaceholder.kt +18 −18 Original line number Diff line number Diff line Loading @@ -18,22 +18,20 @@ package foundation.e.apps.ui.compose.components import androidx.compose.foundation.Image import androidx.annotation.StringRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign.Companion.Center import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp Loading @@ -41,7 +39,7 @@ import foundation.e.apps.R import foundation.e.apps.ui.compose.theme.AppTheme @Composable fun SearchPlaceholder(modifier: Modifier = Modifier) { fun SearchPlaceholder(@StringRes stringResource: Int, modifier: Modifier = Modifier) { Box( modifier = modifier .fillMaxSize(), Loading @@ -51,21 +49,23 @@ fun SearchPlaceholder(modifier: Modifier = Modifier) { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp), ) { Image( painter = painterResource(id = R.drawable.ic_error_circular), contentDescription = stringResource(id = R.string.menu_search), contentScale = ContentScale.Fit, modifier = Modifier .padding(bottom = 4.dp) .size(96.dp), ) Text( text = stringResource(id = R.string.no_apps_found), text = stringResource(id = stringResource), style = MaterialTheme.typography.bodyMedium.copy( fontSize = 18.sp ), color = colorResource(id = R.color.light_grey), textAlign = androidx.compose.ui.text.style.TextAlign.Center, color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.87f), textAlign = Center, ) Text( text = stringResource(R.string.search_empty_results_body), modifier = Modifier.padding(horizontal = 32.dp), textAlign = Center, style = MaterialTheme.typography.bodyMedium.copy( fontSize = 14.sp, fontWeight = FontWeight.Normal ), color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.38f) ) } } Loading @@ -75,6 +75,6 @@ fun SearchPlaceholder(modifier: Modifier = Modifier) { @Composable private fun SearchPlaceholderPreview() { AppTheme(darkTheme = true) { SearchPlaceholder() SearchPlaceholder(stringResource = R.string.search_empty_results_title_playstore) } }
app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt +37 −51 Original line number Diff line number Diff line Loading @@ -187,26 +187,34 @@ private fun SearchTabPage( installButtonStateProvider: (Application) -> InstallButtonState, modifier: Modifier = Modifier, ) { val items: LazyPagingItems<Application>? val emptyResultsStringResource: Int val errorTitleStringResource: Int when (tab) { SearchTabType.COMMON_APPS -> { items = playStoreItems emptyResultsStringResource = R.string.search_empty_results_title_playstore errorTitleStringResource = R.string.search_error_title_playstore } SearchTabType.OPEN_SOURCE -> { PagingSearchResultList( items = fossItems, searchVersion = searchVersion, tab = tab, getScrollPosition = getScrollPosition, onScrollPositionChange = onScrollPositionChange, onItemClick = onResultClick, onPrimaryActionClick = onPrimaryActionClick, onShowMoreClick = onShowMoreClick, onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, modifier = modifier, ) items = fossItems emptyResultsStringResource = R.string.search_empty_results_title_open_source errorTitleStringResource = R.string.search_error_title_opensource } SearchTabType.PWA -> { items = pwaItems emptyResultsStringResource = R.string.search_empty_results_title_pwa errorTitleStringResource = R.string.search_error_title_pwa } } when (tab) { SearchTabType.OPEN_SOURCE, SearchTabType.PWA -> { PagingSearchResultList( items = pwaItems, items = items, searchVersion = searchVersion, tab = tab, getScrollPosition = getScrollPosition, Loading @@ -216,13 +224,15 @@ private fun SearchTabPage( onShowMoreClick = onShowMoreClick, onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, emptyResultsStringResource = emptyResultsStringResource, errorTitleStringResource = errorTitleStringResource, modifier = modifier, ) } SearchTabType.COMMON_APPS -> { PagingPlayStoreResultList( items = playStoreItems, items = items, searchVersion = searchVersion, getScrollPosition = getScrollPosition, onScrollPositionChange = onScrollPositionChange, Loading @@ -231,6 +241,8 @@ private fun SearchTabPage( onShowMoreClick = onShowMoreClick, onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, emptyResultsStringResource = emptyResultsStringResource, errorTitleStringResource = errorTitleStringResource, modifier = modifier, ) } Loading @@ -248,6 +260,8 @@ private fun PagingPlayStoreResultList( onShowMoreClick: (Application) -> Unit, onPrivacyClick: (Application) -> Unit, installButtonStateProvider: (Application) -> InstallButtonState, emptyResultsStringResource: Int, errorTitleStringResource: Int, modifier: Modifier = Modifier, ) { val lazyItems = items ?: return Loading Loading @@ -295,11 +309,7 @@ private fun PagingPlayStoreResultList( } val initialLoadError = refreshError != null && !hasLoadedCurrentQuery.value val showFooterError = hasLoadedCurrentQuery.value && listOf( refreshError, appendError, prependError ).any { it != null } val isEmpty = !isRefreshing && refreshError == null && appendError == null && prependError == null && lazyItems.itemCount == 0 Loading @@ -311,7 +321,7 @@ private fun PagingPlayStoreResultList( initialLoadError -> { SearchErrorState( onRetry = { lazyItems.retry() }, errorTitleStringRes = errorTitleStringResource, modifier = Modifier.fillMaxSize(), fullScreen = true, ) Loading @@ -319,6 +329,7 @@ private fun PagingPlayStoreResultList( isEmpty -> { SearchPlaceholder( stringResource = emptyResultsStringResource, modifier = Modifier .fillMaxWidth() .align(Alignment.Center) Loading Loading @@ -375,18 +386,6 @@ private fun PagingPlayStoreResultList( } } } if (showFooterError) { item(key = "error_footer_play_store") { SearchErrorState( onRetry = { lazyItems.retry() }, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 12.dp), fullScreen = false, ) } } } } } Loading @@ -405,6 +404,8 @@ private fun PagingSearchResultList( onShowMoreClick: (Application) -> Unit, onPrivacyClick: (Application) -> Unit, installButtonStateProvider: (Application) -> InstallButtonState, emptyResultsStringResource: Int, errorTitleStringResource: Int, modifier: Modifier = Modifier, ) { val lazyItems = items ?: return Loading Loading @@ -448,11 +449,7 @@ private fun PagingSearchResultList( } val initialLoadError = refreshError != null && !hasLoadedCurrentQuery.value val showFooterError = hasLoadedCurrentQuery.value && listOf( refreshError, appendError, prependError ).any { it != null } val isEmpty = !isRefreshing && refreshError == null && appendError == null && prependError == null && lazyItems.itemCount == 0 Loading @@ -466,7 +463,7 @@ private fun PagingSearchResultList( initialLoadError -> { SearchErrorState( onRetry = { lazyItems.retry() }, errorTitleStringRes = errorTitleStringResource, modifier = Modifier.fillMaxSize(), fullScreen = true, ) Loading @@ -474,6 +471,7 @@ private fun PagingSearchResultList( isEmpty -> { SearchPlaceholder( stringResource = emptyResultsStringResource, modifier = Modifier .fillMaxWidth() .align(Alignment.Center) Loading Loading @@ -535,18 +533,6 @@ private fun PagingSearchResultList( } } } if (showFooterError) { item(key = "error_footer") { SearchErrorState( onRetry = { lazyItems.retry() }, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 12.dp), fullScreen = false, ) } } } } } Loading
app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchErrorState.kt +21 −26 Original line number Diff line number Diff line Loading @@ -18,28 +18,30 @@ package foundation.e.apps.ui.compose.components.search import androidx.annotation.StringRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import foundation.e.apps.R import foundation.e.apps.ui.compose.theme.AppTheme @Composable fun SearchErrorState( onRetry: () -> Unit, @StringRes errorTitleStringRes: Int, modifier: Modifier = Modifier, fullScreen: Boolean = true, ) { Loading @@ -49,31 +51,29 @@ fun SearchErrorState( modifier.fillMaxWidth() } val contentPadding = if (fullScreen) { PaddingValues(all = 24.dp) } else { PaddingValues(horizontal = 16.dp, vertical = 12.dp) } Box( modifier = containerModifier, contentAlignment = Alignment.Center ) { Column( modifier = Modifier .fillMaxWidth() .padding(contentPadding), .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp), ) { Text( text = stringResource(id = R.string.search_error), style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onBackground, text = stringResource(id = errorTitleStringRes), fontSize = 18.sp, fontWeight = FontWeight.Medium, color = MaterialTheme.colorScheme.onPrimary, ) Text( modifier = Modifier.padding(horizontal = 24.dp), textAlign = TextAlign.Center, text = stringResource(id = R.string.search_error_message), fontSize = 15.sp, color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.38F), ) Button(onClick = onRetry) { Text(text = stringResource(id = R.string.retry)) } } } } Loading @@ -82,14 +82,9 @@ fun SearchErrorState( @Composable private fun SearchErrorStateFullScreenPreview() { AppTheme { SearchErrorState(onRetry = {}, fullScreen = true) } } @Preview(showBackground = true) @Composable private fun SearchErrorStateFooterPreview() { AppTheme { SearchErrorState(onRetry = {}, fullScreen = false) SearchErrorState( errorTitleStringRes = R.string.search_error_title_opensource, fullScreen = true ) } }