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.mohamedrejeb.richeditor.model.rememberRichTextState
import com.mohamedrejeb.richeditor.ui.material3.OutlinedRichTextEditor
import com.mohamedrejeb.richeditor.ui.material3.RichTextEditor
@OptIn(ExperimentalMaterial3Api::class)
@Composable

View File

@ -11,11 +11,13 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogWindow
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.rememberDialogState
import com.jaytux.grader.maxN
import com.jaytux.grader.viewmodel.GroupState
import com.jaytux.grader.viewmodel.StudentState
@ -26,37 +28,114 @@ fun StudentView(state: StudentState) {
val groupGrades by state.groupGrades.entities
val soloGrades by state.soloGrades.entities
// TODO: incorporate grades into UI
Column(Modifier.padding(10.dp)) {
PaneHeader(state.student.name, "student", state.editionCourse)
Row {
Column(Modifier.padding(10.dp).weight(0.45f)) {
Spacer(Modifier.height(10.dp))
InteractToEdit(state.student.name, { state.update { this.name = it } }, "Name")
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)) {}
}
Row {
Column(Modifier.weight(0.5f)) {
Text("Courses", style = MaterialTheme.typography.headlineSmall)
ListOrEmpty(courses, { Text("Not a member of any course") }) { _, it ->
val (ed, course) = it
Text("${course.name} (${ed.name})", style = MaterialTheme.typography.bodyMedium)
Column(Modifier.weight(0.45f)) {
Column(Modifier.padding(10.dp).weight(0.35f)) {
Spacer(Modifier.height(10.dp))
InteractToEdit(state.student.name, { state.update { this.name = it } }, "Name")
InteractToEdit(state.student.contact, { state.update { this.contact = it } }, "Contact")
InteractToEdit(state.student.note, { state.update { this.note = it } }, "Note", singleLine = false)
}
Column(Modifier.weight(0.20f)) {
Text("Courses", style = MaterialTheme.typography.headlineSmall)
ListOrEmpty(courses, { Text("Not a member of any course") }) { _, it ->
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)) {
Text("Groups", style = MaterialTheme.typography.headlineSmall)
ListOrEmpty(groups, { Text("Not a member of any group") }) { _, it ->
item {
Text("Solo assignments", fontWeight = FontWeight.Bold)
}
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 {
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)
Spacer(Modifier.width(10.dp))
Column {
ItalicAndNormal("Assignment: ", assignment)
ItalicAndNormal("Group name: ", group)
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

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