From 89b9e4a30d805a7fc8937190eb05f45f0b7bb4d0 Mon Sep 17 00:00:00 2001 From: sosauce2 <98750531+sosauce@users.noreply.github.com> Date: Thu, 6 Feb 2025 22:11:49 +0100 Subject: [PATCH] v2.4.0 --- app/build.gradle.kts | 4 +- app/src/main/AndroidManifest.xml | 4 +- .../main/java/com/sosauce/cutecalc/AppBar.kt | 157 ------------- .../sosauce/cutecalc/components/AboutCard.kt | 19 +- .../sosauce/cutecalc/components/CuteButton.kt | 35 ++- .../components/CuteNavigationButton.kt | 42 ++++ .../components/HistoryActionButtons.kt | 107 +++++++++ .../cutecalc/components/LongClickButton.kt | 173 ++++++++++++++ .../sosauce/cutecalc/components/Switches.kt | 217 +++++++++--------- .../cutecalc/history/HistoryViewModel.kt | 2 +- .../cutecalc/logic/CalculatorViewModel.kt | 13 +- .../com/sosauce/cutecalc/logic/Evaluator.kt | 21 +- .../com/sosauce/cutecalc/logic/Settings.kt | 5 + .../cutecalc/logic/navigation/Navigation.kt | 7 +- .../sosauce/cutecalc/screens/Calculator.kt | 99 +++++--- .../sosauce/cutecalc/screens/HistoryScreen.kt | 78 +++---- .../cutecalc/screens/LandscapeLayout.kt | 17 +- .../cutecalc/screens/SettingsScreen.kt | 34 +-- .../main/res/drawable/backspace_rounded.xml | 6 +- app/src/main/res/drawable/history_rounded.xml | 6 +- app/src/main/res/drawable/sort_rounded.xml | 6 +- app/src/main/res/drawable/trash_rounded.xml | 6 +- app/src/main/res/values-fr-rFR/strings.xml | 4 + app/src/main/res/values/strings.xml | 2 + 24 files changed, 623 insertions(+), 441 deletions(-) delete mode 100644 app/src/main/java/com/sosauce/cutecalc/AppBar.kt create mode 100644 app/src/main/java/com/sosauce/cutecalc/components/CuteNavigationButton.kt create mode 100644 app/src/main/java/com/sosauce/cutecalc/components/HistoryActionButtons.kt create mode 100644 app/src/main/java/com/sosauce/cutecalc/components/LongClickButton.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e7d4805..df30a1c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -13,8 +13,8 @@ android { applicationId = "com.sosauce.cutecalc" minSdk = 21 targetSdk = 35 - versionCode = 38 - versionName = "3.3.2" + versionCode = 39 + versionName = "3.4.0" } buildTypes { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7cd9388..07ff196 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,7 +3,8 @@ xmlns:tools="http://schemas.android.com/tools"> - + diff --git a/app/src/main/java/com/sosauce/cutecalc/AppBar.kt b/app/src/main/java/com/sosauce/cutecalc/AppBar.kt deleted file mode 100644 index 37cc187..0000000 --- a/app/src/main/java/com/sosauce/cutecalc/AppBar.kt +++ /dev/null @@ -1,157 +0,0 @@ -@file:OptIn(ExperimentalMaterial3Api::class) - -package com.sosauce.cutecalc - -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.rounded.ArrowBack -import androidx.compose.material.icons.rounded.Settings -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import com.sosauce.cutecalc.logic.navigation.Screens -import com.sosauce.cutecalc.logic.rememberSortHistoryASC -import com.sosauce.cutecalc.ui.theme.GlobalFont -import com.sosauce.cutecalc.utils.thenIf - -@Composable -fun AppBar( - title: @Composable () -> Unit = {}, - showBackArrow: Boolean, - showSortButton: Boolean = false, - onNavigate: (Screens) -> Unit, -) { - var dropDownExpanded by remember { mutableStateOf(false) } - var sortASC by rememberSortHistoryASC() - val surfaceContainer = MaterialTheme.colorScheme.surfaceContainer - - - TopAppBar( - title = title, - navigationIcon = { - if (showBackArrow) { - IconButton(onClick = { onNavigate(Screens.MAIN) }) { - Icon( - imageVector = Icons.AutoMirrored.Rounded.ArrowBack, - contentDescription = "Back arrow" - ) - } - } - }, - actions = { - if (!showBackArrow) { - Spacer(Modifier.width(5.dp)) - IconButton(onClick = { onNavigate(Screens.HISTORY) }) { - Icon( - painter = painterResource(R.drawable.history_rounded), - contentDescription = stringResource(R.string.history), - tint = MaterialTheme.colorScheme.onBackground - ) - } - IconButton(onClick = { onNavigate(Screens.SETTINGS) }) { - Icon( - imageVector = Icons.Rounded.Settings, - contentDescription = stringResource(R.string.settings), - tint = MaterialTheme.colorScheme.onBackground - ) - } - } - if (showSortButton) { - IconButton( - onClick = { dropDownExpanded = true } - ) { - Icon( - painter = painterResource(R.drawable.sort_rounded), - contentDescription = null - ) - } - DropdownMenu( - expanded = dropDownExpanded, - onDismissRequest = { dropDownExpanded = false }, - modifier = Modifier - .width(180.dp) - .background(MaterialTheme.colorScheme.surface), - shape = RoundedCornerShape(24.dp) - ) { - Column( - verticalArrangement = Arrangement.Center - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .height(56.dp) - .padding(5.dp) - .clip(RoundedCornerShape(12.dp)) - .clickable { sortASC = true } - .thenIf(sortASC) { - Modifier.background( - color = surfaceContainer, - shape = RoundedCornerShape(12.dp) - ) - }, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = stringResource(R.string.ascending), - fontFamily = GlobalFont, - modifier = Modifier.padding(start = 15.dp) - ) - } - Row( - modifier = Modifier - .fillMaxWidth() - .height(56.dp) - .padding(5.dp) - .clip(RoundedCornerShape(12.dp)) - .clickable { sortASC = false } - .thenIf(!sortASC) { - Modifier.background( - color = surfaceContainer, - shape = RoundedCornerShape(12.dp) - ) - }, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = stringResource(R.string.descending), - fontFamily = GlobalFont, - modifier = Modifier.padding(start = 15.dp) - ) - } - } - - } - } - } - ) -} - - - - - diff --git a/app/src/main/java/com/sosauce/cutecalc/components/AboutCard.kt b/app/src/main/java/com/sosauce/cutecalc/components/AboutCard.kt index 086e30f..8f8c424 100644 --- a/app/src/main/java/com/sosauce/cutecalc/components/AboutCard.kt +++ b/app/src/main/java/com/sosauce/cutecalc/components/AboutCard.kt @@ -6,12 +6,12 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -22,7 +22,6 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.sosauce.cutecalc.R -import com.sosauce.cutecalc.ui.theme.GlobalFont import com.sosauce.cutecalc.utils.GITHUB_RELEASES @Composable @@ -35,6 +34,7 @@ fun AboutCard() { Card( colors = CardDefaults.cardColors(MaterialTheme.colorScheme.surfaceContainer), modifier = Modifier + .statusBarsPadding() .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 2.dp), shape = RoundedCornerShape(24.dp) @@ -49,13 +49,9 @@ fun AboutCard() { .clip(RoundedCornerShape(15)) ) Column { - Text( - text = stringResource(R.string.cc_by_sosauce), - fontFamily = GlobalFont - ) - Text( + CuteText(stringResource(R.string.cc_by_sosauce)) + CuteText( text = "${stringResource(R.string.version)} $version", - fontFamily = GlobalFont, color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.85f) ) } @@ -69,12 +65,7 @@ fun AboutCard() { onClick = { uriHandler.openUri(GITHUB_RELEASES) }, shape = RoundedCornerShape(24.dp), modifier = Modifier.fillMaxWidth() - ) { - Text( - text = stringResource(R.string.update), - fontFamily = GlobalFont - ) - } + ) { CuteText(stringResource(R.string.update)) } } } } diff --git a/app/src/main/java/com/sosauce/cutecalc/components/CuteButton.kt b/app/src/main/java/com/sosauce/cutecalc/components/CuteButton.kt index da9a52d..88a4763 100644 --- a/app/src/main/java/com/sosauce/cutecalc/components/CuteButton.kt +++ b/app/src/main/java/com/sosauce/cutecalc/components/CuteButton.kt @@ -1,6 +1,9 @@ +@file:OptIn(ExperimentalFoundationApi::class) + package com.sosauce.cutecalc.components import androidx.compose.animation.core.animateIntAsState +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.foundation.layout.size @@ -10,7 +13,6 @@ import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember @@ -24,15 +26,16 @@ import androidx.compose.ui.unit.sp import com.sosauce.cutecalc.R import com.sosauce.cutecalc.logic.rememberUseButtonsAnimation import com.sosauce.cutecalc.logic.rememberVibration -import com.sosauce.cutecalc.ui.theme.GlobalFont @Composable fun CuteButton( modifier: Modifier = Modifier, text: String, color: ButtonColors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.surfaceContainer), + onClick: () -> Unit, - textColor: Color = MaterialTheme.colorScheme.onBackground + textColor: Color = MaterialTheme.colorScheme.onBackground, + enabled: Boolean = true ) { val shouldVibrate by rememberVibration() val useButtonsAnimation by rememberUseButtonsAnimation() @@ -52,21 +55,23 @@ fun CuteButton( colors = color, modifier = modifier, shape = RoundedCornerShape(cornerRadius), - interactionSource = interactionSource + interactionSource = interactionSource, + enabled = enabled ) { - Text( + CuteText( text = text, color = textColor, - fontSize = 35.sp, - fontFamily = GlobalFont + fontSize = 35.sp ) } } +@OptIn(ExperimentalFoundationApi::class) @Composable fun CuteIconButton( modifier: Modifier, onClick: () -> Unit, + onLongClick: () -> Unit = {}, color: ButtonColors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.surfaceContainer) ) { val shouldVibrate by rememberVibration() @@ -79,11 +84,16 @@ fun CuteIconButton( targetValue = if (isPressed && useButtonsAnimation) 24 else 50, label = "" ) - Button( + + LongClickButton( onClick = { onClick() if (shouldVibrate) haptic.performHapticFeedback(HapticFeedbackType.LongPress) }, + onLongClick = { + onLongClick() + if (shouldVibrate) haptic.performHapticFeedback(HapticFeedbackType.LongPress) + }, colors = color, modifier = modifier, shape = RoundedCornerShape(cornerRadius), @@ -96,4 +106,11 @@ fun CuteIconButton( modifier = Modifier.size(45.dp) ) } -} \ No newline at end of file + + +} + + + + + diff --git a/app/src/main/java/com/sosauce/cutecalc/components/CuteNavigationButton.kt b/app/src/main/java/com/sosauce/cutecalc/components/CuteNavigationButton.kt new file mode 100644 index 0000000..9c41686 --- /dev/null +++ b/app/src/main/java/com/sosauce/cutecalc/components/CuteNavigationButton.kt @@ -0,0 +1,42 @@ +package com.sosauce.cutecalc.components + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.rounded.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedIconButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.sosauce.cutecalc.logic.navigation.Screens + +@Composable +fun BoxScope.CuteNavigationButton( + onNavigate: (Screens) -> Unit +) { + OutlinedIconButton( + onClick = { onNavigate(Screens.MAIN) }, + modifier = Modifier + .padding(start = 15.dp) + .align(Alignment.BottomStart) + .navigationBarsPadding(), + colors = IconButtonDefaults.iconButtonColors( + containerColor = MaterialTheme.colorScheme.background, + ), + border = BorderStroke( + width = 1.dp, + color = MaterialTheme.colorScheme.onBackground.copy(0.2f) + ) + ) { + Icon( + imageVector = Icons.AutoMirrored.Rounded.ArrowBack, + contentDescription = null + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sosauce/cutecalc/components/HistoryActionButtons.kt b/app/src/main/java/com/sosauce/cutecalc/components/HistoryActionButtons.kt new file mode 100644 index 0000000..960b924 --- /dev/null +++ b/app/src/main/java/com/sosauce/cutecalc/components/HistoryActionButtons.kt @@ -0,0 +1,107 @@ +package com.sosauce.cutecalc.components + +import androidx.compose.animation.AnimatedContent +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Close +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.sosauce.cutecalc.R +import com.sosauce.cutecalc.logic.rememberSortHistoryASC +import com.sosauce.cutecalc.utils.thenIf + +@Composable +fun BoxScope.HistoryActionButtons( + onDeleteHistory: () -> Unit +) { + var dropDownExpanded by remember { mutableStateOf(false) } + var sortASC by rememberSortHistoryASC() + val surfaceContainer = MaterialTheme.colorScheme.surfaceContainer + val sorting = remember { + listOf( + R.string.ascending, + R.string.descending + ) + } + + Row( + modifier = Modifier + .padding(end = 15.dp) + .align(Alignment.BottomEnd) + .clip(RoundedCornerShape(24.dp)) + .border( + width = 1.dp, + color = MaterialTheme.colorScheme.onBackground.copy(0.2f), + shape = RoundedCornerShape(24.dp) + ) + .navigationBarsPadding() + ) { + IconButton( + onClick = { dropDownExpanded = true } + ) { + AnimatedContent( + targetState = !dropDownExpanded + ) { + Icon( + painter = if (it) painterResource(R.drawable.sort_rounded) else rememberVectorPainter( + Icons.Rounded.Close + ), + contentDescription = null + ) + } + } + IconButton( + onClick = onDeleteHistory + ) { + Icon( + painter = painterResource(R.drawable.trash_rounded), + contentDescription = null + ) + } + + DropdownMenu( + expanded = dropDownExpanded, + onDismissRequest = { dropDownExpanded = false }, + modifier = Modifier + .background(MaterialTheme.colorScheme.surface), + shape = RoundedCornerShape(24.dp) + ) { + sorting.forEach { + DropdownMenuItem( + text = { CuteText(stringResource(it)) }, + onClick = { sortASC = it == R.string.descending }, + modifier = Modifier + .padding(5.dp) + .clip(RoundedCornerShape(12.dp)) + .thenIf((!sortASC && it == R.string.ascending) || (sortASC && it == R.string.descending)) { + Modifier.background( + color = surfaceContainer, + shape = RoundedCornerShape(12.dp) + ) + } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sosauce/cutecalc/components/LongClickButton.kt b/app/src/main/java/com/sosauce/cutecalc/components/LongClickButton.kt new file mode 100644 index 0000000..7f50d9c --- /dev/null +++ b/app/src/main/java/com/sosauce/cutecalc/components/LongClickButton.kt @@ -0,0 +1,173 @@ +@file:OptIn(ExperimentalFoundationApi::class) + +package com.sosauce.cutecalc.components + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ButtonColors +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ColorScheme +import androidx.compose.material3.LocalAbsoluteTonalElevation +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.LocalTonalElevationEnabled +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.contentColorFor +import androidx.compose.material3.minimumInteractiveComponentSize +import androidx.compose.material3.surfaceColorAtElevation +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.NonRestartableComposable +import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.sosauce.cutecalc.utils.thenIf + + +@Composable +fun LongClickButton( + onClick: () -> Unit, + onLongClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + shape: Shape = ButtonDefaults.shape, + colors: ButtonColors = ButtonDefaults.buttonColors(), + border: BorderStroke? = null, + contentPadding: PaddingValues = ButtonDefaults.ContentPadding, + interactionSource: MutableInteractionSource? = null, + content: @Composable RowScope.() -> Unit +) { + @Suppress("NAME_SHADOWING") + val interactionSource = interactionSource ?: remember { MutableInteractionSource() } + + CustomSurface( + onClick = onClick, + onLongClick = onLongClick, + modifier = modifier.semantics { role = Role.Button }, + enabled = enabled, + shape = shape, + color = colors.containerColor, + contentColor = colors.contentColor, + border = border, + interactionSource = interactionSource + ) { + Row( + Modifier + .defaultMinSize( + minWidth = ButtonDefaults.MinWidth, + minHeight = ButtonDefaults.MinHeight + ) + .padding(contentPadding), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + content = content + ) + } +} + +// The below code is just to create a long clickable button, thanks for all the "internal" Google :) +@Composable +@NonRestartableComposable +private fun CustomSurface( + onClick: () -> Unit, + onLongClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + shape: Shape = RectangleShape, + color: Color = MaterialTheme.colorScheme.surface, + contentColor: Color = contentColorFor(color), + tonalElevation: Dp = 0.dp, + shadowElevation: Dp = 0.dp, + border: BorderStroke? = null, + interactionSource: MutableInteractionSource? = null, + content: @Composable () -> Unit +) { + val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation + CompositionLocalProvider( + LocalContentColor provides contentColor, + LocalAbsoluteTonalElevation provides absoluteElevation + ) { + Box( + modifier = + modifier + .minimumInteractiveComponentSize() + .surface( + shape = shape, + backgroundColor = + surfaceColorAtElevation(color = color, elevation = absoluteElevation), + border = border, + shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() } + ) + .combinedClickable( + interactionSource = interactionSource, + indication = null, + enabled = enabled, + onClick = onClick, + onLongClick = onLongClick + + ), + propagateMinConstraints = true + ) { + content() + } + } +} + +@Stable +private fun Modifier.surface( + shape: Shape, + backgroundColor: Color, + border: BorderStroke?, + shadowElevation: Float, +) = + + this + .thenIf(shadowElevation > 0f) { + Modifier.graphicsLayer( + shadowElevation = shadowElevation, + shape = shape, + clip = false + ) + } + .then(if (border != null) Modifier.border(border, shape) else Modifier) + .background(color = backgroundColor, shape = shape) + .clip(shape) + +@Composable +private fun surfaceColorAtElevation(color: Color, elevation: Dp): Color = + MaterialTheme.colorScheme.applyTonalElevation(color, elevation) + + +@Composable +@ReadOnlyComposable +internal fun ColorScheme.applyTonalElevation(backgroundColor: Color, elevation: Dp): Color { + val tonalElevationEnabled = LocalTonalElevationEnabled.current + return if (backgroundColor == surface && tonalElevationEnabled) { + surfaceColorAtElevation(elevation) + } else { + backgroundColor + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sosauce/cutecalc/components/Switches.kt b/app/src/main/java/com/sosauce/cutecalc/components/Switches.kt index 1937f86..d85d91f 100644 --- a/app/src/main/java/com/sosauce/cutecalc/components/Switches.kt +++ b/app/src/main/java/com/sosauce/cutecalc/components/Switches.kt @@ -1,170 +1,164 @@ package com.sosauce.cutecalc.components import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.slideInHorizontally -import androidx.compose.animation.slideOutHorizontally import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Info import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Switch -import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue +import androidx.compose.runtime.MutableState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import com.sosauce.cutecalc.R import com.sosauce.cutecalc.logic.rememberDecimal import com.sosauce.cutecalc.logic.rememberFollowSys +import com.sosauce.cutecalc.logic.rememberShowClearButton import com.sosauce.cutecalc.logic.rememberUseAmoledMode import com.sosauce.cutecalc.logic.rememberUseButtonsAnimation import com.sosauce.cutecalc.logic.rememberUseDarkMode import com.sosauce.cutecalc.logic.rememberUseHistory import com.sosauce.cutecalc.logic.rememberUseSystemFont import com.sosauce.cutecalc.logic.rememberVibration -import com.sosauce.cutecalc.ui.theme.GlobalFont - +import kotlin.collections.component1 +import kotlin.collections.component2 + + +//@Composable +//fun History() { +// var enableHistory by rememberUseHistory() +// +// Column { +// CuteText( +// text = stringResource(R.string.history), +// color = MaterialTheme.colorScheme.primary, +// modifier = Modifier.padding(horizontal = 34.dp, vertical = 8.dp) +// ) +// +// SettingsCards( +// checked = enableHistory, +// onCheckedChange = { enableHistory = !enableHistory }, +// topDp = 24.dp, +// bottomDp = 24.dp, +// text = stringResource(R.string.use_history) +// ) +// } +//} @Composable -fun History() { - var enableHistory by rememberUseHistory() +fun UI() { + val settings = mapOf>( + R.string.buttons_anim to rememberUseButtonsAnimation(), + R.string.show_clear_button to rememberShowClearButton(), + R.string.use_sys_font to rememberUseSystemFont() + ) Column { - Text( - text = stringResource(R.string.history), - fontFamily = GlobalFont, + CuteText( + text = "UI", color = MaterialTheme.colorScheme.primary, modifier = Modifier.padding(horizontal = 34.dp, vertical = 8.dp) ) - SettingsCards( - checked = enableHistory, - onCheckedChange = { enableHistory = !enableHistory }, - topDp = 24.dp, - bottomDp = 24.dp, - text = stringResource(R.string.use_history) - ) + settings.onEachIndexed { index, (text, setting) -> + SettingsCards( + checked = setting.value, + onCheckedChange = { setting.value = !setting.value }, + topDp = if (index == 0) 24.dp else 4.dp, + bottomDp = if (index == settings.size - 1) 24.dp else 4.dp, + text = stringResource(text), + optionalDescription = { + if (text == R.string.show_clear_button) { + CuteText( + text = stringResource(R.string.clear_button_desc), + color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.85f), + fontSize = 12.sp + ) + } + } + ) + } } } @Composable fun Misc() { - var decimalSetting by rememberDecimal() - var buttonVibrationSetting by rememberVibration() - var useButtonsAnimation by rememberUseButtonsAnimation() - var useSystemFont by rememberUseSystemFont() - + val settings = mapOf>( + R.string.use_history to rememberUseHistory(), + R.string.decimal_formatting to rememberDecimal(), + R.string.haptic_feedback to rememberVibration(), + ) Column { - Text( + CuteText( text = stringResource(R.string.misc), - fontFamily = GlobalFont, color = MaterialTheme.colorScheme.primary, modifier = Modifier.padding(horizontal = 34.dp, vertical = 8.dp) ) - - SettingsCards( - checked = decimalSetting, - onCheckedChange = { decimalSetting = !decimalSetting }, - topDp = 24.dp, - bottomDp = 4.dp, - text = stringResource(R.string.decimal_formatting) - ) - SettingsCards( - checked = useSystemFont, - onCheckedChange = { useSystemFont = !useSystemFont }, - topDp = 4.dp, - bottomDp = 4.dp, - text = stringResource(R.string.use_sys_font) - ) - SettingsCards( - checked = useButtonsAnimation, - onCheckedChange = { useButtonsAnimation = !useButtonsAnimation }, - topDp = 4.dp, - bottomDp = 4.dp, - text = stringResource(R.string.buttons_anim) - ) - SettingsCards( - checked = buttonVibrationSetting, - onCheckedChange = { buttonVibrationSetting = !buttonVibrationSetting }, - topDp = 4.dp, - bottomDp = 24.dp, - text = stringResource(R.string.haptic_feedback) - ) + settings.onEachIndexed { index, (text, setting) -> + SettingsCards( + checked = setting.value, + onCheckedChange = { setting.value = !setting.value }, + topDp = if (index == 0) 24.dp else 4.dp, + bottomDp = if (index == settings.size - 1) 24.dp else 4.dp, + text = stringResource(text) + ) + } } } @Composable fun ThemeManagement() { - var darkMode by rememberUseDarkMode() - var amoledMode by rememberUseAmoledMode() - var followSys by rememberFollowSys() + + val settings = mapOf>( + R.string.follow_sys to rememberFollowSys(), + R.string.dark_mode to rememberUseDarkMode(), + R.string.amoled_mode to rememberUseAmoledMode(), + ) + Column { - Text( + CuteText( text = stringResource(R.string.theme), - fontFamily = GlobalFont, color = MaterialTheme.colorScheme.primary, modifier = Modifier.padding(horizontal = 34.dp, vertical = 8.dp) ) - SettingsCards( - checked = followSys, - onCheckedChange = { followSys = !followSys }, - topDp = 24.dp, - bottomDp = 4.dp, - text = stringResource(R.string.follow_sys) - ) - AnimatedVisibility( - visible = !followSys, - enter = slideInHorizontally() + fadeIn(), - exit = slideOutHorizontally() + fadeOut() - ) { - SettingsCards( - checked = darkMode, - onCheckedChange = { darkMode = !darkMode }, - topDp = 4.dp, - bottomDp = 4.dp, - text = stringResource(R.string.dark_mode) - ) + + settings.onEachIndexed { index, (text, setting) -> + AnimatedVisibility( + visible = text != R.string.dark_mode || !rememberFollowSys().value + ) { + SettingsCards( + checked = setting.value, + onCheckedChange = { setting.value = !setting.value }, + topDp = if (index == 0) 24.dp else 4.dp, + bottomDp = if (index == settings.size - 1) 24.dp else 4.dp, + text = stringResource(text) + ) + } } - SettingsCards( - checked = amoledMode, - onCheckedChange = { amoledMode = !amoledMode }, - topDp = 4.dp, - bottomDp = 24.dp, - text = stringResource(R.string.amoled_mode) - ) } } @Composable -private fun SettingsCards( - hasInfoDialog: Boolean = false, +fun SettingsCards( checked: Boolean, - onCheckedChange: () -> Unit, - onClick: (() -> Unit)? = null, topDp: Dp, bottomDp: Dp, - text: String + text: String, + onCheckedChange: () -> Unit, + optionalDescription: @Composable () -> Unit = {} ) { Card( colors = CardDefaults.cardColors(MaterialTheme.colorScheme.surfaceContainer), modifier = Modifier - .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 2.dp), shape = RoundedCornerShape( topStart = topDp, @@ -178,22 +172,17 @@ private fun SettingsCards( horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier .padding(15.dp) - .fillMaxWidth() ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Text( - text = text, - fontFamily = GlobalFont - ) - if (hasInfoDialog) { - IconButton( - onClick = { onClick?.invoke() } - ) { - Icon( - imageVector = Icons.Outlined.Info, - contentDescription = "Info Button" - ) - } + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .weight(1f) + ) { + Column { + CuteText( + text = text + ) + optionalDescription() } } Switch( diff --git a/app/src/main/java/com/sosauce/cutecalc/history/HistoryViewModel.kt b/app/src/main/java/com/sosauce/cutecalc/history/HistoryViewModel.kt index 05606a4..369f5c0 100644 --- a/app/src/main/java/com/sosauce/cutecalc/history/HistoryViewModel.kt +++ b/app/src/main/java/com/sosauce/cutecalc/history/HistoryViewModel.kt @@ -28,7 +28,7 @@ class HistoryViewModel( is HistoryEvents.AddCalculation -> { // Only save to history calculations that are not any kind of errors - if (state.value.result.value.all { it.isDigit() || it == '.' || it == '-' || it == ','}) { + if (state.value.result.value.all { it.isDigit() || it == '.' || it == '-' || it == ',' }) { val calculation = Calculation( operation = state.value.operation.value, result = state.value.result.value diff --git a/app/src/main/java/com/sosauce/cutecalc/logic/CalculatorViewModel.kt b/app/src/main/java/com/sosauce/cutecalc/logic/CalculatorViewModel.kt index 4d8a664..f72569b 100644 --- a/app/src/main/java/com/sosauce/cutecalc/logic/CalculatorViewModel.kt +++ b/app/src/main/java/com/sosauce/cutecalc/logic/CalculatorViewModel.kt @@ -10,19 +10,18 @@ import androidx.compose.ui.text.input.getSelectedText import androidx.compose.ui.text.input.getTextAfterSelection import androidx.compose.ui.text.input.getTextBeforeSelection import androidx.lifecycle.ViewModel +import kotlin.text.all class CalcViewModel : ViewModel() { var displayText by mutableStateOf(TextFieldValue("")) - private val processedText by derivedStateOf { - displayText.text.replace("π", "PI") - } val preview by derivedStateOf { - when (displayText) { - TextFieldValue("") -> "" - else -> "= ${Evaluator.eval(processedText)}" - } + val evaluatedText = Evaluator.eval(displayText.text.replace("π", "PI")) + + if (evaluatedText.all { it.isDigit() || it == '.' || it == '-' || it == ',' }) { + "= $evaluatedText" + } else "" } val parenthesis by derivedStateOf { if (displayText.text.count { it == '(' } > displayText.text.count { it == ')' }) ")" else "(" diff --git a/app/src/main/java/com/sosauce/cutecalc/logic/Evaluator.kt b/app/src/main/java/com/sosauce/cutecalc/logic/Evaluator.kt index 8fbd67f..b7b6e2e 100644 --- a/app/src/main/java/com/sosauce/cutecalc/logic/Evaluator.kt +++ b/app/src/main/java/com/sosauce/cutecalc/logic/Evaluator.kt @@ -94,7 +94,7 @@ object Evaluator { @JvmStatic fun eval(formula: String): String = try { - val result = KEVAL.eval(formula) + val result = KEVAL.eval(formula.calculateRelativePercentage()) if (result > Double.MAX_VALUE) { throw ValueTooLargeException() } else { @@ -110,4 +110,23 @@ object Evaluator { "Error" } + fun String.calculateRelativePercentage(): String { + val regex = Regex("""(\d+(?:\.\d+)?)\s*([+\-*])\s*(\d+(?:\.\d+)?)%""") + + return regex.replace(this) { match -> + val firstOperand = match.groupValues[1].toDouble() + val operator = match.groupValues[2] + val percentage = match.groupValues[3].toDouble() + + when (operator) { + "+" -> "$firstOperand + ($firstOperand * $percentage / 100)" + "-" -> "$firstOperand - ($firstOperand * $percentage / 100)" + "*" -> "$firstOperand * ($percentage / 100)" + else -> "$firstOperand" + } + + } + } + + } diff --git a/app/src/main/java/com/sosauce/cutecalc/logic/Settings.kt b/app/src/main/java/com/sosauce/cutecalc/logic/Settings.kt index ecb0dbc..c0dd929 100644 --- a/app/src/main/java/com/sosauce/cutecalc/logic/Settings.kt +++ b/app/src/main/java/com/sosauce/cutecalc/logic/Settings.kt @@ -20,6 +20,7 @@ data object PreferencesKeys { val SORT_HISTORY_ASC = booleanPreferencesKey("sort_history_asc") val USE_BUTTONS_ANIMATIONS = booleanPreferencesKey("use_buttons_animation") val USE_SYSTEM_FONT = booleanPreferencesKey("use_system_font") + val SHOW_CLEAR_BUTTON = booleanPreferencesKey("show_clear_button") } @Composable @@ -58,3 +59,7 @@ fun rememberUseButtonsAnimation() = fun rememberUseSystemFont() = rememberPreference(key = PreferencesKeys.USE_SYSTEM_FONT, defaultValue = false) +@Composable +fun rememberShowClearButton() = + rememberPreference(key = PreferencesKeys.SHOW_CLEAR_BUTTON, defaultValue = true) + diff --git a/app/src/main/java/com/sosauce/cutecalc/logic/navigation/Navigation.kt b/app/src/main/java/com/sosauce/cutecalc/logic/navigation/Navigation.kt index 852794f..024d25d 100644 --- a/app/src/main/java/com/sosauce/cutecalc/logic/navigation/Navigation.kt +++ b/app/src/main/java/com/sosauce/cutecalc/logic/navigation/Navigation.kt @@ -1,6 +1,7 @@ package com.sosauce.cutecalc.logic.navigation import androidx.activity.compose.BackHandler +import androidx.activity.compose.LocalActivity import androidx.compose.animation.AnimatedContent import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -10,10 +11,8 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel -import com.sosauce.cutecalc.MainActivity import com.sosauce.cutecalc.history.HistoryViewModel import com.sosauce.cutecalc.logic.CalcViewModel import com.sosauce.cutecalc.screens.CalculatorUI @@ -27,7 +26,7 @@ import com.sosauce.cutecalc.screens.SettingsScreen fun Nav(historyViewModel: HistoryViewModel) { - val activity = (LocalContext.current as MainActivity) + val activity = LocalActivity.current var screenToDisplay by rememberSaveable { mutableStateOf(Screens.MAIN) } val viewModel = viewModel() val historyState by historyViewModel.state.collectAsStateWithLifecycle() @@ -38,7 +37,7 @@ fun Nav(historyViewModel: HistoryViewModel) { if (screenToDisplay != Screens.MAIN) { screenToDisplay = Screens.MAIN } else { - activity.moveTaskToBack(true) + activity?.moveTaskToBack(true) } } diff --git a/app/src/main/java/com/sosauce/cutecalc/screens/Calculator.kt b/app/src/main/java/com/sosauce/cutecalc/screens/Calculator.kt index c7f008a..1d2e682 100644 --- a/app/src/main/java/com/sosauce/cutecalc/screens/Calculator.kt +++ b/app/src/main/java/com/sosauce/cutecalc/screens/Calculator.kt @@ -1,8 +1,9 @@ +@file:OptIn(ExperimentalMaterial3Api::class) + package com.sosauce.cutecalc.screens import android.annotation.SuppressLint import android.content.res.Configuration -import android.widget.EditText import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -15,9 +16,15 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Settings import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf @@ -28,17 +35,16 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.InterceptPlatformTextInput import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.compose.ui.viewinterop.AndroidView -import androidx.core.content.res.ResourcesCompat -import com.sosauce.cutecalc.AppBar import com.sosauce.cutecalc.R import com.sosauce.cutecalc.components.CuteButton import com.sosauce.cutecalc.components.CuteIconButton +import com.sosauce.cutecalc.components.CuteText import com.sosauce.cutecalc.history.HistoryEvents import com.sosauce.cutecalc.history.HistoryState import com.sosauce.cutecalc.history.HistoryViewModel @@ -48,8 +54,11 @@ import com.sosauce.cutecalc.logic.Evaluator import com.sosauce.cutecalc.logic.formatOrNot import com.sosauce.cutecalc.logic.navigation.Screens import com.sosauce.cutecalc.logic.rememberDecimal +import com.sosauce.cutecalc.logic.rememberShowClearButton import com.sosauce.cutecalc.logic.rememberUseHistory +import com.sosauce.cutecalc.logic.rememberUseSystemFont import com.sosauce.cutecalc.ui.theme.GlobalFont +import kotlinx.coroutines.awaitCancellation @SuppressLint("NewApi") @@ -63,13 +72,19 @@ fun CalculatorUI( val config = LocalConfiguration.current val portraitMode by remember { mutableIntStateOf(config.orientation) } val saveToHistory by rememberUseHistory() + val useSystemFont by rememberUseSystemFont() + val showClearButton by rememberShowClearButton() val firstRow = listOf("!", "%", "√", "π") - val secondRow = listOf("C", viewModel.parenthesis, "^", "/") + val secondRow = listOf( + if (showClearButton) "C" else "(", + if (showClearButton) viewModel.parenthesis else ")", + "^", + "/" + ) val thirdRow = listOf("7", "8", "9", "×") val fourthRow = listOf("4", "5", "6", "-") val fifthRow = listOf("1", "2", "3", "+") val sixthRow = listOf("0", ".") - val textColor = MaterialTheme.colorScheme.onBackground val decimalSetting by rememberDecimal() @@ -84,9 +99,24 @@ fun CalculatorUI( Scaffold( topBar = { - AppBar( - showBackArrow = false, - onNavigate = { onNavigate(it) } + TopAppBar( + title = {}, + actions = { + IconButton(onClick = { onNavigate(Screens.HISTORY) }) { + Icon( + painter = painterResource(R.drawable.history_rounded), + contentDescription = stringResource(R.string.history), + tint = MaterialTheme.colorScheme.onBackground + ) + } + IconButton(onClick = { onNavigate(Screens.SETTINGS) }) { + Icon( + imageVector = Icons.Rounded.Settings, + contentDescription = stringResource(R.string.settings), + tint = MaterialTheme.colorScheme.onBackground + ) + } + } ) } ) { pv -> @@ -111,25 +141,10 @@ fun CalculatorUI( .align(Alignment.End) .horizontalScroll(rememberScrollState()) ) { - AndroidView( - factory = { context -> - EditText(context).apply { - isFocusable = false - isFocusableInTouchMode = false - isSingleLine = true - showSoftInputOnFocus = false - textSize = 32f - maxLines = 1 - background = null - setTextColor(textColor.copy(0.7f).hashCode()) - setTypeface(ResourcesCompat.getFont(context, R.font.nunito)) - } - }, - update = { view -> - view.setText(formatOrNot(viewModel.preview, decimalSetting)) - // Added decimal points and comma need to be taken account for ! - view.setSelection(formatOrNot(viewModel.preview, decimalSetting).length) - } + CuteText( + text = formatOrNot(viewModel.preview, decimalSetting), + fontSize = 32.sp, + color = MaterialTheme.colorScheme.onBackground.copy(0.85f) ) } Row( @@ -138,17 +153,23 @@ fun CalculatorUI( ) { DisableSoftKeyboard { BasicTextField( - value = TextFieldValue(formatOrNot(viewModel.displayText.text, decimalSetting)), + value = viewModel.displayText.copy( + text = formatOrNot( + viewModel.displayText.text, + decimalSetting + ) + ), // Use copy function to keep the correct range, or else the cursor will just stick to the start everytime onValueChange = { viewModel.displayText = it }, singleLine = true, textStyle = TextStyle( textAlign = TextAlign.End, color = MaterialTheme.colorScheme.onBackground, fontSize = 53.sp, - fontFamily = GlobalFont + fontFamily = if (!useSystemFont) GlobalFont else null ), cursorBrush = SolidColor(MaterialTheme.colorScheme.onBackground), ) + } } Row( @@ -290,6 +311,9 @@ fun CalculatorUI( .weight(1f), onClick = { viewModel.handleAction(CalcAction.Backspace) + }, + onLongClick = { + viewModel.handleAction(CalcAction.ResetField) } ) CuteButton( @@ -324,11 +348,18 @@ fun CalculatorUI( // https://stackoverflow.com/a/78720287 @OptIn(ExperimentalComposeUiApi::class) @Composable -fun DisableSoftKeyboard(content: @Composable () -> Unit) { +fun DisableSoftKeyboard( + disable: Boolean = true, + content: @Composable () -> Unit, +) { InterceptPlatformTextInput( interceptor = { request, nextHandler -> - nextHandler.startInputMethod(request) + if (!disable) { + nextHandler.startInputMethod(request) + } else { + awaitCancellation() + } }, - content = content + content = content, ) } \ No newline at end of file diff --git a/app/src/main/java/com/sosauce/cutecalc/screens/HistoryScreen.kt b/app/src/main/java/com/sosauce/cutecalc/screens/HistoryScreen.kt index e94fc24..a8650ad 100644 --- a/app/src/main/java/com/sosauce/cutecalc/screens/HistoryScreen.kt +++ b/app/src/main/java/com/sosauce/cutecalc/screens/HistoryScreen.kt @@ -2,6 +2,7 @@ package com.sosauce.cutecalc.screens import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -9,19 +10,18 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember @@ -34,8 +34,10 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.sosauce.cutecalc.AppBar import com.sosauce.cutecalc.R +import com.sosauce.cutecalc.components.CuteNavigationButton +import com.sosauce.cutecalc.components.CuteText +import com.sosauce.cutecalc.components.HistoryActionButtons import com.sosauce.cutecalc.history.Calculation import com.sosauce.cutecalc.history.HistoryEvents import com.sosauce.cutecalc.history.HistoryState @@ -44,7 +46,7 @@ import com.sosauce.cutecalc.logic.navigation.Screens import com.sosauce.cutecalc.logic.rememberDecimal import com.sosauce.cutecalc.logic.rememberSortHistoryASC import com.sosauce.cutecalc.logic.rememberUseHistory -import com.sosauce.cutecalc.ui.theme.GlobalFont +import com.sosauce.cutecalc.utils.thenIf @Composable fun HistoryScreen( @@ -64,33 +66,11 @@ fun HistoryScreen( } } - Scaffold( - topBar = { - AppBar( - showBackArrow = true, - showSortButton = true, - onNavigate = onNavigate, - title = { - Text( - text = stringResource(R.string.history), - fontFamily = GlobalFont - ) - } - ) - }, - floatingActionButton = { - if (isHistoryEnable) { - FloatingActionButton( - onClick = { onEvents(HistoryEvents.DeleteAllCalculation(state.calculation)) } - ) { - Icon( - painter = painterResource(R.drawable.trash_rounded), - contentDescription = null - ) - } - } - } - ) { values -> + LaunchedEffect(Unit) { + println("history size: ${sortedCalculations.size}") + } + + Box(Modifier.fillMaxSize()) { if (!isHistoryEnable) { Column( modifier = Modifier @@ -98,26 +78,16 @@ fun HistoryScreen( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { - Text( - text = stringResource(R.string.history_not_enabled), - fontFamily = GlobalFont - ) + CuteText(stringResource(R.string.history_not_enabled)) Spacer(Modifier.height(10.dp)) Button( onClick = { isHistoryEnable = !isHistoryEnable } ) { - Text( - text = stringResource(R.string.enable_history), - fontFamily = GlobalFont - ) + CuteText(stringResource(R.string.enable_history)) } } } else { - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(values) - ) { + LazyColumn { itemsIndexed( items = sortedCalculations, key = { _, item -> item.id } @@ -127,11 +97,17 @@ fun HistoryScreen( onEvents = onEvents, topDp = if (index == 0) 24.dp else 4.dp, bottomDp = if (index == state.calculation.size - 1) 24.dp else 4.dp, - modifier = Modifier.animateItem() + modifier = Modifier + .animateItem() + .thenIf(index == 0) { Modifier.statusBarsPadding() } ) } } } + + CuteNavigationButton { onNavigate(it) } + HistoryActionButtons { onEvents(HistoryEvents.DeleteAllCalculation(state.calculation)) } + } } @@ -172,18 +148,16 @@ private fun CalculationItem( .weight(1f), horizontalAlignment = Alignment.Start ) { - Text( + CuteText( text = formatOrNot(calculation.operation, decimalSetting), fontSize = 20.sp, - modifier = Modifier.basicMarquee(), - fontFamily = GlobalFont + modifier = Modifier.basicMarquee() ) - Text( + CuteText( text = "= ${formatOrNot(calculation.result, decimalSetting)}", fontSize = 22.sp, color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.5f), - modifier = Modifier.basicMarquee(), - fontFamily = GlobalFont + modifier = Modifier.basicMarquee() ) } IconButton( diff --git a/app/src/main/java/com/sosauce/cutecalc/screens/LandscapeLayout.kt b/app/src/main/java/com/sosauce/cutecalc/screens/LandscapeLayout.kt index 3b8a793..00ac283 100644 --- a/app/src/main/java/com/sosauce/cutecalc/screens/LandscapeLayout.kt +++ b/app/src/main/java/com/sosauce/cutecalc/screens/LandscapeLayout.kt @@ -21,9 +21,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -71,7 +71,12 @@ fun LandscapeLayout( ) { DisableSoftKeyboard { BasicTextField( - value = TextFieldValue(formatOrNot(viewModel.displayText.text, decimalSetting)), + value = viewModel.displayText.copy( + text = formatOrNot( + viewModel.displayText.text, + decimalSetting + ) + ), onValueChange = { viewModel.displayText = it }, singleLine = true, textStyle = TextStyle( @@ -135,10 +140,11 @@ fun LandscapeLayout( ) { CuteButton( text = "", - color = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.background), + color = ButtonDefaults.buttonColors(disabledContainerColor = Color.Transparent), modifier = Modifier .weight(0.15f), - onClick = {} + onClick = {}, + enabled = false ) CuteButton( text = "9", @@ -167,7 +173,6 @@ fun LandscapeLayout( CuteButton( text = "×", color = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.secondaryContainer), - modifier = Modifier .weight(0.15f), onClick = { @@ -252,6 +257,7 @@ fun LandscapeLayout( modifier = Modifier .weight(0.15f), onClick = { viewModel.handleAction(CalcAction.Backspace) }, + onLongClick = { viewModel.handleAction(CalcAction.ResetField) }, color = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.inversePrimary) ) } @@ -296,7 +302,6 @@ fun LandscapeLayout( CuteButton( text = "-", color = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.secondaryContainer), - modifier = Modifier .weight(0.15f), onClick = { diff --git a/app/src/main/java/com/sosauce/cutecalc/screens/SettingsScreen.kt b/app/src/main/java/com/sosauce/cutecalc/screens/SettingsScreen.kt index e8771ca..d4a2c5f 100644 --- a/app/src/main/java/com/sosauce/cutecalc/screens/SettingsScreen.kt +++ b/app/src/main/java/com/sosauce/cutecalc/screens/SettingsScreen.kt @@ -1,56 +1,36 @@ package com.sosauce.cutecalc.screens +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import com.sosauce.cutecalc.AppBar -import com.sosauce.cutecalc.R import com.sosauce.cutecalc.components.AboutCard -import com.sosauce.cutecalc.components.History +import com.sosauce.cutecalc.components.CuteNavigationButton import com.sosauce.cutecalc.components.Misc import com.sosauce.cutecalc.components.ThemeManagement +import com.sosauce.cutecalc.components.UI import com.sosauce.cutecalc.logic.navigation.Screens -import com.sosauce.cutecalc.ui.theme.GlobalFont @Composable fun SettingsScreen( onNavigate: (Screens) -> Unit ) { - - Scaffold( - topBar = { - AppBar( - showBackArrow = true, - onNavigate = onNavigate, - title = { - Text( - text = stringResource(R.string.settings), - fontFamily = GlobalFont - ) - } - ) - }, - ) { values -> + Box(Modifier.fillMaxSize()) { Column( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) - .padding(values), + .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally ) { AboutCard() ThemeManagement() - History() + UI() Misc() } + CuteNavigationButton { onNavigate(it) } } - } \ No newline at end of file diff --git a/app/src/main/res/drawable/backspace_rounded.xml b/app/src/main/res/drawable/backspace_rounded.xml index 224741e..f909c4b 100644 --- a/app/src/main/res/drawable/backspace_rounded.xml +++ b/app/src/main/res/drawable/backspace_rounded.xml @@ -5,7 +5,7 @@ android:viewportHeight="960" android:tint="@android:color/white" android:autoMirrored="true"> - + diff --git a/app/src/main/res/drawable/history_rounded.xml b/app/src/main/res/drawable/history_rounded.xml index dd93132..8dd36aa 100644 --- a/app/src/main/res/drawable/history_rounded.xml +++ b/app/src/main/res/drawable/history_rounded.xml @@ -4,7 +4,7 @@ android:viewportWidth="960" android:viewportHeight="960" android:tint="@android:color/white"> - + diff --git a/app/src/main/res/drawable/sort_rounded.xml b/app/src/main/res/drawable/sort_rounded.xml index 3975ce1..4b8c1f1 100644 --- a/app/src/main/res/drawable/sort_rounded.xml +++ b/app/src/main/res/drawable/sort_rounded.xml @@ -5,7 +5,7 @@ android:viewportHeight="960" android:tint="@android:color/white" android:autoMirrored="true"> - + diff --git a/app/src/main/res/drawable/trash_rounded.xml b/app/src/main/res/drawable/trash_rounded.xml index 32eb5e2..75d0564 100644 --- a/app/src/main/res/drawable/trash_rounded.xml +++ b/app/src/main/res/drawable/trash_rounded.xml @@ -4,7 +4,7 @@ android:viewportWidth="960" android:viewportHeight="960" android:tint="@android:color/white"> - + diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 2286e8d..afd5abb 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -8,6 +8,7 @@ Mettre à jour CuteCalc par sosauce Suivre le système + Utiliser la police système Animation des buttons Historique Utiliser l\'historique @@ -17,4 +18,7 @@ Vibrations Ascendant Descendant + Format décimal + Afficher le button effacer + Vous pouvez toujours rester appuyer sur le button d\'effacement arrière pour effacer le champs de calcul. \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b8580ee..ba86a60 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,4 +19,6 @@ Ascending Descending Decimal formatting + Show clear button + You can still long press the backspace button to clear the input field. \ No newline at end of file