Skip to content

Commit 01219c0

Browse files
hermannakosclaude
andcommitted
[MBL-19639][Student] Display lock date in device timezone instead of account timezone
Replace server-provided lockExplanation (formatted in account timezone) with locally-formatted lock date using DateFormat to ensure consistency with other dates on the assignment details screen. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 165b0a6 commit 01219c0

5 files changed

Lines changed: 25 additions & 8 deletions

File tree

apps/student/src/main/java/com/instructure/student/fragment/AssignmentBasicFragment.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.instructure.student.fragment
1818

1919
import android.os.Bundle
20+
import java.text.DateFormat
2021
import android.view.LayoutInflater
2122
import android.view.View
2223
import android.view.ViewGroup
@@ -147,10 +148,13 @@ class AssignmentBasicFragment : ParentFragment() {
147148
// Assignment description can be null
148149
var description = when {
149150
assignment.isLocked -> getLockedInfoHTML(assignment.lockInfo!!, R.string.lockedAssignmentDesc)
150-
assignment.lockDate?.before(Calendar.getInstance(Locale.getDefault()).time) == true ->
151+
assignment.lockDate?.before(Calendar.getInstance(Locale.getDefault()).time) == true -> {
151152
// If an assignment has an available from and until field and it has expired (the current date is after "until" it will have a lock explanation,
152153
// but no lock info because it isn't Locked as part of a module
153-
assignment.lockExplanation
154+
val dateString = DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault()).format(assignment.lockDate!!)
155+
val timeString = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(assignment.lockDate!!)
156+
getString(com.instructure.pandautils.R.string.closedSubtext, dateString, timeString)
157+
}
154158
else -> assignment.description
155159
}
156160

libs/pandautils/src/main/java/com/instructure/pandautils/features/assignments/details/AssignmentDetailsViewModel.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,11 @@ class AssignmentDetailsViewModel @Inject constructor(
446446
)
447447
}
448448

449-
val partialLockedMessage = assignment.lockExplanation.takeIf { it.isValid() && assignment.lockDate?.before(Date()).orDefault() }.orEmpty()
449+
val partialLockedMessage = assignment.lockDate?.takeIf { it.before(Date()) }?.let {
450+
val dateString = DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault()).format(it)
451+
val timeString = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(it)
452+
resources.getString(R.string.closedSubtext, dateString, timeString)
453+
}.orEmpty()
450454

451455
val submissionHistory = assignment.submission?.submissionHistory
452456
val attempts = submissionHistory?.let { history ->

libs/pandautils/src/main/java/com/instructure/pandautils/utils/LocaleUtils.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import com.instructure.canvasapi2.utils.isValid
3030
import java.time.DayOfWeek
3131
import java.util.Calendar
3232
import java.util.Locale
33+
import java.util.TimeZone
3334
import kotlin.system.exitProcess
3435

3536
object LocaleUtils {
@@ -66,6 +67,9 @@ object LocaleUtils {
6667
Locale.Builder().setLanguageTag(localeString).build()
6768
}
6869
Locale.setDefault(locale)
70+
// Ensure device timezone is used for all date/time formatting
71+
val deviceTimeZone = TimeZone.getDefault()
72+
TimeZone.setDefault(deviceTimeZone)
6973
val config = Configuration()
7074
config.setLocales(LocaleList(locale))
7175
ContextKeeper.updateLocale(config)

libs/pandautils/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
<string name="noSubmissionTeacher">This student doesn\'t have a submission yet.</string>
172172
<string name="locked">Locked</string>
173173
<string name="lockedSubtext">This assignment is locked until %1$s at %2$s.</string>
174+
<string name="closedSubtext">This assignment was locked on %1$s at %2$s.</string>
174175
<string name="chooseFile">Choose a File</string>
175176
<string name="chooseFileSubtext">Attach a file to your submission by tapping an option below.</string>
176177
<string name="chooseFileForUploadSubtext">Select a file to upload by tapping an option below</string>

libs/pandautils/src/test/java/com/instructure/pandautils/features/assignments/details/AssignmentDetailsViewModelTest.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ import org.junit.Rule
7777
import org.junit.Test
7878
import java.util.Calendar
7979
import java.util.Date
80+
import java.util.Locale
8081

8182
@ExperimentalCoroutinesApi
8283
class AssignmentDetailsViewModelTest {
@@ -188,24 +189,27 @@ class AssignmentDetailsViewModelTest {
188189

189190
@Test
190191
fun `Load partially locked assignment`() {
191-
val lockedExplanation = "locked"
192+
val lockDate = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -1) }.time
193+
val dateString = java.text.DateFormat.getDateInstance(java.text.DateFormat.LONG, Locale.getDefault()).format(lockDate)
194+
val timeString = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT, Locale.getDefault()).format(lockDate)
195+
val expectedLockedMessage = "This assignment was locked on $dateString at $timeString."
192196

193-
every { resources.getString(R.string.errorLoadingAssignment) } returns lockedExplanation
197+
every { resources.getString(R.string.errorLoadingAssignment) } returns ""
198+
every { resources.getString(R.string.closedSubtext, dateString, timeString) } returns expectedLockedMessage
194199

195200
val course = Course(enrollments = mutableListOf(Enrollment(type = Enrollment.EnrollmentType.Student)))
196201
coEvery { assignmentDetailsRepository.getCourseWithGrade(any(), any()) } returns course
197202

198203
val assignment = Assignment(
199-
lockExplanation = lockedExplanation,
200-
lockAt = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -1) }.time.toApiString()
204+
lockAt = lockDate.toApiString()
201205
)
202206
coEvery { assignmentDetailsRepository.getAssignment(any(), any(), any(), any()) } returns assignment
203207

204208
val viewModel = getViewModel()
205209

206210
assertEquals(ViewState.Success, viewModel.state.value)
207211
assertEquals(false, viewModel.data.value?.fullLocked)
208-
assertEquals(lockedExplanation, viewModel.data.value?.lockedMessage)
212+
assertEquals(expectedLockedMessage, viewModel.data.value?.lockedMessage)
209213
}
210214

211215
@Test

0 commit comments

Comments
 (0)