Landscape mode support for calculator

This commit is contained in:
Sad Ellie 2023-02-26 18:58:23 +04:00
parent 6fb4c712ff
commit cb878fb171
4 changed files with 146 additions and 38 deletions

View File

@ -26,10 +26,11 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.minimumInteractiveComponentSize
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -46,7 +47,6 @@ fun BasicKeyboardButton(
onClick: () -> Unit, onClick: () -> Unit,
onLongClick: (() -> Unit)?, onLongClick: (() -> Unit)?,
containerColor: Color, containerColor: Color,
contentColor: Color,
icon: ImageVector, icon: ImageVector,
iconColor: Color, iconColor: Color,
allowVibration: Boolean allowVibration: Boolean
@ -65,7 +65,6 @@ fun BasicKeyboardButton(
onLongClick = onLongClick, onLongClick = onLongClick,
shape = RoundedCornerShape(cornerRadius), shape = RoundedCornerShape(cornerRadius),
containerColor = containerColor, containerColor = containerColor,
contentColor = contentColor,
contentPadding = PaddingValues(24.dp, 8.dp), contentPadding = PaddingValues(24.dp, 8.dp),
interactionSource = interactionSource interactionSource = interactionSource
) { ) {
@ -90,7 +89,6 @@ fun KeyboardButtonLight(
onClick = onClick, onClick = onClick,
onLongClick = onLongClick, onLongClick = onLongClick,
containerColor = MaterialTheme.colorScheme.inverseOnSurface, containerColor = MaterialTheme.colorScheme.inverseOnSurface,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
icon = icon, icon = icon,
iconColor = MaterialTheme.colorScheme.onSurfaceVariant, iconColor = MaterialTheme.colorScheme.onSurfaceVariant,
allowVibration = allowVibration, allowVibration = allowVibration,
@ -110,7 +108,6 @@ fun KeyboardButtonFilled(
onClick = onClick, onClick = onClick,
onLongClick = onLongClick, onLongClick = onLongClick,
containerColor = MaterialTheme.colorScheme.primaryContainer, containerColor = MaterialTheme.colorScheme.primaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
icon = icon, icon = icon,
iconColor = MaterialTheme.colorScheme.onSecondaryContainer, iconColor = MaterialTheme.colorScheme.onSecondaryContainer,
allowVibration = allowVibration allowVibration = allowVibration
@ -123,15 +120,19 @@ fun KeyboardButtonAdditional(
icon: ImageVector, icon: ImageVector,
onClick: () -> Unit onClick: () -> Unit
) { ) {
IconButton( UnittoButton(
onClick = onClick,
modifier = modifier modifier = modifier
.minimumInteractiveComponentSize()
.heightIn(max = 48.dp),
onClick = onClick,
containerColor = Color.Transparent,
contentPadding = PaddingValues(12.dp, 2.dp)
) { ) {
Icon( Icon(
imageVector = icon, imageVector = icon,
contentDescription = null, contentDescription = null,
modifier = Modifier.fillMaxHeight(), modifier = Modifier.fillMaxHeight(),
tint = MaterialTheme.colorScheme.onSecondaryContainer tint = MaterialTheme.colorScheme.onSurfaceVariant
) )
} }
} }

View File

@ -27,14 +27,17 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ripple.rememberRipple import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -44,15 +47,15 @@ import androidx.compose.ui.semantics.Role
@Composable @Composable
fun UnittoButton( fun UnittoButton(
onClick: () -> Unit,
onLongClick: (() -> Unit)?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
shape: Shape, onClick: () -> Unit,
onLongClick: (() -> Unit)? = null,
shape: Shape = RoundedCornerShape(100),
containerColor: Color, containerColor: Color,
contentColor: Color, contentColor: Color = contentColorFor(containerColor),
border: BorderStroke? = null, border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding, contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit content: @Composable RowScope.() -> Unit
) { ) {
Surface( Surface(

View File

@ -18,6 +18,7 @@
package com.sadellie.unitto.feature.calculator package com.sadellie.unitto.feature.calculator
import android.content.res.Configuration
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Animatable
import androidx.compose.animation.rememberSplineBasedDecay import androidx.compose.animation.rememberSplineBasedDecay
@ -56,6 +57,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onPlaced import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalTextToolbar import androidx.compose.ui.platform.LocalTextToolbar
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -233,27 +235,29 @@ private fun CalculatorScreen(
pasteCallback = addSymbol, pasteCallback = addSymbol,
cutCallback = deleteSymbol cutCallback = deleteSymbol
) )
SelectionContainer { if (LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT) {
Text( SelectionContainer {
modifier = Modifier Text(
.fillMaxWidth() modifier = Modifier
.padding(horizontal = 8.dp), .fillMaxWidth()
text = Formatter.format(uiState.output), .padding(horizontal = 8.dp),
textAlign = TextAlign.End, text = Formatter.format(uiState.output),
softWrap = false, textAlign = TextAlign.End,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f), softWrap = false,
style = NumbersTextStyleDisplayMedium, color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
) style = NumbersTextStyleDisplayMedium,
)
}
} }
// Handle // Handle
Box( Box(
Modifier Modifier
.padding(16.dp) .padding(8.dp)
.background( .background(
MaterialTheme.colorScheme.onSurfaceVariant, MaterialTheme.colorScheme.onSurfaceVariant,
RoundedCornerShape(100) RoundedCornerShape(100)
) )
.sizeIn(36.dp, 4.dp) .sizeIn(24.dp, 4.dp)
) )
} }
}, },

View File

@ -18,6 +18,7 @@
package com.sadellie.unitto.feature.calculator.components package com.sadellie.unitto.feature.calculator.components
import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
@ -26,6 +27,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandLess
@ -33,6 +35,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.minimumInteractiveComponentSize
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -40,6 +43,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.base.KEY_0 import com.sadellie.unitto.core.base.KEY_0
@ -119,6 +123,39 @@ internal fun CalculatorKeyboard(
toggleAngleMode: () -> Unit, toggleAngleMode: () -> Unit,
angleMode: AngleMode, angleMode: AngleMode,
evaluate: () -> Unit evaluate: () -> Unit
) {
if (LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT) {
PortraitKeyboard(
modifier = modifier,
addSymbol = addSymbol,
angleMode = angleMode,
toggleAngleMode = toggleAngleMode,
deleteSymbol = deleteSymbol,
clearSymbols = clearSymbols,
evaluate = evaluate
)
} else {
LandscapeKeyboard(
modifier = modifier,
addSymbol = addSymbol,
angleMode = angleMode,
toggleAngleMode = toggleAngleMode,
deleteSymbol = deleteSymbol,
clearSymbols = clearSymbols,
evaluate = evaluate
)
}
}
@Composable
private fun PortraitKeyboard(
modifier: Modifier,
addSymbol: (String) -> Unit,
angleMode: AngleMode,
toggleAngleMode: () -> Unit,
deleteSymbol: () -> Unit,
clearSymbols: () -> Unit,
evaluate: () -> Unit
) { ) {
var showAdditional: Boolean by remember { mutableStateOf(false) } var showAdditional: Boolean by remember { mutableStateOf(false) }
val expandRotation: Float by animateFloatAsState( val expandRotation: Float by animateFloatAsState(
@ -134,6 +171,10 @@ internal fun CalculatorKeyboard(
.fillMaxSize() .fillMaxSize()
.weight(1f) .weight(1f)
.padding(4.dp) .padding(4.dp)
val additionalButtonModifier = Modifier
.minimumInteractiveComponentSize()
.weight(1f)
.heightIn(max = 48.dp)
Row( Row(
modifier = Modifier.padding(vertical = 8.dp), modifier = Modifier.padding(vertical = 8.dp),
@ -142,24 +183,24 @@ internal fun CalculatorKeyboard(
// Additional buttons // Additional buttons
Column(modifier = weightModifier) { Column(modifier = weightModifier) {
Row(Modifier, horizontalArrangement = Arrangement.spacedBy(2.dp)) { Row(Modifier, horizontalArrangement = Arrangement.spacedBy(2.dp)) {
KeyboardButtonAdditional(weightModifier, UnittoIcons.SquareRoot) { addSymbol(KEY_SQRT) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.SquareRoot) { addSymbol(KEY_SQRT) }
KeyboardButtonAdditional(weightModifier, UnittoIcons.Pi) { addSymbol(KEY_PI) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.Pi) { addSymbol(KEY_PI) }
KeyboardButtonAdditional(weightModifier, UnittoIcons.Exponent) { addSymbol(KEY_EXPONENT) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.Exponent) { addSymbol(KEY_EXPONENT) }
KeyboardButtonAdditional(weightModifier, UnittoIcons.Factorial) { addSymbol(KEY_FACTORIAL) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.Factorial) { addSymbol(KEY_FACTORIAL) }
} }
AnimatedVisibility(visible = showAdditional) { AnimatedVisibility(visible = showAdditional) {
Column { Column {
Row(Modifier, horizontalArrangement = Arrangement.spacedBy(2.dp)) { Row(Modifier, horizontalArrangement = Arrangement.spacedBy(2.dp)) {
KeyboardButtonAdditional(weightModifier, if (angleMode == AngleMode.DEG) UnittoIcons.Deg else UnittoIcons.Rad) { toggleAngleMode() } KeyboardButtonAdditional(additionalButtonModifier, if (angleMode == AngleMode.DEG) UnittoIcons.Deg else UnittoIcons.Rad) { toggleAngleMode() }
KeyboardButtonAdditional(weightModifier, UnittoIcons.Sin) { addSymbol(KEY_SIN) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.Sin) { addSymbol(KEY_SIN) }
KeyboardButtonAdditional(weightModifier, UnittoIcons.Cos) { addSymbol(KEY_COS) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.Cos) { addSymbol(KEY_COS) }
KeyboardButtonAdditional(weightModifier, UnittoIcons.Tan) { addSymbol(KEY_TAN) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.Tan) { addSymbol(KEY_TAN) }
} }
Row(Modifier, horizontalArrangement = Arrangement.spacedBy(2.dp)) { Row(Modifier, horizontalArrangement = Arrangement.spacedBy(2.dp)) {
KeyboardButtonAdditional(weightModifier, UnittoIcons.Modulo) { addSymbol(KEY_MODULO) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.Modulo) { addSymbol(KEY_MODULO) }
KeyboardButtonAdditional(weightModifier, UnittoIcons.E) { addSymbol(KEY_E_SMALL) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.E) { addSymbol(KEY_E_SMALL) }
KeyboardButtonAdditional(weightModifier, UnittoIcons.Ln) { addSymbol(KEY_LN) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.Ln) { addSymbol(KEY_LN) }
KeyboardButtonAdditional(weightModifier, UnittoIcons.Log) { addSymbol(KEY_LOG) } KeyboardButtonAdditional(additionalButtonModifier, UnittoIcons.Log) { addSymbol(KEY_LOG) }
} }
} }
} }
@ -207,6 +248,65 @@ internal fun CalculatorKeyboard(
} }
} }
@Composable
private fun LandscapeKeyboard(
modifier: Modifier,
addSymbol: (String) -> Unit,
angleMode: AngleMode,
toggleAngleMode: () -> Unit,
deleteSymbol: () -> Unit,
clearSymbols: () -> Unit,
evaluate: () -> Unit
) {
Column(modifier = modifier) {
val buttonModifier = Modifier.weight(1f).padding(2.dp)
Row(Modifier.weight(1f)) {
KeyboardButtonAdditional(buttonModifier, if (angleMode == AngleMode.DEG) UnittoIcons.Deg else UnittoIcons.Rad) { toggleAngleMode() }
KeyboardButtonAdditional(buttonModifier, UnittoIcons.SquareRoot) { addSymbol(KEY_SQRT) }
KeyboardButtonAdditional(buttonModifier, UnittoIcons.Pi) { addSymbol(KEY_PI) }
KeyboardButtonLight(buttonModifier, UnittoIcons.Key7, { addSymbol(KEY_7) })
KeyboardButtonLight(buttonModifier, UnittoIcons.Key8, { addSymbol(KEY_8) })
KeyboardButtonLight(buttonModifier, UnittoIcons.Key9, { addSymbol(KEY_9) })
KeyboardButtonFilled(buttonModifier, UnittoIcons.LeftBracket, { addSymbol(KEY_LEFT_BRACKET) })
KeyboardButtonFilled(buttonModifier, UnittoIcons.RightBracket, { addSymbol(KEY_RIGHT_BRACKET) })
}
Row(Modifier.weight(1f)) {
KeyboardButtonAdditional(buttonModifier, UnittoIcons.Modulo) { addSymbol(KEY_MODULO) }
KeyboardButtonAdditional(buttonModifier, UnittoIcons.Exponent) { addSymbol(KEY_EXPONENT) }
KeyboardButtonAdditional(buttonModifier, UnittoIcons.Factorial) { addSymbol(KEY_FACTORIAL) }
KeyboardButtonLight(buttonModifier, UnittoIcons.Key4, { addSymbol(KEY_4) })
KeyboardButtonLight(buttonModifier, UnittoIcons.Key5, { addSymbol(KEY_5) })
KeyboardButtonLight(buttonModifier, UnittoIcons.Key6, { addSymbol(KEY_6) })
KeyboardButtonFilled(buttonModifier, UnittoIcons.Multiply, { addSymbol(KEY_MULTIPLY_DISPLAY) })
KeyboardButtonFilled(buttonModifier, UnittoIcons.Divide, { addSymbol(KEY_DIVIDE_DISPLAY) })
}
Row(Modifier.weight(1f)) {
KeyboardButtonAdditional(buttonModifier, UnittoIcons.Sin) { addSymbol(KEY_SIN) }
KeyboardButtonAdditional(buttonModifier, UnittoIcons.Cos) { addSymbol(KEY_COS) }
KeyboardButtonAdditional(buttonModifier, UnittoIcons.Tan) { addSymbol(KEY_TAN) }
KeyboardButtonLight(buttonModifier, UnittoIcons.Key1, { addSymbol(KEY_1) })
KeyboardButtonLight(buttonModifier, UnittoIcons.Key2, { addSymbol(KEY_2) })
KeyboardButtonLight(buttonModifier, UnittoIcons.Key3, { addSymbol(KEY_3) })
KeyboardButtonFilled(buttonModifier, UnittoIcons.Minus, { addSymbol(KEY_MINUS_DISPLAY) })
KeyboardButtonFilled(buttonModifier, UnittoIcons.Percent, { addSymbol(KEY_PERCENT) })
}
Row(Modifier.weight(1f)) {
KeyboardButtonAdditional(buttonModifier, UnittoIcons.E) { addSymbol(KEY_E_SMALL) }
KeyboardButtonAdditional(buttonModifier, UnittoIcons.Ln) { addSymbol(KEY_LN) }
KeyboardButtonAdditional(buttonModifier, UnittoIcons.Log) { addSymbol(KEY_LOG) }
KeyboardButtonLight(buttonModifier, UnittoIcons.Key0, { addSymbol(KEY_0) })
KeyboardButtonLight(buttonModifier, UnittoIcons.Dot, { addSymbol(KEY_DOT) })
KeyboardButtonLight(buttonModifier, UnittoIcons.Delete, { deleteSymbol() }, onLongClick = clearSymbols)
KeyboardButtonFilled(buttonModifier, UnittoIcons.Plus, { addSymbol(KEY_PLUS) })
KeyboardButtonFilled(buttonModifier, UnittoIcons.Equal, { evaluate() })
}
}
}
@Preview @Preview
@Composable @Composable
private fun PreviewCalculatorKeyboard() { private fun PreviewCalculatorKeyboard() {