From 3206fcba9b042f2238cdd93f88bb8a7423a3527a Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sun, 30 Jun 2024 15:38:42 +0200 Subject: [PATCH 1/3] feat(graphing): automatically select distinct function names and colors --- .../youapps/calcyou/data/graphing/Defaults.kt | 1 + .../calcyou/data/graphing/EvalConfig.kt | 1 - .../youapps/calcyou/data/graphing/Function.kt | 5 +++-- .../ui/components/AddNewFunctionDialog.kt | 10 +++++++--- .../ui/screens/graphing/GraphingScreen.kt | 7 +++++-- .../calcyou/viewmodels/GraphViewModel.kt | 19 ++++++++++++++----- 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/net/youapps/calcyou/data/graphing/Defaults.kt b/app/src/main/java/net/youapps/calcyou/data/graphing/Defaults.kt index b5ff60b..d87bcb4 100644 --- a/app/src/main/java/net/youapps/calcyou/data/graphing/Defaults.kt +++ b/app/src/main/java/net/youapps/calcyou/data/graphing/Defaults.kt @@ -45,6 +45,7 @@ object Defaults { ) val defaultVarNameChars: Set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$".toCharArray().toSet() + val defaultFuncNameChars: List = "fghijklmnopqrstuvw".toList() fun getDefaultGenericFunctions(): Map { return mapOf( diff --git a/app/src/main/java/net/youapps/calcyou/data/graphing/EvalConfig.kt b/app/src/main/java/net/youapps/calcyou/data/graphing/EvalConfig.kt index e680b44..17753d2 100644 --- a/app/src/main/java/net/youapps/calcyou/data/graphing/EvalConfig.kt +++ b/app/src/main/java/net/youapps/calcyou/data/graphing/EvalConfig.kt @@ -82,6 +82,5 @@ class EvalConfiguration( this.varNameChars = Defaults.defaultVarNameChars this.genericConstants = Defaults.defaultGenericConstants.toMutableMap() this.genericFunctions = Defaults.getDefaultGenericFunctions().toMutableMap() - } } \ No newline at end of file diff --git a/app/src/main/java/net/youapps/calcyou/data/graphing/Function.kt b/app/src/main/java/net/youapps/calcyou/data/graphing/Function.kt index e86ebe6..52887a1 100644 --- a/app/src/main/java/net/youapps/calcyou/data/graphing/Function.kt +++ b/app/src/main/java/net/youapps/calcyou/data/graphing/Function.kt @@ -5,14 +5,15 @@ import androidx.compose.ui.graphics.Color class Function( val expression: String, val color: Color, + val name: String, val function: (Float) -> Float? ) { companion object { - fun create(expression: String, color: Color): Function { + fun create(expression: String, color: Color, functionName: String): Function { val compiled: CompiledExpression = Evaluator.compile(expression) return Function( - expression, color + expression, color, functionName ) { value -> compiled.execute("x" to value.toDouble())?.toFloat() } diff --git a/app/src/main/java/net/youapps/calcyou/ui/components/AddNewFunctionDialog.kt b/app/src/main/java/net/youapps/calcyou/ui/components/AddNewFunctionDialog.kt index a5900e2..1b6d688 100644 --- a/app/src/main/java/net/youapps/calcyou/ui/components/AddNewFunctionDialog.kt +++ b/app/src/main/java/net/youapps/calcyou/ui/components/AddNewFunctionDialog.kt @@ -39,6 +39,7 @@ import net.youapps.calcyou.viewmodels.GraphViewModel @Composable fun AddNewFunctionDialog( graphViewModel: GraphViewModel, + functionName: String, initialExpression: String, initialColor: Color, onDismissRequest: () -> Unit @@ -46,13 +47,14 @@ fun AddNewFunctionDialog( Dialog(onDismissRequest) { DialogContent( onConfirm = { expression, color -> - graphViewModel.addFunction(expression, color) + graphViewModel.addFunction(expression, color, functionName) onDismissRequest() }, onCancel = onDismissRequest, checkExpression = graphViewModel::checkExpression, isError = graphViewModel.isError, errorMessage = graphViewModel.errorText, + functionName = functionName, initialExpression = initialExpression, initialColor = initialColor ) @@ -67,6 +69,7 @@ private fun DialogContent( checkExpression: (String) -> Unit, isError: Boolean, errorMessage: String, + functionName: String, initialExpression: String = "", initialColor: Color = rainbowColors.first(), ) { @@ -92,7 +95,7 @@ private fun DialogContent( isError = isError, prefix = { Text( - text = "f(x) = ", style = TextStyle( + text = "${functionName}(x) = ", style = TextStyle( fontFamily = FontFamily.Serif, fontWeight = FontWeight.Medium, fontSize = MaterialTheme.typography.bodyLarge.fontSize, @@ -149,6 +152,7 @@ private fun DialogContentPreview() { onCancel = {}, checkExpression = {}, isError = true, - errorMessage = "Invalid token at index 0" + errorMessage = "Invalid token at index 0", + functionName = "f" ) } \ No newline at end of file diff --git a/app/src/main/java/net/youapps/calcyou/ui/screens/graphing/GraphingScreen.kt b/app/src/main/java/net/youapps/calcyou/ui/screens/graphing/GraphingScreen.kt index 76152d3..e872f71 100644 --- a/app/src/main/java/net/youapps/calcyou/ui/screens/graphing/GraphingScreen.kt +++ b/app/src/main/java/net/youapps/calcyou/ui/screens/graphing/GraphingScreen.kt @@ -33,6 +33,7 @@ import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import net.youapps.calcyou.data.graphing.Defaults import net.youapps.calcyou.data.graphing.Function import net.youapps.calcyou.ui.components.AddNewFunctionDialog import net.youapps.calcyou.viewmodels.GraphViewModel @@ -82,6 +83,7 @@ fun GraphingScreen(graphViewModel: GraphViewModel = viewModel()) { graphViewModel.updateSelectedFunction(-1) showAddFunctionDialog = false }, + functionName = remember(graphViewModel.selectedFunctionIndex) { graphViewModel.functionName }, initialColor = remember(graphViewModel.selectedFunctionIndex) { graphViewModel.functionColor }, initialExpression = @@ -100,6 +102,7 @@ fun FunctionList( Column(modifier = modifier) { functions.forEachIndexed { index, function -> FunctionRow( + functionName = function.name, text = function.expression, color = function.color, onClick = { onClickFunction(index) }, @@ -112,7 +115,7 @@ fun FunctionList( } @Composable -fun FunctionRow(text: String, color: Color, onClick: () -> Unit, onClickRemove: () -> Unit) { +fun FunctionRow(functionName: String, text: String, color: Color, onClick: () -> Unit, onClickRemove: () -> Unit) { Row( modifier = Modifier .fillMaxWidth() @@ -122,7 +125,7 @@ fun FunctionRow(text: String, color: Color, onClick: () -> Unit, onClickRemove: ) { Text( - text = "f(x) = ", style = TextStyle( + text = "${functionName}(x) = ", style = TextStyle( fontFamily = FontFamily.Serif, fontWeight = FontWeight.Bold, fontSize = MaterialTheme.typography.titleMedium.fontSize, diff --git a/app/src/main/java/net/youapps/calcyou/viewmodels/GraphViewModel.kt b/app/src/main/java/net/youapps/calcyou/viewmodels/GraphViewModel.kt index 15c33f1..b2a75f6 100644 --- a/app/src/main/java/net/youapps/calcyou/viewmodels/GraphViewModel.kt +++ b/app/src/main/java/net/youapps/calcyou/viewmodels/GraphViewModel.kt @@ -11,14 +11,16 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.Color import androidx.lifecycle.AndroidViewModel import net.youapps.calcyou.R +import net.youapps.calcyou.data.graphing.Defaults import net.youapps.calcyou.data.graphing.Evaluator import net.youapps.calcyou.data.graphing.Function import net.youapps.calcyou.data.graphing.Window +import net.youapps.calcyou.ui.components.rainbowColors import java.text.ParseException import kotlin.random.Random class GraphViewModel(private val application: Application) : AndroidViewModel(application) { - val context: Context + private val context: Context get() = application.applicationContext var window by mutableStateOf(Window(), neverEqualPolicy()) val functions = mutableStateListOf() @@ -30,7 +32,9 @@ class GraphViewModel(private val application: Application) : AndroidViewModel(ap var selectedFunctionIndex by mutableIntStateOf(-1) private set - var functionColor by mutableStateOf(Color.Red) + var functionName by mutableStateOf(Defaults.defaultFuncNameChars.first().toString()) + + var functionColor by mutableStateOf(rainbowColors.first()) var expression by mutableStateOf("") @@ -38,9 +42,14 @@ class GraphViewModel(private val application: Application) : AndroidViewModel(ap selectedFunctionIndex = index if (index == -1) { expression = "" + functionName = Defaults.defaultFuncNameChars[ + functions.size % Defaults.defaultFuncNameChars.size + ].toString() + functionColor = rainbowColors[functions.size % rainbowColors.size] return } val function = functions[index] + functionName = function.name functionColor = function.color expression = function.expression } @@ -64,13 +73,13 @@ class GraphViewModel(private val application: Application) : AndroidViewModel(ap } } - fun addFunction(expression: String, color: Color) { + fun addFunction(expression: String, color: Color, functionName: String) { if (selectedFunctionIndex != -1) { - functions[selectedFunctionIndex] = Function.create(expression, color) + functions[selectedFunctionIndex] = Function.create(expression, color, functionName) updateSelectedFunction(-1) return } - functions.add(Function.create(expression, color)) + functions.add(Function.create(expression, color, functionName)) } fun removeFunction(index: Int) { From 50de8b0de3f1652818a699de8a0cc7256ab9755a Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 9 Oct 2024 13:08:42 +0200 Subject: [PATCH 2/3] fix: improve graphing function list UI/UX --- .../youapps/calcyou/data/graphing/Function.kt | 2 +- .../ui/screens/graphing/GraphingScreen.kt | 35 ++++++++++++++----- .../calcyou/viewmodels/GraphViewModel.kt | 21 ++++++++--- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/net/youapps/calcyou/data/graphing/Function.kt b/app/src/main/java/net/youapps/calcyou/data/graphing/Function.kt index 52887a1..2b8f133 100644 --- a/app/src/main/java/net/youapps/calcyou/data/graphing/Function.kt +++ b/app/src/main/java/net/youapps/calcyou/data/graphing/Function.kt @@ -2,7 +2,7 @@ package net.youapps.calcyou.data.graphing import androidx.compose.ui.graphics.Color -class Function( +data class Function( val expression: String, val color: Color, val name: String, diff --git a/app/src/main/java/net/youapps/calcyou/ui/screens/graphing/GraphingScreen.kt b/app/src/main/java/net/youapps/calcyou/ui/screens/graphing/GraphingScreen.kt index e872f71..8be10df 100644 --- a/app/src/main/java/net/youapps/calcyou/ui/screens/graphing/GraphingScreen.kt +++ b/app/src/main/java/net/youapps/calcyou/ui/screens/graphing/GraphingScreen.kt @@ -7,6 +7,9 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Clear import androidx.compose.material3.BottomSheetScaffold @@ -26,13 +29,16 @@ 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.Color +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import net.youapps.calcyou.R import net.youapps.calcyou.data.graphing.Defaults import net.youapps.calcyou.data.graphing.Function import net.youapps.calcyou.ui.components.AddNewFunctionDialog @@ -69,8 +75,11 @@ fun GraphingScreen(graphViewModel: GraphViewModel = viewModel()) { }) Button( modifier = Modifier.align(Alignment.CenterHorizontally), - onClick = { showAddFunctionDialog = true }) { - Text(text = "Add Function") + onClick = { + graphViewModel.updateSelectedFunction(-1) + showAddFunctionDialog = true + }) { + Text(text = stringResource(R.string.add_new_function)) } } }) { @@ -99,8 +108,10 @@ fun FunctionList( onClickFunction: (Int) -> Unit, onClickRemove: (Int) -> Unit ) { - Column(modifier = modifier) { - functions.forEachIndexed { index, function -> + LazyColumn(modifier = modifier) { + itemsIndexed( + functions, + key = { index, function -> "$index-${function.hashCode()}" }) { index, function -> FunctionRow( functionName = function.name, text = function.expression, @@ -108,19 +119,27 @@ fun FunctionList( onClick = { onClickFunction(index) }, onClickRemove = { onClickRemove(index) - }) + } + ) Divider(Modifier.fillMaxWidth()) } } } @Composable -fun FunctionRow(functionName: String, text: String, color: Color, onClick: () -> Unit, onClickRemove: () -> Unit) { +fun FunctionRow( + functionName: String, + text: String, + color: Color, + onClick: () -> Unit, + onClickRemove: () -> Unit +) { Row( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 8.dp, vertical = 4.dp) - .clickable { onClick.invoke() }, + .clip(RoundedCornerShape(8.dp)) + .clickable { onClick.invoke() } + .padding(horizontal = 8.dp, vertical = 4.dp), verticalAlignment = Alignment.CenterVertically ) { diff --git a/app/src/main/java/net/youapps/calcyou/viewmodels/GraphViewModel.kt b/app/src/main/java/net/youapps/calcyou/viewmodels/GraphViewModel.kt index b2a75f6..519d43e 100644 --- a/app/src/main/java/net/youapps/calcyou/viewmodels/GraphViewModel.kt +++ b/app/src/main/java/net/youapps/calcyou/viewmodels/GraphViewModel.kt @@ -42,10 +42,8 @@ class GraphViewModel(private val application: Application) : AndroidViewModel(ap selectedFunctionIndex = index if (index == -1) { expression = "" - functionName = Defaults.defaultFuncNameChars[ - functions.size % Defaults.defaultFuncNameChars.size - ].toString() - functionColor = rainbowColors[functions.size % rainbowColors.size] + functionName = getFuncName(functions.size) + functionColor = getFuncColor(functions.size) return } val function = functions[index] @@ -84,5 +82,20 @@ class GraphViewModel(private val application: Application) : AndroidViewModel(ap fun removeFunction(index: Int) { functions.removeAt(index) + + // update the other functions following the delete one with new function names and colors + for (i in index until functions.size) { + functions[index] = functions[index].copy(name = getFuncName(i), color = getFuncColor(i)) + } + } + + private fun getFuncName(index: Int): String { + return Defaults.defaultFuncNameChars[ + index % Defaults.defaultFuncNameChars.size + ].toString() + } + + private fun getFuncColor(index: Int): Color { + return rainbowColors[index % rainbowColors.size] } } \ No newline at end of file From f02a3d020510629263edc87a132086e0ef90489c Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 9 Oct 2024 13:08:57 +0200 Subject: [PATCH 3/3] chore: update gradle dependency --- .idea/gradle.xml | 1 + .idea/misc.xml | 3 +- .idea/runConfigurations.xml | 13 ++ gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 43504 bytes gradle/wrapper/gradle-wrapper.properties | 5 +- gradlew | 285 ++++++++++++++--------- gradlew.bat | 37 +-- 7 files changed, 216 insertions(+), 128 deletions(-) create mode 100644 .idea/runConfigurations.xml diff --git a/.idea/gradle.xml b/.idea/gradle.xml index acd3ca5..8d3206b 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,6 +4,7 @@