Skip to content

Commit b858a1e

Browse files
[Student][R-6.6.1][MBL-13100] Quick bandaid for network-related crashes in grades list (#268)
1 parent 16dc91f commit b858a1e

1 file changed

Lines changed: 109 additions & 83 deletions

File tree

apps/student/src/main/java/com/instructure/student/adapter/GradesListRecyclerAdapter.kt

Lines changed: 109 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,22 @@ package com.instructure.student.adapter
1919

2020
import android.content.Context
2121
import android.view.View
22+
import android.widget.Toast
2223
import androidx.recyclerview.widget.RecyclerView
2324
import com.instructure.canvasapi2.StatusCallback
2425
import com.instructure.canvasapi2.managers.AssignmentManager
2526
import com.instructure.canvasapi2.managers.CourseManager
2627
import com.instructure.canvasapi2.managers.EnrollmentManager
2728
import com.instructure.canvasapi2.managers.SubmissionManager
28-
import com.instructure.canvasapi2.models.*
29+
import com.instructure.canvasapi2.models.Assignment
30+
import com.instructure.canvasapi2.models.AssignmentGroup
31+
import com.instructure.canvasapi2.models.CanvasContext
32+
import com.instructure.canvasapi2.models.Course
33+
import com.instructure.canvasapi2.models.CourseGrade
34+
import com.instructure.canvasapi2.models.Enrollment
35+
import com.instructure.canvasapi2.models.GradingPeriod
36+
import com.instructure.canvasapi2.models.GradingPeriodResponse
37+
import com.instructure.canvasapi2.models.Submission
2938
import com.instructure.canvasapi2.utils.ApiPrefs
3039
import com.instructure.canvasapi2.utils.isNullOrEmpty
3140
import com.instructure.canvasapi2.utils.weave.awaitApi
@@ -45,7 +54,8 @@ import kotlinx.coroutines.Dispatchers
4554
import kotlinx.coroutines.GlobalScope
4655
import kotlinx.coroutines.Job
4756
import kotlinx.coroutines.launch
48-
import java.util.*
57+
import java.util.ArrayList
58+
import java.util.HashMap
4959

5060
open class GradesListRecyclerAdapter(
5161
context: Context,
@@ -110,46 +120,50 @@ open class GradesListRecyclerAdapter(
110120

111121
final override fun loadData() {
112122
loadDataJob = GlobalScope.launch(Dispatchers.Main) {
113-
// Logic regarding MGP is similar here as it is in both assignment recycler adapters,
114-
// if changes are made here, check if they are needed in the other recycler adapters
115-
val course = awaitApi<Course>{CourseManager.getCourseWithGrade(canvasContext!!.id, it, true)}
116-
val enrollments = (canvasContext as Course).enrollments
117-
canvasContext = course
118-
119-
// Use the enrollments that were passed in with the course if one returned has none
120-
// Should only be concluded courses that this applies
121-
(canvasContext as Course).apply {
122-
if (this.enrollments.isNullOrEmpty()) {
123-
this.enrollments = enrollments
124-
}
125-
}
126-
127-
// We want to disable what if grading if MGP weights are enabled
128-
if (course.isWeightedGradingPeriods) {
129-
adapterToGradesCallback?.setIsWhatIfGrading(false)
130-
} else {
131-
adapterToGradesCallback?.setIsWhatIfGrading(true)
132-
}
133-
134-
if (isAllGradingPeriodsSelected) {
135-
isRefresh = true
136-
updateCourseGrade()
137-
updateWithAllAssignments()
138-
return@launch
139-
}
140-
141-
course.enrollments!!.firstOrNull {
142-
it.isStudent && it.multipleGradingPeriodsEnabled
143-
}?.let { enrollment ->
144-
setupStudentGrades(enrollment, course)
145-
} ?: course.enrollments!!.firstOrNull { it.isObserver }?.let { enrollment ->
146-
setupObserverGrades(enrollment, course)
147-
}
148-
149-
// If we've made it this far, MGP is not enabled, so we do the standard behavior
150-
isRefresh = true
151-
updateCourseGrade()
152-
updateWithAllAssignments()
123+
try {
124+
// Logic regarding MGP is similar here as it is in both assignment recycler adapters,
125+
// if changes are made here, check if they are needed in the other recycler adapters
126+
val course = awaitApi<Course>{CourseManager.getCourseWithGrade(canvasContext!!.id, it, true)}
127+
val enrollments = (canvasContext as Course).enrollments
128+
canvasContext = course
129+
130+
// Use the enrollments that were passed in with the course if one returned has none
131+
// Should only be concluded courses that this applies
132+
(canvasContext as Course).apply {
133+
if (this.enrollments.isNullOrEmpty()) {
134+
this.enrollments = enrollments
135+
}
136+
}
137+
138+
// We want to disable what if grading if MGP weights are enabled
139+
if (course.isWeightedGradingPeriods) {
140+
adapterToGradesCallback?.setIsWhatIfGrading(false)
141+
} else {
142+
adapterToGradesCallback?.setIsWhatIfGrading(true)
143+
}
144+
145+
if (isAllGradingPeriodsSelected) {
146+
isRefresh = true
147+
updateCourseGrade()
148+
updateWithAllAssignments()
149+
return@launch
150+
}
151+
152+
course.enrollments!!.firstOrNull {
153+
it.isStudent && it.multipleGradingPeriodsEnabled
154+
}?.let { enrollment ->
155+
setupStudentGrades(enrollment, course)
156+
} ?: course.enrollments!!.firstOrNull { it.isObserver }?.let { enrollment ->
157+
setupObserverGrades(enrollment, course)
158+
}
159+
160+
// If we've made it this far, MGP is not enabled, so we do the standard behavior
161+
isRefresh = true
162+
updateCourseGrade()
163+
updateWithAllAssignments()
164+
} catch (e: Throwable) {
165+
Toast.makeText(context, R.string.errorOccurred, Toast.LENGTH_SHORT).show()
166+
}
153167
}
154168
}
155169

@@ -162,38 +176,42 @@ open class GradesListRecyclerAdapter(
162176

163177
// Get the first student that this user is observing
164178
observerCourseGradeJob = GlobalScope.launch(Dispatchers.Main) {
165-
// We need to use an ID from an observee, not the user (who is currently logged in as an observer) when retrieving the enrollments
166-
167-
// Get the first student this user is observing, if none show empty assignments
168-
val student = awaitApi<List<Enrollment>> { EnrollmentManager.getObserveeEnrollments(true, it) }
169-
.firstOrNull { it.courseId == course.id && it.observedUser != null }?.observedUser
170-
?: return@launch updateAssignmentGroups(emptyList())
171-
172-
// Get Assignment Groups
173-
val assignmentGroups = awaitApi<List<AssignmentGroup>> { AssignmentManager.getAssignmentGroupsWithAssignmentsForGradingPeriod(canvasContext!!.id, currentGradingPeriod!!.id,
174-
scopeToStudent = false,
175-
forceNetwork = true,
176-
callback = it
177-
) }
178-
// The assignments in the assignment groups do not come with their submissions (with the associated grades), so we get them all here
179-
val assignmentIds = assignmentGroups.map { it.assignments }.flatten().map { it.id }
180-
val submissions = awaitApi<List<Submission>>{ SubmissionManager.getSubmissionsForMultipleAssignments(student.id, course.id, assignmentIds, it, true) }
181-
assignmentGroups.forEach { group ->
182-
group.assignments.forEach { assignment ->
183-
assignment.submission = submissions.firstOrNull { it.assignmentId == assignment.id }
179+
try {
180+
// We need to use an ID from an observee, not the user (who is currently logged in as an observer) when retrieving the enrollments
181+
182+
// Get the first student this user is observing, if none show empty assignments
183+
val student = awaitApi<List<Enrollment>> { EnrollmentManager.getObserveeEnrollments(true, it) }
184+
.firstOrNull { it.courseId == course.id && it.observedUser != null }?.observedUser
185+
?: return@launch updateAssignmentGroups(emptyList())
186+
187+
// Get Assignment Groups
188+
val assignmentGroups = awaitApi<List<AssignmentGroup>> { AssignmentManager.getAssignmentGroupsWithAssignmentsForGradingPeriod(canvasContext!!.id, currentGradingPeriod!!.id,
189+
scopeToStudent = false,
190+
forceNetwork = true,
191+
callback = it
192+
) }
193+
// The assignments in the assignment groups do not come with their submissions (with the associated grades), so we get them all here
194+
val assignmentIds = assignmentGroups.map { it.assignments }.flatten().map { it.id }
195+
val submissions = awaitApi<List<Submission>>{ SubmissionManager.getSubmissionsForMultipleAssignments(student.id, course.id, assignmentIds, it, true) }
196+
assignmentGroups.forEach { group ->
197+
group.assignments.forEach { assignment ->
198+
assignment.submission = submissions.firstOrNull { it.assignmentId == assignment.id }
199+
}
184200
}
185-
}
186201

187-
updateAssignmentGroups(assignmentGroups)
202+
updateAssignmentGroups(assignmentGroups)
188203

189-
awaitApi<List<Course>> { CourseManager.getCoursesWithSyllabus(true, it) }
190-
.onEach { course ->
191-
course.enrollments?.find { it.userId == student.id }?.let {
192-
course.enrollments = mutableListOf(it)
193-
courseGrade = course.getCourseGradeFromEnrollment(it, false)
194-
adapterToGradesCallback?.notifyGradeChanged(courseGrade)
204+
awaitApi<List<Course>> { CourseManager.getCoursesWithSyllabus(true, it) }
205+
.onEach { course ->
206+
course.enrollments?.find { it.userId == student.id }?.let {
207+
course.enrollments = mutableListOf(it)
208+
courseGrade = course.getCourseGradeFromEnrollment(it, false)
209+
adapterToGradesCallback?.notifyGradeChanged(courseGrade)
210+
}
195211
}
196-
}
212+
} catch (e: Throwable) {
213+
Toast.makeText(context, R.string.errorOccurred, Toast.LENGTH_SHORT).show()
214+
}
197215
}
198216
return
199217
}
@@ -228,16 +246,20 @@ open class GradesListRecyclerAdapter(
228246
val scopeToStudent = (canvasContext as Course).isStudent
229247
if (scopeToStudent) {
230248
assignmentsForGradingPeriodJob = GlobalScope.launch(Dispatchers.Main) {
231-
val assignmentGroups = awaitApi<List<AssignmentGroup>>{AssignmentManager.getAssignmentGroupsWithAssignmentsForGradingPeriod(canvasContext!!.id, gradingPeriodID, scopeToStudent, true, it)}
232-
updateAssignmentGroups(assignmentGroups)
233-
234-
// Fetch the enrollments associated with the selected gradingPeriodID, these will contain the
235-
// correct grade for the period
236-
val enrollments = awaitApi<List<Enrollment>>{CourseManager.getUserEnrollmentsForGradingPeriod(canvasContext!!.id, ApiPrefs.user!!.id, gradingPeriodID, it, true)}
237-
updateCourseGradeFromEnrollments(enrollments)
238-
239-
// Inform the spinner things are done
240-
adapterToGradesCallback?.setTermSpinnerState(true)
249+
try {
250+
val assignmentGroups = awaitApi<List<AssignmentGroup>>{AssignmentManager.getAssignmentGroupsWithAssignmentsForGradingPeriod(canvasContext!!.id, gradingPeriodID, scopeToStudent, true, it)}
251+
updateAssignmentGroups(assignmentGroups)
252+
253+
// Fetch the enrollments associated with the selected gradingPeriodID, these will contain the
254+
// correct grade for the period
255+
val enrollments = awaitApi<List<Enrollment>>{CourseManager.getUserEnrollmentsForGradingPeriod(canvasContext!!.id, ApiPrefs.user!!.id, gradingPeriodID, it, true)}
256+
updateCourseGradeFromEnrollments(enrollments)
257+
258+
// Inform the spinner things are done
259+
adapterToGradesCallback?.setTermSpinnerState(true)
260+
} catch (e: Throwable) {
261+
Toast.makeText(context, R.string.errorOccurred, Toast.LENGTH_SHORT).show()
262+
}
241263
}
242264
}
243265
}
@@ -262,9 +284,13 @@ open class GradesListRecyclerAdapter(
262284

263285
private fun updateWithAllAssignments() {
264286
allAssignmentsAndGroupsJob = GlobalScope.launch(Dispatchers.Main) {
265-
// Standard load assignments, unfiltered
266-
val aGroups = awaitApi<List<AssignmentGroup>>{AssignmentManager.getAssignmentGroupsWithAssignments(canvasContext!!.id, true, it)}
267-
updateAssignmentGroups(aGroups)
287+
try {
288+
// Standard load assignments, unfiltered
289+
val aGroups = awaitApi<List<AssignmentGroup>>{AssignmentManager.getAssignmentGroupsWithAssignments(canvasContext!!.id, true, it)}
290+
updateAssignmentGroups(aGroups)
291+
} catch (e: Throwable) {
292+
Toast.makeText(context, R.string.errorOccurred, Toast.LENGTH_SHORT).show()
293+
}
268294
}
269295
}
270296

0 commit comments

Comments
 (0)