Skip to content

Commit 880099d

Browse files
authored
Release Student 7.12.0 (276) (#2968)
Release Student 7.12.0 (276)
2 parents ba78533 + 5a03bb6 commit 880099d

File tree

362 files changed

+9505
-8939
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

362 files changed

+9505
-8939
lines changed

apps/parent/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ android {
4040
applicationId "com.instructure.parentapp"
4141
minSdkVersion Versions.MIN_SDK
4242
targetSdkVersion Versions.TARGET_SDK
43-
versionCode 56
44-
versionName "4.0.0"
43+
versionCode 57
44+
versionName "4.1.0"
4545

4646
buildConfigField "boolean", "IS_TESTING", "false"
4747
testInstrumentationRunner 'com.instructure.parentapp.ui.espresso.ParentHiltTestRunner'

apps/parent/src/androidTest/java/com/instructure/parentapp/ui/e2e/CalendarE2ETest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ class CalendarE2ETest : ParentComposeTest() {
281281
Log.d(ASSERTION_TAG, "Assert that the event is displayed with the corresponding details (title, context name, date, status) on the page.")
282282
val currentDate = getDateInCanvasCalendarFormat()
283283
calendarScreenPage.assertItemDetails(newEventTitle, parent.name, currentDate)
284+
Thread.sleep(2000)
284285

285286
Log.d(STEP_TAG, "Click on the 'Add' (FAB) button and 'Add To Do' to create a new To Do.")
286287
calendarScreenPage.clickOnAddButton()
@@ -299,7 +300,6 @@ class CalendarE2ETest : ParentComposeTest() {
299300
val calendar = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, 2) }
300301
Log.d(STEP_TAG, "Select a date which is 2 days in the future from today and select '${course.name}' course as the canvas context.")
301302
calendarToDoCreateUpdatePage.selectDate(calendar)
302-
Thread.sleep(2000)
303303
calendarToDoCreateUpdatePage.selectCanvasContext(course.name)
304304

305305
Log.d(STEP_TAG, "Click on the 'Save' button.")

apps/parent/src/androidTest/java/com/instructure/parentapp/ui/e2e/SettingsE2ETest.kt

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,19 @@ import androidx.test.espresso.Espresso
2121
import com.instructure.canvas.espresso.E2E
2222
import com.instructure.canvas.espresso.FeatureCategory
2323
import com.instructure.canvas.espresso.Priority
24+
import com.instructure.canvas.espresso.SecondaryFeatureCategory
2425
import com.instructure.canvas.espresso.TestCategory
2526
import com.instructure.canvas.espresso.TestMetaData
27+
import com.instructure.canvas.espresso.checkToastText
2628
import com.instructure.dataseeding.api.AssignmentsApi
2729
import com.instructure.dataseeding.model.GradingType
2830
import com.instructure.dataseeding.model.SubmissionType
2931
import com.instructure.dataseeding.util.days
3032
import com.instructure.dataseeding.util.fromNow
3133
import com.instructure.dataseeding.util.iso8601
34+
import com.instructure.espresso.ViewUtils
3235
import com.instructure.pandautils.utils.AppTheme
36+
import com.instructure.parentapp.R
3337
import com.instructure.parentapp.utils.ParentComposeTest
3438
import com.instructure.parentapp.utils.seedData
3539
import com.instructure.parentapp.utils.tokenLogin
@@ -154,4 +158,74 @@ class SettingsE2ETest : ParentComposeTest() {
154158
Log.d(STEP_TAG,"Assert that the Instructure company logo has been displayed on the About page.")
155159
aboutPage.assertInstructureLogoDisplayed()
156160
}
161+
162+
@E2E
163+
@Test
164+
@TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.E2E, SecondaryFeatureCategory.INBOX_SIGNATURE)
165+
fun testInboxSignatureE2E() {
166+
167+
Log.d(PREPARATION_TAG, "Seeding data.")
168+
val data = seedData(students = 1, courses = 1, parents = 1)
169+
val course = data.coursesList[0]
170+
val parent = data.parentsList[0]
171+
val student = data.studentsList[0]
172+
173+
Log.d(STEP_TAG, "Login with user: '${parent.name}', login id: '${parent.loginId}'.")
174+
tokenLogin(parent)
175+
dashboardPage.waitForRender()
176+
177+
Log.d(STEP_TAG, "Open the Left Side Navigation Drawer menu.")
178+
dashboardPage.openLeftSideMenu()
179+
180+
Log.d(STEP_TAG, "Navigate to User Settings Page.")
181+
leftSideNavigationDrawerPage.clickSettings()
182+
183+
Log.d(ASSERTION_TAG, "Assert that by default the Inbox Signature is 'Not Set'.")
184+
settingsPage.assertSettingsItemDisplayed("Inbox Signature", "Not Set")
185+
186+
Log.d(STEP_TAG, "Click on the 'Inbox Signature' settings.")
187+
settingsPage.clickOnSettingsItem("Inbox Signature")
188+
189+
Log.d(ASSERTION_TAG, "Assert that by default the 'Inbox Signature' toggle is turned off.")
190+
inboxSignatureSettingsPage.assertSignatureEnabledState(false)
191+
192+
val signatureText = "President of AC Milan\nVice President of Ferencvaros"
193+
194+
Log.d(STEP_TAG, "Turn on the 'Inbox Signature' and set the inbox signature text to: '$signatureText'. Save the changes.")
195+
inboxSignatureSettingsPage.toggleSignatureEnabledState()
196+
inboxSignatureSettingsPage.changeSignatureText(signatureText)
197+
inboxSignatureSettingsPage.saveChanges()
198+
199+
Log.d(ASSERTION_TAG, "Assert that the 'Inbox settings saved!' toast message is displayed.")
200+
checkToastText(R.string.inboxSignatureSettingsUpdated, activityRule.activity)
201+
202+
Log.d(STEP_TAG, "Refresh the Settings page.")
203+
settingsPage.refresh()
204+
205+
Log.d(ASSERTION_TAG, "Assert that the Inbox Signature became 'Enabled'.")
206+
settingsPage.assertSettingsItemDisplayed("Inbox Signature", "Enabled")
207+
208+
Log.d(STEP_TAG, "Click on the 'Inbox Signature' settings.")
209+
settingsPage.clickOnSettingsItem("Inbox Signature")
210+
211+
Log.d(ASSERTION_TAG, "Assert that the previously changed inbox signature text has been really set to: '$signatureText' and the toggle has turned off.")
212+
inboxSignatureSettingsPage.assertSignatureText(signatureText)
213+
inboxSignatureSettingsPage.assertSignatureEnabledState(true)
214+
215+
Log.d(STEP_TAG, "Navigate back to the Dashboard.")
216+
ViewUtils.pressBackButton(2)
217+
218+
Log.d(STEP_TAG, "Open the Left Side Navigation Drawer menu.")
219+
dashboardPage.openLeftSideMenu()
220+
221+
Log.d(STEP_TAG, "Open 'Inbox' menu.")
222+
leftSideNavigationDrawerPage.clickInbox()
223+
224+
Log.d(STEP_TAG,"Click on 'New Message' button.")
225+
inboxPage.pressNewMessageButton()
226+
inboxCoursePickerPage.selectCourseWithUser(course.name, student.shortName)
227+
228+
Log.d(ASSERTION_TAG, "Assert that the previously set inbox signature text is displayed by default when the user opens the Compose New Message Page.")
229+
inboxComposeMessagePage.assertBodyText("\n\n---\nPresident of AC Milan\nVice President of Ferencvaros")
230+
}
157231
}

apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/CoursesPage.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class CoursesPage(private val composeTestRule: ComposeTestRule) {
100100
.performScrollTo()
101101
.assertIsDisplayed()
102102
.performClick()
103+
composeTestRule.waitForIdle()
103104
}
104105

105106
fun refresh() {

apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentComposeTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import com.instructure.canvas.espresso.common.pages.compose.CalendarToDoDetailsP
2828
import com.instructure.canvas.espresso.common.pages.compose.GradesPage
2929
import com.instructure.canvas.espresso.common.pages.compose.InboxComposePage
3030
import com.instructure.canvas.espresso.common.pages.compose.InboxDetailsPage
31+
import com.instructure.canvas.espresso.common.pages.compose.InboxSignatureSettingsPage
3132
import com.instructure.canvas.espresso.common.pages.compose.RecipientPickerPage
3233
import com.instructure.canvas.espresso.common.pages.compose.SettingsPage
3334
import com.instructure.parentapp.features.login.LoginActivity
@@ -78,6 +79,7 @@ abstract class ParentComposeTest : ParentTest() {
7879
protected val calendarToDoDetailsPage = CalendarToDoDetailsPage(composeTestRule)
7980
protected val calendarFilterPage = CalendarFilterPage(composeTestRule)
8081
protected val reminderPage = ReminderPage(composeTestRule)
82+
protected val inboxSignatureSettingsPage = InboxSignatureSettingsPage(composeTestRule)
8183

8284
override fun displaysPageObjects() = Unit
8385
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (C) 2025 - present Instructure, Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, version 3 of the License.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*
16+
*/
17+
package com.instructure.parentapp.di.feature
18+
19+
import com.instructure.pandautils.features.assignments.list.AssignmentListBehavior
20+
import com.instructure.pandautils.features.assignments.list.AssignmentListRepository
21+
import com.instructure.pandautils.features.assignments.list.AssignmentListRouter
22+
import dagger.Module
23+
import dagger.Provides
24+
import dagger.hilt.InstallIn
25+
import dagger.hilt.android.components.FragmentComponent
26+
import dagger.hilt.android.components.ViewModelComponent
27+
28+
@Module
29+
@InstallIn(FragmentComponent::class)
30+
class AssignmentListFragmentModule {
31+
@Provides
32+
fun provideAssignmentListRouter(): AssignmentListRouter {
33+
throw NotImplementedError()
34+
}
35+
}
36+
37+
@Module
38+
@InstallIn(ViewModelComponent::class)
39+
class AssignmentListModule {
40+
@Provides
41+
fun provideAssignmentListBehavior(): AssignmentListBehavior {
42+
throw NotImplementedError()
43+
}
44+
45+
@Provides
46+
fun provideAssignmentListRepository(): AssignmentListRepository {
47+
throw NotImplementedError()
48+
}
49+
}

apps/parent/src/main/java/com/instructure/parentapp/di/feature/LoginModule.kt

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,67 @@
1717

1818
package com.instructure.parentapp.di.feature
1919

20+
import android.content.Context
21+
import android.content.Intent
2022
import androidx.fragment.app.FragmentActivity
23+
import com.instructure.canvasapi2.LoginRouter
24+
import com.instructure.canvasapi2.models.AccountDomain
2125
import com.instructure.canvasapi2.utils.Analytics
26+
import com.instructure.canvasapi2.utils.ApiPrefs
2227
import com.instructure.loginapi.login.LoginNavigation
2328
import com.instructure.loginapi.login.features.acceptableusepolicy.AcceptableUsePolicyRouter
29+
import com.instructure.loginapi.login.util.LoginPrefs
2430
import com.instructure.pandautils.features.reminder.AlarmScheduler
2531
import com.instructure.parentapp.features.login.ParentAcceptableUsePolicyRouter
2632
import com.instructure.parentapp.features.login.ParentLoginNavigation
33+
import com.instructure.parentapp.features.login.SignInActivity
2734
import dagger.Module
2835
import dagger.Provides
2936
import dagger.hilt.InstallIn
3037
import dagger.hilt.android.components.ActivityComponent
38+
import dagger.hilt.android.qualifiers.ApplicationContext
39+
import dagger.hilt.components.SingletonComponent
40+
import javax.inject.Singleton
3141

3242
@Module
3343
@InstallIn(ActivityComponent::class)
3444
class LoginModule {
3545

3646
@Provides
37-
fun provideAcceptableUsePolicyRouter(activity: FragmentActivity, alarmScheduler: AlarmScheduler, analytics: Analytics): AcceptableUsePolicyRouter {
47+
fun provideAcceptableUsePolicyRouter(
48+
activity: FragmentActivity,
49+
alarmScheduler: AlarmScheduler,
50+
analytics: Analytics
51+
): AcceptableUsePolicyRouter {
3852
return ParentAcceptableUsePolicyRouter(activity, alarmScheduler, analytics)
3953
}
4054

4155
@Provides
42-
fun provideLoginNavigation(activity: FragmentActivity, alarmScheduler: AlarmScheduler): LoginNavigation {
56+
fun provideLoginNavigation(
57+
activity: FragmentActivity,
58+
alarmScheduler: AlarmScheduler
59+
): LoginNavigation {
4360
return ParentLoginNavigation(activity, alarmScheduler)
4461
}
62+
}
63+
64+
@Module
65+
@InstallIn(SingletonComponent::class)
66+
class LoginRouterModule {
67+
@Provides
68+
@Singleton
69+
fun provideLoginRouter(
70+
@ApplicationContext context: Context,
71+
loginPrefs: LoginPrefs,
72+
apiPrefs: ApiPrefs
73+
): LoginRouter {
74+
return object : LoginRouter {
75+
override fun loginIntent(): Intent {
76+
return SignInActivity.createIntent(
77+
context,
78+
loginPrefs.lastSavedLogin?.accountDomain ?: AccountDomain(apiPrefs.domain)
79+
)
80+
}
81+
}
82+
}
4583
}

apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsScreen.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ private fun CourseDetailsScreenContent(
132132

133133
LaunchedEffect(pagerState) {
134134
snapshotFlow { pagerState.currentPage }.collect { page ->
135-
actionHandler(CourseDetailsAction.CurrentTabChanged(uiState.tabs[page]))
135+
uiState.tabs.getOrNull(page)?.let {
136+
actionHandler(CourseDetailsAction.CurrentTabChanged(it))
137+
}
136138
}
137139
}
138140

apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryUiState.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ sealed class ScreenState {
3333
data object Error : ScreenState()
3434
data object Empty : ScreenState()
3535
data object Content : ScreenState()
36-
}
36+
}

apps/parent/src/main/java/com/instructure/parentapp/features/grades/ParentGradesRepository.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@ import com.instructure.canvasapi2.models.Enrollment
2929
import com.instructure.canvasapi2.models.GradingPeriod
3030
import com.instructure.canvasapi2.utils.depaginate
3131
import com.instructure.pandautils.features.grades.GradesRepository
32+
import com.instructure.pandautils.features.grades.gradepreferences.SortBy
3233
import com.instructure.pandautils.utils.orDefault
3334
import com.instructure.parentapp.util.ParentPrefs
3435

3536

3637
class ParentGradesRepository(
3738
private val assignmentApi: AssignmentAPI.AssignmentInterface,
3839
private val courseApi: CourseAPI.CoursesInterface,
39-
parentPrefs: ParentPrefs
40+
private val parentPrefs: ParentPrefs
4041
) : GradesRepository {
4142

4243
override val studentId = parentPrefs.currentStudent?.id.orDefault()
@@ -51,6 +52,7 @@ class ParentGradesRepository(
5152
val filteredAssignments = group.assignments
5253
.filter { assignment -> assignment.published }
5354
.filter { assignment -> getGradingTypeFromAPIString(assignment.gradingType.orEmpty()) != Assignment.GradingType.NOT_GRADED }
55+
.filter { assignment -> assignment.submissionList.isNullOrEmpty() || assignment.submissionList?.any { submission -> submission.userId == studentId } == true}
5456
group.copy(assignments = filteredAssignments).toAssignmentGroup(studentId)
5557
}
5658
}.dataOrThrow
@@ -85,4 +87,14 @@ class ParentGradesRepository(
8587
firstEnrollment == null && gradingPeriodId == null
8688
)
8789
}
90+
91+
override fun getSortBy(): SortBy? {
92+
return parentPrefs.gradesSortBy?.let {
93+
SortBy.valueOf(it)
94+
}
95+
}
96+
97+
override fun setSortBy(sortBy: SortBy) {
98+
parentPrefs.gradesSortBy = sortBy.name
99+
}
88100
}

0 commit comments

Comments
 (0)