UI changes: can go back in edition view

This commit is contained in:
jay-tux 2025-03-04 16:53:39 +01:00
parent b69b46afee
commit 63c4197cfc
Signed by: jay-tux
GPG Key ID: 84302006B056926E
4 changed files with 56 additions and 34 deletions

View File

@ -20,8 +20,6 @@ import com.mohamedrejeb.richeditor.ui.material3.OutlinedRichTextEditor
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun GroupAssignmentView(state: GroupAssignmentState) { fun GroupAssignmentView(state: GroupAssignmentState) {
val (course, edition) = state.editionCourse
val name by state.name
val task by state.task val task by state.task
val deadline by state.deadline val deadline by state.deadline
val allFeedback by state.feedback.entities val allFeedback by state.feedback.entities
@ -29,7 +27,6 @@ fun GroupAssignmentView(state: GroupAssignmentState) {
var idx by remember(state) { mutableStateOf(0) } var idx by remember(state) { mutableStateOf(0) }
Column(Modifier.padding(10.dp)) { Column(Modifier.padding(10.dp)) {
PaneHeader(name, "group assignment", course, edition)
if(allFeedback.any { it.second.feedback == null }) { if(allFeedback.any { it.second.feedback == null }) {
Text("Groups in bold have no feedback yet.", fontStyle = FontStyle.Italic) Text("Groups in bold have no feedback yet.", fontStyle = FontStyle.Italic)
} }
@ -150,8 +147,6 @@ fun groupFeedback(state: GroupAssignmentState, fdbk: GroupAssignmentState.LocalG
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SoloAssignmentView(state: SoloAssignmentState) { fun SoloAssignmentView(state: SoloAssignmentState) {
val name by state.name
val (course, edition) = state.editionCourse
val task by state.task val task by state.task
val deadline by state.deadline val deadline by state.deadline
val suggestions by state.autofill.entities val suggestions by state.autofill.entities
@ -160,7 +155,6 @@ fun SoloAssignmentView(state: SoloAssignmentState) {
var idx by remember(state) { mutableStateOf(0) } var idx by remember(state) { mutableStateOf(0) }
Column(Modifier.padding(10.dp)) { Column(Modifier.padding(10.dp)) {
PaneHeader(name, "individual assignment", course, edition)
Row { Row {
Surface(Modifier.weight(0.25f), tonalElevation = 10.dp) { Surface(Modifier.weight(0.25f), tonalElevation = 10.dp) {
LazyColumn(Modifier.fillMaxHeight().padding(10.dp)) { LazyColumn(Modifier.fillMaxHeight().padding(10.dp)) {

View File

@ -15,10 +15,6 @@ import androidx.compose.ui.window.*
import com.jaytux.grader.data.* import com.jaytux.grader.data.*
import com.jaytux.grader.viewmodel.* import com.jaytux.grader.viewmodel.*
enum class OpenPanel(val tabName: String) {
Student("Students"), Group("Groups"), Assignment("Assignments")
}
data class Navigators( data class Navigators(
val student: (Student) -> Unit, val student: (Student) -> Unit,
val group: (Group) -> Unit, val group: (Group) -> Unit,
@ -36,41 +32,41 @@ fun EditionView(state: EditionState) = Row(Modifier.padding(0.dp)) {
val mergedAssignments by remember(solo, groupAs) { val mergedAssignments by remember(solo, groupAs) {
mutableStateOf(Assignment.merge(groupAs, solo)) mutableStateOf(Assignment.merge(groupAs, solo))
} }
var selected by remember { mutableStateOf(-1) } val hist by state.history
var tab by remember { mutableStateOf(OpenPanel.Assignment) }
val navs = Navigators( val navs = Navigators(
student = { tab = OpenPanel.Student; selected = students.indexOfFirst { s -> s.id == it.id } }, student = { state.navTo(OpenPanel.Student, students.indexOfFirst{ s -> s.id == it.id }) },
group = { tab = OpenPanel.Group; selected = groups.indexOfFirst { g -> g.id == it.id } }, group = { state.navTo(OpenPanel.Group, groups.indexOfFirst { g -> g.id == it.id }) },
assignment = { tab = OpenPanel.Assignment; selected = mergedAssignments.indexOfFirst { a -> a.id() == it.id() } } assignment = { state.navTo(OpenPanel.Assignment, mergedAssignments.indexOfFirst { a -> a.id() == it.id() }) }
) )
val (id, tab) = hist.last()
Surface(Modifier.weight(0.25f), tonalElevation = 5.dp) { Surface(Modifier.weight(0.25f), tonalElevation = 5.dp) {
TabLayout( TabLayout(
OpenPanel.entries, OpenPanel.entries,
tab.ordinal, tab.ordinal,
{ tab = OpenPanel.entries[it]; selected = -1 }, { state.navTo(OpenPanel.entries[it]) },
{ Text(it.tabName) } { Text(it.tabName) }
) { ) {
when(tab) { when(tab) {
OpenPanel.Student -> StudentPanel( OpenPanel.Student -> StudentPanel(
course, edition, students, availableStudents, selected, course, edition, students, availableStudents, id,
{ selected = it }, { state.navTo(it) },
{ name, note, contact, add -> state.newStudent(name, contact, note, add) }, { name, note, contact, add -> state.newStudent(name, contact, note, add) },
{ students -> state.addToCourse(students) }, { students -> state.addToCourse(students) },
{ s, name -> state.setStudentName(s, name) } { s, name -> state.setStudentName(s, name) }
) { s -> state.delete(s) } ) { s -> state.delete(s) }
OpenPanel.Group -> GroupPanel( OpenPanel.Group -> GroupPanel(
course, edition, groups, selected, course, edition, groups, id,
{ selected = it }, { state.navTo(it) },
{ name -> state.newGroup(name) }, { name -> state.newGroup(name) },
{ g, name -> state.setGroupName(g, name) } { g, name -> state.setGroupName(g, name) }
) { g -> state.delete(g) } ) { g -> state.delete(g) }
OpenPanel.Assignment -> AssignmentPanel( OpenPanel.Assignment -> AssignmentPanel(
course, edition, mergedAssignments, selected, course, edition, mergedAssignments, id,
{ selected = it }, { state.navTo(it) },
{ type, name -> state.newAssignment(type, name) }, { type, name -> state.newAssignment(type, name) },
{ a, name -> state.setAssignmentTitle(a, name) } { a, name -> state.setAssignmentTitle(a, name) }
) { a -> state.delete(a) } ) { a -> state.delete(a) }
@ -78,15 +74,36 @@ fun EditionView(state: EditionState) = Row(Modifier.padding(0.dp)) {
} }
} }
Box(Modifier.weight(0.75f)) { Column(Modifier.weight(0.75f)) {
if(selected != -1) { Row {
IconButton({ state.back() }, enabled = hist.size >= 2) {
Icon(ChevronLeft, "Back", Modifier.size(MaterialTheme.typography.headlineMedium.fontSize.toDp()).align(Alignment.CenterVertically))
}
when(tab) { when(tab) {
OpenPanel.Student -> StudentView(StudentState(students[selected], edition), navs) OpenPanel.Student -> {
OpenPanel.Group -> GroupView(GroupState(groups[selected]), navs) if(id == -1) PaneHeader("Nothing selected", "students", course, edition)
else PaneHeader(students[id].name, "student", course, edition)
}
OpenPanel.Group -> {
if(id == -1) PaneHeader("Nothing selected", "groups", course, edition)
else PaneHeader(groups[id].name, "group", course, edition)
}
OpenPanel.Assignment -> { OpenPanel.Assignment -> {
when(val a = mergedAssignments[selected]) { if(id == -1) PaneHeader("Nothing selected", "assignments", course, edition)
is Assignment.SAssignment -> SoloAssignmentView(SoloAssignmentState(a.assignment)) else PaneHeader(mergedAssignments[id].name(), "assignment", course, edition)
is Assignment.GAssignment -> GroupAssignmentView(GroupAssignmentState(a.assignment)) }
}
}
Box(Modifier.weight(1f)) {
if (id != -1) {
when (tab) {
OpenPanel.Student -> StudentView(StudentState(students[id], edition), navs)
OpenPanel.Group -> GroupView(GroupState(groups[id]), navs)
OpenPanel.Assignment -> {
when (val a = mergedAssignments[id]) {
is Assignment.SAssignment -> SoloAssignmentView(SoloAssignmentState(a.assignment))
is Assignment.GAssignment -> GroupAssignmentView(GroupAssignmentState(a.assignment))
}
} }
} }
} }

View File

@ -17,8 +17,6 @@ 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.data.Group
import com.jaytux.grader.data.Student
import com.jaytux.grader.maxN 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
@ -31,7 +29,6 @@ fun StudentView(state: StudentState, nav: Navigators) {
val soloGrades by state.soloGrades.entities val soloGrades by state.soloGrades.entities
Column(Modifier.padding(10.dp)) { Column(Modifier.padding(10.dp)) {
PaneHeader(state.student.name, "student", state.editionCourse)
Row { Row {
Column(Modifier.weight(0.45f)) { Column(Modifier.weight(0.45f)) {
Column(Modifier.padding(10.dp).weight(0.35f)) { Column(Modifier.padding(10.dp).weight(0.35f)) {
@ -150,12 +147,10 @@ fun GroupView(state: GroupState, nav: Navigators) {
val members by state.members.entities val members by state.members.entities
val available by state.availableStudents.entities val available by state.availableStudents.entities
val allRoles by state.roles.entities val allRoles by state.roles.entities
val (course, edition) = state.course
var pickRole: Pair<String?, (String?) -> Unit>? by remember { mutableStateOf(null) } var pickRole: Pair<String?, (String?) -> Unit>? by remember { mutableStateOf(null) }
Column(Modifier.padding(10.dp)) { Column(Modifier.padding(10.dp)) {
PaneHeader(state.group.name, "group", course, edition)
Row { Row {
Column(Modifier.weight(0.5f)) { Column(Modifier.weight(0.5f)) {
Text("Students", style = MaterialTheme.typography.headlineSmall) Text("Students", style = MaterialTheme.typography.headlineSmall)

View File

@ -87,12 +87,18 @@ class EditionListState(val course: Course) {
} }
} }
enum class OpenPanel(val tabName: String) {
Student("Students"), Group("Groups"), Assignment("Assignments")
}
class EditionState(val edition: Edition) { class EditionState(val edition: Edition) {
val course = transaction { edition.course } val course = transaction { edition.course }
val students = RawDbState { edition.soloStudents.sortAsc(Students.name).toList() } val students = RawDbState { edition.soloStudents.sortAsc(Students.name).toList() }
val groups = RawDbState { edition.groups.sortAsc(Groups.name).toList() } val groups = RawDbState { edition.groups.sortAsc(Groups.name).toList() }
val solo = RawDbState { edition.soloAssignments.sortAsc(SoloAssignments.name).toList() } val solo = RawDbState { edition.soloAssignments.sortAsc(SoloAssignments.name).toList() }
val groupAs = RawDbState { edition.groupAssignments.sortAsc(GroupAssignments.name).toList() } val groupAs = RawDbState { edition.groupAssignments.sortAsc(GroupAssignments.name).toList() }
private val _history = mutableStateOf(listOf(-1 to OpenPanel.Assignment))
val history = _history.immutable()
val availableStudents = RawDbState { val availableStudents = RawDbState {
Student.find { Student.find {
@ -217,6 +223,16 @@ class EditionState(val edition: Edition) {
is Assignment.GAssignment -> delete(assignment.assignment) is Assignment.GAssignment -> delete(assignment.assignment)
is Assignment.SAssignment -> delete(assignment.assignment) is Assignment.SAssignment -> delete(assignment.assignment)
} }
fun navTo(panel: OpenPanel, id: Int = -1) {
_history.value += (id to panel)
}
fun navTo(id: Int) = navTo(_history.value.last().second, id)
fun back() {
var temp = _history.value.dropLast(1)
while(temp.last().first == -1 && temp.size >= 2) temp = temp.dropLast(1)
_history.value = temp
}
} }
class StudentState(val student: Student, edition: Edition) { class StudentState(val student: Student, edition: Edition) {