diff --git a/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/component/ErrorStateTest.kt b/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/component/ErrorStateTest.kt index 808113a3..c25a5eab 100644 --- a/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/component/ErrorStateTest.kt +++ b/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/component/ErrorStateTest.kt @@ -2,7 +2,6 @@ package dev.shorthouse.coinwatch.ui.component import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.createComposeRule -import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithText import dev.shorthouse.coinwatch.ui.theme.AppTheme import org.junit.Rule @@ -24,7 +23,6 @@ class ErrorStateTest { } composeTestRule.apply { - onNodeWithContentDescription("Error").assertIsDisplayed() onNodeWithText("An error has occurred").assertIsDisplayed() } } @@ -40,6 +38,7 @@ class ErrorStateTest { } composeTestRule.apply { + onNodeWithText("An error has occurred").assertIsDisplayed() onNodeWithText("Error message").assertIsDisplayed() } } diff --git a/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/MarketScreenTest.kt b/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/MarketScreenTest.kt index 8057e5ef..ff17e2c8 100644 --- a/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/MarketScreenTest.kt +++ b/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/MarketScreenTest.kt @@ -434,8 +434,8 @@ class MarketScreenTest { } composeTestRule.apply { - onNodeWithText("No coins").assertIsDisplayed() - onNodeWithText("Please try again later").assertIsDisplayed() + onNodeWithText("Couldn't load coins").assertIsDisplayed() + onNodeWithText("Check your internet connection").assertIsDisplayed() } } diff --git a/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/SearchScreenTest.kt b/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/SearchScreenTest.kt index e711bbe7..13dd1984 100644 --- a/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/SearchScreenTest.kt +++ b/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/SearchScreenTest.kt @@ -26,7 +26,7 @@ class SearchScreenTest { @Test fun when_uiStateError_should_showErrorMessage() { val uiState = SearchUiState( - errorMessage = "Error message" + errorMessage = "Unable to fetch coin search results" ) composeTestRule.setContent { @@ -42,7 +42,7 @@ class SearchScreenTest { composeTestRule.apply { onNodeWithText("An error has occurred").assertIsDisplayed() - onNodeWithText("Error message").assertIsDisplayed() + onNodeWithText("Unable to fetch coin search results").assertIsDisplayed() } } @@ -90,6 +90,27 @@ class SearchScreenTest { } } + @Test + fun when_searchQueryIsEmpty_should_displayQueryEmptyState() { + val uiState = SearchUiState() + + composeTestRule.setContent { + AppTheme { + SearchScreen( + uiState = uiState, + searchQuery = "", + onSearchQueryChange = {}, + onCoinClick = {} + ) + } + } + + composeTestRule.apply { + onNodeWithText("Explore coins").assertIsDisplayed() + onNodeWithText("Search by name or symbol").assertIsDisplayed() + } + } + @Test fun when_searchQueryEntered_should_displaySearchQuery() { val searchQuery = "Bitcoin" @@ -134,6 +155,28 @@ class SearchScreenTest { } } + @Test + fun when_searchQueryEmpty_should_notDisplayClearSearchButton() { + val searchQuery = "" + + val uiState = SearchUiState() + + composeTestRule.setContent { + AppTheme { + SearchScreen( + uiState = uiState, + searchQuery = searchQuery, + onSearchQueryChange = {}, + onCoinClick = {} + ) + } + } + + composeTestRule.apply { + onNodeWithContentDescription("Clear search").assertDoesNotExist() + } + } + @Test fun when_clearSearchClicked_should_clearSearchQuery() { val searchQuery = mutableStateOf("Bitcoin") @@ -206,7 +249,7 @@ class SearchScreenTest { AppTheme { SearchScreen( uiState = uiState, - searchQuery = "", + searchQuery = "Bit", onSearchQueryChange = {}, onCoinClick = {} ) @@ -240,7 +283,7 @@ class SearchScreenTest { AppTheme { SearchScreen( uiState = uiState, - searchQuery = "", + searchQuery = "Bit", onSearchQueryChange = {}, onCoinClick = { onCoinClickCalled = true } ) diff --git a/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/SettingsScreenTest.kt b/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/SettingsScreenTest.kt index 6bba7351..6d002b7a 100644 --- a/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/SettingsScreenTest.kt +++ b/app/src/androidTest/java/dev/shorthouse/coinwatch/ui/screen/SettingsScreenTest.kt @@ -1,12 +1,8 @@ package dev.shorthouse.coinwatch.ui.screen -import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.SemanticsProperties import androidx.compose.ui.test.SemanticsMatcher -import androidx.compose.ui.test.assertHasClickAction import androidx.compose.ui.test.assertIsDisplayed -import androidx.compose.ui.test.assertIsNotSelected -import androidx.compose.ui.test.assertIsSelected import androidx.compose.ui.test.hasText import androidx.compose.ui.test.isNotSelected import androidx.compose.ui.test.isSelected @@ -42,7 +38,8 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } @@ -67,7 +64,8 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } @@ -88,7 +86,8 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } @@ -126,7 +125,8 @@ class SettingsScreenTest { onNavigateUp = { onNavigateUpCalled = true }, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } @@ -139,8 +139,10 @@ class SettingsScreenTest { } @Test - fun when_startScreenClicked_should_openStartScreenDialog() { - val uiState = SettingsUiState() + fun when_currencyIsUsd_should_displayCurrencyAsUsd() { + val uiState = SettingsUiState( + currency = Currency.USD + ) composeTestRule.setContent { AppTheme { @@ -149,31 +151,23 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } - val radioButtonMatcher = SemanticsMatcher.expectValue( - SemanticsProperties.Role, - Role.RadioButton - ) composeTestRule.apply { - onNodeWithText("Start screen").performClick() - onNode(hasText("Market").and(radioButtonMatcher)) - .assertIsDisplayed().assertHasClickAction() - onNode(hasText("Favourites").and(radioButtonMatcher)) - .assertIsDisplayed().assertHasClickAction() - onNode(hasText("Search").and(radioButtonMatcher)) - .assertIsDisplayed().assertHasClickAction() + onNodeWithText("Currency").assertIsDisplayed() + onNodeWithText("USD").assertIsDisplayed() } } @Test - fun when_startScreenDialogOptionClicked_should_callOnUpdateStartScreen() { - val uiState = SettingsUiState() - - var onUpdateStartScreenCalled = false + fun when_currencyIsGbp_should_displayCurrencyAsGbp() { + val uiState = SettingsUiState( + currency = Currency.GBP + ) composeTestRule.setContent { AppTheme { @@ -182,25 +176,22 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = { startScreen -> - onUpdateStartScreenCalled = startScreen == StartScreen.Search - } + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } composeTestRule.apply { - onNodeWithText("Start screen").performClick() - onNodeWithText("Search").performClick() + onNodeWithText("Currency").assertIsDisplayed() + onNodeWithText("GBP").assertIsDisplayed() } - - assertThat(onUpdateStartScreenCalled).isTrue() } @Test - fun when_startScreenIsMarket_should_haveMarketOptionSelected() { + fun when_currencyIsEur_should_displayCurrencyAsEur() { val uiState = SettingsUiState( - startScreen = StartScreen.Market + currency = Currency.EUR ) composeTestRule.setContent { @@ -210,32 +201,45 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } - val radioButtonMatcher = SemanticsMatcher.expectValue( - SemanticsProperties.Role, - Role.RadioButton - ) composeTestRule.apply { - onNodeWithText("Market").assertIsDisplayed() - onNodeWithText("Start screen").performClick() + onNodeWithText("Currency").assertIsDisplayed() + onNodeWithText("EUR").assertIsDisplayed() + } + } - onNode(hasText("Market").and(radioButtonMatcher)) - .assertIsDisplayed().assertIsSelected() - onNode(hasText("Favourites").and(radioButtonMatcher)) - .assertIsDisplayed().assertIsNotSelected() - onNode(hasText("Search").and(radioButtonMatcher)) - .assertIsDisplayed().assertIsNotSelected() + @Test + fun when_currencySettingsClicked_should_callShowCurrencyBottomSheet() { + var showCurrencyBottomSheet = false + val uiState = SettingsUiState() + + composeTestRule.setContent { + AppTheme { + SettingsScreen( + uiState = uiState, + onNavigateUp = {}, + onUpdateCurrency = {}, + onUpdateIsCurrencySheetShown = { showCurrencyBottomSheet = true }, + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} + ) + } } + + composeTestRule.onNodeWithText("Currency").performClick() + assertThat(showCurrencyBottomSheet).isTrue() } @Test - fun when_startScreenIsFavourites_should_haveFavouritesOptionSelected() { + fun when_currencyIsUsd_should_haveUsdSelectedInCurrencyBottomSheet() { val uiState = SettingsUiState( - startScreen = StartScreen.Favourites + currency = Currency.USD, + isCurrencySheetShown = true ) composeTestRule.setContent { @@ -245,32 +249,25 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } - val radioButtonMatcher = SemanticsMatcher.expectValue( - SemanticsProperties.Role, - Role.RadioButton - ) composeTestRule.apply { - onNodeWithText("Favourites").assertIsDisplayed() - onNodeWithText("Start screen").performClick() - - onNode(hasText("Market").and(radioButtonMatcher)) - .assertIsDisplayed().assertIsNotSelected() - onNode(hasText("Favourites").and(radioButtonMatcher)) - .assertIsDisplayed().assertIsSelected() - onNode(hasText("Search").and(radioButtonMatcher)) - .assertIsDisplayed().assertIsNotSelected() + onNodeWithText("Coin currency").assertIsDisplayed() + onNode(hasText("USD").and(isSelected())).assertIsDisplayed() + onNode(hasText("GBP").and(isNotSelected())).assertIsDisplayed() + onNode(hasText("EUR").and(isNotSelected())).assertIsDisplayed() } } @Test - fun when_startScreenIsSearch_should_haveSearchOptionSelected() { + fun when_currencyIsGbp_should_haveGbpSelectedInCurrencyBottomSheet() { val uiState = SettingsUiState( - startScreen = StartScreen.Search + currency = Currency.GBP, + isCurrencySheetShown = true ) composeTestRule.setContent { @@ -280,32 +277,82 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } - val radioButtonMatcher = SemanticsMatcher.expectValue( - SemanticsProperties.Role, - Role.RadioButton + composeTestRule.apply { + onNodeWithText("Coin currency").assertIsDisplayed() + onNode(hasText("USD").and(isNotSelected())).assertIsDisplayed() + onNode(hasText("GBP").and(isSelected())).assertIsDisplayed() + onNode(hasText("EUR").and(isNotSelected())).assertIsDisplayed() + } + } + + @Test + fun when_currencyIsEur_should_haveEurSelectedInCurrencyBottomSheet() { + val uiState = SettingsUiState( + currency = Currency.EUR, + isCurrencySheetShown = true ) + + composeTestRule.setContent { + AppTheme { + SettingsScreen( + uiState = uiState, + onNavigateUp = {}, + onUpdateCurrency = {}, + onUpdateIsCurrencySheetShown = {}, + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} + ) + } + } + composeTestRule.apply { - onNodeWithText("Search").assertIsDisplayed() - onNodeWithText("Start screen").performClick() + onNodeWithText("Coin currency").assertIsDisplayed() + onNode(hasText("USD").and(isNotSelected())).assertIsDisplayed() + onNode(hasText("GBP").and(isNotSelected())).assertIsDisplayed() + onNode(hasText("EUR").and(isSelected())).assertIsDisplayed() + } + } + + @Test + fun when_chooseCurrencyBottomSheetOption_should_callUpdateCurrency() { + var updateCurrencyCalled = false + val uiState = SettingsUiState( + currency = Currency.USD, + isCurrencySheetShown = true + ) + + composeTestRule.setContent { + AppTheme { + SettingsScreen( + uiState = uiState, + onNavigateUp = {}, + onUpdateCurrency = { currency -> + updateCurrencyCalled = currency == Currency.GBP + }, + onUpdateIsCurrencySheetShown = {}, + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} + ) + } + } - onNode(hasText("Market").and(radioButtonMatcher)) - .assertIsDisplayed().assertIsNotSelected() - onNode(hasText("Favourites").and(radioButtonMatcher)) - .assertIsDisplayed().assertIsNotSelected() - onNode(hasText("Search").and(radioButtonMatcher)) - .assertIsDisplayed().assertIsSelected() + composeTestRule.apply { + onNodeWithText("GBP").performClick() } + + assertThat(updateCurrencyCalled).isTrue() } @Test - fun when_currencyIsUsd_should_displayCurrencyAsUsd() { + fun when_startScreenIsMarket_should_displayStartScreenAsMarket() { val uiState = SettingsUiState( - currency = Currency.USD + startScreen = StartScreen.Market ) composeTestRule.setContent { @@ -315,21 +362,22 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } composeTestRule.apply { - onNodeWithText("Currency").assertIsDisplayed() - onNodeWithText("USD").assertIsDisplayed() + onNodeWithText("Start screen").assertIsDisplayed() + onNodeWithText("Market").assertIsDisplayed() } } @Test - fun when_currencyIsGbp_should_displayCurrencyAsGbp() { + fun when_startScreenIsFavourites_should_displayStartScreenAsFavourites() { val uiState = SettingsUiState( - currency = Currency.GBP + startScreen = StartScreen.Favourites ) composeTestRule.setContent { @@ -339,21 +387,22 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } composeTestRule.apply { - onNodeWithText("Currency").assertIsDisplayed() - onNodeWithText("GBP").assertIsDisplayed() + onNodeWithText("Start screen").assertIsDisplayed() + onNodeWithText("Favourites").assertIsDisplayed() } } @Test - fun when_currencyIsEur_should_displayCurrencyAsEur() { + fun when_startScreenIsSearch_should_displayStartScreenAsSearch() { val uiState = SettingsUiState( - currency = Currency.EUR + startScreen = StartScreen.Search ) composeTestRule.setContent { @@ -363,21 +412,22 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } composeTestRule.apply { - onNodeWithText("Currency").assertIsDisplayed() - onNodeWithText("EUR").assertIsDisplayed() + onNodeWithText("Start screen").assertIsDisplayed() + onNodeWithText("Search").assertIsDisplayed() } } @Test - fun when_currencySettingsClicked_should_callShowCurrencyBottomSheet() { - var showCurrencyBottomSheet = false + fun when_startScreenSettingsClicked_should_callShowStartScreenBottomSheet() { val uiState = SettingsUiState() + var showStartScreenBottomSheet = false composeTestRule.setContent { AppTheme { @@ -385,21 +435,25 @@ class SettingsScreenTest { uiState = uiState, onNavigateUp = {}, onUpdateCurrency = {}, - onUpdateIsCurrencySheetShown = { showCurrencyBottomSheet = true }, - onUpdateStartScreen = {} + onUpdateIsCurrencySheetShown = {}, + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = { showStartScreenBottomSheet = true } ) } } - composeTestRule.onNodeWithText("Currency").performClick() - assertThat(showCurrencyBottomSheet).isTrue() + composeTestRule.apply { + onNodeWithText("Start screen").performClick() + } + + assertThat(showStartScreenBottomSheet).isTrue() } @Test - fun when_currencyIsUsd_should_haveUsdSelectedInCurrencyBottomSheet() { + fun when_startScreenIsMarket_should_haveMarketSelectedInStartScreenBottomSheet() { val uiState = SettingsUiState( - currency = Currency.USD, - isCurrencySheetShown = true + startScreen = StartScreen.Market, + isStartScreenSheetShown = true ) composeTestRule.setContent { @@ -409,24 +463,25 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } composeTestRule.apply { - onNodeWithText("Coin currency").assertIsDisplayed() - onNode(hasText("USD").and(isSelected())).assertIsDisplayed() - onNode(hasText("GBP").and(isNotSelected())).assertIsDisplayed() - onNode(hasText("EUR").and(isNotSelected())).assertIsDisplayed() + onNodeWithText("App start screen").assertIsDisplayed() + onNode(hasText("Market").and(isSelected())).assertIsDisplayed() + onNode(hasText("Favourites").and(isNotSelected())).assertIsDisplayed() + onNode(hasText("Search").and(isNotSelected())).assertIsDisplayed() } } @Test - fun when_currencyIsGbp_should_haveGbpSelectedInCurrencyBottomSheet() { + fun when_startScreenIsFavourites_should_haveFavouritesSelectedInStartScreenBottomSheet() { val uiState = SettingsUiState( - currency = Currency.GBP, - isCurrencySheetShown = true + startScreen = StartScreen.Favourites, + isStartScreenSheetShown = true ) composeTestRule.setContent { @@ -436,24 +491,25 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } composeTestRule.apply { - onNodeWithText("Coin currency").assertIsDisplayed() - onNode(hasText("USD").and(isNotSelected())).assertIsDisplayed() - onNode(hasText("GBP").and(isSelected())).assertIsDisplayed() - onNode(hasText("EUR").and(isNotSelected())).assertIsDisplayed() + onNodeWithText("App start screen").assertIsDisplayed() + onNode(hasText("Market").and(isNotSelected())).assertIsDisplayed() + onNode(hasText("Favourites").and(isSelected())).assertIsDisplayed() + onNode(hasText("Search").and(isNotSelected())).assertIsDisplayed() } } @Test - fun when_currencyIsEur_should_haveEurSelectedInCurrencyBottomSheet() { + fun when_startScreenIsSearch_should_haveSearchSelectedInStartScreenBottomSheet() { val uiState = SettingsUiState( - currency = Currency.EUR, - isCurrencySheetShown = true + startScreen = StartScreen.Search, + isStartScreenSheetShown = true ) composeTestRule.setContent { @@ -463,25 +519,26 @@ class SettingsScreenTest { onNavigateUp = {}, onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = {}, + onUpdateIsStartScreenSheetShown = {} ) } } composeTestRule.apply { - onNodeWithText("Coin currency").assertIsDisplayed() - onNode(hasText("USD").and(isNotSelected())).assertIsDisplayed() - onNode(hasText("GBP").and(isNotSelected())).assertIsDisplayed() - onNode(hasText("EUR").and(isSelected())).assertIsDisplayed() + onNodeWithText("App start screen").assertIsDisplayed() + onNode(hasText("Market").and(isNotSelected())).assertIsDisplayed() + onNode(hasText("Favourites").and(isNotSelected())).assertIsDisplayed() + onNode(hasText("Search").and(isSelected())).assertIsDisplayed() } } @Test - fun when_chooseCurrencyBottomSheetOption_should_callUpdateCurrency() { - var updateCurrencyCalled = false + fun when_chooseStartScreenBottomSheetOption_should_callUpdateStartScreen() { + var updateStartScreenCalled = false val uiState = SettingsUiState( - currency = Currency.USD, - isCurrencySheetShown = true + startScreen = StartScreen.Market, + isStartScreenSheetShown = true, ) composeTestRule.setContent { @@ -489,19 +546,20 @@ class SettingsScreenTest { SettingsScreen( uiState = uiState, onNavigateUp = {}, - onUpdateCurrency = { currency -> - updateCurrencyCalled = currency == Currency.GBP - }, + onUpdateCurrency = {}, onUpdateIsCurrencySheetShown = {}, - onUpdateStartScreen = {} + onUpdateStartScreen = { startScreen -> + updateStartScreenCalled = startScreen == StartScreen.Favourites + }, + onUpdateIsStartScreenSheetShown = {} ) } } composeTestRule.apply { - onNodeWithText("GBP").performClick() + onNodeWithText("Favourites").performClick() } - assertThat(updateCurrencyCalled).isTrue() + assertThat(updateStartScreenCalled).isTrue() } } diff --git a/app/src/main/java/dev/shorthouse/coinwatch/ui/component/EmptyState.kt b/app/src/main/java/dev/shorthouse/coinwatch/ui/component/EmptyState.kt index eae7dccb..5fa2b45b 100644 --- a/app/src/main/java/dev/shorthouse/coinwatch/ui/component/EmptyState.kt +++ b/app/src/main/java/dev/shorthouse/coinwatch/ui/component/EmptyState.kt @@ -7,11 +7,9 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height 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 @@ -38,16 +36,16 @@ fun EmptyState( verticalArrangement = Arrangement.Center, modifier = Modifier .fillMaxWidth() - .fillMaxHeight(0.9f) + .fillMaxHeight(0.70f) .padding(12.dp) ) { Image( painter = image, contentDescription = null, - modifier = Modifier.size(250.dp) + modifier = Modifier.height(180.dp) ) - Spacer(Modifier.height(12.dp)) + Spacer(Modifier.height(24.dp)) Text( text = title, @@ -63,7 +61,7 @@ fun EmptyState( } @Composable -@Preview +@Preview(heightDp = 400) private fun EmptyStatePreview() { AppTheme { EmptyState( diff --git a/app/src/main/java/dev/shorthouse/coinwatch/ui/component/ErrorState.kt b/app/src/main/java/dev/shorthouse/coinwatch/ui/component/ErrorState.kt index be7dfa6d..cd03f1af 100644 --- a/app/src/main/java/dev/shorthouse/coinwatch/ui/component/ErrorState.kt +++ b/app/src/main/java/dev/shorthouse/coinwatch/ui/component/ErrorState.kt @@ -1,75 +1,39 @@ package dev.shorthouse.coinwatch.ui.component -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults 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.tooling.preview.Preview -import androidx.compose.ui.unit.dp import dev.shorthouse.coinwatch.R import dev.shorthouse.coinwatch.ui.theme.AppTheme @Composable fun ErrorState( message: String?, - modifier: Modifier = Modifier, + modifier: Modifier = Modifier ) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, + EmptyState( + image = painterResource(R.drawable.error_state), + title = stringResource(R.string.error_occurred), + subtitle = { + message?.let { + Text( + text = it, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + }, modifier = modifier - .fillMaxWidth() - .fillMaxHeight(0.9f) - .padding(12.dp) - .background(MaterialTheme.colorScheme.background) - ) { - Image( - painter = painterResource(R.drawable.error_state), - contentDescription = stringResource(R.string.cd_error_state), - modifier = Modifier.size(250.dp) - ) - - Spacer(Modifier.height(12.dp)) - - Text( - text = stringResource(R.string.error_occurred), - style = MaterialTheme.typography.titleMedium, - color = MaterialTheme.colorScheme.onBackground - ) - - Spacer(Modifier.height(4.dp)) - - message?.let { - Text( - text = it, - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } - - Spacer(Modifier.height(24.dp)) - } + ) } @Composable -@Preview -private fun ErrorStateRetryPreview() { +@Preview(heightDp = 400) +private fun ErrorStatePreview() { AppTheme { ErrorState( message = "No internet connection", diff --git a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/favourites/FavouritesScreen.kt b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/favourites/FavouritesScreen.kt index 4dea930a..12732c7a 100644 --- a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/favourites/FavouritesScreen.kt +++ b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/favourites/FavouritesScreen.kt @@ -255,14 +255,15 @@ fun FavouritesContent( CompositionLocalProvider(LocalOverscrollConfiguration provides null) { when { favouriteCoins.isEmpty() -> { - FavouritesEmptyState(modifier = modifier.padding(12.dp)) + FavouritesEmptyState() } isFavouritesCondensed -> { FavouritesCondensedList( favouriteCoins = favouriteCoins, onCoinClick = onCoinClick, - listState = listState + listState = listState, + modifier = modifier ) } @@ -270,7 +271,8 @@ fun FavouritesContent( FavouritesList( favouriteCoins = favouriteCoins, onCoinClick = onCoinClick, - gridState = gridState + gridState = gridState, + modifier = modifier ) } } diff --git a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/favourites/component/FavouritesEmptyState.kt b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/favourites/component/FavouritesEmptyState.kt index fcc4a62b..9b7088d9 100644 --- a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/favourites/component/FavouritesEmptyState.kt +++ b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/favourites/component/FavouritesEmptyState.kt @@ -22,7 +22,7 @@ import dev.shorthouse.coinwatch.ui.theme.AppTheme @Composable fun FavouritesEmptyState(modifier: Modifier = Modifier) { EmptyState( - image = painterResource(R.drawable.empty_state_favourite_coins), + image = painterResource(R.drawable.empty_state_favourites), title = stringResource(R.string.empty_state_favourite_coins_title), subtitle = { Row(verticalAlignment = Alignment.CenterVertically) { @@ -38,7 +38,7 @@ fun FavouritesEmptyState(modifier: Modifier = Modifier) { tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier .size(22.dp) - .padding(start = 2.dp, top = 2.dp, end = 2.dp) + .padding(start = 4.dp, top = 2.dp, end = 4.dp) ) Text( @@ -53,7 +53,7 @@ fun FavouritesEmptyState(modifier: Modifier = Modifier) { } @Composable -@Preview +@Preview(heightDp = 400) private fun FavouritesEmptyStatePreview() { AppTheme { FavouritesEmptyState() diff --git a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/market/MarketScreen.kt b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/market/MarketScreen.kt index 2d898c39..d7d3753c 100644 --- a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/market/MarketScreen.kt +++ b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/market/MarketScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -64,9 +65,9 @@ import dev.shorthouse.coinwatch.ui.component.pullrefresh.rememberPullRefreshStat import dev.shorthouse.coinwatch.ui.model.TimeOfDay import dev.shorthouse.coinwatch.ui.previewdata.MarketUiStatePreviewProvider import dev.shorthouse.coinwatch.ui.screen.market.component.CoinSortBottomSheet +import dev.shorthouse.coinwatch.ui.screen.market.component.CoinsEmptyState import dev.shorthouse.coinwatch.ui.screen.market.component.MarketChip import dev.shorthouse.coinwatch.ui.screen.market.component.MarketCoinItem -import dev.shorthouse.coinwatch.ui.screen.market.component.MarketEmptyState import dev.shorthouse.coinwatch.ui.screen.market.component.SearchPrompt import dev.shorthouse.coinwatch.ui.theme.AppTheme import kotlinx.collections.immutable.ImmutableList @@ -306,48 +307,50 @@ fun MarketContent( lazyListState: LazyListState, modifier: Modifier = Modifier ) { - Column(modifier = modifier.padding(horizontal = 12.dp)) { - if (coins.isEmpty()) { - MarketEmptyState() - } else { - LazyColumn(state = lazyListState) { - item { - MarketChip( - label = stringResource(coinSort.nameId), - onClick = { onUpdateIsCoinSortSheetShown(true) } - ) - } - items( - count = coins.size, - key = { coins[it].id }, - itemContent = { index -> - val coinListItem = coins[index] - - val cardShape = when (index) { - 0 -> MaterialTheme.shapes.medium.copy( - bottomStart = CornerSize(0.dp), - bottomEnd = CornerSize(0.dp) - ) - - coins.lastIndex -> MaterialTheme.shapes.medium.copy( - topStart = CornerSize(0.dp), - topEnd = CornerSize(0.dp) - ) + if (coins.isEmpty()) { + CoinsEmptyState() + } else { + LazyColumn( + state = lazyListState, + contentPadding = PaddingValues(start = 12.dp, end = 12.dp), + modifier = modifier + ) { + item { + MarketChip( + label = stringResource(coinSort.nameId), + onClick = { onUpdateIsCoinSortSheetShown(true) } + ) + } + items( + count = coins.size, + key = { coins[it].id }, + itemContent = { index -> + val coinListItem = coins[index] - else -> RoundedCornerShape(0.dp) - } + val cardShape = when (index) { + 0 -> MaterialTheme.shapes.medium.copy( + bottomStart = CornerSize(0.dp), + bottomEnd = CornerSize(0.dp) + ) - MarketCoinItem( - coin = coinListItem, - onCoinClick = { onCoinClick(coinListItem) }, - cardShape = cardShape + coins.lastIndex -> MaterialTheme.shapes.medium.copy( + topStart = CornerSize(0.dp), + topEnd = CornerSize(0.dp) ) + + else -> RoundedCornerShape(0.dp) } - ) - item { - SearchPrompt(modifier = Modifier.padding(vertical = 12.dp)) + MarketCoinItem( + coin = coinListItem, + onCoinClick = { onCoinClick(coinListItem) }, + cardShape = cardShape + ) } + ) + + item { + SearchPrompt(modifier = Modifier.padding(vertical = 12.dp)) } } } diff --git a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/market/component/MarketEmptyState.kt b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/market/component/CoinsEmptyState.kt similarity index 87% rename from app/src/main/java/dev/shorthouse/coinwatch/ui/screen/market/component/MarketEmptyState.kt rename to app/src/main/java/dev/shorthouse/coinwatch/ui/screen/market/component/CoinsEmptyState.kt index e5eebfe1..726f963c 100644 --- a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/market/component/MarketEmptyState.kt +++ b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/market/component/CoinsEmptyState.kt @@ -12,7 +12,7 @@ import dev.shorthouse.coinwatch.ui.component.EmptyState import dev.shorthouse.coinwatch.ui.theme.AppTheme @Composable -fun MarketEmptyState(modifier: Modifier = Modifier) { +fun CoinsEmptyState(modifier: Modifier = Modifier) { EmptyState( image = painterResource(R.drawable.empty_state_coins), title = stringResource(R.string.empty_state_coins_title), @@ -28,9 +28,9 @@ fun MarketEmptyState(modifier: Modifier = Modifier) { } @Composable -@Preview -private fun MarketEmptyStatePreview() { +@Preview(heightDp = 400) +private fun CoinsEmptyStatePreview() { AppTheme { - MarketEmptyState() + CoinsEmptyState() } } diff --git a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/SearchScreen.kt b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/SearchScreen.kt index 1aee6807..28057f6b 100644 --- a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/SearchScreen.kt +++ b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/SearchScreen.kt @@ -18,11 +18,9 @@ import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp @@ -33,8 +31,9 @@ import dev.shorthouse.coinwatch.model.SearchCoin import dev.shorthouse.coinwatch.ui.component.ErrorState import dev.shorthouse.coinwatch.ui.component.LoadingIndicator import dev.shorthouse.coinwatch.ui.previewdata.SearchUiStatePreviewProvider -import dev.shorthouse.coinwatch.ui.screen.search.component.SearchEmptyState import dev.shorthouse.coinwatch.ui.screen.search.component.SearchListItem +import dev.shorthouse.coinwatch.ui.screen.search.component.SearchQueryEmptyState +import dev.shorthouse.coinwatch.ui.screen.search.component.SearchResultsEmptyState import dev.shorthouse.coinwatch.ui.theme.AppTheme import kotlinx.collections.immutable.ImmutableList @@ -57,7 +56,7 @@ fun SearchScreen( ) } -@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) +@OptIn(ExperimentalMaterial3Api::class) @Composable fun SearchScreen( uiState: SearchUiState, @@ -113,11 +112,15 @@ fun SearchScreen( } uiState.errorMessage != null -> { - ErrorState(message = uiState.errorMessage) + ErrorState( + message = uiState.errorMessage, + modifier = Modifier.padding(bottom = 12.dp) + ) } else -> { SearchContent( + searchQuery = searchQuery, searchResults = uiState.searchResults, queryHasNoResults = uiState.queryHasNoResults, onCoinClick = onCoinClick @@ -129,45 +132,57 @@ fun SearchScreen( @Composable fun SearchContent( + searchQuery: String, searchResults: ImmutableList, queryHasNoResults: Boolean, onCoinClick: (SearchCoin) -> Unit, modifier: Modifier = Modifier ) { - if (queryHasNoResults) { - SearchEmptyState(modifier = modifier.padding(12.dp)) - } else { - LazyColumn(contentPadding = PaddingValues(12.dp)) { - items( - count = searchResults.size, - key = { index -> searchResults[index].id }, - itemContent = { index -> - val searchCoin = searchResults[index] - - val cardShape = when { - searchResults.size == 1 -> MaterialTheme.shapes.medium - - index == 0 -> MaterialTheme.shapes.medium.copy( - bottomStart = CornerSize(0.dp), - bottomEnd = CornerSize(0.dp) - ) + when { + searchQuery.isEmpty() -> { + SearchQueryEmptyState() + } - index == searchResults.lastIndex -> - MaterialTheme.shapes.medium.copy( - topStart = CornerSize(0.dp), - topEnd = CornerSize(0.dp) + queryHasNoResults -> { + SearchResultsEmptyState() + } + + else -> { + LazyColumn( + contentPadding = PaddingValues(12.dp), + modifier = modifier + ) { + items( + count = searchResults.size, + key = { index -> searchResults[index].id }, + itemContent = { index -> + val searchCoin = searchResults[index] + + val cardShape = when { + searchResults.size == 1 -> MaterialTheme.shapes.medium + + index == 0 -> MaterialTheme.shapes.medium.copy( + bottomStart = CornerSize(0.dp), + bottomEnd = CornerSize(0.dp) ) - else -> RoundedCornerShape(0.dp) - } + index == searchResults.lastIndex -> + MaterialTheme.shapes.medium.copy( + topStart = CornerSize(0.dp), + topEnd = CornerSize(0.dp) + ) - SearchListItem( - searchCoin = searchCoin, - onCoinClick = onCoinClick, - cardShape = cardShape - ) - } - ) + else -> RoundedCornerShape(0.dp) + } + + SearchListItem( + searchCoin = searchCoin, + onCoinClick = onCoinClick, + cardShape = cardShape + ) + } + ) + } } } } diff --git a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/component/SearchEmptyState.kt b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/component/SearchQueryEmptyState.kt similarity index 71% rename from app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/component/SearchEmptyState.kt rename to app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/component/SearchQueryEmptyState.kt index 7feb0582..9034a391 100644 --- a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/component/SearchEmptyState.kt +++ b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/component/SearchQueryEmptyState.kt @@ -1,5 +1,6 @@ package dev.shorthouse.coinwatch.ui.screen.search.component +import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -7,14 +8,15 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import dev.shorthouse.coinwatch.R import dev.shorthouse.coinwatch.ui.component.EmptyState import dev.shorthouse.coinwatch.ui.theme.AppTheme @Composable -fun SearchEmptyState(modifier: Modifier = Modifier) { +fun SearchQueryEmptyState(modifier: Modifier = Modifier) { EmptyState( - image = painterResource(R.drawable.empty_state_search), + image = painterResource(R.drawable.empty_state_search_query), title = stringResource(R.string.empty_state_search_title), subtitle = { Text( @@ -23,14 +25,14 @@ fun SearchEmptyState(modifier: Modifier = Modifier) { color = MaterialTheme.colorScheme.onSurfaceVariant ) }, - modifier = modifier + modifier = modifier.padding(bottom = 12.dp) ) } @Composable -@Preview -private fun SearchEmptyStatePreview() { +@Preview(heightDp = 400) +private fun SearchQueryEmptyStatePreview() { AppTheme { - SearchEmptyState() + SearchQueryEmptyState() } } diff --git a/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/component/SearchResultsEmptyState.kt b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/component/SearchResultsEmptyState.kt new file mode 100644 index 00000000..539bec06 --- /dev/null +++ b/app/src/main/java/dev/shorthouse/coinwatch/ui/screen/search/component/SearchResultsEmptyState.kt @@ -0,0 +1,39 @@ +package dev.shorthouse.coinwatch.ui.screen.search.component + +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import dev.shorthouse.coinwatch.R +import dev.shorthouse.coinwatch.ui.component.EmptyState +import dev.shorthouse.coinwatch.ui.theme.AppTheme + + +@Composable +fun SearchResultsEmptyState(modifier: Modifier = Modifier) { + EmptyState( + image = painterResource(R.drawable.empty_state_search_results), + title = stringResource(R.string.empty_state_search_results_title), + subtitle = { + Text( + text = stringResource(R.string.empty_state_search_results_subtitle), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + }, + modifier = modifier.padding(bottom = 12.dp) + ) +} + +@Composable +@Preview(heightDp = 400) +private fun SearchResultsEmptyStatePreview() { + AppTheme { + SearchResultsEmptyState() + } +} diff --git a/app/src/main/res/drawable/empty_state_coins.xml b/app/src/main/res/drawable/empty_state_coins.xml index 50a9e523..473c12f3 100644 --- a/app/src/main/res/drawable/empty_state_coins.xml +++ b/app/src/main/res/drawable/empty_state_coins.xml @@ -1,114 +1,67 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:width="797.5dp" + android:height="834.5dp" + android:viewportWidth="797.5" + android:viewportHeight="834.5"> + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/empty_state_favourite_coins.xml b/app/src/main/res/drawable/empty_state_favourite_coins.xml deleted file mode 100644 index 28958d32..00000000 --- a/app/src/main/res/drawable/empty_state_favourite_coins.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/empty_state_favourites.xml b/app/src/main/res/drawable/empty_state_favourites.xml new file mode 100644 index 00000000..8e9a863e --- /dev/null +++ b/app/src/main/res/drawable/empty_state_favourites.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/empty_state_search.xml b/app/src/main/res/drawable/empty_state_search.xml deleted file mode 100644 index 9844c3c1..00000000 --- a/app/src/main/res/drawable/empty_state_search.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/empty_state_search_query.xml b/app/src/main/res/drawable/empty_state_search_query.xml new file mode 100644 index 00000000..effd9891 --- /dev/null +++ b/app/src/main/res/drawable/empty_state_search_query.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/empty_state_search_results.xml b/app/src/main/res/drawable/empty_state_search_results.xml new file mode 100644 index 00000000..5443fc00 --- /dev/null +++ b/app/src/main/res/drawable/empty_state_search_results.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/error_state.xml b/app/src/main/res/drawable/error_state.xml index c3e04db8..124a8ccb 100644 --- a/app/src/main/res/drawable/error_state.xml +++ b/app/src/main/res/drawable/error_state.xml @@ -1,57 +1,57 @@ - - - - - - - - - - - - - - - - - + android:width="524.67dp" + android:height="418.27dp" + android:viewportWidth="524.67" + android:viewportHeight="418.27"> + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 736d12e2..f3322fc5 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,9 +3,11 @@ #152241 #152241 #223260 + #384670 #6F6C88 #3F3d56 #FFFFFF + #000000 #F2F2F2 #97636b #FFB6B6 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 113d910c..50311ce9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -31,13 +31,13 @@ No favourite coins Tap the to favourite a coin - No coins - Please try again later + Couldn\'t load coins + Check your internet connection An error has occurred Clear search Search coins - No coins found - Try adjusting your search + No coins found + Try adjusting your search No chart data available No chart range data available No chart data @@ -71,7 +71,7 @@ More Settings Start screen - Made with ❤️️ by Short Labs + Made for you by Short Labs CoinWatch version Source code Privacy policy @@ -90,4 +90,7 @@ Expand favourites list Condense favourites list Currency + Explore coins + Search by name or symbol + App start screen