Fix loading bug

This commit is contained in:
2025-06-10 16:41:02 +02:00
parent f7b4f29e2e
commit 0883d2332e
2 changed files with 41 additions and 57 deletions

View File

@ -12,11 +12,9 @@ import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.layout import androidx.compose.ui.layout.layout
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.jaytux.grader.data.GroupAssignment
import com.jaytux.grader.data.GroupAssignmentCriterion import com.jaytux.grader.data.GroupAssignmentCriterion
import com.jaytux.grader.data.SoloAssignmentCriterion import com.jaytux.grader.data.SoloAssignmentCriterion
import com.jaytux.grader.data.Student import com.jaytux.grader.data.Student
@ -26,7 +24,6 @@ import com.jaytux.grader.viewmodel.SoloAssignmentState
import com.mohamedrejeb.richeditor.model.rememberRichTextState import com.mohamedrejeb.richeditor.model.rememberRichTextState
import com.mohamedrejeb.richeditor.ui.material3.OutlinedRichTextEditor import com.mohamedrejeb.richeditor.ui.material3.OutlinedRichTextEditor
import kotlinx.datetime.LocalDateTime import kotlinx.datetime.LocalDateTime
import org.jetbrains.exposed.sql.transactions.inTopLevelTransaction
@Composable @Composable
fun GroupAssignmentView(state: GroupAssignmentState) { fun GroupAssignmentView(state: GroupAssignmentState) {
@ -189,7 +186,7 @@ fun groupTaskWidget(
@Composable @Composable
fun groupFeedback(state: GroupAssignmentState, fdbk: GroupAssignmentState.LocalGFeedback) { fun groupFeedback(state: GroupAssignmentState, fdbk: GroupAssignmentState.LocalGFeedback) {
val (group, feedback, individual) = fdbk val (group, feedback, individual) = fdbk
var idx by remember(fdbk) { mutableStateOf(0) } var studentIdx by remember(fdbk) { mutableStateOf(0) }
var critIdx by remember(fdbk) { mutableStateOf(0) } var critIdx by remember(fdbk) { mutableStateOf(0) }
val criteria by state.criteria.entities val criteria by state.criteria.entities
val suggestions by state.autofill.entities val suggestions by state.autofill.entities
@ -199,8 +196,8 @@ fun groupFeedback(state: GroupAssignmentState, fdbk: GroupAssignmentState.LocalG
LazyColumn(Modifier.fillMaxHeight().padding(10.dp)) { LazyColumn(Modifier.fillMaxHeight().padding(10.dp)) {
item { item {
Surface( Surface(
Modifier.fillMaxWidth().clickable { idx = 0 }, Modifier.fillMaxWidth().clickable { studentIdx = 0 },
tonalElevation = if (idx == 0) 50.dp else 0.dp, tonalElevation = if (studentIdx == 0) 50.dp else 0.dp,
shape = MaterialTheme.shapes.medium shape = MaterialTheme.shapes.medium
) { ) {
Text("Group feedback", Modifier.padding(5.dp), fontStyle = FontStyle.Italic) Text("Group feedback", Modifier.padding(5.dp), fontStyle = FontStyle.Italic)
@ -210,8 +207,8 @@ fun groupFeedback(state: GroupAssignmentState, fdbk: GroupAssignmentState.LocalG
itemsIndexed(individual.toList()) { i, (student, details) -> itemsIndexed(individual.toList()) { i, (student, details) ->
val (role, _) = details val (role, _) = details
Surface( Surface(
Modifier.fillMaxWidth().clickable { idx = i + 1 }, Modifier.fillMaxWidth().clickable { studentIdx = i + 1 },
tonalElevation = if (idx == i + 1) 50.dp else 0.dp, tonalElevation = if (studentIdx == i + 1) 50.dp else 0.dp,
shape = MaterialTheme.shapes.medium shape = MaterialTheme.shapes.medium
) { ) {
Text("${student.name} (${role ?: "no role"})", Modifier.padding(5.dp)) Text("${student.name} (${role ?: "no role"})", Modifier.padding(5.dp))
@ -220,45 +217,25 @@ fun groupFeedback(state: GroupAssignmentState, fdbk: GroupAssignmentState.LocalG
} }
} }
val updateGrade = { grade: String -> val onSave = { grade: String, fdbk: String ->
if(idx == 0) { when {
state.upsertGroupFeedback(group, feedback.global?.feedback ?: "", grade) studentIdx == 0 && critIdx == 0 -> state.upsertGroupFeedback(group, fdbk, grade)
} studentIdx == 0 && critIdx != 0 -> state.upsertGroupFeedback(group, fdbk, grade, criteria[critIdx - 1])
else { studentIdx != 0 && critIdx == 0 -> state.upsertIndividualFeedback(individual[studentIdx - 1].first, group, fdbk, grade)
val ind = individual[idx - 1] else -> state.upsertIndividualFeedback(individual[studentIdx - 1].first, group, fdbk, grade, criteria[critIdx - 1])
val glob = ind.second.second.global
state.upsertIndividualFeedback(ind.first, group, glob?.feedback ?: "", grade)
}
}
val updateFeedback = { fdbk: String ->
if(idx == 0) {
if(critIdx == 0) {
state.upsertGroupFeedback(group, fdbk, feedback.global?.grade ?: "", null)
}
else {
val current = feedback.byCriterion[critIdx - 1]
state.upsertGroupFeedback(group, fdbk, current.entry?.grade ?: "", current.criterion)
}
}
else {
val ind = individual[idx - 1]
if(critIdx == 0) {
val entry = ind.second.second
state.upsertIndividualFeedback(ind.first, group, fdbk, entry.global?.grade ?: "", null)
}
else {
val entry = ind.second.second.byCriterion[critIdx - 1]
state.upsertIndividualFeedback(ind.first, group, fdbk, entry.entry?.grade ?: "", entry.criterion)
}
} }
} }
groupFeedbackPane( groupFeedbackPane(
criteria, critIdx, { critIdx = it }, feedback.global, criteria, critIdx, { critIdx = it },
if(critIdx == 0) feedback.global else feedback.byCriterion[critIdx - 1].entry, when {
suggestions, updateGrade, updateFeedback, Modifier.weight(0.75f).padding(10.dp), studentIdx == 0 && critIdx == 0 -> feedback.global
key = idx to critIdx studentIdx == 0 && critIdx != 0 -> feedback.byCriterion[critIdx - 1].entry
studentIdx != 0 && critIdx == 0 -> individual[studentIdx - 1].second.second.global
else -> individual[studentIdx - 1].second.second.byCriterion[critIdx - 1].entry
},
suggestions, onSave, Modifier.weight(0.75f).padding(10.dp),
key = studentIdx to critIdx
) )
} }
} }
@ -268,19 +245,17 @@ fun groupFeedbackPane(
criteria: List<GroupAssignmentCriterion>, criteria: List<GroupAssignmentCriterion>,
currentCriterion: Int, currentCriterion: Int,
onSelectCriterion: (Int) -> Unit, onSelectCriterion: (Int) -> Unit,
globFeedback: GroupAssignmentState.FeedbackEntry?, rawFeedback: GroupAssignmentState.FeedbackEntry?,
criterionFeedback: GroupAssignmentState.FeedbackEntry?,
autofill: List<String>, autofill: List<String>,
onSetGrade: (String) -> Unit, onSave: (String, String) -> Unit,
onSetFeedback: (String) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
key: Any? = null key: Any? = null
) { ) {
var grade by remember(globFeedback, key) { mutableStateOf(globFeedback?.grade ?: "") } var grade by remember(rawFeedback, key) { mutableStateOf(rawFeedback?.grade ?: "") }
val feedback = rememberRichTextState() val feedback = rememberRichTextState()
LaunchedEffect(currentCriterion, criteria, criterionFeedback, key) { LaunchedEffect(currentCriterion, criteria, rawFeedback, key) {
feedback.setMarkdown(criterionFeedback?.feedback ?: "") feedback.setMarkdown(rawFeedback?.feedback ?: "")
} }
Column(modifier) { Column(modifier) {
@ -289,7 +264,7 @@ fun groupFeedbackPane(
OutlinedTextField(grade, { grade = it }, Modifier.weight(0.2f)) OutlinedTextField(grade, { grade = it }, Modifier.weight(0.2f))
Spacer(Modifier.weight(0.6f)) Spacer(Modifier.weight(0.6f))
Button( Button(
{ onSetGrade(grade); onSetFeedback(feedback.toMarkdown()) }, { onSave(grade, feedback.toMarkdown()) },
Modifier.weight(0.2f).align(Alignment.CenterVertically) Modifier.weight(0.2f).align(Alignment.CenterVertically)
) { ) {
Text("Save") Text("Save")

View File

@ -171,10 +171,14 @@ class EditionState(val edition: Edition) {
fun newSoloAssignment(name: String) { fun newSoloAssignment(name: String) {
transaction { transaction {
SoloAssignment.new { val assign = SoloAssignment.new {
this.name = name; this.edition = this@EditionState.edition; assignment = ""; deadline = now() this.name = name; this.edition = this@EditionState.edition; assignment = ""; deadline = now()
this.number = nextIdx() this.number = nextIdx()
} }
val global = SoloAssignmentCriterion.new {
this.name = "_global"; this.description = "[Global] Meta-criterion for $name"; this.assignment = assign
}
assign.globalCriterion = global
solo.refresh() solo.refresh()
} }
} }
@ -186,10 +190,14 @@ class EditionState(val edition: Edition) {
} }
fun newGroupAssignment(name: String) { fun newGroupAssignment(name: String) {
transaction { transaction {
GroupAssignment.new { val assign = GroupAssignment.new {
this.name = name; this.edition = this@EditionState.edition; assignment = ""; deadline = now() this.name = name; this.edition = this@EditionState.edition; assignment = ""; deadline = now()
this.number = nextIdx() this.number = nextIdx()
} }
val global = GroupAssignmentCriterion.new {
this.name = "_global"; this.description = "[Global] Meta-criterion for $name"; this.assignment = assign
}
assign.globalCriterion = global
groupAs.refresh() groupAs.refresh()
} }
} }
@ -494,7 +502,7 @@ class GroupAssignmentState(val assignment: GroupAssignment) {
private fun Transaction.loadFeedback(): List<Pair<Group, LocalGFeedback>> { private fun Transaction.loadFeedback(): List<Pair<Group, LocalGFeedback>> {
val allCrit = GroupAssignmentCriterion.find { val allCrit = GroupAssignmentCriterion.find {
GroupAssignmentCriteria.assignmentId eq assignment.id GroupAssignmentCriteria.assignmentId eq assignment.id
}.filter { it.id != assignment.globalCriterion.id } }//.filter { it.id != assignment.globalCriterion.id }
return Group.find { return Group.find {
(Groups.editionId eq assignment.edition.id) (Groups.editionId eq assignment.edition.id)
@ -525,11 +533,12 @@ class GroupAssignmentState(val assignment: GroupAssignment) {
val student = it.student val student = it.student
val role = it.role val role = it.role
val forSt = (IndividualFeedbacks innerJoin Groups innerJoin GroupStudents) val forSt = (IndividualFeedbacks innerJoin Groups)
.selectAll().where { .selectAll().where {
(IndividualFeedbacks.assignmentId eq assignment.id) and (IndividualFeedbacks.assignmentId eq assignment.id) and
(GroupStudents.studentId eq student.id) and (Groups.id eq group.id) (IndividualFeedbacks.studentId eq student.id) and (Groups.id eq group.id)
}.map { row -> }.map { row ->
val stdId = row[IndividualFeedbacks.studentId]
val crit = GroupAssignmentCriterion[row[IndividualFeedbacks.criterionId]] val crit = GroupAssignmentCriterion[row[IndividualFeedbacks.criterionId]]
val fdbk = row[IndividualFeedbacks.feedback] val fdbk = row[IndividualFeedbacks.feedback]
val grade = row[IndividualFeedbacks.grade] val grade = row[IndividualFeedbacks.grade]
@ -537,7 +546,7 @@ class GroupAssignmentState(val assignment: GroupAssignment) {
crit to FeedbackEntry(fdbk, grade) crit to FeedbackEntry(fdbk, grade)
} }
val global = forSt.firstOrNull { it.first == assignment.globalCriterion.id }?.second val global = forSt.firstOrNull { it.first.id == assignment.globalCriterion.id }?.second
val byCrit_ = forSt val byCrit_ = forSt
.filter { it.first != assignment.globalCriterion.id } .filter { it.first != assignment.globalCriterion.id }
.map { LocalCriterionFeedback(it.first, it.second) } .map { LocalCriterionFeedback(it.first, it.second) }