diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/UIUtils.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/UIUtils.kt
index b055c7af..68b6f554 100644
--- a/core/ui/src/main/java/com/sadellie/unitto/core/ui/UIUtils.kt
+++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/UIUtils.kt
@@ -21,8 +21,11 @@ package com.sadellie.unitto.core.ui
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
+import android.content.res.Configuration
import android.net.Uri
import android.widget.Toast
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalConfiguration
import com.sadellie.unitto.core.base.R
/**
@@ -35,3 +38,6 @@ fun openLink(mContext: Context, url: String) {
Toast.makeText(mContext, R.string.error_label, Toast.LENGTH_SHORT).show()
}
}
+
+@Composable
+fun isPortrait() = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/KeyboardButton.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/KeyboardButton.kt
index 0f663262..c51763c9 100644
--- a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/KeyboardButton.kt
+++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/KeyboardButton.kt
@@ -18,7 +18,6 @@
package com.sadellie.unitto.core.ui.common
-import android.content.res.Configuration
import android.view.HapticFeedbackConstants
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
@@ -29,20 +28,20 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalView
+import com.sadellie.unitto.core.ui.isPortrait
import kotlinx.coroutines.launch
@Composable
fun BasicKeyboardButton(
modifier: Modifier,
+ contentHeight: Float,
onClick: () -> Unit,
onLongClick: (() -> Unit)?,
containerColor: Color,
icon: ImageVector,
iconColor: Color,
allowVibration: Boolean,
- contentHeight: Float,
) {
val view = LocalView.current
val coroutineScope = rememberCoroutineScope()
@@ -53,7 +52,6 @@ fun BasicKeyboardButton(
}
}
}
-
UnittoButton(
modifier = modifier,
onClick = { onClick(); vibrate() },
@@ -75,18 +73,19 @@ fun KeyboardButtonLight(
modifier: Modifier,
icon: ImageVector,
allowVibration: Boolean,
+ contentHeight: Float = if (isPortrait()) 0.51f else 0.7f,
onLongClick: (() -> Unit)? = null,
onClick: () -> Unit,
) {
BasicKeyboardButton(
modifier = modifier,
+ contentHeight = contentHeight,
onClick = onClick,
onLongClick = onLongClick,
containerColor = MaterialTheme.colorScheme.inverseOnSurface,
icon = icon,
iconColor = MaterialTheme.colorScheme.onSurfaceVariant,
allowVibration = allowVibration,
- contentHeight = if (isPortrait()) 0.51f else 0.7f
)
}
@@ -95,18 +94,19 @@ fun KeyboardButtonFilled(
modifier: Modifier,
icon: ImageVector,
allowVibration: Boolean,
+ contentHeight: Float = if (isPortrait()) 0.51f else 0.7f,
onLongClick: (() -> Unit)? = null,
onClick: () -> Unit,
) {
BasicKeyboardButton(
modifier = modifier,
+ contentHeight = contentHeight,
onClick = onClick,
onLongClick = onLongClick,
containerColor = MaterialTheme.colorScheme.primaryContainer,
icon = icon,
iconColor = MaterialTheme.colorScheme.onSecondaryContainer,
allowVibration = allowVibration,
- contentHeight = if (isPortrait()) 0.51f else 0.7f
)
}
@@ -115,21 +115,18 @@ fun KeyboardButtonAdditional(
modifier: Modifier,
icon: ImageVector,
allowVibration: Boolean,
+ contentHeight: Float = 0.8f,
onLongClick: (() -> Unit)? = null,
onClick: () -> Unit,
) {
BasicKeyboardButton(
modifier = modifier,
+ contentHeight = contentHeight,
onClick = onClick,
onLongClick = onLongClick,
containerColor = Color.Transparent,
icon = icon,
iconColor = MaterialTheme.colorScheme.onSurfaceVariant,
allowVibration = allowVibration,
- contentHeight = if (isPortrait()) 0.8f else 0.8f
)
}
-
-@Composable
-private fun isPortrait() =
- LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoScreenWithTopBar.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoScreenWithTopBar.kt
index e87eedc2..8e508963 100644
--- a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoScreenWithTopBar.kt
+++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoScreenWithTopBar.kt
@@ -18,6 +18,11 @@
package com.sadellie.unitto.core.ui.common
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideInVertically
+import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.CenterAlignedTopAppBar
@@ -51,18 +56,25 @@ fun UnittoScreenWithTopBar(
floatingActionButton: @Composable () -> Unit = {},
floatingActionButtonPosition: FabPosition = FabPosition.End,
scrollBehavior: TopAppBarScrollBehavior? = null,
+ showTopBar: Boolean = true,
content: @Composable (PaddingValues) -> Unit
) {
Scaffold(
modifier = modifier,
topBar = {
- CenterAlignedTopAppBar(
- title = title,
- navigationIcon = navigationIcon,
- actions = actions,
- colors = colors,
- scrollBehavior = scrollBehavior,
- )
+ AnimatedVisibility(
+ visible = showTopBar,
+ enter = slideInVertically() + fadeIn(),
+ exit = slideOutVertically() + fadeOut()
+ ) {
+ CenterAlignedTopAppBar(
+ title = title,
+ navigationIcon = navigationIcon,
+ actions = actions,
+ colors = colors,
+ scrollBehavior = scrollBehavior,
+ )
+ }
},
floatingActionButton = floatingActionButton,
floatingActionButtonPosition = floatingActionButtonPosition,
diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/key/unittoicons/Check.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/key/unittoicons/Check.kt
new file mode 100644
index 00000000..48f26960
--- /dev/null
+++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/key/unittoicons/Check.kt
@@ -0,0 +1,56 @@
+/*
+ * 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 .
+ */
+
+package com.sadellie.unitto.core.ui.common.key.unittoicons
+
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.unit.dp
+import com.sadellie.unitto.core.ui.common.key.UnittoIcons
+
+val @Suppress("UnusedReceiverParameter") UnittoIcons.Check: ImageVector
+ get() {
+ if (_check != null) {
+ return _check!!
+ }
+ _check = Builder(name = "Check", defaultWidth = 150.0.dp, defaultHeight = 150.0.dp,
+ viewportWidth = 150.0f, viewportHeight = 150.0f).apply {
+ path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f,
+ strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f,
+ pathFillType = NonZero) {
+ moveTo(59.625f, 112.156f)
+ lineTo(24.0f, 76.531f)
+ lineTo(32.906f, 67.625f)
+ lineTo(59.625f, 94.344f)
+ lineTo(116.969f, 37.0f)
+ lineTo(125.875f, 45.906f)
+ lineTo(59.625f, 112.156f)
+ close()
+ }
+ }
+ .build()
+ return _check!!
+ }
+
+private var _check: ImageVector? = null
diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/key/unittoicons/Tab.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/key/unittoicons/Tab.kt
new file mode 100644
index 00000000..08cc365c
--- /dev/null
+++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/key/unittoicons/Tab.kt
@@ -0,0 +1,65 @@
+/*
+ * 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 .
+ */
+
+package com.sadellie.unitto.core.ui.common.key.unittoicons
+
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.unit.dp
+import com.sadellie.unitto.core.ui.common.key.UnittoIcons
+
+val @Suppress("UnusedReceiverParameter") UnittoIcons.Tab: ImageVector
+ get() {
+ if (_tab != null) {
+ return _tab!!
+ }
+ _tab = Builder(name = "Tab", defaultWidth = 150.0.dp, defaultHeight = 150.0.dp,
+ viewportWidth = 150.0f, viewportHeight = 150.0f).apply {
+ path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f,
+ strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f,
+ pathFillType = NonZero) {
+ moveTo(125.0f, 112.5f)
+ verticalLineTo(37.5f)
+ horizontalLineTo(137.5f)
+ verticalLineTo(112.5f)
+ horizontalLineTo(125.0f)
+ close()
+ moveTo(75.0f, 112.5f)
+ lineTo(66.094f, 103.75f)
+ lineTo(88.594f, 81.25f)
+ horizontalLineTo(12.5f)
+ verticalLineTo(68.75f)
+ horizontalLineTo(88.594f)
+ lineTo(66.25f, 46.25f)
+ lineTo(75.0f, 37.5f)
+ lineTo(112.5f, 75.0f)
+ lineTo(75.0f, 112.5f)
+ close()
+ }
+ }
+ .build()
+ return _tab!!
+ }
+
+private var _tab: ImageVector? = null
diff --git a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt
index 7d70a9f6..c9439e0c 100644
--- a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt
+++ b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt
@@ -126,6 +126,7 @@ data class UnitGroupsPreferences(
data class AddSubtractPreferences(
val separator: Int = Separator.SPACE,
+ val enableVibrations: Boolean = true,
)
data class AboutPreferences(
@@ -232,7 +233,8 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
val addSubtractPrefs: Flow = data
.map { preferences ->
AddSubtractPreferences(
- separator = preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACE
+ separator = preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACE,
+ enableVibrations = preferences[PrefsKeys.ENABLE_VIBRATIONS] ?: true,
)
}
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 b879496b..9b73756c 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
@@ -386,7 +386,7 @@ private fun PortraitKeyboard(
KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key0, allowVibration) { addSymbol(Token.Digit._0) }
KeyboardButtonLight(mainButtonModifier, fractionalIcon, allowVibration) { addSymbol(Token.Digit.dot) }
}
- KeyboardButtonLight(mainButtonModifier, UnittoIcons.Backspace, allowVibration, clearSymbols) { deleteSymbol() }
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Backspace, allowVibration, onLongClick = clearSymbols) { deleteSymbol() }
KeyboardButtonFilled(mainButtonModifier, UnittoIcons.Equal, allowVibration) { evaluate() }
}
@@ -538,7 +538,7 @@ private fun LandscapeKeyboard(
KeyboardButtonLight(buttonModifier, UnittoIcons.Key9, allowVibration) { addSymbol(Token.Digit._9) }
KeyboardButtonLight(buttonModifier, UnittoIcons.Key6, allowVibration) { addSymbol(Token.Digit._6) }
KeyboardButtonLight(buttonModifier, UnittoIcons.Key3, allowVibration) { addSymbol(Token.Digit._3) }
- KeyboardButtonLight(buttonModifier, UnittoIcons.Backspace, allowVibration, clearSymbols) { deleteSymbol() }
+ KeyboardButtonLight(buttonModifier, UnittoIcons.Backspace, allowVibration, onLongClick = clearSymbols) { deleteSymbol() }
}
Column(Modifier.weight(1f)) {
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 bf43af88..ded64c51 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
@@ -109,7 +109,7 @@ internal fun DefaultKeyboard(
KeyboardButtonLight(bModifier, UnittoIcons.Key0, allowVibration) { addDigit(Token.Digit._0) }
KeyboardButtonLight(bModifier, fractionalIcon, allowVibration) { addDigit(Token.Digit.dot) }
}
- KeyboardButtonLight(bModifier, UnittoIcons.Backspace, allowVibration, clearInput) { deleteDigit() }
+ KeyboardButtonLight(bModifier, UnittoIcons.Backspace, allowVibration, onLongClick = clearInput) { deleteDigit() }
KeyboardButtonFilled(bModifier, UnittoIcons.Plus, allowVibration) { addDigit(Token.Operator.plus) }
}
}
@@ -159,7 +159,7 @@ internal fun NumberBaseKeyboard(
Row(cModifier, horizontalArrangement) {
KeyboardButtonLight(bModifier, UnittoIcons.Key0, allowVibration) { addDigit(Token.Digit._0) }
KeyboardButtonLight(
- Modifier.fillMaxSize().weight(2f).padding(it.maxWidth * 0.015f, it.maxHeight * 0.008f), UnittoIcons.Backspace, allowVibration, clearInput) { deleteDigit() }
+ Modifier.fillMaxSize().weight(2f).padding(it.maxWidth * 0.015f, it.maxHeight * 0.008f), UnittoIcons.Backspace, allowVibration, onLongClick = clearInput) { deleteDigit() }
}
}
}
diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/DateCalculatorScreen.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/DateCalculatorScreen.kt
index d9337f73..542a7517 100644
--- a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/DateCalculatorScreen.kt
+++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/DateCalculatorScreen.kt
@@ -26,8 +26,11 @@ import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
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
@@ -60,6 +63,7 @@ internal fun DateCalculatorScreen(
val addSubtractLabel = "${stringResource(R.string.add)}/${stringResource(R.string.subtract)}"
val differenceLabel = stringResource(R.string.difference)
val focusManager = LocalFocusManager.current
+ var topBarShown by remember { mutableStateOf(true) }
val allTabs = remember { mutableListOf(addSubtractLabel, differenceLabel) }
val pagerState = rememberPagerState { allTabs.size }
@@ -69,9 +73,8 @@ internal fun DateCalculatorScreen(
modifier = Modifier,
title = { Text(stringResource(R.string.date_calculator)) },
navigationIcon = { MenuButton(navigateToMenu) },
- actions = {
- SettingsButton(navigateToSettings)
- },
+ actions = { SettingsButton(navigateToSettings) },
+ showTopBar = topBarShown,
) { paddingValues ->
Column(
modifier = Modifier.padding(paddingValues),
@@ -97,9 +100,14 @@ internal fun DateCalculatorScreen(
verticalAlignment = Alignment.Top
) { page ->
when (page) {
- 0 -> AddSubtractPage()
- 1 -> DateDifferencePage().also {
+ 0 -> AddSubtractPage(
+ toggleTopBar = { topBarShown = it }
+ )
+ 1 -> {
focusManager.clearFocus(true)
+ topBarShown = true
+
+ DateDifferencePage()
}
}
}
diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractPage.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractPage.kt
index a379dc11..d2e5f3e1 100644
--- a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractPage.kt
+++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractPage.kt
@@ -24,11 +24,19 @@ import android.content.Context
import android.content.Intent
import android.provider.CalendarContract
import android.widget.Toast
+import androidx.activity.compose.BackHandler
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideInVertically
+import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
@@ -37,25 +45,34 @@ 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.Scaffold
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
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.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
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.R
+import com.sadellie.unitto.core.ui.common.textfield.addTokens
+import com.sadellie.unitto.core.ui.common.textfield.deleteTokens
+import com.sadellie.unitto.core.ui.isPortrait
+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
@@ -65,18 +82,20 @@ import java.time.ZonedDateTime
@Composable
internal fun AddSubtractPage(
viewModel: AddSubtractViewModel = hiltViewModel(),
+ toggleTopBar: (Boolean) -> Unit,
) {
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
AddSubtractView(
uiState = uiState,
+ toggleTopBar = toggleTopBar,
updateStart = viewModel::updateStart,
updateYears = viewModel::updateYears,
updateMonths = viewModel::updateMonths,
updateDays = viewModel::updateDays,
updateHours = viewModel::updateHours,
updateMinutes = viewModel::updateMinutes,
- updateAddition = viewModel::updateAddition
+ updateAddition = viewModel::updateAddition,
)
}
@@ -85,120 +104,207 @@ internal fun AddSubtractPage(
@Composable
private fun AddSubtractView(
uiState: AddSubtractState,
+ toggleTopBar: (Boolean) -> Unit,
updateStart: (ZonedDateTime) -> Unit,
- updateYears: (String) -> Unit,
- updateMonths: (String) -> Unit,
- updateDays: (String) -> Unit,
- updateHours: (String) -> Unit,
- updateMinutes: (String) -> Unit,
+ updateYears: (TextFieldValue) -> Unit,
+ updateMonths: (TextFieldValue) -> Unit,
+ updateDays: (TextFieldValue) -> Unit,
+ updateHours: (TextFieldValue) -> Unit,
+ updateMinutes: (TextFieldValue) -> Unit,
updateAddition: (Boolean) -> Unit,
) {
var dialogState by remember { mutableStateOf(DialogState.NONE) }
val mContext = LocalContext.current
+ var addSymbol: ((TextFieldValue) -> Unit)? by remember { mutableStateOf(null) }
+ var focusedTextFieldValue: TextFieldValue? by remember { mutableStateOf(null) }
+ val showKeyboard = (addSymbol != null) and (focusedTextFieldValue != null)
+ val landscape = !isPortrait()
+ val focusManager = LocalFocusManager.current
- Scaffold(
- floatingActionButton = {
- FloatingActionButton(onClick = { mContext.addEvent(uiState.start, uiState.result) }) {
- Icon(
- imageVector = Icons.Default.Event,
- contentDescription = null,
- )
+ LaunchedEffect(showKeyboard, landscape) {
+ toggleTopBar(showKeyboard and landscape)
+ }
+
+ BackHandler(showKeyboard) {
+ focusManager.clearFocus()
+ addSymbol = null
+ focusedTextFieldValue = null
+ }
+
+ Column(Modifier.fillMaxSize()) {
+ Scaffold(
+ modifier = Modifier
+ .fillMaxHeight()
+ .weight(1f),
+ floatingActionButton = {
+ FloatingActionButton(
+ onClick = {
+ mContext.addEvent(uiState.start, uiState.result)
+ }
+ ) {
+ Icon(
+ imageVector = Icons.Default.Event,
+ contentDescription = null,
+ )
+ }
+ }
+ ) {
+ LazyColumn(
+ modifier = Modifier.padding(horizontal = 16.dp),
+ verticalArrangement = Arrangement.spacedBy(16.dp),
+ contentPadding = PaddingValues(top = 16.dp)
+ ) {
+ item("dates") {
+ FlowRow(
+ modifier = Modifier,
+ maxItemsInEachRow = 2,
+ verticalArrangement = Arrangement.spacedBy(16.dp),
+ horizontalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+ DateTimeSelectorBlock(
+ modifier = Modifier
+ .weight(1f)
+ .fillMaxWidth(),
+ title = stringResource(R.string.date_difference_start),
+ dateTime = uiState.start,
+ onLongClick = { updateStart(ZonedDateTime.now()) },
+ onClick = { dialogState = DialogState.FROM },
+ onTimeClick = { dialogState = DialogState.FROM_TIME },
+ onDateClick = { dialogState = DialogState.FROM_DATE },
+ )
+
+ DateTimeSelectorBlock(
+ modifier = Modifier
+ .weight(1f)
+ .fillMaxWidth(),
+ title = stringResource(R.string.date_difference_end),
+ dateTime = uiState.result,
+ )
+ }
+ }
+
+ item("modes") {
+ SingleChoiceSegmentedButtonRow(
+ modifier = Modifier
+ .fillMaxWidth(),
+ ) {
+ SegmentedButton(
+ selected = uiState.addition,
+ onClick = { updateAddition(true) },
+ shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2),
+ icon = {}
+ ) {
+ Icon(Icons.Outlined.Add, null)
+ }
+ SegmentedButton(
+ selected = !uiState.addition,
+ onClick = { updateAddition(false) },
+ shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2),
+ icon = {}
+ ) {
+ Icon(Icons.Outlined.Remove, null)
+ }
+ }
+ }
+
+ item("textFields") {
+ Column {
+ TimeUnitTextField(
+ modifier = Modifier.onFocusEvent {
+ if (it.hasFocus) {
+ addSymbol = updateYears
+ focusedTextFieldValue = uiState.years
+ }
+ },
+ value = uiState.years,
+ onValueChange = updateYears,
+ label = stringResource(R.string.date_difference_years),
+ formatterSymbols = uiState.formatterSymbols
+ )
+ TimeUnitTextField(
+ modifier = Modifier.onFocusEvent {
+ if (it.hasFocus) {
+ addSymbol = updateMonths
+ focusedTextFieldValue = uiState.months
+ }
+ },
+ value = uiState.months,
+ onValueChange = updateMonths,
+ label = stringResource(R.string.date_difference_months),
+ formatterSymbols = uiState.formatterSymbols
+ )
+ TimeUnitTextField(
+ modifier = Modifier.onFocusEvent {
+ if (it.hasFocus) {
+ addSymbol = updateDays
+ focusedTextFieldValue = uiState.days
+ }
+ },
+ value = uiState.days,
+ onValueChange = updateDays,
+ label = stringResource(R.string.date_difference_days),
+ formatterSymbols = uiState.formatterSymbols
+ )
+ TimeUnitTextField(
+ modifier = Modifier.onFocusEvent {
+ if (it.hasFocus) {
+ addSymbol = updateHours
+ focusedTextFieldValue = uiState.hours
+ }
+ },
+ value = uiState.hours,
+ onValueChange = updateHours,
+ label = stringResource(R.string.date_difference_hours),
+ formatterSymbols = uiState.formatterSymbols
+ )
+ TimeUnitTextField(
+ modifier = Modifier.onFocusEvent {
+ if (it.hasFocus) {
+ addSymbol = updateMinutes
+ focusedTextFieldValue = uiState.minutes
+ }
+ },
+ value = uiState.minutes,
+ onValueChange = updateMinutes,
+ label = stringResource(R.string.date_difference_minutes),
+ formatterSymbols = uiState.formatterSymbols
+ )
+ }
+ }
}
}
- ) {
- LazyColumn(
- modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp),
- verticalArrangement = Arrangement.spacedBy(16.dp),
- contentPadding = PaddingValues(bottom = 88.dp)
+ AnimatedVisibility(
+ visible = showKeyboard,
+ enter = slideInVertically { it / 2 } + fadeIn(),
+ exit = slideOutVertically { it / 2 } + fadeOut()
) {
- item("dates") {
- FlowRow(
- modifier = Modifier,
- maxItemsInEachRow = 2,
- verticalArrangement = Arrangement.spacedBy(16.dp),
- horizontalArrangement = Arrangement.spacedBy(16.dp)
- ) {
- DateTimeSelectorBlock(
- modifier = Modifier
- .weight(1f)
- .fillMaxWidth(),
- title = stringResource(R.string.date_difference_start),
- dateTime = uiState.start,
- onLongClick = { updateStart(ZonedDateTime.now()) },
- onClick = { dialogState = DialogState.FROM },
- onTimeClick = { dialogState = DialogState.FROM_TIME },
- onDateClick = { dialogState = DialogState.FROM_DATE },
- )
-
- DateTimeSelectorBlock(
- modifier = Modifier
- .weight(1f)
- .fillMaxWidth(),
- title = stringResource(R.string.date_difference_end),
- dateTime = uiState.result,
- )
- }
- }
-
- item("modes") {
- SingleChoiceSegmentedButtonRow(
- modifier = Modifier
- .fillMaxWidth(),
- ) {
- SegmentedButton(
- selected = uiState.addition,
- onClick = { updateAddition(true) },
- shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2),
- icon = {}
- ) {
- Icon(Icons.Outlined.Add, null)
+ HorizontalDivider()
+ AddSubtractKeyboard(
+ modifier = Modifier
+ .weight(1f)
+ .fillMaxWidth()
+ .fillMaxHeight(if (isPortrait()) 0.4f else 0.6f)
+ .padding(2.dp, 4.dp),
+ addSymbol = {
+ val newValue = focusedTextFieldValue?.addTokens(it)
+ if (newValue != null) {
+ addSymbol?.invoke(newValue)
}
- SegmentedButton(
- selected = !uiState.addition,
- onClick = { updateAddition(false) },
- shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2),
- icon = {}
- ) {
- Icon(Icons.Outlined.Remove, null)
+ },
+ deleteSymbol = {
+ val newValue = focusedTextFieldValue?.deleteTokens()
+ if (newValue != null) {
+ addSymbol?.invoke(newValue)
}
- }
- }
-
- item("textFields") {
- Column {
- TimeUnitTextField(
- value = uiState.years,
- onValueChange = updateYears,
- label = stringResource(R.string.date_difference_years),
- formatterSymbols = uiState.formatterSymbols
- )
- TimeUnitTextField(
- value = uiState.months,
- onValueChange = updateMonths,
- label = stringResource(R.string.date_difference_months),
- formatterSymbols = uiState.formatterSymbols
- )
- TimeUnitTextField(
- value = uiState.days,
- onValueChange = updateDays,
- label = stringResource(R.string.date_difference_days),
- formatterSymbols = uiState.formatterSymbols
- )
- TimeUnitTextField(
- value = uiState.hours,
- onValueChange = updateHours,
- label = stringResource(R.string.date_difference_hours),
- formatterSymbols = uiState.formatterSymbols
- )
- TimeUnitTextField(
- value = uiState.minutes,
- onValueChange = updateMinutes,
- label = stringResource(R.string.date_difference_minutes),
- imeAction = ImeAction.Done,
- formatterSymbols = uiState.formatterSymbols
- )
- }
- }
+ },
+ onConfirm = {
+ focusManager.clearFocus()
+ addSymbol = null
+ focusedTextFieldValue = null
+ },
+ allowVibration = uiState.allowVibration,
+ imeAction = if (addSymbol == updateMinutes) ImeAction.Done else ImeAction.Next
+ )
}
}
@@ -234,14 +340,15 @@ private fun Context.addEvent(start: ZonedDateTime, end: ZonedDateTime) {
fun AddSubtractViewPreview() {
AddSubtractView(
uiState = AddSubtractState(
- years = "12"
+ years = TextFieldValue("12")
),
+ toggleTopBar = {},
updateStart = {},
updateYears = {},
updateMonths = {},
updateDays = {},
updateHours = {},
updateMinutes = {},
- updateAddition = {}
+ updateAddition = {},
)
}
diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractUIState.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractUIState.kt
index 6afe641c..740830b2 100644
--- a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractUIState.kt
+++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractUIState.kt
@@ -18,17 +18,19 @@
package com.sadellie.unitto.feature.datecalculator.addsubtract
+import androidx.compose.ui.text.input.TextFieldValue
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import java.time.ZonedDateTime
internal data class AddSubtractState(
val start: ZonedDateTime = ZonedDateTime.now(),
val result: ZonedDateTime = ZonedDateTime.now(),
- val years: String = "",
- val months: String = "",
- val days: String = "",
- val hours: String = "",
- val minutes: String = "",
+ val years: TextFieldValue = TextFieldValue(),
+ val months: TextFieldValue = TextFieldValue(),
+ val days: TextFieldValue = TextFieldValue(),
+ val hours: TextFieldValue = TextFieldValue(),
+ val minutes: TextFieldValue = TextFieldValue(),
val addition: Boolean = true,
val formatterSymbols: FormatterSymbols = FormatterSymbols.Spaces,
+ val allowVibration: Boolean = false,
)
diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractViewModel.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractViewModel.kt
index 710be166..2245f157 100644
--- a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractViewModel.kt
+++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractViewModel.kt
@@ -18,6 +18,8 @@
package com.sadellie.unitto.feature.datecalculator.addsubtract
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
@@ -44,7 +46,8 @@ internal class AddSubtractViewModel @Inject constructor(
val uiState: StateFlow = _uiState
.combine(userPreferencesRepository.addSubtractPrefs) { uiState, userPrefs ->
return@combine uiState.copy(
- formatterSymbols = AllFormatterSymbols.getById(userPrefs.separator)
+ formatterSymbols = AllFormatterSymbols.getById(userPrefs.separator),
+ allowVibration = userPrefs.enableVibrations,
)
}
.onEach { updateResult() }
@@ -52,78 +55,57 @@ internal class AddSubtractViewModel @Inject constructor(
fun updateStart(newValue: ZonedDateTime) = _uiState.update { it.copy(start = newValue) }
- fun updateYears(newValue: String) = _uiState.update {
- val years = when {
- newValue.isEmpty() -> newValue
- newValue.toLong() > 9_999L -> "9999"
- else -> newValue
- }
-
- it.copy(years = years)
+ fun updateYears(value: TextFieldValue) = _uiState.update {
+ it.copy(years = checkWithMax(value, 9_999L))
}
- fun updateMonths(newValue: String) = _uiState.update {
- val months = when {
- newValue.isEmpty() -> newValue
- newValue.toLong() > 9_999L -> "9999"
- else -> newValue
- }
-
- it.copy(months = months)
+ fun updateMonths(value: TextFieldValue) = _uiState.update {
+ it.copy(months = checkWithMax(value, 9_999L))
}
- fun updateDays(newValue: String) = _uiState.update {
- val days = when {
- newValue.isEmpty() -> newValue
- newValue.toLong() > 99_999L -> "99999"
- else -> newValue
- }
-
- it.copy(days = days)
+ fun updateDays(value: TextFieldValue) = _uiState.update {
+ it.copy(days = checkWithMax(value, 99_999L))
}
- fun updateHours(newValue: String) = _uiState.update {
- val hours = when {
- newValue.isEmpty() -> newValue
- newValue.toLong() > 9_999_999L -> "9999999"
- else -> newValue
- }
-
- it.copy(hours = hours)
+ fun updateHours(value: TextFieldValue) = _uiState.update {
+ it.copy(hours = checkWithMax(value, 9_999_999L))
}
- fun updateMinutes(newValue: String) = _uiState.update {
- val minutes = when {
- newValue.isEmpty() -> newValue
- newValue.toLong() > 99_999_999L -> "99999999"
- else -> newValue
- }
-
- it.copy(minutes = minutes)
+ fun updateMinutes(value: TextFieldValue) = _uiState.update {
+ it.copy(minutes = checkWithMax(value, 99_999_999L))
}
// BCE is not handled properly because who gives a shit...
- fun updateAddition(newValue: Boolean) = _uiState.update { it.copy(addition = newValue) }
+ fun updateAddition(newValue: Boolean) = _uiState.update {
+ it.copy(addition = newValue)
+ }
private fun updateResult() = viewModelScope.launch(Dispatchers.Default) {
// Gets canceled, works with latest _uiState only
_uiState.update { ui ->
val newResult = if (ui.addition) {
ui.start
- .plusYears(ui.years.ifEmpty { "0" }.toLong())
- .plusMonths(ui.months.ifEmpty { "0" }.toLong())
- .plusDays(ui.days.ifEmpty { "0" }.toLong())
- .plusHours(ui.hours.ifEmpty { "0" }.toLong())
- .plusMinutes(ui.minutes.ifEmpty { "0" }.toLong())
+ .plusYears(ui.years.text.ifEmpty { "0" }.toLong())
+ .plusMonths(ui.months.text.ifEmpty { "0" }.toLong())
+ .plusDays(ui.days.text.ifEmpty { "0" }.toLong())
+ .plusHours(ui.hours.text.ifEmpty { "0" }.toLong())
+ .plusMinutes(ui.minutes.text.ifEmpty { "0" }.toLong())
} else {
ui.start
- .minusYears(ui.years.ifEmpty { "0" }.toLong())
- .minusMonths(ui.months.ifEmpty { "0" }.toLong())
- .minusDays(ui.days.ifEmpty { "0" }.toLong())
- .minusHours(ui.hours.ifEmpty { "0" }.toLong())
- .minusMinutes(ui.minutes.ifEmpty { "0" }.toLong())
+ .minusYears(ui.years.text.ifEmpty { "0" }.toLong())
+ .minusMonths(ui.months.text.ifEmpty { "0" }.toLong())
+ .minusDays(ui.days.text.ifEmpty { "0" }.toLong())
+ .minusHours(ui.hours.text.ifEmpty { "0" }.toLong())
+ .minusMinutes(ui.minutes.text.ifEmpty { "0" }.toLong())
}
ui.copy(result = newResult)
}
}
+
+ private fun checkWithMax(value: TextFieldValue, maxValue: Long): TextFieldValue {
+ if (value.text.isEmpty()) return value
+ if (value.text.toLong() <= maxValue) return value
+ val maxValueText = maxValue.toString()
+ return TextFieldValue(maxValueText, TextRange(maxValueText.length))
+ }
}
diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/Keyboard.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/Keyboard.kt
new file mode 100644
index 00000000..59d11355
--- /dev/null
+++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/Keyboard.kt
@@ -0,0 +1,145 @@
+/*
+ * 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 .
+ */
+
+package com.sadellie.unitto.feature.datecalculator.components
+
+import androidx.compose.animation.Crossfade
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+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.unit.dp
+import com.sadellie.unitto.core.base.Token
+import com.sadellie.unitto.core.ui.common.KeyboardButtonFilled
+import com.sadellie.unitto.core.ui.common.KeyboardButtonLight
+import com.sadellie.unitto.core.ui.common.key.UnittoIcons
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Backspace
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Check
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Key0
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Key1
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Key2
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Key3
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Key4
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Key5
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Key6
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Key7
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Key8
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Key9
+import com.sadellie.unitto.core.ui.common.key.unittoicons.Tab
+import com.sadellie.unitto.core.ui.isPortrait
+
+@Composable
+internal fun AddSubtractKeyboard(
+ modifier: Modifier,
+ addSymbol: (String) -> Unit,
+ deleteSymbol: () -> Unit,
+ onConfirm: () -> Unit,
+ allowVibration: Boolean,
+ imeAction: ImeAction,
+ focusManager: FocusManager = LocalFocusManager.current
+) {
+ Row(modifier) {
+ val weightModifier = Modifier.weight(1f)
+ val mainButtonModifier = Modifier
+ .fillMaxSize()
+ .weight(1f)
+ .padding(4.dp)
+ val actionIconHeight = if (isPortrait()) 0.35f else 0.6f
+
+ fun keyboardAction() {
+ when (imeAction) {
+ ImeAction.Next -> focusManager.moveFocus(FocusDirection.Next)
+ else -> onConfirm()
+ }
+ }
+
+ Column(weightModifier) {
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key7, allowVibration) {
+ addSymbol(Token.Digit._7)
+ }
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key4, allowVibration) {
+ addSymbol(Token.Digit._4
+ )
+ }
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key1, allowVibration) {
+ addSymbol(Token.Digit._1)
+ }
+ Spacer(mainButtonModifier)
+ }
+
+ Column(weightModifier) {
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key8, allowVibration) {
+ addSymbol(Token.Digit._8)
+ }
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key5, allowVibration) {
+ addSymbol(Token.Digit._5)
+ }
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key2, allowVibration) {
+ addSymbol(Token.Digit._2)
+ }
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key0, allowVibration) {
+ addSymbol(Token.Digit._0)
+ }
+ }
+
+ Column(weightModifier) {
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key9, allowVibration) {
+ addSymbol(Token.Digit._9)
+ }
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key6, allowVibration) {
+ addSymbol(Token.Digit._6)
+ }
+ KeyboardButtonLight(mainButtonModifier, UnittoIcons.Key3, allowVibration) {
+ addSymbol(Token.Digit._3)
+ }
+ Spacer(mainButtonModifier)
+ }
+
+ Column(weightModifier) {
+ Crossfade(targetState = imeAction, modifier = mainButtonModifier) {
+ when (it) {
+ ImeAction.Next -> KeyboardButtonFilled(
+ Modifier.fillMaxSize(),
+ UnittoIcons.Tab,
+ allowVibration,
+ actionIconHeight
+ ) { keyboardAction() }
+ else -> KeyboardButtonFilled(
+ Modifier.fillMaxSize(),
+ UnittoIcons.Check,
+ allowVibration,
+ actionIconHeight
+ ) { keyboardAction() }
+ }
+ }
+ KeyboardButtonLight(
+ mainButtonModifier,
+ UnittoIcons.Backspace,
+ allowVibration,
+ actionIconHeight
+ ) { deleteSymbol() }
+ }
+ }
+}
diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/TimeUnitTextField.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/TimeUnitTextField.kt
index b6472698..8e63858e 100644
--- a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/TimeUnitTextField.kt
+++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/TimeUnitTextField.kt
@@ -22,7 +22,6 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Clear
import androidx.compose.material3.Icon
@@ -31,43 +30,39 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.input.ImeAction
-import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.platform.LocalTextInputService
+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
@Composable
internal fun TimeUnitTextField(
- value: String,
- onValueChange: (String) -> Unit,
+ modifier: Modifier,
+ value: TextFieldValue,
+ onValueChange: (TextFieldValue) -> Unit,
label: String,
- imeAction: ImeAction = ImeAction.Next,
formatterSymbols: FormatterSymbols
-) {
+) = CompositionLocalProvider(LocalTextInputService provides null) {
OutlinedTextField(
- modifier = Modifier.fillMaxWidth(),
+ modifier = modifier.fillMaxWidth(),
value = value,
onValueChange = { newValue ->
- onValueChange(newValue.filter { it.isDigit() })
+ onValueChange(newValue.copy(newValue.text.filter { it.isDigit() }))
},
label = { Text(label, color = MaterialTheme.colorScheme.onSurfaceVariant) },
trailingIcon = {
AnimatedVisibility(
- visible = value.isNotBlank(),
+ visible = value.text.isNotBlank(),
enter = scaleIn(),
exit = scaleOut()
) {
- IconButton(onClick = { onValueChange("") }) {
+ IconButton(onClick = { onValueChange(TextFieldValue()) }) {
Icon(Icons.Outlined.Clear, null)
}
}
},
- keyboardOptions = KeyboardOptions(
- autoCorrect = false,
- keyboardType = KeyboardType.Decimal,
- imeAction = imeAction
- ),
visualTransformation = ExpressionTransformer(formatterSymbols)
)
}