Expanded student view

This commit is contained in:
jay-tux 2025-02-27 19:58:21 +01:00
parent fbc450e0ee
commit 97fe7a8139
Signed by: jay-tux
GPG Key ID: 84302006B056926E
4 changed files with 118 additions and 25 deletions

View File

@ -0,0 +1,9 @@
package com.jaytux.grader
fun String.maxN(n: Int): String {
return if (this.length > n) {
this.substring(0, n - 3) + "..."
} else {
this
}
}

View File

@ -15,7 +15,6 @@ import androidx.compose.ui.unit.dp
import com.jaytux.grader.viewmodel.GroupAssignmentState import com.jaytux.grader.viewmodel.GroupAssignmentState
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 com.mohamedrejeb.richeditor.ui.material3.RichTextEditor
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable

View File

@ -11,11 +11,13 @@ import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogWindow import androidx.compose.ui.window.DialogWindow
import androidx.compose.ui.window.WindowPosition import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.rememberDialogState import androidx.compose.ui.window.rememberDialogState
import com.jaytux.grader.maxN
import com.jaytux.grader.viewmodel.GroupState import com.jaytux.grader.viewmodel.GroupState
import com.jaytux.grader.viewmodel.StudentState import com.jaytux.grader.viewmodel.StudentState
@ -26,37 +28,114 @@ fun StudentView(state: StudentState) {
val groupGrades by state.groupGrades.entities val groupGrades by state.groupGrades.entities
val soloGrades by state.soloGrades.entities val soloGrades by state.soloGrades.entities
// TODO: incorporate grades into UI
Column(Modifier.padding(10.dp)) { Column(Modifier.padding(10.dp)) {
PaneHeader(state.student.name, "student", state.editionCourse) PaneHeader(state.student.name, "student", state.editionCourse)
Row { Row {
Column(Modifier.padding(10.dp).weight(0.45f)) { Column(Modifier.weight(0.45f)) {
Spacer(Modifier.height(10.dp)) Column(Modifier.padding(10.dp).weight(0.35f)) {
InteractToEdit(state.student.name, { state.update { this.name = it } }, "Name") Spacer(Modifier.height(10.dp))
InteractToEdit(state.student.contact, { state.update { this.contact = it } }, "Contact") InteractToEdit(state.student.name, { state.update { this.name = it } }, "Name")
InteractToEdit(state.student.note, { state.update { this.note = it } }, "Note", singleLine = false) InteractToEdit(state.student.contact, { state.update { this.contact = it } }, "Contact")
} InteractToEdit(state.student.note, { state.update { this.note = it } }, "Note", singleLine = false)
Box(Modifier.weight(0.55f)) {} }
} Column(Modifier.weight(0.20f)) {
Row { Text("Courses", style = MaterialTheme.typography.headlineSmall)
Column(Modifier.weight(0.5f)) { ListOrEmpty(courses, { Text("Not a member of any course") }) { _, it ->
Text("Courses", style = MaterialTheme.typography.headlineSmall) val (ed, course) = it
ListOrEmpty(courses, { Text("Not a member of any course") }) { _, it -> Text("${course.name} (${ed.name})", style = MaterialTheme.typography.bodyMedium)
val (ed, course) = it }
Text("${course.name} (${ed.name})", style = MaterialTheme.typography.bodyMedium) }
Column(Modifier.weight(0.45f)) {
Text("Groups", style = MaterialTheme.typography.headlineSmall)
ListOrEmpty(groups, { Text("Not a member of any group") }) { _, it ->
Row {
val (group, c) = it
val (course, ed) = c
Text(group.name, style = MaterialTheme.typography.bodyMedium)
Spacer(Modifier.width(5.dp))
Text(
"(in course $course ($ed))",
Modifier.align(Alignment.Bottom),
style = MaterialTheme.typography.bodySmall
)
}
}
} }
} }
Column(Modifier.weight(0.55f)) {
Text("Courses", style = MaterialTheme.typography.headlineSmall)
LazyColumn {
item {
Text("As group member", fontWeight = FontWeight.Bold)
}
items(groupGrades) {
groupGradeWidget(it)
}
Column(Modifier.weight(0.5f)) { item {
Text("Groups", style = MaterialTheme.typography.headlineSmall) Text("Solo assignments", fontWeight = FontWeight.Bold)
ListOrEmpty(groups, { Text("Not a member of any group") }) { _, it -> }
items(soloGrades) {
soloGradeWidget(it)
}
}
}
}
}
}
@Composable
fun groupGradeWidget(gg: StudentState.LocalGroupGrade) {
val (group, assignment, gGrade, iGrade) = gg
var expanded by remember { mutableStateOf(false) }
Row(Modifier.padding(5.dp)) {
Spacer(Modifier.width(10.dp))
Surface(
Modifier.clickable { expanded = !expanded }.fillMaxWidth(),
tonalElevation = 5.dp,
shape = MaterialTheme.shapes.medium
) {
Column(Modifier.padding(5.dp)) {
Text("${assignment.maxN(25)} (${iGrade ?: gGrade ?: "no grade yet"})")
if (expanded) {
Row { Row {
val (group, c) = it Spacer(Modifier.width(10.dp))
val (course, ed) = c Column {
Text(group.name, style = MaterialTheme.typography.bodyMedium) ItalicAndNormal("Assignment: ", assignment)
Spacer(Modifier.width(5.dp)) ItalicAndNormal("Group name: ", group)
Text("(in course $course ($ed))", Modifier.align(Alignment.Bottom), style = MaterialTheme.typography.bodySmall) ItalicAndNormal("Group grade: ", gGrade ?: "no grade yet")
ItalicAndNormal("Individual grade: ", iGrade ?: "no individual grade")
}
}
}
}
}
}
}
@Composable
fun soloGradeWidget(sg: StudentState.LocalSoloGrade) {
val (assignment, grade) = sg
var expanded by remember { mutableStateOf(false) }
Row(Modifier.padding(5.dp)) {
Spacer(Modifier.width(10.dp))
Surface(
Modifier.clickable { expanded = !expanded }.fillMaxWidth(),
tonalElevation = 5.dp,
shape = MaterialTheme.shapes.medium
) {
Column(Modifier.padding(5.dp)) {
Text("${assignment.maxN(25)} (${grade ?: "no grade yet"})")
if (expanded) {
Row {
Spacer(Modifier.width(10.dp))
Column {
ItalicAndNormal("Assignment: ", assignment)
ItalicAndNormal("Individual grade: ", grade ?: "no grade yet")
}
} }
} }
} }

View File

@ -342,4 +342,10 @@ fun DateTimePicker(
// ) // )
// } // }
} }
}
@Composable
fun ItalicAndNormal(italic: String, normal: String) = Row{
Text(italic, fontStyle = FontStyle.Italic)
Text(normal)
} }