Refactor CalculatorScreen

This commit is contained in:
Sad Ellie 2023-09-19 15:28:01 +03:00
parent 8fee9d065d
commit b04e95e56e
3 changed files with 155 additions and 17 deletions

View File

@ -25,10 +25,14 @@ plugins {
android { android {
namespace = "com.sadellie.unitto.feature.calculator" namespace = "com.sadellie.unitto.feature.calculator"
testOptions.unitTests.isIncludeAndroidResources = true
} }
dependencies { dependencies {
testImplementation(libs.junit) testImplementation(libs.junit)
testImplementation(libs.org.robolectric)
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
debugImplementation(libs.androidx.compose.ui.test.manifest)
implementation(project(":data:common")) implementation(project(":data:common"))
implementation(project(":data:userprefs")) implementation(project(":data:userprefs"))

View File

@ -0,0 +1,101 @@
/*
* Unitto is a unit converter for Android
* Copyright (c) 2023 Elshan Agaev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.feature.calculator
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeDown
import com.sadellie.unitto.core.base.R
import org.junit.Rule
import org.junit.Test
class CalculatorScreenTest {
@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
@Test
fun loading_showLoadingKeyboard(): Unit = with(composeTestRule) {
setContent {
CalculatorScreen(
uiState = CalculatorUIState.Loading,
navigateToMenu = {},
navigateToSettings = {},
addTokens = {},
clearInput = {},
deleteTokens = {},
onCursorChange = {},
toggleCalculatorMode = {},
evaluate = {},
clearHistory = {}
)
}
onNodeWithTag("loading").assertExists()
}
@Test
fun ready_showRealKeyboard(): Unit = with(composeTestRule) {
setContent {
CalculatorScreen(
uiState = CalculatorUIState.Ready(),
navigateToMenu = {},
navigateToSettings = {},
addTokens = {},
clearInput = {},
deleteTokens = {},
onCursorChange = {},
toggleCalculatorMode = {},
evaluate = {},
clearHistory = {}
)
}
onNodeWithTag("loading").assertDoesNotExist()
onNodeWithTag("ready").assertExists()
}
@Test
fun ready_swipeForHistory(): Unit = with(composeTestRule) {
setContent {
CalculatorScreen(
uiState = CalculatorUIState.Ready(),
navigateToMenu = {},
navigateToSettings = {},
addTokens = {},
clearInput = {},
deleteTokens = {},
onCursorChange = {},
toggleCalculatorMode = {},
evaluate = {},
clearHistory = {}
)
}
onNodeWithTag("inputBox")
.performTouchInput { swipeDown() }
onNodeWithTag("historyButton")
.performClick()
onNodeWithText(composeTestRule.activity.getString(R.string.calculator_clear_history_support))
.assertExists()
}
}

View File

@ -58,6 +58,8 @@ import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@ -84,30 +86,57 @@ internal fun CalculatorRoute(
navigateToSettings: () -> Unit, navigateToSettings: () -> Unit,
viewModel: CalculatorViewModel = hiltViewModel() viewModel: CalculatorViewModel = hiltViewModel()
) { ) {
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value val uiState = viewModel.uiState.collectAsStateWithLifecycle()
CalculatorScreen(
uiState = uiState.value,
navigateToMenu = navigateToMenu,
navigateToSettings = navigateToSettings,
addTokens = viewModel::addTokens,
clearInput = viewModel::clearInput,
deleteTokens = viewModel::deleteTokens,
onCursorChange = viewModel::onCursorChange,
toggleCalculatorMode = viewModel::toggleCalculatorMode,
evaluate = viewModel::evaluate,
clearHistory = viewModel::clearHistory
)
}
@Composable
internal fun CalculatorScreen(
uiState: CalculatorUIState,
navigateToMenu: () -> Unit,
navigateToSettings: () -> Unit,
addTokens: (String) -> Unit,
clearInput: () -> Unit,
deleteTokens: () -> Unit,
onCursorChange: (TextRange) -> Unit,
toggleCalculatorMode: () -> Unit,
evaluate: () -> Unit,
clearHistory: () -> Unit
) {
when (uiState) { when (uiState) {
is CalculatorUIState.Loading -> Loading( is CalculatorUIState.Loading -> Loading(
navigateToMenu = navigateToMenu, navigateToMenu = navigateToMenu,
navigateToSettings = navigateToSettings, navigateToSettings = navigateToSettings,
) )
is CalculatorUIState.Ready -> CalculatorScreen( is CalculatorUIState.Ready -> Ready(
uiState = uiState, uiState = uiState,
navigateToMenu = navigateToMenu, navigateToMenu = navigateToMenu,
navigateToSettings = navigateToSettings, navigateToSettings = navigateToSettings,
addSymbol = viewModel::addTokens, addSymbol = addTokens,
clearSymbols = viewModel::clearInput, clearSymbols = clearInput,
deleteSymbol = viewModel::deleteTokens, deleteSymbol = deleteTokens,
onCursorChange = viewModel::onCursorChange, onCursorChange = onCursorChange,
toggleAngleMode = viewModel::toggleCalculatorMode, toggleAngleMode = toggleCalculatorMode,
evaluate = viewModel::evaluate, evaluate = evaluate,
clearHistory = viewModel::clearHistory clearHistory = clearHistory
) )
} }
} }
@Composable @Composable
private fun CalculatorScreen( private fun Ready(
uiState: CalculatorUIState.Ready, uiState: CalculatorUIState.Ready,
navigateToMenu: () -> Unit, navigateToMenu: () -> Unit,
navigateToSettings: () -> Unit, navigateToSettings: () -> Unit,
@ -137,7 +166,8 @@ private fun CalculatorScreen(
Icons.Default.Delete, Icons.Default.Delete,
stringResource(R.string.calculator_clear_history_title) stringResource(R.string.calculator_clear_history_title)
) )
} },
modifier = Modifier.semantics { testTag = "historyButton" }
) )
} else { } else {
SettingsButton(navigateToSettings) SettingsButton(navigateToSettings)
@ -202,7 +232,8 @@ private fun CalculatorScreen(
// Input // Input
Column( Column(
Modifier modifier = Modifier
.semantics { testTag = "inputBox" }
.offset(y = dragDp) .offset(y = dragDp)
.height(textBoxHeight) .height(textBoxHeight)
.background( .background(
@ -286,6 +317,7 @@ private fun CalculatorScreen(
// Keyboard // Keyboard
CalculatorKeyboard( CalculatorKeyboard(
modifier = Modifier modifier = Modifier
.semantics { testTag = "ready" }
.offset(y = dragDp + textBoxHeight) .offset(y = dragDp + textBoxHeight)
.height(keyboardHeight) .height(keyboardHeight)
.fillMaxWidth() .fillMaxWidth()
@ -337,7 +369,7 @@ private fun CalculatorScreen(
} }
@Composable @Composable
private fun Loading( internal fun Loading(
navigateToMenu: () -> Unit, navigateToMenu: () -> Unit,
navigateToSettings: () -> Unit, navigateToSettings: () -> Unit,
) { ) {
@ -401,6 +433,7 @@ private fun Loading(
// Keyboard // Keyboard
CalculatorKeyboardLoading( CalculatorKeyboardLoading(
modifier = Modifier modifier = Modifier
.semantics { testTag = "loading" }
.offset(y = maxHeight * 0.25f) .offset(y = maxHeight * 0.25f)
.height(maxHeight * 0.75f) .height(maxHeight * 0.75f)
.fillMaxWidth() .fillMaxWidth()
@ -446,11 +479,11 @@ private fun PreviewCalculatorScreen() {
), ),
navigateToMenu = {}, navigateToMenu = {},
navigateToSettings = {}, navigateToSettings = {},
addSymbol = {}, addTokens = {},
clearSymbols = {}, clearInput = {},
deleteSymbol = {}, deleteTokens = {},
onCursorChange = {}, onCursorChange = {},
toggleAngleMode = {}, toggleCalculatorMode = {},
evaluate = {}, evaluate = {},
clearHistory = {} clearHistory = {}
) )