From f7b4f29e2e73883c68c3ee09f0b4ef795979e474 Mon Sep 17 00:00:00 2001 From: jay-tux Date: Tue, 10 Jun 2025 15:50:43 +0200 Subject: [PATCH] Allow rich-text in feedback --- .../com/jaytux/grader/ui/Assignments.kt | 52 +++++++++---------- .../kotlin/com/jaytux/grader/ui/RichText.kt | 15 ++++++ .../kotlin/com/jaytux/grader/ui/Widgets.kt | 4 +- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/Assignments.kt b/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/Assignments.kt index 9132253..8d06552 100644 --- a/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/Assignments.kt +++ b/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/Assignments.kt @@ -126,14 +126,15 @@ fun groupTaskWidget( Row { DateTimePicker(deadline, onSetDeadline) } - RichTextStyleRow(state = updTask) - OutlinedRichTextEditor( - state = updTask, - modifier = Modifier.fillMaxWidth().weight(1f), - singleLine = false, - minLines = 5, - label = { Text("Task") } - ) + RichTextField(updTask, Modifier.fillMaxWidth().weight(1f)) { Text("Task") } +// RichTextStyleRow(state = updTask) +// OutlinedRichTextEditor( +// state = updTask, +// modifier = Modifier.fillMaxWidth().weight(1f), +// singleLine = false, +// minLines = 5, +// label = { Text("Task") } +// ) CancelSaveRow( true, { updTask.setMarkdown(taskMD) }, @@ -276,16 +277,20 @@ fun groupFeedbackPane( key: Any? = null ) { var grade by remember(globFeedback, key) { mutableStateOf(globFeedback?.grade ?: "") } - var feedback by remember(currentCriterion, criteria, criterionFeedback, key) { mutableStateOf(TextFieldValue(criterionFeedback?.feedback ?: "")) } + val feedback = rememberRichTextState() + + LaunchedEffect(currentCriterion, criteria, criterionFeedback, key) { + feedback.setMarkdown(criterionFeedback?.feedback ?: "") + } + Column(modifier) { Row { Text("Overall grade: ", Modifier.align(Alignment.CenterVertically)) OutlinedTextField(grade, { grade = it }, Modifier.weight(0.2f)) Spacer(Modifier.weight(0.6f)) Button( - { onSetGrade(grade); onSetFeedback(feedback.text) }, - Modifier.weight(0.2f).align(Alignment.CenterVertically), - enabled = grade.isNotBlank() || feedback.text.isNotBlank() + { onSetGrade(grade); onSetFeedback(feedback.toMarkdown()) }, + Modifier.weight(0.2f).align(Alignment.CenterVertically) ) { Text("Save") } @@ -297,11 +302,7 @@ fun groupFeedbackPane( } } Spacer(Modifier.height(5.dp)) - AutocompleteLineField( - feedback, { feedback = it }, Modifier.fillMaxWidth().weight(1f), { Text("Feedback") } - ) { filter -> - autofill.filter { x -> x.trim().startsWith(filter.trim()) } - } + RichTextField(feedback, Modifier.fillMaxWidth().weight(1f)) { Text("Feedback") } } } @@ -480,16 +481,19 @@ fun soloFeedbackPane( key: Any? = null ) { var grade by remember(globFeedback, key) { mutableStateOf(globFeedback?.grade ?: "") } - var feedback by remember(currentCriterion, criteria, key) { mutableStateOf(TextFieldValue(criterionFeedback?.feedback ?: "")) } + val feedback = rememberRichTextState() + + LaunchedEffect(currentCriterion, criteria, criterionFeedback, key) { + feedback.setMarkdown(criterionFeedback?.feedback ?: "") + } Column(modifier) { Row { Text("Overall grade: ", Modifier.align(Alignment.CenterVertically)) OutlinedTextField(grade, { grade = it }, Modifier.weight(0.2f)) Spacer(Modifier.weight(0.6f)) Button( - { onSetGrade(grade); onSetFeedback(feedback.text) }, - Modifier.weight(0.2f).align(Alignment.CenterVertically), - enabled = grade.isNotBlank() || feedback.text.isNotBlank() + { onSetGrade(grade); onSetFeedback(feedback.toMarkdown()) }, + Modifier.weight(0.2f).align(Alignment.CenterVertically) ) { Text("Save") } @@ -501,11 +505,7 @@ fun soloFeedbackPane( } } Spacer(Modifier.height(5.dp)) - AutocompleteLineField( - feedback, { feedback = it }, Modifier.fillMaxWidth().weight(1f), { Text("Feedback") } - ) { filter -> - autofill.filter { x -> x.trim().startsWith(filter.trim()) } - } + RichTextField(feedback, Modifier.fillMaxWidth().weight(1f)) { Text("Feedback") } } } diff --git a/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/RichText.kt b/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/RichText.kt index 3be15cf..838fa87 100644 --- a/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/RichText.kt +++ b/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/RichText.kt @@ -28,6 +28,7 @@ import androidx.compose.ui.unit.sp import com.jaytux.grader.loadClipboard import com.jaytux.grader.toClipboard import com.mohamedrejeb.richeditor.model.RichTextState +import com.mohamedrejeb.richeditor.ui.material.OutlinedRichTextEditor @Composable fun RichTextStyleRow( @@ -237,4 +238,18 @@ fun RichTextStyleButton( ) ) } +} + +@Composable +fun RichTextField( + state: RichTextState, + modifier: Modifier = Modifier, + buttonsModifier: Modifier = Modifier, + outerModifier: Modifier = Modifier, + label: @Composable (() -> Unit)? = null +) = Column(outerModifier) { + RichTextStyleRow(buttonsModifier, state) + OutlinedRichTextEditor( + state = state, modifier = modifier, singleLine = false, minLines = 5, label = label + ) } \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/Widgets.kt b/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/Widgets.kt index fe51e68..475427a 100644 --- a/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/Widgets.kt +++ b/composeApp/src/desktopMain/kotlin/com/jaytux/grader/ui/Widgets.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.window.* import com.jaytux.grader.data.Course import com.jaytux.grader.data.Edition import com.jaytux.grader.viewmodel.PeerEvaluationState +import com.mohamedrejeb.richeditor.model.RichTextState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.datetime.* @@ -211,7 +212,8 @@ fun PaneHeader(name: String, type: String, courseEdition: Pair) @OptIn(ExperimentalFoundationApi::class) @Composable -fun AutocompleteLineField( +fun AutocompleteLineField__( +// state: RichTextState, value: TextFieldValue, onValueChange: (TextFieldValue) -> Unit, modifier: Modifier = Modifier, label: @Composable (() -> Unit)? = null, onFilter: (String) -> List