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 {
namespace = "com.sadellie.unitto.feature.calculator"
testOptions.unitTests.isIncludeAndroidResources = true
}
dependencies {
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: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.LocalFocusManager
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.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
@ -84,30 +86,57 @@ internal fun CalculatorRoute(
navigateToSettings: () -> Unit,
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) {
is CalculatorUIState.Loading -> Loading(
navigateToMenu = navigateToMenu,
navigateToSettings = navigateToSettings,
)
is CalculatorUIState.Ready -> CalculatorScreen(
is CalculatorUIState.Ready -> Ready(
uiState = uiState,
navigateToMenu = navigateToMenu,
navigateToSettings = navigateToSettings,
addSymbol = viewModel::addTokens,
clearSymbols = viewModel::clearInput,
deleteSymbol = viewModel::deleteTokens,
onCursorChange = viewModel::onCursorChange,
toggleAngleMode = viewModel::toggleCalculatorMode,
evaluate = viewModel::evaluate,
clearHistory = viewModel::clearHistory
addSymbol = addTokens,
clearSymbols = clearInput,
deleteSymbol = deleteTokens,
onCursorChange = onCursorChange,
toggleAngleMode = toggleCalculatorMode,
evaluate = evaluate,
clearHistory = clearHistory
)
}
}
@Composable
private fun CalculatorScreen(
private fun Ready(
uiState: CalculatorUIState.Ready,
navigateToMenu: () -> Unit,
navigateToSettings: () -> Unit,
@ -137,7 +166,8 @@ private fun CalculatorScreen(
Icons.Default.Delete,
stringResource(R.string.calculator_clear_history_title)
)
}
},
modifier = Modifier.semantics { testTag = "historyButton" }
)
} else {
SettingsButton(navigateToSettings)
@ -202,7 +232,8 @@ private fun CalculatorScreen(
// Input
Column(
Modifier
modifier = Modifier
.semantics { testTag = "inputBox" }
.offset(y = dragDp)
.height(textBoxHeight)
.background(
@ -286,6 +317,7 @@ private fun CalculatorScreen(
// Keyboard
CalculatorKeyboard(
modifier = Modifier
.semantics { testTag = "ready" }
.offset(y = dragDp + textBoxHeight)
.height(keyboardHeight)
.fillMaxWidth()
@ -337,7 +369,7 @@ private fun CalculatorScreen(
}
@Composable
private fun Loading(
internal fun Loading(
navigateToMenu: () -> Unit,
navigateToSettings: () -> Unit,
) {
@ -401,6 +433,7 @@ private fun Loading(
// Keyboard
CalculatorKeyboardLoading(
modifier = Modifier
.semantics { testTag = "loading" }
.offset(y = maxHeight * 0.25f)
.height(maxHeight * 0.75f)
.fillMaxWidth()
@ -446,11 +479,11 @@ private fun PreviewCalculatorScreen() {
),
navigateToMenu = {},
navigateToSettings = {},
addSymbol = {},
clearSymbols = {},
deleteSymbol = {},
addTokens = {},
clearInput = {},
deleteTokens = {},
onCursorChange = {},
toggleAngleMode = {},
toggleCalculatorMode = {},
evaluate = {},
clearHistory = {}
)