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 f91e66af..aa4493b4 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 @@ -20,25 +20,18 @@ package com.sadellie.unitto.core.ui.common import android.content.res.Configuration import android.view.HapticFeedbackConstants -import androidx.compose.animation.core.FastOutSlowInEasing -import androidx.compose.animation.core.animateIntAsState -import androidx.compose.animation.core.tween -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember +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 kotlinx.coroutines.launch @Composable fun BasicKeyboardButton( @@ -52,21 +45,21 @@ fun BasicKeyboardButton( contentHeight: Float ) { val view = LocalView.current - val interactionSource = remember { MutableInteractionSource() } - val isPressed by interactionSource.collectIsPressedAsState() - val cornerRadius: Int by animateIntAsState( - targetValue = if (isPressed) 30 else 50, - animationSpec = tween(easing = FastOutSlowInEasing), - ) + val coroutineScope = rememberCoroutineScope() UnittoButton( modifier = modifier, - onClick = onClick, + onClick = { + onClick() + if (allowVibration) { + coroutineScope.launch { + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) + } + } + }, onLongClick = onLongClick, - shape = RoundedCornerShape(cornerRadius), containerColor = containerColor, - contentPadding = PaddingValues(), - interactionSource = interactionSource + contentPadding = PaddingValues() ) { Icon( imageVector = icon, @@ -75,10 +68,6 @@ fun BasicKeyboardButton( tint = iconColor ) } - - LaunchedEffect(key1 = isPressed) { - if (isPressed and allowVibration) view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) - } } @Composable diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/ModifierExtensions.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/ModifierExtensions.kt new file mode 100644 index 00000000..bca4b685 --- /dev/null +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/ModifierExtensions.kt @@ -0,0 +1,83 @@ +/* + * 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 + +import androidx.compose.animation.core.FastOutSlowInEasing +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.animateIntAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsPressedAsState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.ripple.rememberRipple +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.draw.clip +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.Dp + +fun Modifier.squashable( + onClick: () -> Unit = {}, + onLongClick: (() -> Unit)? = null, + interactionSource: MutableInteractionSource, + cornerRadiusRange: IntRange, + role: Role = Role.Button, +) = composed { + val isPressed by interactionSource.collectIsPressedAsState() + val cornerRadius: Int by animateIntAsState( + targetValue = if (isPressed) cornerRadiusRange.first else cornerRadiusRange.last, + animationSpec = tween(easing = FastOutSlowInEasing), + ) + + Modifier + .clip(RoundedCornerShape(cornerRadius)) + .combinedClickable( + onClick = onClick, + onLongClick = onLongClick, + interactionSource = interactionSource, + indication = rememberRipple(), + role = role, + ) +} + +fun Modifier.squashable( + onClick: () -> Unit = {}, + onLongClick: (() -> Unit)? = null, + interactionSource: MutableInteractionSource, + cornerRadiusRange: ClosedRange, + role: Role = Role.Button, +) = composed { + val isPressed by interactionSource.collectIsPressedAsState() + val cornerRadius: Dp by animateDpAsState( + targetValue = if (isPressed) cornerRadiusRange.start else cornerRadiusRange.endInclusive, + animationSpec = tween(easing = FastOutSlowInEasing), + ) + + Modifier + .clip(RoundedCornerShape(cornerRadius)) + .combinedClickable( + onClick = onClick, + onLongClick = onLongClick, + interactionSource = interactionSource, + indication = rememberRipple(), + role = role, + ) +}