Skip to content
This repository was archived by the owner on Dec 21, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ fun getKatexMenuWidth(): Dp {
}

else -> {
400.dp
375.dp
}
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ import com.belmontCrest.cardCrafter.localDatabase.tables.Card
import com.belmontCrest.cardCrafter.model.uiModels.StringVar
import com.belmontCrest.cardCrafter.model.uiModels.SelectedCard
import com.belmontCrest.cardCrafter.model.uiModels.SelectedKeyboard
import com.belmontCrest.cardCrafter.model.uiModels.SelectedKeyboard.Answer
import com.belmontCrest.cardCrafter.model.uiModels.SelectedKeyboard.Question
import com.belmontCrest.cardCrafter.model.uiModels.SelectedKeyboard.Step
import com.belmontCrest.cardCrafter.model.uiModels.WhichDeck
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
Expand Down Expand Up @@ -215,7 +212,7 @@ class NavViewModel(
}

fun toggleKeyboard() {
_showKatexKeyboard.update { savedStateHandle[SHOW_KB] = !it;!it }
_showKatexKeyboard.update { savedStateHandle[SHOW_KB] = !it; !it }
}

fun resetOffset() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.belmontCrest.cardCrafter.ui.theme.textColor
import com.belmontCrest.cardCrafter.uiFunctions.katex.menu.KaTeXMenu
import com.belmontCrest.cardCrafter.uiFunctions.katex.isInside
import com.belmontCrest.cardCrafter.uiFunctions.katex.katexMapper
import com.belmontCrest.cardCrafter.uiFunctions.katex.menu.IsInsideException
import com.belmontCrest.cardCrafter.uiFunctions.katex.menu.SelectedAnnotation
import com.belmontCrest.cardCrafter.uiFunctions.katex.menu.updateCursor
import com.belmontCrest.cardCrafter.uiFunctions.katex.menu.updateNotation
Expand Down Expand Up @@ -150,18 +151,24 @@ fun LatexKeyboard(
}
LaunchedEffect(kt) {
val text = textFieldValue.text
if (kt.sa is SelectedAnnotation.CursorChange) {
textFieldValue = updateCursor(kt.sa, textFieldValue, text)
onIdle()
return@LaunchedEffect
}
if (!textFieldValue.selection.collapsed) {
Log.w(kk, "text field not collapsed.")
return@LaunchedEffect
}
if (kt.sa is SelectedAnnotation.CursorChange) {
try {
textFieldValue = updateCursor(kt.sa, textFieldValue, text) { onValueChanged(it) }
} catch (e : IsInsideException) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Missing onIdle() call after catching exception

onIdle() should be called in the catch block to ensure the selection state is reset after an exception.

Log.e(kk, "$e")
showToastMessage(context, "Cannot put notation inside a notation")
}
onIdle()
return@LaunchedEffect
}
if (!isInside(text, text.length, textFieldValue.selection)) {
if (kt.notation != null) {
showToastMessage(context, "Make sure the symbol is between the delimiters.")
onIdle()
}
return@LaunchedEffect
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ fun katexMapper(
return Pair(
TextFieldValue(
text = replaced,
selection = TextRange(insertionPoint)
selection = TextRange(insertionPoint),
composition = TextRange(insertionPoint)
),
replaced
)
Expand All @@ -66,7 +67,8 @@ fun katexMapper(
return Pair(
TextFieldValue(
text = replaced,
selection = TextRange(insertionPoint)
selection = TextRange(insertionPoint),
composition = TextRange(insertionPoint)
),
replaced
)
Expand All @@ -93,7 +95,8 @@ fun katexMapper(
return Pair(
TextFieldValue(
text = replaced,
selection = TextRange(insertionPoint)
selection = TextRange(insertionPoint),
composition = TextRange(insertionPoint)
),
replaced
)
Expand Down Expand Up @@ -235,7 +238,8 @@ private fun katexWord(
return Pair(
TextFieldValue(
text = replaced,
selection = TextRange(insertionPoint)
selection = TextRange(insertionPoint),
composition = TextRange(insertionPoint)
),
replaced
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fun getWebView(
fun onFracBinoSelected(eq: String) {
Handler(Looper.getMainLooper()).postAtFrontOfQueue {
val replaced = eq.replace("bra", "\\\\bra").replace("frac", "\\\\frac")
.replace("gen", "\\\\gen").replace("bin", "\\\\bin")
.replace("gen", "\\\\gen").replace("bin", "\\\\bin")
onSelectNotation(replaced, SelectedAnnotation.EQ)
}
}
Expand All @@ -68,10 +68,7 @@ fun getWebView(
@JavascriptInterface
fun onNormSelected(sel: String) {
Handler(Looper.getMainLooper()).postAtFrontOfQueue {
val replaced = sel.replace("l", "\\\\l").replace("gt", "\\\\gt")
.replace("sqrt", "\\\\sqrt").replace("pi", "\\\\pi")
.replace("ti", "\\\\ti").replace("div", "\\\\div").replace("a", "")
.replace("{x}", "{}").replace("b", "")
val replaced = sel.convertNormSel()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): convertNormSel() is not defined in scope

Please implement String.convertNormSel() (using latexNormMap), or revert to the previous replace chain to prevent compilation errors.

onSelectNotation(replaced, SelectedAnnotation.NORM)
}
}
Expand Down Expand Up @@ -115,4 +112,42 @@ fun getWebView(
loadUrl("file:///android_asset/katex-menu.html")
}
}
}
}

private val latexNormMap = mapOf(
// comparisons
"lt" to "\\\\lt",
"gt" to "\\\\gt",
"le" to "\\\\le",
"ge" to "\\\\ge",

// fractions & roots
"times" to "\\\\times",
"div" to "\\\\div",
"sqrt{x}" to "\\\\sqrt{}",
"sqrt[a]{x}" to "\\\\sqrt[]{}",

// constants
"pi" to "\\\\pi",

// exponents & letters
"a^2" to "^2",
"a^{b}" to "^{}",
"|a|" to "||",

// punctuation & parens
"(" to "(",
")" to ")",
"," to ",",
"." to ".",
"=" to "=",
"{}" to "{}",

// digits
"0" to "0", "1" to "1", "2" to "2", "3" to "3", "4" to "4",
"5" to "5", "6" to "6", "7" to "7", "8" to "8", "9" to "9"
)



private fun String.convertNormSel(): String = latexNormMap[this] ?: this
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ private val BIG_OPERATORS = listOf(
)

private val NORMAL_OPS_NUMS = listOf(
"x", "y", "a^2", "a^{b}", "(", ")",
"x", "y", "a^2", "a^{b}", "(", ")", "\\\\{\\\\}",
"\\\\lt", "\\\\gt", "|a|", ",", "\\\\le", "\\\\ge",
"\\\\sqrt{x}", "\\\\sqrt[a]{x}", "\\\\pi",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,33 @@ import android.webkit.WebView
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
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.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
Expand All @@ -32,6 +42,7 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import com.belmontCrest.cardCrafter.model.getIsLandScape
import com.belmontCrest.cardCrafter.model.getKatexMenuWidth
import com.belmontCrest.cardCrafter.ui.theme.GetUIStyle
import kotlinx.parcelize.Parcelize
Expand Down Expand Up @@ -62,12 +73,19 @@ sealed class SelectedAnnotation : Parcelable {
sealed class CursorChange : SelectedAnnotation() {
data object Forward : CursorChange()
data object Backward : CursorChange()
data object Inline : CursorChange()
data object NewLine : CursorChange()
data object Delete : CursorChange()
}

@Parcelize
data object Idle : SelectedAnnotation()
}


class IsInsideException :
Exception("You cannot put a notation equation inside a notation equation.")

//private const val KATEX_MENU = "KatexMenu"

@OptIn(ExperimentalStdlibApi::class)
Expand All @@ -79,6 +97,8 @@ fun KaTeXMenu(
webView: WebView, scrollState: ScrollState,
onCursorChange: (SelectedAnnotation.CursorChange) -> Unit
) {

var expanded by rememberSaveable { mutableStateOf(false) }
/*
val maxY = getMaxHeight().value
val maxX = getMaxWidth().value
Expand All @@ -90,10 +110,92 @@ fun KaTeXMenu(
Log.i(KATEX_MENU, "max height: $maxY")
}*/

val isLandscape = getIsLandScape()
val width = if (isLandscape) getKatexMenuWidth() / 2.5.dp else getKatexMenuWidth() / 2.dp
val offsetMod =
if (!isLandscape) Modifier.offset(y = -(126.dp)) else Modifier.offset(x = -(width.dp))
Box(
modifier = modifier
.offset { IntOffset(offsetProvider().x.roundToInt(), offsetProvider().y.roundToInt()) }
) {
if (expanded) {
Column(
modifier = offsetMod
.width(width.dp)
.height(126.dp)
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consume()
onOffset(dragAmount)
}
}
.background(getUIStyle.katexMenuHeaderColor(), RoundedCornerShape(12.dp))
.border(1.5.dp, getUIStyle.defaultIconColor(), RoundedCornerShape(12.dp)),
verticalArrangement = Arrangement.SpaceEvenly
) {
Row(
modifier = Modifier
.align(Alignment.Start)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically
) {
IconButton(
modifier = Modifier.size(30.dp),
onClick = { onCursorChange(SelectedAnnotation.CursorChange.Backward) },
) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null,
modifier = Modifier.size(25.dp)
)
}
IconButton(
modifier = Modifier.size(30.dp),
onClick = { onCursorChange(SelectedAnnotation.CursorChange.Forward) },
) {
Icon(
Icons.AutoMirrored.Filled.ArrowForward, contentDescription = null,
modifier = Modifier.size(25.dp)
)
}
Text(
text = "delete",
modifier = Modifier
.clickable {
onCursorChange(SelectedAnnotation.CursorChange.Delete)
},
textAlign = TextAlign.End,
fontSize = 14.sp,
color = getUIStyle.titleColor()
)

}
HorizontalDivider(color = getUIStyle.defaultIconColor())
Text(
text = "Start Inline",
modifier = Modifier
.clickable {
onCursorChange(SelectedAnnotation.CursorChange.Inline)
}
.fillMaxWidth(),
textAlign = TextAlign.Center,
fontSize = 16.sp,
color = getUIStyle.titleColor()
)
HorizontalDivider(color = getUIStyle.defaultIconColor())
Text(
text = "Start New Line",
modifier = Modifier
.clickable {
onCursorChange(SelectedAnnotation.CursorChange.NewLine)
}
.fillMaxWidth(),
textAlign = TextAlign.Center,
fontSize = 16.sp,
color = getUIStyle.titleColor()
)
}
}
Box(
modifier = Modifier
.width(getKatexMenuWidth())
Expand Down Expand Up @@ -123,20 +225,16 @@ fun KaTeXMenu(
}
.border(1.5.dp, getUIStyle.defaultIconColor())
) {

Row(
modifier = Modifier.align(Alignment.TopStart),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically
) {
IconButton(
onClick = { onCursorChange(SelectedAnnotation.CursorChange.Backward) },
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
IconButton(
onClick = { onCursorChange(SelectedAnnotation.CursorChange.Forward) },
) { Icon(Icons.AutoMirrored.Filled.ArrowForward, contentDescription = null) }
}

Text(
text = if (!expanded) "Expand" else "Minimize",
modifier = Modifier
.padding(start = 4.dp)
.align(Alignment.TopStart)
.clickable { expanded = !expanded },
textAlign = TextAlign.Start,
fontSize = 16.sp,
color = getUIStyle.titleColor()
)
Text(
text = "Drag here",
modifier = Modifier.align(Alignment.Center),
Expand Down
Loading