Loading app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultsContentTest.kt +0 −45 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 app/src/androidTest/java/foundation/e/apps/ui/compose/components/search/SearchErrorStateTest.kt +2 −8 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ class SearchErrorStateTest { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { SearchErrorState(onRetry = {}, fullScreen = true) SearchErrorState(fullScreen = true) } } } Loading @@ -49,9 +49,6 @@ class SearchErrorStateTest { composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) ).assertIsDisplayed() } @Test Loading @@ -59,7 +56,7 @@ class SearchErrorStateTest { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { SearchErrorState(onRetry = {}, fullScreen = false) SearchErrorState(fullScreen = false) } } } Loading @@ -67,8 +64,5 @@ class SearchErrorStateTest { composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) ).assertIsDisplayed() } } app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt +2 −36 Original line number Diff line number Diff line Loading @@ -295,11 +295,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 +307,6 @@ private fun PagingPlayStoreResultList( initialLoadError -> { SearchErrorState( onRetry = { lazyItems.retry() }, modifier = Modifier.fillMaxSize(), fullScreen = true, ) Loading Loading @@ -375,18 +370,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 Loading @@ -448,11 +431,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 +445,6 @@ private fun PagingSearchResultList( initialLoadError -> { SearchErrorState( onRetry = { lazyItems.retry() }, modifier = Modifier.fillMaxSize(), fullScreen = true, ) Loading Loading @@ -535,18 +513,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 −9 Original line number Diff line number Diff line Loading @@ -25,21 +25,24 @@ 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.Icon 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.painterResource 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, modifier: Modifier = Modifier, fullScreen: Boolean = true, ) { Loading @@ -66,14 +69,23 @@ fun SearchErrorState( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp), ) { Icon( painter = painterResource(R.drawable.ic_maintainance), contentDescription = stringResource(R.string.search_error_icon_cd) ) Text( text = stringResource(id = R.string.search_error), style = MaterialTheme.typography.bodyLarge, text = stringResource(id = R.string.search_error_title), fontSize = 18.sp, fontWeight = FontWeight.Medium, color = MaterialTheme.colorScheme.onBackground, ) Button(onClick = onRetry) { Text(text = stringResource(id = R.string.retry)) } Text( modifier = Modifier.padding(horizontal = 48.dp), textAlign = TextAlign.Center, text = stringResource(id = R.string.search_error), fontSize = 16.sp, color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.38F), ) } } } Loading @@ -82,7 +94,7 @@ fun SearchErrorState( @Composable private fun SearchErrorStateFullScreenPreview() { AppTheme { SearchErrorState(onRetry = {}, fullScreen = true) SearchErrorState(fullScreen = true) } } Loading @@ -90,6 +102,6 @@ private fun SearchErrorStateFullScreenPreview() { @Composable private fun SearchErrorStateFooterPreview() { AppTheme { SearchErrorState(onRetry = {}, fullScreen = false) SearchErrorState(fullScreen = false) } } app/src/main/res/drawable/ic_maintainance.xml 0 → 100644 +10 −0 Original line number Diff line number Diff line <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" android:height="64dp" android:viewportWidth="64" android:viewportHeight="64"> <path android:pathData="M35.826,40.194L51.16,55.527L56.552,50.007L41.218,34.674L35.826,40.194ZM45.333,26.905C44.336,26.905 43.263,26.777 42.42,26.419L13.312,55.399L7.919,50.007L26.856,31.096L22.333,26.547L20.493,28.336L16.787,24.733V32.042L14.998,33.83L6.003,24.733L7.792,22.944H14.973L11.395,19.34L20.493,10.243C23.483,7.253 28.287,7.253 31.277,10.243L25.885,15.762L29.488,19.34L27.674,21.155L32.248,25.704L36.9,20.899C36.542,20.056 36.388,18.983 36.388,18.037C36.388,13.002 40.375,9.041 45.333,9.041C46.841,9.041 48.17,9.399 49.371,10.115L42.547,16.938L46.381,20.771L53.204,13.948C53.92,15.149 54.277,16.427 54.277,18.037C54.277,22.944 50.316,26.905 45.333,26.905Z" android:fillColor="#000000" android:fillAlpha="0.12"/> </vector> Loading
app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultsContentTest.kt +0 −45 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
app/src/androidTest/java/foundation/e/apps/ui/compose/components/search/SearchErrorStateTest.kt +2 −8 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ class SearchErrorStateTest { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { SearchErrorState(onRetry = {}, fullScreen = true) SearchErrorState(fullScreen = true) } } } Loading @@ -49,9 +49,6 @@ class SearchErrorStateTest { composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) ).assertIsDisplayed() } @Test Loading @@ -59,7 +56,7 @@ class SearchErrorStateTest { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { SearchErrorState(onRetry = {}, fullScreen = false) SearchErrorState(fullScreen = false) } } } Loading @@ -67,8 +64,5 @@ class SearchErrorStateTest { composeRule.onNodeWithText( composeRule.activity.getString(R.string.search_error) ).assertIsDisplayed() composeRule.onNodeWithText( composeRule.activity.getString(R.string.retry) ).assertIsDisplayed() } }
app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt +2 −36 Original line number Diff line number Diff line Loading @@ -295,11 +295,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 +307,6 @@ private fun PagingPlayStoreResultList( initialLoadError -> { SearchErrorState( onRetry = { lazyItems.retry() }, modifier = Modifier.fillMaxSize(), fullScreen = true, ) Loading Loading @@ -375,18 +370,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 Loading @@ -448,11 +431,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 +445,6 @@ private fun PagingSearchResultList( initialLoadError -> { SearchErrorState( onRetry = { lazyItems.retry() }, modifier = Modifier.fillMaxSize(), fullScreen = true, ) Loading Loading @@ -535,18 +513,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 −9 Original line number Diff line number Diff line Loading @@ -25,21 +25,24 @@ 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.Icon 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.painterResource 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, modifier: Modifier = Modifier, fullScreen: Boolean = true, ) { Loading @@ -66,14 +69,23 @@ fun SearchErrorState( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp), ) { Icon( painter = painterResource(R.drawable.ic_maintainance), contentDescription = stringResource(R.string.search_error_icon_cd) ) Text( text = stringResource(id = R.string.search_error), style = MaterialTheme.typography.bodyLarge, text = stringResource(id = R.string.search_error_title), fontSize = 18.sp, fontWeight = FontWeight.Medium, color = MaterialTheme.colorScheme.onBackground, ) Button(onClick = onRetry) { Text(text = stringResource(id = R.string.retry)) } Text( modifier = Modifier.padding(horizontal = 48.dp), textAlign = TextAlign.Center, text = stringResource(id = R.string.search_error), fontSize = 16.sp, color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.38F), ) } } } Loading @@ -82,7 +94,7 @@ fun SearchErrorState( @Composable private fun SearchErrorStateFullScreenPreview() { AppTheme { SearchErrorState(onRetry = {}, fullScreen = true) SearchErrorState(fullScreen = true) } } Loading @@ -90,6 +102,6 @@ private fun SearchErrorStateFullScreenPreview() { @Composable private fun SearchErrorStateFooterPreview() { AppTheme { SearchErrorState(onRetry = {}, fullScreen = false) SearchErrorState(fullScreen = false) } }
app/src/main/res/drawable/ic_maintainance.xml 0 → 100644 +10 −0 Original line number Diff line number Diff line <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="64dp" android:height="64dp" android:viewportWidth="64" android:viewportHeight="64"> <path android:pathData="M35.826,40.194L51.16,55.527L56.552,50.007L41.218,34.674L35.826,40.194ZM45.333,26.905C44.336,26.905 43.263,26.777 42.42,26.419L13.312,55.399L7.919,50.007L26.856,31.096L22.333,26.547L20.493,28.336L16.787,24.733V32.042L14.998,33.83L6.003,24.733L7.792,22.944H14.973L11.395,19.34L20.493,10.243C23.483,7.253 28.287,7.253 31.277,10.243L25.885,15.762L29.488,19.34L27.674,21.155L32.248,25.704L36.9,20.899C36.542,20.056 36.388,18.983 36.388,18.037C36.388,13.002 40.375,9.041 45.333,9.041C46.841,9.041 48.17,9.399 49.371,10.115L42.547,16.938L46.381,20.771L53.204,13.948C53.92,15.149 54.277,16.427 54.277,18.037C54.277,22.944 50.316,26.905 45.333,26.905Z" android:fillColor="#000000" android:fillAlpha="0.12"/> </vector>