mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 00:35:26 +02:00
Refactor text fields for number input
- removed custom keyboard to improve accessibility
This commit is contained in:
parent
84c29682f8
commit
5141652394
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2024 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.core.ui.common.textfield
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Clear
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
|
||||
@Composable
|
||||
fun OutlinedDecimalTextField(
|
||||
modifier: Modifier,
|
||||
value: TextFieldValue,
|
||||
onValueChange: (TextFieldValue) -> Unit,
|
||||
label: @Composable () -> Unit,
|
||||
expressionFormatter: VisualTransformation,
|
||||
imeAction: ImeAction = ImeAction.Next
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = modifier,
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
trailingIcon = {
|
||||
AnimatedVisibility(value.text.isNotBlank(), enter = scaleIn(), exit = scaleOut()) {
|
||||
IconButton(onClick = { onValueChange(TextFieldValue()) }) {
|
||||
Icon(Icons.Outlined.Clear, null)
|
||||
}
|
||||
}
|
||||
},
|
||||
label = label,
|
||||
singleLine = true,
|
||||
visualTransformation = expressionFormatter,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Decimal,
|
||||
imeAction = imeAction
|
||||
),
|
||||
)
|
||||
}
|
@ -153,7 +153,6 @@ private fun BodyMassScreen(
|
||||
onValueChange = updateHeight1,
|
||||
label = "${stringResource(R.string.body_mass_height)}, ${stringResource(R.string.unit_centimeter_short)}",
|
||||
expressionFormatter = expressionTransformer,
|
||||
imeAction = ImeAction.Next
|
||||
)
|
||||
} else {
|
||||
Row(
|
||||
@ -165,7 +164,6 @@ private fun BodyMassScreen(
|
||||
onValueChange = updateHeight1,
|
||||
label = "${stringResource(R.string.body_mass_height)}, ${stringResource(R.string.unit_foot_short)}",
|
||||
expressionFormatter = expressionTransformer,
|
||||
imeAction = ImeAction.Next
|
||||
)
|
||||
BodyMassTextField(
|
||||
modifier = Modifier.weight(1f),
|
||||
@ -173,7 +171,6 @@ private fun BodyMassScreen(
|
||||
onValueChange = updateHeight2,
|
||||
label = "${stringResource(R.string.body_mass_height)}, ${stringResource(R.string.unit_inch_short)}",
|
||||
expressionFormatter = expressionTransformer,
|
||||
imeAction = ImeAction.Next
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -19,32 +19,25 @@
|
||||
package com.sadellie.unitto.feature.bodymass.components
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import com.sadellie.unitto.core.base.Token
|
||||
import com.sadellie.unitto.core.ui.common.textfield.OutlinedDecimalTextField
|
||||
|
||||
@Composable
|
||||
internal fun BodyMassTextField(
|
||||
modifier: Modifier,
|
||||
value: TextFieldValue,
|
||||
onValueChange: (TextFieldValue) -> Unit,
|
||||
label: String,
|
||||
onValueChange: (TextFieldValue) -> Unit,
|
||||
expressionFormatter: VisualTransformation,
|
||||
imeAction: ImeAction
|
||||
imeAction: ImeAction = ImeAction.Next
|
||||
) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
OutlinedTextField(
|
||||
OutlinedDecimalTextField(
|
||||
modifier = modifier,
|
||||
value = value,
|
||||
onValueChange = {
|
||||
@ -56,13 +49,7 @@ internal fun BodyMassTextField(
|
||||
onValueChange(it.copy(cleanText))
|
||||
},
|
||||
label = { AnimatedContent(label) { Text(it) } },
|
||||
singleLine = true,
|
||||
visualTransformation = expressionFormatter,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Decimal,
|
||||
imeAction = imeAction
|
||||
),
|
||||
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.End),
|
||||
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() })
|
||||
expressionFormatter = expressionFormatter,
|
||||
imeAction = imeAction
|
||||
)
|
||||
}
|
||||
|
@ -26,11 +26,9 @@ import androidx.compose.material3.PrimaryTabRow
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
@ -63,7 +61,6 @@ internal fun DateCalculatorScreen(
|
||||
val addSubtractLabel = "${stringResource(R.string.date_calculator_add)}/${stringResource(R.string.date_calculator_subtract)}"
|
||||
val differenceLabel = stringResource(R.string.date_calculator_difference)
|
||||
val focusManager = LocalFocusManager.current
|
||||
var showKeyboard by remember { mutableStateOf(false) }
|
||||
|
||||
val allTabs = remember { listOf(addSubtractLabel, differenceLabel) }
|
||||
val pagerState = rememberPagerState { allTabs.size }
|
||||
@ -99,14 +96,9 @@ internal fun DateCalculatorScreen(
|
||||
verticalAlignment = Alignment.Top
|
||||
) { page ->
|
||||
when (page) {
|
||||
0 -> AddSubtractPage(
|
||||
showKeyboard = showKeyboard,
|
||||
toggleKeyboard = {showKeyboard = it }
|
||||
)
|
||||
0 -> AddSubtractPage()
|
||||
1 -> {
|
||||
focusManager.clearFocus(true)
|
||||
showKeyboard = false
|
||||
|
||||
SideEffect { focusManager.clearFocus(true) }
|
||||
DateDifferencePage()
|
||||
}
|
||||
}
|
||||
|
@ -23,14 +23,10 @@ import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.CalendarContract
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.SizeTransform
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@ -50,25 +46,20 @@ import androidx.compose.material.icons.filled.Event
|
||||
import androidx.compose.material.icons.outlined.Add
|
||||
import androidx.compose.material.icons.outlined.Remove
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SegmentedButton
|
||||
import androidx.compose.material3.SegmentedButtonDefaults
|
||||
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
|
||||
import com.sadellie.unitto.core.ui.WindowHeightSizeClass
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.onFocusEvent
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
@ -77,12 +68,9 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.ui.LocalWindowSize
|
||||
import com.sadellie.unitto.core.ui.common.textfield.addTokens
|
||||
import com.sadellie.unitto.core.ui.common.textfield.deleteTokens
|
||||
import com.sadellie.unitto.core.ui.common.textfield.ExpressionTransformer
|
||||
import com.sadellie.unitto.core.ui.showToast
|
||||
import com.sadellie.unitto.feature.datecalculator.ZonedDateTimeUtils
|
||||
import com.sadellie.unitto.feature.datecalculator.components.AddSubtractKeyboard
|
||||
import com.sadellie.unitto.feature.datecalculator.components.DateTimeDialogs
|
||||
import com.sadellie.unitto.feature.datecalculator.components.DateTimeSelectorBlock
|
||||
import com.sadellie.unitto.feature.datecalculator.components.DialogState
|
||||
@ -92,15 +80,11 @@ import java.time.ZonedDateTime
|
||||
@Composable
|
||||
internal fun AddSubtractPage(
|
||||
viewModel: AddSubtractViewModel = hiltViewModel(),
|
||||
showKeyboard: Boolean,
|
||||
toggleKeyboard: (Boolean) -> Unit,
|
||||
) {
|
||||
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
|
||||
|
||||
AddSubtractView(
|
||||
uiState = uiState,
|
||||
showKeyboard = showKeyboard,
|
||||
toggleKeyboard = toggleKeyboard,
|
||||
updateStart = viewModel::updateStart,
|
||||
updateYears = viewModel::updateYears,
|
||||
updateMonths = viewModel::updateMonths,
|
||||
@ -115,8 +99,6 @@ internal fun AddSubtractPage(
|
||||
@Composable
|
||||
private fun AddSubtractView(
|
||||
uiState: AddSubtractState,
|
||||
showKeyboard: Boolean,
|
||||
toggleKeyboard: (Boolean) -> Unit,
|
||||
updateStart: (ZonedDateTime) -> Unit,
|
||||
updateYears: (TextFieldValue) -> Unit,
|
||||
updateMonths: (TextFieldValue) -> Unit,
|
||||
@ -126,20 +108,9 @@ private fun AddSubtractView(
|
||||
updateAddition: (Boolean) -> Unit,
|
||||
) {
|
||||
val mContext = LocalContext.current
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
var dialogState by remember { mutableStateOf(DialogState.NONE) }
|
||||
var addSymbol: ((TextFieldValue) -> Unit)? by remember { mutableStateOf(null) }
|
||||
var focusedTextFieldValue: TextFieldValue? by remember { mutableStateOf(null) }
|
||||
|
||||
LaunchedEffect(addSymbol, focusedTextFieldValue) {
|
||||
toggleKeyboard((addSymbol != null) and (focusedTextFieldValue != null))
|
||||
}
|
||||
|
||||
BackHandler(showKeyboard) {
|
||||
focusManager.clearFocus()
|
||||
addSymbol = null
|
||||
focusedTextFieldValue = null
|
||||
val expressionTransformer = remember(uiState.formatterSymbols) {
|
||||
ExpressionTransformer(uiState.formatterSymbols)
|
||||
}
|
||||
|
||||
val showResult = remember(uiState.start, uiState.result) { uiState.start != uiState.result }
|
||||
@ -241,127 +212,58 @@ private fun AddSubtractView(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
TimeUnitTextField(
|
||||
modifier = Modifier
|
||||
.onFocusEvent {
|
||||
if (it.hasFocus) {
|
||||
addSymbol = updateYears
|
||||
focusedTextFieldValue = uiState.years
|
||||
}
|
||||
}
|
||||
.fillMaxWidth(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = uiState.years,
|
||||
onValueChange = updateYears,
|
||||
label = stringResource(R.string.date_calculator_years),
|
||||
formatterSymbols = uiState.formatterSymbols
|
||||
expressionFormatter = expressionTransformer,
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
TimeUnitTextField(
|
||||
modifier = Modifier
|
||||
.onFocusEvent {
|
||||
if (it.hasFocus) {
|
||||
addSymbol = updateMonths
|
||||
focusedTextFieldValue = uiState.months
|
||||
}
|
||||
}
|
||||
.weight(1f),
|
||||
modifier = Modifier.weight(1f),
|
||||
value = uiState.months,
|
||||
onValueChange = updateMonths,
|
||||
label = stringResource(R.string.date_calculator_months),
|
||||
formatterSymbols = uiState.formatterSymbols
|
||||
expressionFormatter = expressionTransformer,
|
||||
)
|
||||
|
||||
TimeUnitTextField(
|
||||
modifier = Modifier
|
||||
.onFocusEvent {
|
||||
if (it.hasFocus) {
|
||||
addSymbol = updateDays
|
||||
focusedTextFieldValue = uiState.days
|
||||
}
|
||||
}
|
||||
.weight(1f),
|
||||
modifier = Modifier.weight(1f),
|
||||
value = uiState.days,
|
||||
onValueChange = updateDays,
|
||||
label = stringResource(R.string.date_calculator_days),
|
||||
formatterSymbols = uiState.formatterSymbols
|
||||
expressionFormatter = expressionTransformer,
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
TimeUnitTextField(
|
||||
modifier = Modifier
|
||||
.onFocusEvent {
|
||||
if (it.hasFocus) {
|
||||
addSymbol = updateHours
|
||||
focusedTextFieldValue = uiState.hours
|
||||
}
|
||||
}
|
||||
.weight(1f),
|
||||
modifier = Modifier.weight(1f),
|
||||
value = uiState.hours,
|
||||
onValueChange = updateHours,
|
||||
label = stringResource(R.string.date_calculator_hours),
|
||||
formatterSymbols = uiState.formatterSymbols
|
||||
expressionFormatter = expressionTransformer,
|
||||
)
|
||||
|
||||
TimeUnitTextField(
|
||||
modifier = Modifier
|
||||
.onFocusEvent {
|
||||
if (it.hasFocus) {
|
||||
addSymbol = updateMinutes
|
||||
focusedTextFieldValue = uiState.minutes
|
||||
}
|
||||
}
|
||||
.weight(1f),
|
||||
modifier = Modifier.weight(1f),
|
||||
value = uiState.minutes,
|
||||
onValueChange = updateMinutes,
|
||||
label = stringResource(R.string.date_calculator_minutes),
|
||||
formatterSymbols = uiState.formatterSymbols
|
||||
expressionFormatter = expressionTransformer,
|
||||
imeAction = ImeAction.Done
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = showKeyboard,
|
||||
enter = slideInVertically { it / 2 } + fadeIn(),
|
||||
exit = slideOutVertically { it / 2 } + fadeOut()
|
||||
) {
|
||||
HorizontalDivider()
|
||||
AddSubtractKeyboard(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(if (LocalWindowSize.current.heightSizeClass > WindowHeightSizeClass.Compact) 0.4f else 0.6f)
|
||||
.padding(2.dp, 4.dp),
|
||||
addSymbol = {
|
||||
val newValue = focusedTextFieldValue?.addTokens(it)
|
||||
if (newValue != null) {
|
||||
addSymbol?.invoke(newValue)
|
||||
}
|
||||
},
|
||||
deleteSymbol = {
|
||||
val newValue = focusedTextFieldValue?.deleteTokens()
|
||||
if (newValue != null) {
|
||||
addSymbol?.invoke(newValue)
|
||||
}
|
||||
},
|
||||
onConfirm = {
|
||||
focusManager.clearFocus()
|
||||
addSymbol = null
|
||||
focusedTextFieldValue = null
|
||||
},
|
||||
allowVibration = uiState.allowVibration,
|
||||
imeAction = if (addSymbol == updateMinutes) ImeAction.Done else ImeAction.Next
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DateTimeDialogs(
|
||||
@ -399,8 +301,6 @@ fun AddSubtractViewPreview() {
|
||||
start = ZonedDateTimeUtils.nowWithMinutes(),
|
||||
result = ZonedDateTimeUtils.nowWithMinutes().plusSeconds(1)
|
||||
),
|
||||
showKeyboard = false,
|
||||
toggleKeyboard = {},
|
||||
updateStart = {},
|
||||
updateYears = {},
|
||||
updateMonths = {},
|
||||
|
@ -1,141 +0,0 @@
|
||||
/*
|
||||
* 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.datecalculator.components
|
||||
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.foundation.layout.Row
|
||||
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.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusDirection
|
||||
import androidx.compose.ui.focus.FocusManager
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.sadellie.unitto.core.base.Token
|
||||
import com.sadellie.unitto.core.ui.LocalWindowSize
|
||||
import com.sadellie.unitto.core.ui.WindowHeightSizeClass
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonContentHeightTall
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonFilled
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonLight
|
||||
import com.sadellie.unitto.core.ui.common.KeypadFlow
|
||||
import com.sadellie.unitto.core.ui.common.icons.IconPack
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Backspace
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Check
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Key0
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Key1
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Key2
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Key3
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Key4
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Key5
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Key6
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Key7
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Key8
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Key9
|
||||
import com.sadellie.unitto.core.ui.common.icons.iconpack.Tab
|
||||
|
||||
@Composable
|
||||
internal fun AddSubtractKeyboard(
|
||||
modifier: Modifier,
|
||||
addSymbol: (String) -> Unit,
|
||||
deleteSymbol: () -> Unit,
|
||||
onConfirm: () -> Unit,
|
||||
allowVibration: Boolean,
|
||||
imeAction: ImeAction,
|
||||
focusManager: FocusManager = LocalFocusManager.current
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
) {
|
||||
KeypadFlow(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(3f),
|
||||
rows = 4,
|
||||
columns = 3
|
||||
) { width, height ->
|
||||
val buttonModifier = Modifier
|
||||
.fillMaxWidth(width)
|
||||
.fillMaxHeight(height)
|
||||
|
||||
KeyboardButtonLight(buttonModifier, IconPack.Key7, allowVibration, KeyboardButtonContentHeightTall) { addSymbol(Token.Digit._7) }
|
||||
KeyboardButtonLight(buttonModifier, IconPack.Key8, allowVibration, KeyboardButtonContentHeightTall) { addSymbol(Token.Digit._8) }
|
||||
KeyboardButtonLight(buttonModifier, IconPack.Key9, allowVibration, KeyboardButtonContentHeightTall) { addSymbol(Token.Digit._9) }
|
||||
|
||||
KeyboardButtonLight(buttonModifier, IconPack.Key4, allowVibration, KeyboardButtonContentHeightTall) { addSymbol(Token.Digit._4) }
|
||||
KeyboardButtonLight(buttonModifier, IconPack.Key5, allowVibration, KeyboardButtonContentHeightTall) { addSymbol(Token.Digit._5) }
|
||||
KeyboardButtonLight(buttonModifier, IconPack.Key6, allowVibration, KeyboardButtonContentHeightTall) { addSymbol(Token.Digit._6) }
|
||||
|
||||
KeyboardButtonLight(buttonModifier, IconPack.Key1, allowVibration, KeyboardButtonContentHeightTall) { addSymbol(Token.Digit._1) }
|
||||
KeyboardButtonLight(buttonModifier, IconPack.Key2, allowVibration, KeyboardButtonContentHeightTall) { addSymbol(Token.Digit._2) }
|
||||
KeyboardButtonLight(buttonModifier, IconPack.Key3, allowVibration, KeyboardButtonContentHeightTall) { addSymbol(Token.Digit._3) }
|
||||
|
||||
Spacer(buttonModifier)
|
||||
KeyboardButtonLight(buttonModifier, IconPack.Key0, allowVibration, KeyboardButtonContentHeightTall) { addSymbol(Token.Digit._0) }
|
||||
Spacer(buttonModifier)
|
||||
}
|
||||
|
||||
KeypadFlow(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(1f),
|
||||
rows = 2,
|
||||
columns = 1,
|
||||
// In digits keypad there are 4 rows with verticalPadding set to 10
|
||||
// In this keypad we have 2 times less rows, we use 2 times smaller verticalPadding -> 5
|
||||
verticalPadding = 5
|
||||
) { width, height ->
|
||||
val mainButtonModifier = Modifier
|
||||
.fillMaxWidth(width)
|
||||
.fillMaxHeight(height)
|
||||
val actionIconHeight = if (LocalWindowSize.current.heightSizeClass > WindowHeightSizeClass.Compact) 0.8f else 1.3f
|
||||
|
||||
Crossfade(
|
||||
targetState = imeAction == ImeAction.Next,
|
||||
modifier = mainButtonModifier,
|
||||
label = "Primary button animation"
|
||||
) { showNext ->
|
||||
if (showNext) {
|
||||
KeyboardButtonFilled(Modifier.fillMaxSize(), IconPack.Tab, allowVibration, actionIconHeight) { focusManager.moveFocus(FocusDirection.Next) }
|
||||
} else {
|
||||
KeyboardButtonFilled(Modifier.fillMaxSize(), IconPack.Check, allowVibration, actionIconHeight) { onConfirm() }
|
||||
}
|
||||
}
|
||||
KeyboardButtonLight(mainButtonModifier, IconPack.Backspace, allowVibration, actionIconHeight) { deleteSymbol() }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewAddSubtractKeyboardNew() {
|
||||
AddSubtractKeyboard(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
addSymbol = {},
|
||||
deleteSymbol = {},
|
||||
onConfirm = {},
|
||||
allowVibration = true,
|
||||
imeAction = ImeAction.Next
|
||||
)
|
||||
}
|
@ -18,50 +18,32 @@
|
||||
|
||||
package com.sadellie.unitto.feature.datecalculator.components
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Clear
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalTextInputService
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.sadellie.unitto.core.ui.common.textfield.ExpressionTransformer
|
||||
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import com.sadellie.unitto.core.ui.common.textfield.OutlinedDecimalTextField
|
||||
|
||||
@Composable
|
||||
internal fun TimeUnitTextField(
|
||||
modifier: Modifier,
|
||||
value: TextFieldValue,
|
||||
onValueChange: (TextFieldValue) -> Unit,
|
||||
label: String,
|
||||
formatterSymbols: FormatterSymbols
|
||||
) = CompositionLocalProvider(LocalTextInputService provides null) {
|
||||
OutlinedTextField(
|
||||
onValueChange: (TextFieldValue) -> Unit,
|
||||
expressionFormatter: VisualTransformation,
|
||||
imeAction: ImeAction = ImeAction.Next,
|
||||
) {
|
||||
OutlinedDecimalTextField(
|
||||
modifier = modifier,
|
||||
value = value,
|
||||
onValueChange = { newValue ->
|
||||
onValueChange(newValue.copy(newValue.text.filter { it.isDigit() }))
|
||||
},
|
||||
label = { Text(label, color = MaterialTheme.colorScheme.onSurfaceVariant) },
|
||||
trailingIcon = {
|
||||
AnimatedVisibility(
|
||||
visible = value.text.isNotBlank(),
|
||||
enter = scaleIn(),
|
||||
exit = scaleOut()
|
||||
) {
|
||||
IconButton(onClick = { onValueChange(TextFieldValue()) }) {
|
||||
Icon(Icons.Outlined.Clear, null)
|
||||
}
|
||||
}
|
||||
},
|
||||
visualTransformation = ExpressionTransformer(formatterSymbols)
|
||||
label = { AnimatedContent(label) { Text(it) } },
|
||||
expressionFormatter = expressionFormatter,
|
||||
imeAction = imeAction
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user