diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorScreen.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorScreen.kt index 5930c9d6..4fcc1ba9 100644 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorScreen.kt +++ b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorScreen.kt @@ -70,6 +70,7 @@ import com.sadellie.unitto.core.ui.common.textfield.ExpressionTextField import com.sadellie.unitto.core.ui.common.textfield.UnformattedTextField import com.sadellie.unitto.data.model.HistoryItem import com.sadellie.unitto.feature.calculator.components.CalculatorKeyboard +import com.sadellie.unitto.feature.calculator.components.CalculatorKeyboardLoading import com.sadellie.unitto.feature.calculator.components.HistoryList import java.text.SimpleDateFormat import java.util.Locale @@ -80,25 +81,31 @@ internal fun CalculatorRoute( navigateToSettings: () -> Unit, viewModel: CalculatorViewModel = hiltViewModel() ) { - val uiState = viewModel.uiState.collectAsStateWithLifecycle() + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value - CalculatorScreen( - uiState = uiState.value, - 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 - ) + when (uiState) { + is CalculatorUIState.Loading -> Loading( + navigateToMenu = navigateToMenu, + navigateToSettings = navigateToSettings, + ) + is CalculatorUIState.Ready -> CalculatorScreen( + 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 + ) + } } @Composable private fun CalculatorScreen( - uiState: CalculatorUIState, + uiState: CalculatorUIState.Ready, navigateToMenu: () -> Unit, navigateToSettings: () -> Unit, addSymbol: (String) -> Unit, @@ -317,6 +324,80 @@ private fun CalculatorScreen( } } +@Composable +private fun Loading( + navigateToMenu: () -> Unit, + navigateToSettings: () -> Unit, +) { + UnittoScreenWithTopBar( + title = { Text(stringResource(R.string.calculator)) }, + navigationIcon = { MenuButton { navigateToMenu() } }, + colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceVariant), + actions = { SettingsButton(navigateToSettings) } + ) { paddingValues -> + BoxWithConstraints( + modifier = Modifier.padding(paddingValues), + ) { + // Input + Column( + Modifier + .height(maxHeight * 0.25f) + .background( + MaterialTheme.colorScheme.surfaceVariant, + RoundedCornerShape( + topStartPercent = 0, topEndPercent = 0, + bottomStartPercent = 20, bottomEndPercent = 20 + ) + ) + .padding(top = 12.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + UnformattedTextField( + modifier = Modifier + .weight(2f) + .fillMaxWidth() + .padding(horizontal = 8.dp), + value = TextFieldValue(), + minRatio = 0.5f, + onCursorChange = {}, + ) + if (LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT) { + UnformattedTextField( + modifier = Modifier + .weight(1f) + .fillMaxWidth() + .padding(horizontal = 8.dp), + value = TextFieldValue(), + minRatio = 1f, + onCursorChange = {}, + readOnly = true, + ) + } + // Handle + Box( + Modifier + .padding(8.dp) + .background( + MaterialTheme.colorScheme.onSurfaceVariant, + RoundedCornerShape(100) + ) + .sizeIn(24.dp, 4.dp) + ) + } + + // Keyboard + CalculatorKeyboardLoading( + modifier = Modifier + .offset(y = maxHeight * 0.25f) + .height(maxHeight * 0.75f) + .fillMaxWidth() + .padding(horizontal = 8.dp, vertical = 4.dp), + ) + } + } +} + @Preview(widthDp = 432, heightDp = 1008, device = "spec:parent=pixel_5,orientation=portrait") @Preview(widthDp = 432, heightDp = 864, device = "spec:parent=pixel_5,orientation=portrait") @Preview(widthDp = 597, heightDp = 1393, device = "spec:parent=pixel_5,orientation=portrait") @@ -346,7 +427,7 @@ private fun PreviewCalculatorScreen() { } CalculatorScreen( - uiState = CalculatorUIState( + uiState = CalculatorUIState.Ready( input = TextFieldValue("1.2345"), output = CalculationResult.Default("1234"), history = historyItems diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorUIState.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorUIState.kt index 11f2f056..51a3e4ba 100644 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorUIState.kt +++ b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorUIState.kt @@ -24,15 +24,19 @@ import com.sadellie.unitto.core.base.R import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols import com.sadellie.unitto.data.model.HistoryItem -data class CalculatorUIState( - val input: TextFieldValue = TextFieldValue(), - val output: CalculationResult = CalculationResult.Default(), - val radianMode: Boolean = true, - val history: List = emptyList(), - val allowVibration: Boolean = false, - val formatterSymbols: FormatterSymbols = FormatterSymbols.Spaces, - val middleZero: Boolean = false, -) +internal sealed class CalculatorUIState { + data object Loading : CalculatorUIState() + + data class Ready( + val input: TextFieldValue = TextFieldValue(), + val output: CalculationResult = CalculationResult.Default(), + val radianMode: Boolean = true, + val history: List = emptyList(), + val allowVibration: Boolean = false, + val formatterSymbols: FormatterSymbols = FormatterSymbols.Spaces, + val middleZero: Boolean = false, + ) : CalculatorUIState() +} sealed class CalculationResult(@StringRes val label: Int? = null) { data class Default(val text: String = "") : CalculationResult() diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorViewModel.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorViewModel.kt index 234af7fa..c770a1a6 100644 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorViewModel.kt +++ b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/CalculatorViewModel.kt @@ -69,7 +69,7 @@ internal class CalculatorViewModel @Inject constructor( val uiState = combine( _input, _output, _history, _userPrefs ) { input, output, history, userPrefs -> - return@combine CalculatorUIState( + return@combine CalculatorUIState.Ready( input = input, output = output, radianMode = userPrefs.radianMode, @@ -79,7 +79,7 @@ internal class CalculatorViewModel @Inject constructor( middleZero = userPrefs.middleZero, ) }.stateIn( - viewModelScope, SharingStarted.WhileSubscribed(5000L), CalculatorUIState() + viewModelScope, SharingStarted.WhileSubscribed(5000L), CalculatorUIState.Loading ) fun addTokens(tokens: String) = _input.update { it.addTokens(tokens) } diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/components/CalculatorKeyboard.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/components/CalculatorKeyboard.kt index 83402bc1..fe2e2857 100644 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/components/CalculatorKeyboard.kt +++ b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/components/CalculatorKeyboard.kt @@ -24,6 +24,7 @@ import androidx.compose.animation.Crossfade import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -34,6 +35,7 @@ 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.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material3.Icon @@ -48,9 +50,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import com.sadellie.unitto.core.base.Token import com.sadellie.unitto.core.ui.common.ColumnWithConstraints import com.sadellie.unitto.core.ui.common.KeyboardButtonAdditional @@ -140,6 +144,118 @@ internal fun CalculatorKeyboard( } } +@Composable +internal fun CalculatorKeyboardLoading( + modifier: Modifier +) { + if (LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT) { + PortraitKeyboardLoading(modifier) + } else { + LandscapeKeyboardLoading(modifier) + } +} + +@Composable +private fun PortraitKeyboardLoading( + modifier: Modifier +) { + ColumnWithConstraints( + modifier = modifier + ) { constraints -> + + val additionalButtonHeight by remember { + mutableStateOf(constraints.maxHeight * 0.09f) + } + + val spacerHeight by remember { + mutableStateOf(constraints.maxHeight * 0.025f) + } + + val additionalRowSpacedBy by remember { + mutableStateOf(constraints.maxWidth * 0.03f) + } + + val weightModifier = Modifier.weight(1f) + val additionalButtonModifier = Modifier + .weight(1f) + .height(additionalButtonHeight) + + Spacer(modifier = Modifier.height(spacerHeight)) + + Row( + modifier = Modifier, + horizontalArrangement = Arrangement.spacedBy(additionalRowSpacedBy) + ) { + // Additional buttons + Box(weightModifier) { + AdditionalButtonsPortrait( + modifier = additionalButtonModifier, + allowVibration = false, + addSymbol = {}, + showAdditional = false, + radianMode = false, + toggleAngleMode = {}, + toggleInvMode = {} + ) + } + + Box( + modifier = Modifier.size(additionalButtonHeight), + contentAlignment = Alignment.Center + ) { + // Expand/Collapse + IconButton( + onClick = { }, + colors = IconButtonDefaults.iconButtonColors(containerColor = MaterialTheme.colorScheme.inverseOnSurface) + ) { + Icon(Icons.Default.ExpandLess, null) + } + } + } + + Spacer(modifier = Modifier.height(spacerHeight)) + + Box( + modifier = weightModifier + .clip(RoundedCornerShape(32.dp)) + .background(MaterialTheme.colorScheme.inverseOnSurface) + .fillMaxSize() + ) + + Spacer(modifier = Modifier.height(spacerHeight)) + } +} + +@Composable +private fun LandscapeKeyboardLoading( + modifier: Modifier +) { + RowWithConstraints(modifier) { constraints -> + val buttonModifier = Modifier + .fillMaxWidth() + .weight(1f) + .padding(constraints.maxWidth * 0.005f, constraints.maxHeight * 0.02f) + + AdditionalButtonsLandscape( + modifier = Modifier.weight(1f), + buttonModifier = buttonModifier, + allowVibration = false, + radianMode = false, + addSymbol = {}, + toggleAngleMode = {}, + toggleInvMode = {} + ) + + Box( + modifier = Modifier + .clip(RoundedCornerShape(32.dp)) + .background(MaterialTheme.colorScheme.inverseOnSurface) + .weight(5f) + .fillMaxSize() + ) + } +} + @Composable private fun PortraitKeyboard( modifier: Modifier, diff --git a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt index 58d601b0..b6e254a7 100644 --- a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt +++ b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt @@ -28,12 +28,15 @@ import androidx.compose.animation.expandHorizontally import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.SwapHoriz import androidx.compose.material3.Icon @@ -48,6 +51,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext @@ -56,6 +60,7 @@ import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.sadellie.unitto.core.base.OutputFormat @@ -72,7 +77,6 @@ import com.sadellie.unitto.core.ui.common.textfield.UnformattedTextField import com.sadellie.unitto.data.common.format import com.sadellie.unitto.data.model.unit.AbstractUnit import com.sadellie.unitto.feature.converter.components.DefaultKeyboard -import com.sadellie.unitto.feature.converter.components.LoadingKeyboard import com.sadellie.unitto.feature.converter.components.NumberBaseKeyboard import com.sadellie.unitto.feature.converter.components.UnitSelectionButton @@ -191,7 +195,12 @@ private fun ConverterLoading(modifier: Modifier) { } }, content2 = { - LoadingKeyboard(modifier = it) + Box( + modifier = it + .clip(RoundedCornerShape(32.dp)) + .background(MaterialTheme.colorScheme.inverseOnSurface) + .fillMaxSize() + ) } ) } diff --git a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/ConverterKeyboard.kt b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/ConverterKeyboard.kt index e239853c..bf43af88 100644 --- a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/ConverterKeyboard.kt +++ b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/ConverterKeyboard.kt @@ -18,19 +18,13 @@ package com.sadellie.unitto.feature.converter.components -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.unit.dp import com.sadellie.unitto.core.base.Token import com.sadellie.unitto.core.ui.common.ColumnWithConstraints import com.sadellie.unitto.core.ui.common.KeyboardButtonFilled @@ -169,15 +163,3 @@ internal fun NumberBaseKeyboard( } } } - -@Composable -internal fun LoadingKeyboard( - modifier: Modifier, -) { - Box( - modifier = modifier - .clip(RoundedCornerShape(32.dp)) - .background(MaterialTheme.colorScheme.inverseOnSurface) - .fillMaxSize() - ) -}