diff --git a/README.md b/README.md index 9e2c4c61d3..5bfce5e8d6 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,6 @@ App | Description Module | Description --- | --- annotations | A wrapper for the PSPDFKit library and logic for annotation handling and converting in PDF documents. -blueprint | An MVP Architecture that depends on PandaRecyclerView. (deprecated) buildSrc | Library for common gradle dependencies and gradle transformers that are used by the project. canvas-api-2 | Canvas for Android Api used to talk to the Canvas LMS and is testable. dataseedingapi | gRPC wrapper for Canvas that enables creating data to test the apps. diff --git a/apps/flutter_parent/lib/l10n/res/intl_fr_CA.arb b/apps/flutter_parent/lib/l10n/res/intl_fr_CA.arb index 267e9daadc..9cd6a1677b 100644 --- a/apps/flutter_parent/lib/l10n/res/intl_fr_CA.arb +++ b/apps/flutter_parent/lib/l10n/res/intl_fr_CA.arb @@ -741,7 +741,7 @@ "placeholders_order": [], "placeholders": {} }, - "Syllabus": "Programme", + "Syllabus": "Plan de cours", "@Syllabus": { "description": "Label for the \"Syllabus\" tab in course details", "type": "text", diff --git a/apps/flutter_parent/lib/screens/login_landing_screen.dart b/apps/flutter_parent/lib/screens/login_landing_screen.dart index 941e66ac4e..dae6585ca9 100644 --- a/apps/flutter_parent/lib/screens/login_landing_screen.dart +++ b/apps/flutter_parent/lib/screens/login_landing_screen.dart @@ -63,7 +63,8 @@ class LoginLandingScreen extends StatelessWidget { // TODO: needs test locator().push( context, - WebLoginScreen(snicker.domain, + WebLoginScreen( + snicker.domain, user: snicker.username, pass: snicker.password), ); @@ -361,7 +362,7 @@ class LoginLandingScreen extends StatelessWidget { locator().pushRoute( context, PandaRouter.loginWeb(lastAccount.item1.domain, - accountName: lastAccount.item1.name!, loginFlow: lastAccount.item2)); + accountName: lastAccount.item1.name!, authenticationProvider: lastAccount.item1.authenticationProvider, loginFlow: lastAccount.item2)); } void _changeLoginFlow(BuildContext context) { diff --git a/apps/flutter_parent/lib/screens/web_login/web_login_screen.dart b/apps/flutter_parent/lib/screens/web_login/web_login_screen.dart index dd8f5e7c08..fa9aacd72c 100644 --- a/apps/flutter_parent/lib/screens/web_login/web_login_screen.dart +++ b/apps/flutter_parent/lib/screens/web_login/web_login_screen.dart @@ -216,6 +216,7 @@ class _WebLoginScreenState extends State { ); final lastAccount = new SchoolDomain((builder) => builder + ..authenticationProvider = widget.authenticationProvider ..domain = widget.domain ..name = widget.accountName); ApiPrefs.setLastAccount(lastAccount, widget.loginFlow); diff --git a/apps/flutter_parent/pubspec.yaml b/apps/flutter_parent/pubspec.yaml index 73f2be78c6..adf0e4da09 100644 --- a/apps/flutter_parent/pubspec.yaml +++ b/apps/flutter_parent/pubspec.yaml @@ -25,7 +25,7 @@ description: Canvas Parent # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.13.0+53 +version: 3.14.0+54 module: androidX: true diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/compose/courses/details/CourseDetailsScreenTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/compose/courses/details/CourseDetailsScreenTest.kt index 13a7470308..0be595af88 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/compose/courses/details/CourseDetailsScreenTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/compose/courses/details/CourseDetailsScreenTest.kt @@ -20,9 +20,11 @@ package com.instructure.parentapp.ui.compose.courses.details import androidx.compose.ui.test.assertHasClickAction import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsNotDisplayed +import androidx.compose.ui.test.hasAnyAncestor import androidx.compose.ui.test.hasContentDescription import androidx.compose.ui.test.hasParent import androidx.compose.ui.test.hasTestTag +import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithTag @@ -50,6 +52,7 @@ class CourseDetailsScreenTest { isLoading = true ), actionHandler = {}, + applyOnWebView = {}, navigationActionClick = {} ) } @@ -67,6 +70,7 @@ class CourseDetailsScreenTest { isError = true ), actionHandler = {}, + applyOnWebView = {}, navigationActionClick = {} ) } @@ -86,9 +90,10 @@ class CourseDetailsScreenTest { isLoading = false, isError = false, courseName = "Course 1", - tabs = listOf(TabType.SYLLABUS, TabType.SUMMARY) + tabs = listOf(TabType.SYLLABUS) ), actionHandler = {}, + applyOnWebView = {}, navigationActionClick = {} ) } @@ -100,21 +105,13 @@ class CourseDetailsScreenTest { .assertHasClickAction() composeTestRule.onNodeWithText("Course 1") .assertIsDisplayed() - composeTestRule.onNodeWithText("SYLLABUS") - .assertIsDisplayed() - composeTestRule.onNodeWithText("SUMMARY") - .assertIsDisplayed() - composeTestRule.onNodeWithTag("courseDetailsTabRow") - .assertIsDisplayed() - composeTestRule.onNodeWithTag("courseDetailsPager") - .assertIsDisplayed() composeTestRule.onNodeWithContentDescription("Send a message about this course") .assertIsDisplayed() .assertHasClickAction() } @Test - fun assertCourseDetailsContentWithJustOnTab() { + fun assertCourseDetailsContentWithJustOneTab() { composeTestRule.setContent { CourseDetailsScreen( uiState = CourseDetailsUiState( @@ -124,6 +121,7 @@ class CourseDetailsScreenTest { tabs = listOf(TabType.SYLLABUS) ), actionHandler = {}, + applyOnWebView = {}, navigationActionClick = {} ) } @@ -138,4 +136,25 @@ class CourseDetailsScreenTest { .assertIsDisplayed() .assertHasClickAction() } + + @Test + fun assertSnackbarText() { + composeTestRule.setContent { + CourseDetailsScreen( + uiState = CourseDetailsUiState( + isLoading = false, + isError = false, + courseName = "Course 1", + tabs = listOf(TabType.SYLLABUS), + snackbarMessage = "Snackbar message" + ), + actionHandler = {}, + applyOnWebView = {}, + navigationActionClick = {} + ) + } + + val snackbarText = composeTestRule.onNode(hasText("Snackbar message").and(hasAnyAncestor(hasTestTag("snackbarHost")))) + snackbarText.assertIsDisplayed() + } } diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/compose/courses/details/frontpage/FrontPageScreenTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/compose/courses/details/frontpage/FrontPageScreenTest.kt new file mode 100644 index 0000000000..78b37c7c9c --- /dev/null +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/compose/courses/details/frontpage/FrontPageScreenTest.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.instructure.parentapp.ui.compose.courses.details.frontpage + +import androidx.compose.ui.test.assertHasClickAction +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.instructure.parentapp.features.courses.details.frontpage.FrontPageContent +import com.instructure.parentapp.features.courses.details.frontpage.FrontPageUiState +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + + +@RunWith(AndroidJUnit4::class) +class FrontPageScreenTest { + + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun assertLoadingContent() { + composeTestRule.setContent { + FrontPageContent( + uiState = FrontPageUiState( + isLoading = true + ), + actionHandler = {}, + applyOnWebView = {}, + onLtiButtonPressed = {} + ) + } + + composeTestRule.onNodeWithTag("loading") + .assertIsDisplayed() + } + + @Test + fun assertErrorContent() { + composeTestRule.setContent { + FrontPageContent( + uiState = FrontPageUiState( + isLoading = false, + isError = true + ), + actionHandler = {}, + applyOnWebView = {}, + onLtiButtonPressed = {} + ) + } + + composeTestRule.onNodeWithText("An unexpected error occurred.") + .assertIsDisplayed() + composeTestRule.onNodeWithText("Retry") + .assertIsDisplayed() + .assertHasClickAction() + } + + @Test + fun assertCourseDetailsContent() { + composeTestRule.setContent { + FrontPageContent( + uiState = FrontPageUiState( + isLoading = false, + isError = false, + htmlContent = "Front page content" + ), + actionHandler = {}, + applyOnWebView = {}, + onLtiButtonPressed = {} + ) + } + + composeTestRule.onNodeWithTag("CourseDetailsWebViewScreen") + .assertIsDisplayed() + } +} diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/compose/courses/details/summary/SummaryScreenTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/compose/courses/details/summary/SummaryScreenTest.kt new file mode 100644 index 0000000000..02373178b8 --- /dev/null +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/compose/courses/details/summary/SummaryScreenTest.kt @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.parentapp.ui.compose.courses.details.summary + +import androidx.compose.ui.test.assertHasClickAction +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.instructure.canvasapi2.models.ScheduleItem +import com.instructure.canvasapi2.utils.toApiString +import com.instructure.canvasapi2.utils.toSimpleDate +import com.instructure.pandautils.utils.toFormattedString +import com.instructure.parentapp.features.courses.details.summary.ScreenState +import com.instructure.parentapp.features.courses.details.summary.SummaryContent +import com.instructure.parentapp.features.courses.details.summary.SummaryUiState +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import java.util.Calendar + +@RunWith(AndroidJUnit4::class) +class SummaryScreenTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun assertLoadingContent() { + composeTestRule.setContent { + SummaryContent( + uiState = SummaryUiState( + state = ScreenState.Loading + ), + onRefresh = {}, + navigateToAssignmentDetails = { _, _ ->}, + navigateToCalendarEvent = { _, _, _ ->} + ) + } + + composeTestRule.onNodeWithTag("Loading") + .assertIsDisplayed() + } + + @Test + fun assertErrorContent() { + composeTestRule.setContent { + SummaryContent( + uiState = SummaryUiState( + state = ScreenState.Error + ), + onRefresh = {}, + navigateToAssignmentDetails = { _, _ ->}, + navigateToCalendarEvent = { _, _, _ ->} + ) + } + + composeTestRule.onNodeWithText("Failed to load summary") + .assertIsDisplayed() + composeTestRule.onNodeWithText("Retry") + .assertIsDisplayed() + .assertHasClickAction() + } + + @Test + fun assertEmptyContent() { + composeTestRule.setContent { + SummaryContent( + uiState = SummaryUiState( + state = ScreenState.Empty + ), + onRefresh = {}, + navigateToAssignmentDetails = { _, _ ->}, + navigateToCalendarEvent = { _, _, _ ->} + ) + } + + composeTestRule.onNodeWithText("No summary items to display") + .assertIsDisplayed() + } + + @Test + fun assertSuccessContent() { + val assignmentDueDate = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, 1) } + composeTestRule.setContent { + SummaryContent( + uiState = SummaryUiState( + state = ScreenState.Content, + courseId = 1, + items = listOf( + ScheduleItem( + title = "Assignment 1", + startAt = assignmentDueDate.time.toApiString(), + type = "assignment" + ), + ScheduleItem( + title = "Calendar 1", + type = "event" + ) + ) + ), + onRefresh = {}, + navigateToAssignmentDetails = { _, _ ->}, + navigateToCalendarEvent = { _, _, _ ->} + ) + } + + composeTestRule.onNodeWithText("Assignment 1") + .assertIsDisplayed() + composeTestRule.onNodeWithText(assignmentDueDate.time.toApiString().toSimpleDate()?.toFormattedString().orEmpty()) + .assertIsDisplayed() + + composeTestRule.onNodeWithText("Calendar 1") + .assertIsDisplayed() + composeTestRule.onNodeWithText("No Due Date") + .assertIsDisplayed() + } +} \ No newline at end of file diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/e2e/LoginE2ETest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/e2e/LoginE2ETest.kt new file mode 100644 index 0000000000..bb440d0d1c --- /dev/null +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/e2e/LoginE2ETest.kt @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.instructure.parentapp.ui.e2e + +import android.util.Log +import com.instructure.canvas.espresso.E2E +import com.instructure.canvas.espresso.FeatureCategory +import com.instructure.canvas.espresso.Priority +import com.instructure.canvas.espresso.TestCategory +import com.instructure.canvas.espresso.TestMetaData +import com.instructure.dataseeding.model.CanvasUserApiModel +import com.instructure.parentapp.utils.ParentComposeTest +import com.instructure.parentapp.utils.seedData +import dagger.hilt.android.testing.HiltAndroidTest +import org.junit.Test + +@HiltAndroidTest +class LoginE2ETest : ParentComposeTest() { + override fun displaysPageObjects() = Unit + + override fun enableAndConfigureAccessibilityChecks() = Unit + + @E2E + @Test + @TestMetaData(Priority.MANDATORY, FeatureCategory.LOGIN, TestCategory.E2E) + fun testLoginE2E() { + + Log.d(PREPARATION_TAG, "Seeding data.") + val data = seedData(students = 2, teachers = 1, courses = 1, parents = 2) + val parent = data.parentsList[0] + val parent2 = data.parentsList[1] + val student = data.studentsList[0] + val teacher = data.teachersList[0] + + Log.d(STEP_TAG, "Login with user: '${parent.name}', login id: '${parent.loginId}'.") + loginWithUser(parent) + + Log.d(STEP_TAG, "Assert that the Dashboard Page is the landing page and it is loaded successfully.") + dashboardPage.waitForRender() + dashboardPage.assertPageObjects() + + Log.d(ASSERTION_TAG, "Assert that the '${parent.name}' parent user has logged in.") + leftSideNavigationDrawerPage.assertUserLoggedIn(parent) + + Log.d(STEP_TAG, "Open the Left Side Navigation Drawer menu (to be able to log out).") + dashboardPage.openNavigationDrawer() + + Log.d(STEP_TAG, "Log out with '${student.name}' student.") + leftSideNavigationDrawerPage.logout() + + Log.d(STEP_TAG, "Login with user: '${student.name}', login id: '${student.loginId}'.") + loginWithUser(student, true) + + Log.d(ASSERTION_TAG, "Assert that the 'Not a Parent' page has been displayed with all the corresponding information on it.") + notAParentPage.assertNotAParentPageDetails() + + Log.d(STEP_TAG, "Click on 'Return to login' button to navigate back to the login page.") + notAParentPage.clickReturnToLogin() + + Log.d(STEP_TAG, "Login with user: '${teacher.name}', login id: '${teacher.loginId}'.") + loginWithUser(teacher, true) + + Log.d(ASSERTION_TAG, "Assert that the 'Not a Parent' page has been displayed with all the corresponding information on it.") + notAParentPage.assertNotAParentPageDetails() + + Log.d(STEP_TAG, "Expand the 'Are you a student or teacher?' option to see the Canvas Student and Canvas Teacher app icons as links. Also, assert that the subtitle message is displayed.") + notAParentPage.expandAppOptions() + notAParentPage.assertOtherAppSubtitleDisplayed() + notAParentPage.assertStudentAppDisplayed() + notAParentPage.assertTeacherAppDisplayed() + + Log.d(STEP_TAG, "Click on 'Return to login' button to navigate back to the login page.") + notAParentPage.clickReturnToLogin() + + Log.d(STEP_TAG, "Login with user: '${parent.name}', login id: '${parent.loginId}'.") + loginWithUser(parent, true) + + Log.d(STEP_TAG, "Assert that the Dashboard Page is the landing page and it is loaded successfully.") + dashboardPage.waitForRender() + dashboardPage.assertPageObjects() + + Log.d(ASSERTION_TAG, "Assert that the '${parent.name}' parent user has logged in.") + leftSideNavigationDrawerPage.assertUserLoggedIn(parent) + + Log.d(STEP_TAG, "Open the Left Side Navigation Drawer menu (to be able to log out).") + dashboardPage.openNavigationDrawer() + + Log.d(STEP_TAG, "Click on 'Switch Users' button on the left-side menu.") + leftSideNavigationDrawerPage.clickSwitchUsers() + + Log.d(STEP_TAG, "Assert that the previously logins has been displayed.") + loginLandingPage.assertDisplaysPreviousLogins() + + Log.d(STEP_TAG, "Login with user: '${parent2.name}', login id: '${parent2.loginId}'.") + loginWithUser(parent2, true) + + Log.d(STEP_TAG, "Assert that the Dashboard Page is the landing page and it is loaded successfully.") + dashboardPage.waitForRender() + dashboardPage.assertPageObjects() + + Log.d(ASSERTION_TAG, "Assert that the '${parent2.name}' parent user has logged in.") + leftSideNavigationDrawerPage.assertUserLoggedIn(parent2) + + Log.d(STEP_TAG, "Open the Left Side Navigation Drawer menu (to be able to log out).") + dashboardPage.openNavigationDrawer() + + Log.d(STEP_TAG, "Click on 'Switch Users' button on the left-side menu.") + leftSideNavigationDrawerPage.clickSwitchUsers() + + Log.d(ASSERTION_TAG, "Assert that the 'Previous Logins' section is displayed and both the '${parent.name}' and '${parent2.name}' parents are displayed on the previous login list.") + loginLandingPage.assertDisplaysPreviousLogins() + loginLandingPage.assertPreviousLoginUserDisplayed(parent.name) + loginLandingPage.assertPreviousLoginUserDisplayed(parent2.name) + + Log.d(STEP_TAG, "Remove '${parent.name}' parent from the previous login section.") + loginLandingPage.removeUserFromPreviousLogins(parent.name) + + Log.d(STEP_TAG, "Login with the '${parent2.name}' user, with one click, by clicking on the user's name on the bottom.") + loginLandingPage.loginWithPreviousUser(parent2) + + Log.d(STEP_TAG, "Assert that the Dashboard Page is the landing page and it is loaded successfully.") + dashboardPage.waitForRender() + dashboardPage.assertPageObjects() + + Log.d(STEP_TAG, "Open the Left Side Navigation Drawer menu (to be able to log out).") + dashboardPage.openNavigationDrawer() + + Log.d(STEP_TAG, "Click on 'Switch Users' button on the left-side menu.") + leftSideNavigationDrawerPage.clickSwitchUsers() + + Log.d(STEP_TAG, "Assert that the previously logins has been displayed. Assert that '${parent2.name}' parent is displayed but '${parent.name}' parent is not displayed within the previous logins list (as it was removed before).") + loginLandingPage.assertDisplaysPreviousLogins() + loginLandingPage.assertPreviousLoginUserDisplayed(parent2.name) + loginLandingPage.assertPreviousLoginUserNotExist(parent.name) + + Log.d(STEP_TAG, "Remove '${parent2.name}' parent from the previous login section as well.") + loginLandingPage.removeUserFromPreviousLogins(parent2.name) + + Log.d(STEP_TAG, "Assert that none of the parents, '${parent.name}' and '${parent2.name}' are displayed and not even the 'Previous Logins' label is displayed.") + loginLandingPage.assertPreviousLoginUserNotExist(parent.name) + loginLandingPage.assertPreviousLoginUserNotExist(parent2.name) + loginLandingPage.assertNotDisplaysPreviousLogins() + + } + + @E2E + @Test + @TestMetaData(Priority.MANDATORY, FeatureCategory.LOGIN, TestCategory.E2E) + fun testLoginE2EWithLastSavedSchool() { + + Log.d(PREPARATION_TAG, "Seeding data.") + val data = seedData(students = 1, courses = 1, parents = 1) + val parent = data.parentsList[0] + + Log.d(STEP_TAG, "Login with user: '${parent.name}', login id: '${parent.loginId}'.") + loginWithUser(parent) + + Log.d(STEP_TAG, "Assert that the Dashboard Page is the landing page and it is loaded successfully.") + dashboardPage.waitForRender() + dashboardPage.assertPageObjects() + + Log.d(ASSERTION_TAG, "Assert that the '${parent.name}' parent user has logged in.") + leftSideNavigationDrawerPage.assertUserLoggedIn(parent) + + Log.d(STEP_TAG, "Open the Left Side Navigation Drawer menu (to be able to log out).") + dashboardPage.openNavigationDrawer() + + Log.d(STEP_TAG, "Log out with '${parent.name}' student.") + leftSideNavigationDrawerPage.logout() + + Log.d(STEP_TAG, "Login with user: '${parent.name}', login id: '${parent.loginId}'.") + loginWithLastSavedSchool(parent) + + Log.d(STEP_TAG, "Assert that the Dashboard Page is the landing page and it is loaded successfully.") + dashboardPage.waitForRender() + dashboardPage.assertPageObjects() + + Log.d(ASSERTION_TAG, "Assert that the '${parent.name}' parent user has logged in.") + leftSideNavigationDrawerPage.assertUserLoggedIn(parent) + } + + @E2E + @Test + @TestMetaData(Priority.IMPORTANT, FeatureCategory.LOGIN, TestCategory.E2E) + fun testInvalidAndEmptyLoginCredentialsE2E() { + + val INVALID_USERNAME = "invalidusercred@test.com" + val INVALID_PASSWORD = "invalidpw" + val INVALID_CREDENTIALS_ERROR_MESSAGE = "Please verify your username or password and try again. Trouble logging in? Check out our Login FAQs." + val NO_PASSWORD_GIVEN_ERROR_MESSAGE = "No password was given" + val DOMAIN = "mobileqa.beta" + + Log.d(STEP_TAG, "Click 'Find My School' button.") + loginLandingPage.clickFindMySchoolButton() + + Log.d(STEP_TAG,"Enter domain: '$DOMAIN.instructure.com.'") + loginFindSchoolPage.enterDomain(DOMAIN) + + Log.d(STEP_TAG,"Click on 'Next' button on the Toolbar.") + loginFindSchoolPage.clickToolbarNextMenuItem() + + Log.d(STEP_TAG, "Try to login with invalid, non-existing credentials ($INVALID_USERNAME, $INVALID_PASSWORD)." + + "Assert that the invalid credentials error message is displayed.") + loginSignInPage.loginAs(INVALID_USERNAME, INVALID_PASSWORD) + loginSignInPage.assertLoginErrorMessage(INVALID_CREDENTIALS_ERROR_MESSAGE) + + Log.d(STEP_TAG, "Try to login with no credentials typed in either of the username and password field." + + "Assert that the no password was given error message is displayed.") + loginSignInPage.loginAs(EMPTY_STRING, EMPTY_STRING) + loginSignInPage.assertLoginErrorMessage(NO_PASSWORD_GIVEN_ERROR_MESSAGE) + + Log.d(STEP_TAG, "Try to login with leaving only the password field empty." + + "Assert that the no password was given error message is displayed.") + loginSignInPage.loginAs(INVALID_USERNAME, EMPTY_STRING) + loginSignInPage.assertLoginErrorMessage(NO_PASSWORD_GIVEN_ERROR_MESSAGE) + + Log.d(STEP_TAG, "Try to login with leaving only the username field empty." + + "Assert that the invalid credentials error message is displayed.") + loginSignInPage.loginAs(EMPTY_STRING, INVALID_PASSWORD) + loginSignInPage.assertLoginErrorMessage(INVALID_CREDENTIALS_ERROR_MESSAGE) + } + + private fun loginWithUser(user: CanvasUserApiModel, lastSchoolSaved: Boolean = false) { + + Thread.sleep(5100) //Need to wait > 5 seconds before each login attempt because of new 'too many attempts' login policy on web. + + if (lastSchoolSaved) { + Log.d(STEP_TAG, "Click 'Find Another School' button.") + loginLandingPage.clickFindAnotherSchoolButton() + } else { + Log.d(STEP_TAG, "Click 'Find My School' button.") + loginLandingPage.clickFindMySchoolButton() + } + + Log.d(STEP_TAG, "Enter domain: '${user.domain}'.") + loginFindSchoolPage.enterDomain(user.domain) + + Log.d(STEP_TAG, "Click on 'Next' button on the Toolbar.") + loginFindSchoolPage.clickToolbarNextMenuItem() + loginSignInPage.loginAs(user) + } + + private fun loginWithLastSavedSchool(user: CanvasUserApiModel) { + + Log.d(STEP_TAG, "Click on last saved school's button.") + loginLandingPage.clickOnLastSavedSchoolButton() + + Log.d(STEP_TAG, "Login with '${user.name}' user.") + loginSignInPage.loginAs(user) + } + +} \ No newline at end of file diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AddStudentInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AddStudentInteractionTest.kt index 08b6dbf689..470d183e99 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AddStudentInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AddStudentInteractionTest.kt @@ -161,7 +161,7 @@ class AddStudentInteractionTest : ParentComposeTest() { val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) dashboardPage.openNavigationDrawer() - dashboardPage.tapManageStudents() + leftSideNavigationDrawerPage.clickManageStudents() manageStudentsPage.tapAddStudent() } diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AlertSettingsInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AlertSettingsInteractionTest.kt index 9a2ada3184..a5d13ef5a1 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AlertSettingsInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AlertSettingsInteractionTest.kt @@ -147,7 +147,7 @@ class AlertSettingsInteractionTest : ParentComposeTest() { val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) dashboardPage.openNavigationDrawer() - dashboardPage.tapManageStudents() + leftSideNavigationDrawerPage.clickManageStudents() manageStudentsPage.tapStudent(data.students.first().shortName!!) } diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AlertsInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AlertsInteractionTest.kt index 1f91a23e04..3aad3cbe88 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AlertsInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AlertsInteractionTest.kt @@ -233,7 +233,7 @@ class AlertsInteractionTest : ParentComposeTest() { val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) - dashboardPage.clickAlerts() + dashboardPage.clickAlertsBottomMenu() } override fun enableAndConfigureAccessibilityChecks() { diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AssignmentDetailsInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AssignmentDetailsInteractionTest.kt index 3ebdb61d0b..902f192ee5 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AssignmentDetailsInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/AssignmentDetailsInteractionTest.kt @@ -19,8 +19,13 @@ import androidx.compose.ui.platform.ComposeView import androidx.test.espresso.matcher.ViewMatchers import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck +import com.instructure.canvas.espresso.FeatureCategory +import com.instructure.canvas.espresso.Priority +import com.instructure.canvas.espresso.TestCategory +import com.instructure.canvas.espresso.TestMetaData import com.instructure.canvas.espresso.checkToastText import com.instructure.canvas.espresso.common.pages.AssignmentDetailsPage +import com.instructure.canvas.espresso.common.pages.ReminderPage import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.addAssignment import com.instructure.canvas.espresso.mockCanvas.addAssignmentsToGroups @@ -33,6 +38,7 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.CourseSettings import com.instructure.canvasapi2.utils.toApiString import com.instructure.espresso.ModuleItemInteractions +import com.instructure.pandautils.utils.toFormattedString import com.instructure.parentapp.R import com.instructure.parentapp.utils.ParentComposeTest import com.instructure.parentapp.utils.tokenLogin @@ -47,6 +53,7 @@ class AssignmentDetailsInteractionTest : ParentComposeTest() { override fun displaysPageObjects() = Unit private val assignmentDetailsPage = AssignmentDetailsPage(ModuleItemInteractions()) + private val reminderPage = ReminderPage(composeTestRule) @Test fun testSubmissionStatus_Missing() { @@ -242,7 +249,8 @@ class AssignmentDetailsInteractionTest : ParentComposeTest() { } @Test - fun testReminderSectionIsNotVisibleWhenThereIsNoFutureDueDate() { + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + fun testReminderSectionIsVisibleWhenThereIsNoFutureDueDate() { val data = setupData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { @@ -250,23 +258,23 @@ class AssignmentDetailsInteractionTest : ParentComposeTest() { }.time.toApiString()) gotoAssignment(data, assignment) - assignmentDetailsPage.assertReminderSectionNotDisplayed() + reminderPage.assertReminderSectionDisplayed() } @Test - fun testReminderSectionIsVisibleWhenThereIsFutureDueDate() { + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + fun testReminderSectionIsVisibleWhenThereIsNoDueDate() { val data = setupData() val course = data.courses.values.first() - val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { - add(Calendar.DAY_OF_MONTH, 1) - }.time.toApiString()) + val assignment = data.addAssignment(course.id, name = "Test Assignment") gotoAssignment(data, assignment) - assignmentDetailsPage.assertReminderSectionDisplayed() + reminderPage.assertReminderSectionDisplayed() } @Test - fun testAddReminder() { + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + fun testReminderSectionIsVisibleWhenThereIsFutureDueDate() { val data = setupData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { @@ -274,53 +282,62 @@ class AssignmentDetailsInteractionTest : ParentComposeTest() { }.time.toApiString()) gotoAssignment(data, assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Hour Before") - - assignmentDetailsPage.assertReminderDisplayedWithText("1 Hour Before") + reminderPage.assertReminderSectionDisplayed() } @Test - fun testRemoveReminder() { + @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + fun testAddReminder() { + val reminderCalendar = Calendar.getInstance().apply { + add(Calendar.DAY_OF_MONTH, 1) + } val data = setupData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { - add(Calendar.DAY_OF_MONTH, 1) + add(Calendar.DAY_OF_MONTH, 2) }.time.toApiString()) gotoAssignment(data, assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Hour Before") - - assignmentDetailsPage.assertReminderDisplayedWithText("1 Hour Before") + reminderPage.clickAddReminder() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderCalendar) + reminderPage.selectTime(reminderCalendar) - assignmentDetailsPage.removeReminderWithText("1 Hour Before") - - assignmentDetailsPage.assertReminderNotDisplayedWithText("1 Hour Before") + reminderPage.assertReminderDisplayedWithText(reminderCalendar.time.toFormattedString()) } @Test - fun testAddCustomReminder() { + @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + fun testRemoveReminder() { + val reminderCalendar = Calendar.getInstance().apply { + add(Calendar.DAY_OF_MONTH, 1) + } val data = setupData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { - add(Calendar.DAY_OF_MONTH, 1) + add(Calendar.DAY_OF_MONTH, 2) }.time.toApiString()) gotoAssignment(data, assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.clickCustom() - assignmentDetailsPage.assertDoneButtonIsDisabled() - assignmentDetailsPage.fillQuantity("15") - assignmentDetailsPage.assertDoneButtonIsDisabled() - assignmentDetailsPage.clickHoursBefore() - assignmentDetailsPage.clickDone() + reminderPage.clickAddReminder() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderCalendar) + reminderPage.selectTime(reminderCalendar) - assignmentDetailsPage.assertReminderDisplayedWithText("15 Hours Before") + + reminderPage.assertReminderDisplayedWithText(reminderCalendar.time.toFormattedString()) + + reminderPage.removeReminderWithText(reminderCalendar.time.toFormattedString()) + + reminderPage.assertReminderNotDisplayedWithText(reminderCalendar.time.toFormattedString()) } @Test + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) fun testAddReminderInPastShowsError() { + val reminderCalendar = Calendar.getInstance().apply { + add(Calendar.DAY_OF_MONTH, -1) + } val data = setupData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { @@ -328,46 +345,36 @@ class AssignmentDetailsInteractionTest : ParentComposeTest() { }.time.toApiString()) gotoAssignment(data, assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Hour Before") + reminderPage.clickAddReminder() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderCalendar) + reminderPage.selectTime(reminderCalendar) checkToastText(R.string.reminderInPast, activityRule.activity) } @Test + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) fun testAddReminderForTheSameTimeShowsError() { - val data = setupData() - val course = data.courses.values.first() - val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { + val reminderCalendar = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, 1) - }.time.toApiString()) - gotoAssignment(data, assignment) - - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Hour Before") - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Hour Before") - - checkToastText(R.string.reminderAlreadySet, activityRule.activity) - } - - @Test - fun testAddReminderForTheSameTimeWithDifferentMeasureOfTimeShowsError() { + } val data = setupData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { - add(Calendar.DAY_OF_MONTH, 10) + add(Calendar.DAY_OF_MONTH, 2) }.time.toApiString()) gotoAssignment(data, assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Week Before") - assignmentDetailsPage.clickAddReminder() + reminderPage.clickAddReminder() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderCalendar) + reminderPage.selectTime(reminderCalendar) - assignmentDetailsPage.clickCustom() - assignmentDetailsPage.fillQuantity("7") - assignmentDetailsPage.clickDaysBefore() - assignmentDetailsPage.clickDone() + reminderPage.clickAddReminder() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderCalendar) + reminderPage.selectTime(reminderCalendar) checkToastText(R.string.reminderAlreadySet, activityRule.activity) } @@ -409,7 +416,7 @@ class AssignmentDetailsInteractionTest : ParentComposeTest() { tokenLogin(data.domain, data.tokenFor(observer)!!, observer) composeTestRule.waitForIdle() - dashboardPage.clickAlerts() + dashboardPage.clickAlertsBottomMenu() composeTestRule.waitForIdle() val alert = data.addObserverAlert( diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/DashboardInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/DashboardInteractionTest.kt index aab220c0f4..adc4afab0f 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/DashboardInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/DashboardInteractionTest.kt @@ -69,9 +69,9 @@ class DashboardInteractionTest : ParentComposeTest() { goToDashboard(data) dashboardPage.openNavigationDrawer() - dashboardPage.tapLogout() - dashboardPage.assertLogoutDialog() - dashboardPage.tapOk() + leftSideNavigationDrawerPage.clickLogout() + leftSideNavigationDrawerPage.assertLogoutDialog() + leftSideNavigationDrawerPage.clickOk() waitForMatcherWithSleeps(ViewMatchers.withId(R.id.canvasLogo), 20000).check( ViewAssertions.matches( ViewMatchers.isDisplayed() @@ -86,7 +86,7 @@ class DashboardInteractionTest : ParentComposeTest() { goToDashboard(data) dashboardPage.openNavigationDrawer() - dashboardPage.tapSwitchUsers() + leftSideNavigationDrawerPage.clickSwitchUsers() waitForMatcherWithSleeps(ViewMatchers.withId(R.id.canvasLogo), 20000).check( ViewAssertions.matches( ViewMatchers.isDisplayed() @@ -101,10 +101,10 @@ class DashboardInteractionTest : ParentComposeTest() { goToDashboard(data) try { - dashboardPage.tapAddStudent() + dashboardPage.clickAddStudent() } catch (e: Exception) { dashboardPage.openStudentSelector() - dashboardPage.tapAddStudent() + dashboardPage.clickAddStudent() } addStudentPage.tapPairingCode() @@ -119,10 +119,10 @@ class DashboardInteractionTest : ParentComposeTest() { goToDashboard(data) try { - dashboardPage.tapAddStudent() + dashboardPage.clickAddStudent() } catch (e: Exception) { dashboardPage.openStudentSelector() - dashboardPage.tapAddStudent() + dashboardPage.clickAddStudent() } addStudentPage.tapQrCode() diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ManageStudentsInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ManageStudentsInteractionTest.kt index 6e3f8496fc..79b28dd473 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ManageStudentsInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ManageStudentsInteractionTest.kt @@ -111,7 +111,7 @@ class ManageStudentsInteractionTest : ParentComposeTest() { val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) dashboardPage.openNavigationDrawer() - dashboardPage.tapManageStudents() + leftSideNavigationDrawerPage.clickManageStudents() } override fun enableAndConfigureAccessibilityChecks() { diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/NotAParentInteractionsTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/NotAParentInteractionsTest.kt index 2b6e3e9267..42b4a31b1a 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/NotAParentInteractionsTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/NotAParentInteractionsTest.kt @@ -59,7 +59,7 @@ class NotAParentInteractionsTest : ParentComposeTest() { val data = initData() goToNotAParentScreen(data) - notAParentPage.tapReturnToLogin() + notAParentPage.clickReturnToLogin() waitForMatcherWithSleeps(ViewMatchers.withId(R.id.canvasLogo), 20000).check( ViewAssertions.matches( ViewMatchers.isDisplayed() @@ -82,7 +82,7 @@ class NotAParentInteractionsTest : ParentComposeTest() { ) ) Intents.intending(expectedIntent).respondWith(Instrumentation.ActivityResult(0, null)) - notAParentPage.tapApp("STUDENT") + notAParentPage.clickApp("STUDENT") Intents.intended(expectedIntent) } @@ -101,7 +101,7 @@ class NotAParentInteractionsTest : ParentComposeTest() { ) ) Intents.intending(expectedIntent).respondWith(Instrumentation.ActivityResult(0, null)) - notAParentPage.tapApp("TEACHER") + notAParentPage.clickApp("TEACHER") Intents.intended(expectedIntent) } diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCalendarInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCalendarInteractionTest.kt index c1db9f2719..98107bae21 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCalendarInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCalendarInteractionTest.kt @@ -45,7 +45,7 @@ class ParentCalendarInteractionTest : CalendarInteractionTest() { val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) - dashboardPage.clickCalendar() + dashboardPage.clickCalendarBottomMenu() composeTestRule.waitForIdle() } diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCreateUpdateEventInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCreateUpdateEventInteractionTest.kt index 09365aedb6..954aaf1deb 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCreateUpdateEventInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCreateUpdateEventInteractionTest.kt @@ -45,7 +45,7 @@ class ParentCreateUpdateEventInteractionTest : CreateUpdateEventInteractionTest( val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) - dashboardPage.clickCalendar() + dashboardPage.clickCalendarBottomMenu() composeTestRule.waitForIdle() calendarScreenPage.clickOnAddButton() @@ -57,7 +57,7 @@ class ParentCreateUpdateEventInteractionTest : CreateUpdateEventInteractionTest( val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) - dashboardPage.clickCalendar() + dashboardPage.clickCalendarBottomMenu() val event = data.userCalendarEvents[parent.id]!!.first() diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCreateUpdateToDoInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCreateUpdateToDoInteractionTest.kt index a40c6cc6fd..030aaea55b 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCreateUpdateToDoInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentCreateUpdateToDoInteractionTest.kt @@ -45,7 +45,7 @@ class ParentCreateUpdateToDoInteractionTest : CreateUpdateToDoInteractionTest() val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) - dashboardPage.clickCalendar() + dashboardPage.clickCalendarBottomMenu() composeTestRule.waitForIdle() calendarScreenPage.clickOnAddButton() @@ -57,7 +57,7 @@ class ParentCreateUpdateToDoInteractionTest : CreateUpdateToDoInteractionTest() val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) - dashboardPage.clickCalendar() + dashboardPage.clickCalendarBottomMenu() val todo = data.todos.first() diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentEventDetailsInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentEventDetailsInteractionTest.kt index e685a3520c..4a05c97fb6 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentEventDetailsInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentEventDetailsInteractionTest.kt @@ -44,7 +44,7 @@ class ParentEventDetailsInteractionTest : EventDetailsInteractionTest() { val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) - dashboardPage.clickCalendar() + dashboardPage.clickCalendarBottomMenu() val event = data.courseCalendarEvents.values.first().first() diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentSettingsInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentSettingsInteractionTest.kt index e83142be59..6d95522552 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentSettingsInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentSettingsInteractionTest.kt @@ -25,6 +25,7 @@ import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.parentapp.BuildConfig import com.instructure.parentapp.features.login.LoginActivity import com.instructure.parentapp.ui.pages.DashboardPage +import com.instructure.parentapp.ui.pages.LeftSideNavigationDrawerPage import com.instructure.parentapp.utils.ParentActivityTestRule import com.instructure.parentapp.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest @@ -39,6 +40,8 @@ class ParentSettingsInteractionTest : SettingsInteractionTest() { private val dashboardPage = DashboardPage() + private val leftSideNavigationDrawerPage = LeftSideNavigationDrawerPage() + override fun initData(): MockCanvas { return MockCanvas.init( parentCount = 1, @@ -52,7 +55,7 @@ class ParentSettingsInteractionTest : SettingsInteractionTest() { val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) dashboardPage.openNavigationDrawer() - dashboardPage.tapSettings() + leftSideNavigationDrawerPage.clickSettings() } override fun enableAndConfigureAccessibilityChecks() { diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentToDoDetailsInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentToDoDetailsInteractionTest.kt index 2a374c8ad9..b809c6deba 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentToDoDetailsInteractionTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/ParentToDoDetailsInteractionTest.kt @@ -50,7 +50,7 @@ class ParentToDoDetailsInteractionTest : ToDoDetailsInteractionTest() { val token = data.tokenFor(parent)!! tokenLogin(data.domain, token, parent) - dashboardPage.clickCalendar() + dashboardPage.clickCalendarBottomMenu() val todo = data.todos.first() diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/SummaryInteractionTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/SummaryInteractionTest.kt new file mode 100644 index 0000000000..86b50efb50 --- /dev/null +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/interaction/SummaryInteractionTest.kt @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.parentapp.ui.interaction + +import androidx.test.core.app.ApplicationProvider +import com.instructure.canvas.espresso.common.pages.AssignmentDetailsPage +import com.instructure.canvas.espresso.common.pages.compose.CalendarEventDetailsPage +import com.instructure.canvas.espresso.mockCanvas.MockCanvas +import com.instructure.canvas.espresso.mockCanvas.addAssignment +import com.instructure.canvas.espresso.mockCanvas.addCourseCalendarEvent +import com.instructure.canvas.espresso.mockCanvas.init +import com.instructure.canvasapi2.models.Course +import com.instructure.canvasapi2.models.CourseSettings +import com.instructure.canvasapi2.models.ScheduleItem +import com.instructure.canvasapi2.models.Tab +import com.instructure.canvasapi2.utils.toApiString +import com.instructure.espresso.ModuleItemInteractions +import com.instructure.pandautils.utils.getDisplayDate +import com.instructure.parentapp.utils.ParentComposeTest +import com.instructure.parentapp.utils.tokenLogin +import dagger.hilt.android.testing.HiltAndroidTest +import org.junit.Test +import java.util.Calendar + +@HiltAndroidTest +class SummaryInteractionTest: ParentComposeTest() { + private val assignmentDetailsPage = AssignmentDetailsPage(ModuleItemInteractions()) + private val calendarEventDetailsPage = CalendarEventDetailsPage(composeTestRule) + + @Test + fun testSummaryItemsAreDisplayed() { + val data = initData() + val course = data.courses.values.first() + setupTabs(data, course) + + goToCourseDetails(data, course.name) + composeTestRule.waitForIdle() + + val courseEvents = data.courseCalendarEvents.values.flatten() + courseEvents.forEach { + summaryPage.assertItemDisplayed(it.title!!, it.getDisplayDate(ApplicationProvider.getApplicationContext())) + } + + val userEvents = data.userCalendarEvents.values.flatten() + userEvents.forEach { + summaryPage.assertItemDisplayed(it.title!!, it.getDisplayDate(ApplicationProvider.getApplicationContext())) + } + + val assignments = data.assignments.values + assignments.forEach { + summaryPage.assertItemDisplayed(it.name!!, ScheduleItem(startAt = it.dueAt).getDisplayDate(ApplicationProvider.getApplicationContext())) + } + } + + @Test + fun testAssignmentItemNavigation() { + val data = initData() + val course = data.courses.values.first() + setupTabs(data, course) + + goToCourseDetails(data, course.name) + composeTestRule.waitForIdle() + + val assignment = data.assignments.values.first() + summaryPage.selectItem(assignment.name!!, ScheduleItem(startAt = assignment.dueAt).getDisplayDate(ApplicationProvider.getApplicationContext())) + composeTestRule.waitForIdle() + + + assignmentDetailsPage.assertAssignmentDetails(assignment) + } + + @Test + fun testCalendarItemNavigation() { + val data = initData() + val course = data.courses.values.first() + setupTabs(data, course) + + goToCourseDetails(data, course.name) + composeTestRule.waitForIdle() + + val calendarItems = data.courseCalendarEvents.values.flatten().first() + summaryPage.selectItem(calendarItems.title!!, calendarItems.getDisplayDate(ApplicationProvider.getApplicationContext())) + composeTestRule.waitForIdle() + + calendarEventDetailsPage.assertEventTitle(calendarItems.title!!) + } + + private fun initData(): MockCanvas { + return MockCanvas.init( + parentCount = 1, + studentCount = 1, + courseCount = 1 + ) + } + + private fun setupTabs(data: MockCanvas, course: Course) { + course.homePage = Course.HomePage.HOME_SYLLABUS + course.syllabusBody = "This is the syllabus" + data.courseTabs[course.id]?.add(Tab(tabId = Tab.SYLLABUS_ID)) + data.courseSettings[course.id] = CourseSettings( + courseSummary = true + ) + + val dueDate = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, 1) }.time.toApiString() + val item = data.addCourseCalendarEvent( + course, + dueDate, + "Course Calendar Event", + "Course Calendar Event Description", + ) + data.courseCalendarEvents[course.id] = mutableListOf(item.copy(htmlUrl = "https://${data.domain}/calendar?event_id=${item.id}")) + + data.addAssignment(course.id, dueAt = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, 1) }.time.toApiString()) + } + + private fun goToCourseDetails(data: MockCanvas, courseName: String) { + val parent = data.parents.first() + val token = data.tokenFor(parent)!! + tokenLogin(data.domain, token, parent) + coursesPage.tapCurseItem(courseName) + courseDetailsPage.selectTab("SUMMARY") + } +} \ No newline at end of file diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/AlertSettingsPage.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/AlertSettingsPage.kt index b573deae61..9b028a010a 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/AlertSettingsPage.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/AlertSettingsPage.kt @@ -27,7 +27,7 @@ import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performTextClearance import androidx.compose.ui.test.performTextInput import com.instructure.canvasapi2.models.AlertType -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage class AlertSettingsPage(private val composeTestRule: ComposeTestRule) : BasePage() { diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/AlertsPage.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/AlertsPage.kt index 09f206e617..249bf7d6eb 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/AlertsPage.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/AlertsPage.kt @@ -29,8 +29,8 @@ import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.swipeDown import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onViewWithText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onViewWithText class AlertsPage(private val composeTestRule: ComposeTestRule) : BasePage() { diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/DashboardPage.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/DashboardPage.kt index 97a8dbc0f7..719177caed 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/DashboardPage.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/DashboardPage.kt @@ -17,21 +17,22 @@ package com.instructure.parentapp.ui.pages +import androidx.test.espresso.assertion.ViewAssertions +import androidx.test.espresso.matcher.ViewMatchers import com.instructure.canvasapi2.models.User import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithContentDescription -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithContentDescription +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withText +import com.instructure.espresso.waitForCheck import com.instructure.parentapp.R -import org.hamcrest.Matchers.equalToIgnoringCase class DashboardPage : BasePage(R.id.drawer_layout) { @@ -40,6 +41,10 @@ class DashboardPage : BasePage(R.id.drawer_layout) { private val alertsItem by OnViewWithId(R.id.alerts) private val calendarItem by OnViewWithId(R.id.calendar) + fun waitForRender() { + onViewWithId(R.id.navigationButtonHolder).waitForCheck(ViewAssertions.matches(ViewMatchers.isDisplayed())) + } + fun assertObserverData(user: User) { onViewWithText(user.name).assertDisplayed() onViewWithText(user.email.orEmpty()).assertDisplayed() @@ -61,37 +66,19 @@ class DashboardPage : BasePage(R.id.drawer_layout) { onView(withText(name) + withAncestor(R.id.student_list)).click() } - fun tapAddStudent() { + fun clickAddStudent() { onViewWithContentDescription(R.string.a11y_addStudentContentDescription).click() } - fun tapLogout() { - onViewWithText(R.string.logout).click() - } - - fun assertLogoutDialog() { - onViewWithText(R.string.logout_warning).assertDisplayed() - onViewWithText(equalToIgnoringCase(getStringFromResource(android.R.string.cancel))).assertDisplayed() - onViewWithText(equalToIgnoringCase(getStringFromResource(android.R.string.ok))).assertDisplayed() - } - - fun tapOk() { - onViewWithText(android.R.string.ok).click() - } - - fun tapSwitchUsers() { - onViewWithText(R.string.navigationDrawerSwitchUsers).click() - } - fun clickInbox() { onViewWithText(R.string.inbox).click() } - fun clickAlerts() { + fun clickAlertsBottomMenu() { alertsItem.click() } - fun clickCalendar() { + fun clickCalendarBottomMenu() { calendarItem.click() } @@ -99,11 +86,4 @@ class DashboardPage : BasePage(R.id.drawer_layout) { onViewWithId(R.id.todayButtonHolder).click() } - fun tapManageStudents() { - onViewWithText(R.string.screenTitleManageStudents).click() - } - - fun tapSettings() { - onViewWithText(R.string.settings).click() - } } diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/LeftSideNavigationDrawerPage.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/LeftSideNavigationDrawerPage.kt new file mode 100644 index 0000000000..e978453a18 --- /dev/null +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/LeftSideNavigationDrawerPage.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.instructure.parentapp.ui.pages + +import androidx.test.espresso.Espresso +import androidx.test.espresso.assertion.ViewAssertions +import androidx.test.espresso.matcher.ViewMatchers +import com.instructure.canvas.espresso.waitForMatcherWithSleeps +import com.instructure.dataseeding.model.CanvasUserApiModel +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.click +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.parentapp.R +import org.hamcrest.Matchers + +class LeftSideNavigationDrawerPage: BasePage(R.id.drawer_layout) { + + fun clickManageStudents() { + onViewWithText(R.string.screenTitleManageStudents).click() + } + + fun clickSettings() { + onViewWithText(R.string.settings).click() + } + + fun clickLogout() { + onViewWithText(R.string.logout).click() + } + + fun clickOk() { + onViewWithText(android.R.string.ok).click() + } + + fun clickSwitchUsers() { + onViewWithText(R.string.navigationDrawerSwitchUsers).click() + } + + fun assertLogoutDialog() { + onViewWithText(R.string.logout_warning).assertDisplayed() + onViewWithText(Matchers.equalToIgnoringCase(getStringFromResource(android.R.string.cancel))).assertDisplayed() + onViewWithText(Matchers.equalToIgnoringCase(getStringFromResource(android.R.string.ok))).assertDisplayed() + } + + fun logout() { + clickLogout() + assertLogoutDialog() + clickOk() + waitForMatcherWithSleeps(ViewMatchers.withId(com.instructure.loginapi.login.R.id.canvasLogo), 20000).check( + ViewAssertions.matches( + ViewMatchers.isDisplayed() + ) + ) + } + + fun assertUserLoggedIn(user: CanvasUserApiModel) { + onViewWithId(R.id.navigationButtonHolder).click() + onViewWithText(user.name).assertDisplayed() + Espresso.pressBack() + } + +} \ No newline at end of file diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/SummaryPage.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/SummaryPage.kt new file mode 100644 index 0000000000..78b56439d5 --- /dev/null +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/SummaryPage.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.parentapp.ui.pages + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.hasAnySibling +import androidx.compose.ui.test.hasText +import androidx.compose.ui.test.junit4.ComposeTestRule +import androidx.compose.ui.test.performClick + +class SummaryPage(private val composeTestRule: ComposeTestRule) { + fun assertItemDisplayed(itemName: String, date: String) { + composeTestRule.onNode(hasText(itemName).and(hasAnySibling(hasText(date)))).assertIsDisplayed() + } + + fun selectItem(itemName: String, date: String) { + composeTestRule.onNode(hasText(itemName).and(hasAnySibling(hasText(date)))).performClick() + } +} \ No newline at end of file diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/compose/NotAParentPage.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/compose/NotAParentPage.kt new file mode 100644 index 0000000000..31e0d454a1 --- /dev/null +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/compose/NotAParentPage.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.instructure.parentapp.ui.pages.compose + +import androidx.compose.ui.test.assertHasClickAction +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.ComposeTestRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import com.instructure.parentapp.utils.ParentComposeWaitMatchers + + +class NotAParentPage(private val composeTestRule: ComposeTestRule) { + + fun expandAppOptions() { + composeTestRule.onNodeWithText("Are you a student or teacher?").performClick() + } + + fun clickReturnToLogin() { + composeTestRule.onNodeWithText("Return to login").performClick() + } + + fun clickApp(appName: String) { + composeTestRule.onNodeWithText(appName).performClick() + } + + fun assertStudentAppDisplayed() { + composeTestRule.onNodeWithText("STUDENT").assertIsDisplayed().assertHasClickAction() + } + + fun assertTeacherAppDisplayed() { + composeTestRule.onNodeWithText("TEACHER").assertIsDisplayed().assertHasClickAction() + } + + fun assertOtherAppSubtitleDisplayed() { + ParentComposeWaitMatchers.waitForNodeWithText(composeTestRule, "We couldn't find any students associated with your account") + } + + fun assertNotAParentPageDetails() { + ParentComposeWaitMatchers.waitForNodeWithText(composeTestRule, "Not a parent?") + composeTestRule.onNodeWithText("We couldn't find any students associated with your account").assertIsDisplayed() + composeTestRule.onNodeWithText("Return to login") + .assertIsDisplayed() + .assertHasClickAction() + composeTestRule.onNodeWithText("Are you a student or teacher?") + .assertIsDisplayed() + .assertHasClickAction() + } +} diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentComposeTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentComposeTest.kt index 3f75c06699..7026fc5ed8 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentComposeTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentComposeTest.kt @@ -26,9 +26,10 @@ import com.instructure.parentapp.ui.pages.AnnouncementDetailsPage import com.instructure.parentapp.ui.pages.CourseDetailsPage import com.instructure.parentapp.ui.pages.CoursesPage import com.instructure.parentapp.ui.pages.ManageStudentsPage -import com.instructure.parentapp.ui.pages.NotAParentPage import com.instructure.parentapp.ui.pages.PairingCodePage import com.instructure.parentapp.ui.pages.QrPairingPage +import com.instructure.parentapp.ui.pages.SummaryPage +import com.instructure.parentapp.ui.pages.compose.NotAParentPage import org.junit.Rule @@ -46,6 +47,7 @@ abstract class ParentComposeTest : ParentTest() { protected val coursesPage = CoursesPage(composeTestRule) protected val notAParentPage = NotAParentPage(composeTestRule) protected val courseDetailsPage = CourseDetailsPage(composeTestRule) + protected val summaryPage = SummaryPage(composeTestRule) protected val announcementDetailsPage = AnnouncementDetailsPage(composeTestRule) override fun displaysPageObjects() = Unit diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/NotAParentPage.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentComposeWaitMatchers.kt similarity index 60% rename from apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/NotAParentPage.kt rename to apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentComposeWaitMatchers.kt index 72ba16cb88..4d828451ae 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/ui/pages/NotAParentPage.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentComposeWaitMatchers.kt @@ -14,25 +14,20 @@ * limitations under the License. * */ +package com.instructure.parentapp.utils -package com.instructure.parentapp.ui.pages - +import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.ComposeTestRule +import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.onNodeWithText -import androidx.compose.ui.test.performClick - -class NotAParentPage(private val composeTestRule: ComposeTestRule) { +object ParentComposeWaitMatchers { - fun expandAppOptions() { - composeTestRule.onNodeWithText("Are you a student or teacher?").performClick() + fun waitForNodeWithText(composeTestRule: ComposeTestRule, text: String, timeoutMillis: Long = 5000) { + composeTestRule.waitUntil(timeoutMillis) { + composeTestRule.onAllNodesWithText(text).fetchSemanticsNodes().isNotEmpty() + } + composeTestRule.onNodeWithText(text).assertIsDisplayed() } - fun tapReturnToLogin() { - composeTestRule.onNodeWithText("Return to login").performClick() - } - - fun tapApp(appName: String) { - composeTestRule.onNodeWithText(appName).performClick() - } -} +} \ No newline at end of file diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentTest.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentTest.kt index 1d1a2b3d2f..457fba8454 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentTest.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentTest.kt @@ -18,9 +18,13 @@ package com.instructure.parentapp.utils import com.instructure.canvas.espresso.CanvasTest +import com.instructure.espresso.pages.common.LoginFindSchoolPage +import com.instructure.espresso.pages.common.LoginLandingPage +import com.instructure.espresso.pages.common.LoginSignInPage import com.instructure.parentapp.BuildConfig import com.instructure.parentapp.features.login.LoginActivity import com.instructure.parentapp.ui.pages.DashboardPage +import com.instructure.parentapp.ui.pages.LeftSideNavigationDrawerPage abstract class ParentTest : CanvasTest() { @@ -30,4 +34,10 @@ abstract class ParentTest : CanvasTest() { override val activityRule = ParentActivityTestRule(LoginActivity::class.java) val dashboardPage = DashboardPage() + val leftSideNavigationDrawerPage = LeftSideNavigationDrawerPage() + + //Common pages + val loginLandingPage = LoginLandingPage() + val loginFindSchoolPage = LoginFindSchoolPage() + val loginSignInPage = LoginSignInPage() } \ No newline at end of file diff --git a/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentTestExtensions.kt b/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentTestExtensions.kt index dd9292fe80..6cb71e671b 100644 --- a/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentTestExtensions.kt +++ b/apps/parent/src/androidTest/java/com/instructure/parentapp/utils/ParentTestExtensions.kt @@ -19,9 +19,28 @@ package com.instructure.parentapp.utils import com.instructure.canvas.espresso.CanvasTest import com.instructure.canvasapi2.models.User +import com.instructure.dataseeding.api.SeedApi +import com.instructure.dataseeding.model.CanvasUserApiModel import com.instructure.parentapp.features.login.LoginActivity +fun ParentTest.tokenLogin(user: CanvasUserApiModel) { + activityRule.runOnUiThread { + (originalActivity as LoginActivity).loginWithToken( + user.token, + user.domain, + User( + id = user.id, + name = user.name, + shortName = user.shortName, + avatarUrl = user.avatarUrl, + effective_locale = "en" // Needed so we don't restart for custom languages (system.exit(0) kills the test process) + ) + ) + } + dashboardPage.assertPageObjects() +} + fun CanvasTest.tokenLogin(domain: String, token: String, user: User, assertDashboard: Boolean = true) { activityRule.runOnUiThread { (originalActivity as LoginActivity).loginWithToken( @@ -35,3 +54,39 @@ fun CanvasTest.tokenLogin(domain: String, token: String, user: User, assertDashb dashboardPage.assertPageObjects() } } + +fun seedData( + teachers: Int = 0, + tas: Int = 0, + pastCourses: Int = 0, + courses: Int = 0, + students: Int = 0, + parents: Int = 0, + favoriteCourses: Int = 0, + homeroomCourses: Int = 0, + announcements: Int = 0, + locked: Boolean = false, + discussions: Int = 0, + syllabusBody: String? = null, + gradingPeriods: Boolean = false, + modules: Int = 0 +): SeedApi.SeededDataApiModel { + + val request = SeedApi.SeedDataRequest ( + teachers = teachers, + TAs = tas, + students = students, + parents = parents, + pastCourses = pastCourses, + courses = courses, + favoriteCourses = favoriteCourses, + homeroomCourses = homeroomCourses, + gradingPeriods = gradingPeriods, + discussions = discussions, + announcements = announcements, + locked = locked, + syllabusBody = syllabusBody, + modules = modules + ) + return SeedApi.seedData(request) +} diff --git a/apps/parent/src/main/java/com/instructure/parentapp/di/DefaultBindingsModule.kt b/apps/parent/src/main/java/com/instructure/parentapp/di/DefaultBindingsModule.kt index e80ad959ed..9d2cc6a949 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/di/DefaultBindingsModule.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/di/DefaultBindingsModule.kt @@ -20,6 +20,7 @@ package com.instructure.parentapp.di import com.instructure.pandautils.features.dashboard.edit.EditDashboardRepository import com.instructure.pandautils.features.dashboard.edit.EditDashboardRouter import com.instructure.pandautils.features.dashboard.notifications.DashboardRouter +import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragmentBehavior import com.instructure.pandautils.features.discussion.router.DiscussionRouteHelperRepository import com.instructure.pandautils.features.discussion.router.DiscussionRouter import com.instructure.pandautils.features.elementary.grades.GradesRouter @@ -29,6 +30,7 @@ import com.instructure.pandautils.features.elementary.resources.itemviewmodels.R import com.instructure.pandautils.features.elementary.schedule.ScheduleRouter import com.instructure.pandautils.features.offline.sync.SyncRouter import com.instructure.pandautils.features.shareextension.ShareExtensionRouter +import com.instructure.pandautils.features.smartsearch.SmartSearchRouter import com.instructure.pandautils.utils.ToolbarSetupBehavior import dagger.Module import dagger.Provides @@ -104,4 +106,14 @@ class DefaultBindingsModule { fun provideSyncRouter(): SyncRouter { throw NotImplementedError() } + + @Provides + fun provideDiscussionDetailsWebViewFragmentBehavior(): DiscussionDetailsWebViewFragmentBehavior { + throw NotImplementedError() + } + + @Provides + fun provideSmartSearchRouter(): SmartSearchRouter { + throw NotImplementedError() + } } \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/di/feature/FrontPageModule.kt b/apps/parent/src/main/java/com/instructure/parentapp/di/feature/FrontPageModule.kt new file mode 100644 index 0000000000..96e85e8b6f --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/di/feature/FrontPageModule.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.instructure.parentapp.di.feature + +import com.instructure.canvasapi2.apis.PageAPI +import com.instructure.parentapp.features.courses.details.frontpage.FrontPageRepository +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ViewModelComponent + +@Module +@InstallIn(ViewModelComponent::class) +class FrontPageModule { + + @Provides + fun provideFrontPageRepository( + pageApi: PageAPI.PagesInterface + ): FrontPageRepository { + return FrontPageRepository(pageApi) + } +} diff --git a/apps/parent/src/main/java/com/instructure/parentapp/di/feature/LtiLaunchModule.kt b/apps/parent/src/main/java/com/instructure/parentapp/di/feature/LtiLaunchModule.kt index d250896b30..cb1d5d22cb 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/di/feature/LtiLaunchModule.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/di/feature/LtiLaunchModule.kt @@ -1,34 +1,34 @@ /* * Copyright (C) 2024 - present Instructure, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package com.instructure.parentapp.di.feature -import com.instructure.canvasapi2.apis.LaunchDefinitionsAPI -import com.instructure.parentapp.features.lti.LtiLaunchRepository +import com.instructure.pandautils.features.lti.LtiLaunchFragmentBehavior +import com.instructure.parentapp.features.lti.ParentLtiLaunchFragmentBehavior +import com.instructure.parentapp.util.ParentPrefs import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.components.ViewModelComponent +import dagger.hilt.android.components.FragmentComponent @Module -@InstallIn(ViewModelComponent::class) +@InstallIn(FragmentComponent::class) class LtiLaunchModule { @Provides - fun provideLtiLaunchRepository(launchDefinitionsInterface: LaunchDefinitionsAPI.LaunchDefinitionsInterface): LtiLaunchRepository { - return LtiLaunchRepository(launchDefinitionsInterface) + fun provideLtiLaunchFragmentBehavior(parentPrefs: ParentPrefs): LtiLaunchFragmentBehavior { + return ParentLtiLaunchFragmentBehavior(parentPrefs) } } \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/di/feature/SettingsModule.kt b/apps/parent/src/main/java/com/instructure/parentapp/di/feature/SettingsModule.kt index 0c256eac71..b68ef90bb6 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/di/feature/SettingsModule.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/di/feature/SettingsModule.kt @@ -18,6 +18,7 @@ package com.instructure.parentapp.di.feature import com.instructure.pandautils.features.settings.SettingsBehaviour import com.instructure.pandautils.features.settings.SettingsRouter +import com.instructure.parentapp.features.dashboard.SelectedStudentHolder import com.instructure.parentapp.features.settings.ParentSettingsBehaviour import com.instructure.parentapp.features.settings.ParentSettingsRouter import dagger.Module @@ -30,8 +31,8 @@ import dagger.hilt.components.SingletonComponent class SettingsModule { @Provides - fun provideSettingsBehaviour(): SettingsBehaviour { - return ParentSettingsBehaviour() + fun provideSettingsBehaviour(selectedStudentHolder: SelectedStudentHolder): SettingsBehaviour { + return ParentSettingsBehaviour(selectedStudentHolder) } @Provides diff --git a/apps/parent/src/main/java/com/instructure/parentapp/di/feature/SummaryModule.kt b/apps/parent/src/main/java/com/instructure/parentapp/di/feature/SummaryModule.kt new file mode 100644 index 0000000000..af5944c3a6 --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/di/feature/SummaryModule.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.parentapp.di.feature + +import com.instructure.canvasapi2.apis.CalendarEventAPI +import com.instructure.canvasapi2.apis.CourseAPI +import com.instructure.parentapp.features.courses.details.summary.SummaryRepository +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ViewModelComponent + +@Module +@InstallIn(ViewModelComponent::class) +class SummaryModule { + @Provides + fun provideSummaryRepository(courseApi: CourseAPI.CoursesInterface, calendarEventApi: CalendarEventAPI.CalendarEventInterface): SummaryRepository { + return SummaryRepository(courseApi, calendarEventApi) + } +} \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/AddStudentScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/AddStudentScreen.kt index b00cafdc39..d5ba870732 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/AddStudentScreen.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/AddStudentScreen.kt @@ -31,10 +31,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.instructure.pandautils.compose.CanvasTheme import com.instructure.parentapp.R @Composable @@ -42,27 +42,27 @@ fun AddStudentScreen( onPairingCodeClick: () -> Unit, onQrCodeClick: () -> Unit ) { - Column(modifier = Modifier.padding(vertical = 16.dp)) { - Text( - modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp), - text = stringResource(id = R.string.addStudentTitle), - style = TextStyle( + CanvasTheme { + Column(modifier = Modifier.padding(vertical = 16.dp)) { + Text( + modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp), + text = stringResource(id = R.string.addStudentTitle), color = colorResource(id = R.color.textDarkest), fontSize = 14.sp ) - ) - AddStudentButton( - title = R.string.addStudentPairingCodeTitle, - explanation = R.string.addStudentPairingCodeExplanation, - icon = R.drawable.ic_keyboard_shortcut, - onClick = onPairingCodeClick - ) - AddStudentButton( - title = R.string.addStudentQrCodeTitle, - explanation = R.string.addStudentQrCodeExplanation, - icon = R.drawable.ic_qr_code, - onClick = onQrCodeClick - ) + AddStudentButton( + title = R.string.addStudentPairingCodeTitle, + explanation = R.string.addStudentPairingCodeExplanation, + icon = R.drawable.ic_keyboard_shortcut, + onClick = onPairingCodeClick + ) + AddStudentButton( + title = R.string.addStudentQrCodeTitle, + explanation = R.string.addStudentQrCodeExplanation, + icon = R.drawable.ic_qr_code, + onClick = onQrCodeClick + ) + } } } @@ -88,20 +88,15 @@ private fun AddStudentButton( ) Column { Text( - text = stringResource(id = title), style = TextStyle( - color = colorResource( - id = R.color.textDarkest - ), - fontSize = 16.sp - ) + text = stringResource(id = title), + color = colorResource(id = R.color.textDarkest), + fontSize = 16.sp ) Text( modifier = Modifier.padding(top = 4.dp), text = stringResource(id = explanation), - style = TextStyle( - color = colorResource(id = R.color.textDarkest), - fontSize = 14.sp - ) + color = colorResource(id = R.color.textDarkest), + fontSize = 14.sp ) } } diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/pairingcode/PairingCodeDialogFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/pairingcode/PairingCodeDialogFragment.kt index 088740a74e..54b428eeef 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/pairingcode/PairingCodeDialogFragment.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/pairingcode/PairingCodeDialogFragment.kt @@ -27,7 +27,7 @@ import androidx.appcompat.app.AlertDialog import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.platform.ComposeView -import androidx.fragment.app.DialogFragment +import com.instructure.pandautils.base.BaseCanvasDialogFragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import com.instructure.pandautils.utils.collectOneOffEvents @@ -39,7 +39,7 @@ import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class PairingCodeDialogFragment : DialogFragment() { +class PairingCodeDialogFragment : BaseCanvasDialogFragment() { private val addStudentViewModel: AddStudentViewModel by activityViewModels() diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/pairingcode/PairingCodeScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/pairingcode/PairingCodeScreen.kt index e15c2d271b..b3e12afc44 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/pairingcode/PairingCodeScreen.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/pairingcode/PairingCodeScreen.kt @@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.material.TextField @@ -36,10 +37,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import com.instructure.canvasapi2.utils.ContextKeeper import com.instructure.pandautils.compose.CanvasTheme import com.instructure.pandautils.compose.composables.Loading @@ -77,61 +76,63 @@ private fun PairingScreenContent( onCancelClick: () -> Unit ) { var pairingCode by remember { mutableStateOf("") } - Column(modifier = modifier) { - TextField( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 8.dp) - .testTag("pairingCodeTextField"), - value = pairingCode, - onValueChange = { - pairingCode = it - if (uiState.isError) { - uiState.actionHandler(AddStudentAction.ResetError) - } - }, - colors = TextFieldDefaults.textFieldColors( - backgroundColor = Color.Transparent, - focusedIndicatorColor = if (uiState.isError) { - colorResource(id = R.color.textDanger) - } else { - Color(uiState.color) + CanvasTheme { + Column(modifier = modifier) { + TextField( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp) + .testTag("pairingCodeTextField"), + value = pairingCode, + onValueChange = { + pairingCode = it + if (uiState.isError) { + uiState.actionHandler(AddStudentAction.ResetError) + } }, - focusedLabelColor = Color(uiState.color), - cursorColor = Color(uiState.color), - textColor = colorResource(id = R.color.textDarkest), - unfocusedLabelColor = colorResource(id = R.color.textDark), - unfocusedIndicatorColor = colorResource(id = R.color.textDark) - ), - textStyle = TextStyle(fontSize = 16.sp), - label = { - Text( - text = stringResource(id = R.string.pairingCodeDialogLabel) - ) - }) - if (uiState.isError) { - Text( - modifier = Modifier.testTag("errorText"), - text = stringResource(id = R.string.pairingCodeDialogError), - style = TextStyle(color = colorResource(id = R.color.textDanger)) - ) - } - - Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { - TextButton(onClick = { onCancelClick() }) { + colors = TextFieldDefaults.textFieldColors( + backgroundColor = Color.Transparent, + focusedIndicatorColor = if (uiState.isError) { + colorResource(id = R.color.textDanger) + } else { + Color(uiState.color) + }, + focusedLabelColor = Color(uiState.color), + cursorColor = Color(uiState.color), + textColor = colorResource(id = R.color.textDarkest), + unfocusedLabelColor = colorResource(id = R.color.textDark), + unfocusedIndicatorColor = colorResource(id = R.color.textDark) + ), + textStyle = MaterialTheme.typography.body1, + label = { + Text( + text = stringResource(id = R.string.pairingCodeDialogLabel) + ) + }) + if (uiState.isError) { Text( - text = stringResource(id = R.string.pairingCodeDialogNegativeButton), - style = TextStyle(color = Color(uiState.color)) + modifier = Modifier.testTag("errorText"), + text = stringResource(id = R.string.pairingCodeDialogError), + color = colorResource(id = R.color.textDanger) ) } - TextButton( - modifier = Modifier.testTag("okButton"), - onClick = { uiState.actionHandler(AddStudentAction.PairStudent(pairingCode)) }, - ) { - Text( - text = stringResource(id = R.string.pairingCodeDialogPositiveButton), - style = TextStyle(color = Color(uiState.color)) - ) + + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { + TextButton(onClick = { onCancelClick() }) { + Text( + text = stringResource(id = R.string.pairingCodeDialogNegativeButton), + color = Color(uiState.color) + ) + } + TextButton( + modifier = Modifier.testTag("okButton"), + onClick = { uiState.actionHandler(AddStudentAction.PairStudent(pairingCode)) }, + ) { + Text( + text = stringResource(id = R.string.pairingCodeDialogPositiveButton), + color = Color(uiState.color) + ) + } } } } diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/qr/QrPairingFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/qr/QrPairingFragment.kt index ced6ac90dd..382178c59c 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/qr/QrPairingFragment.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/qr/QrPairingFragment.kt @@ -25,7 +25,7 @@ import androidx.activity.result.ActivityResultLauncher import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.platform.ComposeView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import com.instructure.loginapi.login.R @@ -40,7 +40,7 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @AndroidEntryPoint -class QrPairingFragment : Fragment() { +class QrPairingFragment : BaseCanvasFragment() { private val viewModel: AddStudentViewModel by activityViewModels() diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/qr/QrPairingScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/qr/QrPairingScreen.kt index 12807488bd..d6a6686fbb 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/qr/QrPairingScreen.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/addstudent/qr/QrPairingScreen.kt @@ -34,7 +34,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -71,10 +70,8 @@ fun QrPairingScreen( TextButton(onClick = onNextClicked) { Text( text = stringResource(id = R.string.next), - style = TextStyle( - color = colorResource(id = R.color.textInfo), - fontSize = 16.sp - ) + color = colorResource(id = R.color.textInfo), + fontSize = 16.sp ) } } @@ -127,19 +124,15 @@ private fun QrPairingError( Text( modifier = Modifier.padding(bottom = 8.dp), text = stringResource(id = R.string.qrPairingErrorTitle), - style = TextStyle( - color = colorResource(id = R.color.textDarkest), - fontSize = 18.sp, - textAlign = TextAlign.Center - ) + color = colorResource(id = R.color.textDarkest), + textAlign = TextAlign.Center, + fontSize = 18.sp ) Text( text = stringResource(id = R.string.qrPairingErrorDescription), - style = TextStyle( - color = colorResource(id = R.color.textDarkest), - fontSize = 16.sp, - textAlign = TextAlign.Center - ) + color = colorResource(id = R.color.textDarkest), + fontSize = 16.sp, + textAlign = TextAlign.Center ) OutlinedButton( modifier = Modifier.padding(top = 16.dp), @@ -149,10 +142,8 @@ private fun QrPairingError( }) { Text( text = stringResource(id = R.string.retry), - style = TextStyle( - color = colorResource(id = R.color.textDarkest), - fontSize = 18.sp, - ) + color = colorResource(id = R.color.textDarkest), + fontSize = 18.sp, ) } Spacer( @@ -171,10 +162,8 @@ private fun QrPairingContent() { ) { Text( text = stringResource(id = R.string.qrPairingDescription), - style = TextStyle( - color = colorResource(id = R.color.textDarkest), - fontSize = 18.sp - ) + color = colorResource(id = R.color.textDarkest), + fontSize = 18.sp ) Spacer( modifier = Modifier diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/details/AnnouncementDetailsFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/details/AnnouncementDetailsFragment.kt index a4aae98ae4..e7f62785d5 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/details/AnnouncementDetailsFragment.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/details/AnnouncementDetailsFragment.kt @@ -24,14 +24,14 @@ import android.view.ViewGroup import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.platform.ComposeView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import com.instructure.pandautils.utils.ViewStyler import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class AnnouncementDetailsFragment : Fragment() { +class AnnouncementDetailsFragment : BaseCanvasFragment() { private val viewModel: AnnouncementDetailsViewModel by viewModels() diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/details/AnnouncementDetailsScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/details/AnnouncementDetailsScreen.kt index 65516031fb..1afb276aa5 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/details/AnnouncementDetailsScreen.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/details/AnnouncementDetailsScreen.kt @@ -46,7 +46,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -105,7 +104,7 @@ fun AnnouncementDetailsScreen( actionHandler(AnnouncementDetailsAction.Refresh) } ) - Box(modifier = modifier.pullRefresh(pullRefreshState)) { + Box(modifier = modifier.padding(padding).pullRefresh(pullRefreshState)) { when { uiState.isError -> { ErrorContent( @@ -164,10 +163,8 @@ private fun AnnouncementDetailsSuccessScreen( Column(modifier = Modifier.padding(horizontal = padding)) { Text( text = uiState.announcementTitle.orEmpty(), - style = TextStyle( - color = colorResource(id = R.color.textDarkest), - fontSize = 24.sp - ) + color = colorResource(id = R.color.textDarkest), + fontSize = 24.sp ) Text( text = DateHelper.getDateAtTimeString( @@ -176,10 +173,8 @@ private fun AnnouncementDetailsSuccessScreen( uiState.postedDate ).orEmpty(), modifier = Modifier.padding(top = 4.dp, bottom = 18.dp), - style = TextStyle( - color = colorResource(id = R.color.textDarkest), - fontSize = 14.sp - ) + color = colorResource(id = R.color.textDarkest), + fontSize = 14.sp ) AttachmentsRow(uiState.attachment, actionHandler) } @@ -190,11 +185,9 @@ private fun AnnouncementDetailsSuccessScreen( top = 18.dp, bottom = 6.dp, start = padding, end = padding ), text = stringResource(R.string.description), - style = TextStyle( - color = colorResource(id = R.color.textDarkest), - fontSize = 12.sp, - fontWeight = FontWeight.Medium - ) + color = colorResource(id = R.color.textDarkest), + fontSize = 12.sp, + fontWeight = FontWeight.Medium ) ComposeCanvasWebViewWrapper( modifier = Modifier.padding(horizontal = 6.dp), diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/list/AlertsFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/list/AlertsFragment.kt index eec0ce9350..a68d30e408 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/list/AlertsFragment.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/list/AlertsFragment.kt @@ -24,7 +24,7 @@ import android.view.ViewGroup import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.platform.ComposeView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import com.google.android.material.snackbar.Snackbar @@ -35,7 +35,7 @@ import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @AndroidEntryPoint -class AlertsFragment : Fragment() { +class AlertsFragment : BaseCanvasFragment() { @Inject lateinit var navigation: Navigation diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/list/AlertsScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/list/AlertsScreen.kt index 7c72717b0c..0be0128a51 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/list/AlertsScreen.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/list/AlertsScreen.kt @@ -54,7 +54,6 @@ import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -158,7 +157,7 @@ fun AlertsListContent( alert = alert, userColor = uiState.studentColor, actionHandler = actionHandler, - modifier = Modifier.animateItemPlacement() + modifier = Modifier.animateItem() ) Spacer(modifier = Modifier.size(8.dp)) } @@ -182,18 +181,22 @@ fun AlertsListItem( R.string.assignmentGradeHighAlertTitle, threshold ) + AlertType.ASSIGNMENT_GRADE_LOW -> context.getString( R.string.assignmentGradeLowAlertTitle, threshold ) + AlertType.COURSE_GRADE_HIGH -> context.getString( R.string.courseGradeHighAlertTitle, threshold ) + AlertType.COURSE_GRADE_LOW -> context.getString( R.string.courseGradeLowAlertTitle, threshold ) + AlertType.COURSE_ANNOUNCEMENT -> context.getString(R.string.courseAnnouncementAlertTitle) AlertType.INSTITUTION_ANNOUNCEMENT -> context.getString(R.string.institutionAnnouncementAlertTitle) } @@ -220,7 +223,14 @@ fun AlertsListItem( Row(modifier = modifier .fillMaxWidth() .clickable { - actionHandler(AlertsAction.Navigate(alert.alertId, alert.contextId, alert.htmlUrl, alert.alertType)) + actionHandler( + AlertsAction.Navigate( + alert.alertId, + alert.contextId, + alert.htmlUrl, + alert.alertType + ) + ) } .padding(8.dp) .testTag("alertItem"), @@ -251,12 +261,14 @@ fun AlertsListItem( Column(modifier = Modifier.weight(1f)) { Text( text = alertTitle(alert.alertType, alert.observerAlertThreshold), - style = TextStyle(color = Color(alertColor(alert.alertType)), fontSize = 12.sp) + color = Color(alertColor(alert.alertType)), + fontSize = 12.sp ) Text( modifier = Modifier.padding(vertical = 4.dp), text = alert.title, - style = TextStyle(color = colorResource(id = R.color.textDarkest), fontSize = 16.sp) + color = colorResource(id = R.color.textDarkest), + fontSize = 16.sp ) alert.date?.let { Text( @@ -265,10 +277,8 @@ fun AlertsListItem( com.instructure.pandares.R.string.alertDateTime, it ) ?: "", - style = TextStyle( - color = colorResource(id = R.color.textDark), - fontSize = 12.sp - ) + fontSize = 12.sp, + color = colorResource(id = R.color.textDark) ) } } diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/settings/AlertSettingsFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/settings/AlertSettingsFragment.kt index c91f5f0be1..8da5763615 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/settings/AlertSettingsFragment.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/settings/AlertSettingsFragment.kt @@ -23,7 +23,7 @@ import android.view.ViewGroup import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.platform.ComposeView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope @@ -39,7 +39,7 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch @AndroidEntryPoint -class AlertSettingsFragment : Fragment() { +class AlertSettingsFragment : BaseCanvasFragment() { private val addStudentViewModel: AddStudentViewModel by activityViewModels() diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/settings/AlertSettingsScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/settings/AlertSettingsScreen.kt index 95067605a9..3b3196218f 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/settings/AlertSettingsScreen.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/alerts/settings/AlertSettingsScreen.kt @@ -55,7 +55,6 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.input.KeyboardType @@ -126,7 +125,10 @@ fun AlertSettingsScreen( showConfirmationDialog = true } }) { - Text(text = stringResource(id = R.string.delete), color = colorResource(id = R.color.textDarkest)) + Text( + text = stringResource(id = R.string.delete), + color = colorResource(id = R.color.textDarkest) + ) } } } @@ -174,7 +176,8 @@ fun AlertSettingsContent(uiState: AlertSettingsUiState, modifier: Modifier) { Text( modifier = Modifier.padding(start = 16.dp, end = 16.dp), text = stringResource(id = R.string.alertSettingsThresholdsTitle), - style = TextStyle(fontSize = 14.sp, color = colorResource(id = R.color.textDark)) + fontSize = 14.sp, + color = colorResource(id = R.color.textDark) ) listOf( AlertType.COURSE_GRADE_LOW, @@ -329,12 +332,14 @@ private fun PercentageItem( Text( modifier = Modifier.testTag("${alertType.name}_thresholdTitle"), text = title, - style = TextStyle(fontSize = 16.sp, color = colorResource(id = R.color.textDarkest)) + fontSize = 16.sp, + color = colorResource(id = R.color.textDarkest) ) Text( text = threshold?.let { stringResource(id = R.string.alertSettingsPercentage, it) } ?: stringResource(id = R.string.alertSettingsThresholdNever), - style = TextStyle(color = color, textAlign = TextAlign.End), + color = color, + textAlign = TextAlign.End, modifier = Modifier .padding(8.dp) .testTag("${alertType.name}_thresholdValue") @@ -375,7 +380,8 @@ private fun SwitchItem( Text( modifier = Modifier.testTag("${alertType.name}_thresholdTitle"), text = title, - style = TextStyle(fontSize = 16.sp, color = colorResource(id = R.color.textDarkest)) + fontSize = 16.sp, + color = colorResource(id = R.color.textDarkest) ) Switch( modifier = Modifier.testTag("${alertType.name}_thresholdSwitch"), @@ -403,7 +409,7 @@ private fun ThresholdDialog( onDismiss: () -> Unit ) { var percentage by remember { mutableStateOf(threshold.orEmpty()) } - val enabled = percentage.toIntOrNull().orDefault() in (min + 1)..< max + val enabled = percentage.toIntOrNull().orDefault() in (min + 1).. { navigation.navigate(activity, navigation.assignmentDetailsRoute(action.courseId, action.assignmentId)) } + + is CourseDetailsViewModelAction.NavigateToCalendarEvent -> { + navigation.navigate(activity, navigation.calendarEventRoute(action.contextType, action.contextId, action.eventId)) + } + + is CourseDetailsViewModelAction.OpenLtiScreen -> { + navigation.navigate(activity, navigation.ltiLaunchRoute(action.url, getString(R.string.utils_externalToolTitle), sessionlessLaunch = true)) + } } } } diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsScreen.kt index 5f4ed66ef5..6aa92c947c 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsScreen.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsScreen.kt @@ -17,7 +17,6 @@ package com.instructure.parentapp.features.courses.details -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -26,12 +25,16 @@ import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material.FloatingActionButton import androidx.compose.material.Icon import androidx.compose.material.Scaffold +import androidx.compose.material.SnackbarHost +import androidx.compose.material.SnackbarHostState +import androidx.compose.material.SnackbarResult import androidx.compose.material.Surface import androidx.compose.material.Tab import androidx.compose.material.TabRow import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier @@ -52,6 +55,10 @@ import com.instructure.pandautils.compose.composables.CanvasThemedAppBar import com.instructure.pandautils.compose.composables.ErrorContent import com.instructure.pandautils.compose.composables.Loading import com.instructure.pandautils.utils.ThemePrefs +import com.instructure.pandautils.views.CanvasWebView +import com.instructure.parentapp.features.courses.details.frontpage.FrontPageScreen +import com.instructure.parentapp.features.courses.details.grades.ParentGradesScreen +import com.instructure.parentapp.features.courses.details.summary.SummaryScreen import kotlinx.coroutines.launch @@ -59,6 +66,7 @@ import kotlinx.coroutines.launch internal fun CourseDetailsScreen( uiState: CourseDetailsUiState, actionHandler: (CourseDetailsAction) -> Unit, + applyOnWebView: (CanvasWebView.() -> Unit), navigationActionClick: () -> Unit ) { CanvasTheme { @@ -90,6 +98,7 @@ internal fun CourseDetailsScreen( uiState = uiState, actionHandler = actionHandler, navigationActionClick = navigationActionClick, + applyOnWebView = applyOnWebView, modifier = Modifier.fillMaxSize() ) } @@ -98,14 +107,26 @@ internal fun CourseDetailsScreen( } } -@OptIn(ExperimentalFoundationApi::class) @Composable private fun CourseDetailsScreenContent( uiState: CourseDetailsUiState, actionHandler: (CourseDetailsAction) -> Unit, navigationActionClick: () -> Unit, + applyOnWebView: (CanvasWebView.() -> Unit), modifier: Modifier = Modifier ) { + val snackbarHostState = remember { SnackbarHostState() } + val localCoroutineScope = rememberCoroutineScope() + uiState.snackbarMessage?.let { + LaunchedEffect(Unit) { + localCoroutineScope.launch { + val result = snackbarHostState.showSnackbar(it) + if (result == SnackbarResult.Dismissed) { + actionHandler(CourseDetailsAction.SnackbarDismissed) + } + } + } + } val pagerState = rememberPagerState { uiState.tabs.size } val coroutineScope = rememberCoroutineScope() @@ -115,28 +136,72 @@ private fun CourseDetailsScreenContent( } } - val tabContents: List<@Composable () -> Unit> = uiState.tabs.map { - when (it) { + val tabContents: List<@Composable () -> Unit> = uiState.tabs.map { tabType -> + when (tabType) { TabType.GRADES -> { - { ParentGradesScreen(actionHandler) } + { + ParentGradesScreen( + navigateToAssignmentDetails = { courseId, assignmentId -> + actionHandler(CourseDetailsAction.NavigateToAssignmentDetails(courseId, assignmentId)) + } + ) + } } TabType.FRONT_PAGE -> { - { FrontPageScreen() } + { + FrontPageScreen( + applyOnWebView = applyOnWebView, + onLtiButtonPressed = { + actionHandler(CourseDetailsAction.OnLtiClicked(it)) + }, + showSnackbar = { + actionHandler(CourseDetailsAction.ShowSnackbar(it)) + } + ) + } } TabType.SYLLABUS -> { - { SyllabusScreen() } + { + CourseDetailsWebViewScreen( + html = uiState.syllabus, + isRefreshing = uiState.isRefreshing, + studentColor = uiState.studentColor, + onRefresh = { + actionHandler(CourseDetailsAction.RefreshCourse) + }, + applyOnWebView = applyOnWebView, + onLtiButtonPressed = { + actionHandler(CourseDetailsAction.OnLtiClicked(it)) + } + ) + } } TabType.SUMMARY -> { - { SummaryScreen() } + { + SummaryScreen( + navigateToCalendarEvent = { contextType, contextId, eventId -> + actionHandler(CourseDetailsAction.NavigateToCalendarEvent(contextType, contextId, eventId)) + }, + navigateToAssignmentDetails = { courseId, assignmentId -> + actionHandler(CourseDetailsAction.NavigateToAssignmentDetails(courseId, assignmentId)) + } + ) + } } } } Scaffold( backgroundColor = colorResource(id = R.color.backgroundLightest), + snackbarHost = { + SnackbarHost( + hostState = snackbarHostState, + modifier = Modifier.testTag("snackbarHost") + ) + }, topBar = { CanvasThemedAppBar( title = uiState.courseName, @@ -219,6 +284,7 @@ private fun CourseDetailsScreenPreview() { ) ), actionHandler = {}, + applyOnWebView = {}, navigationActionClick = {} ) } @@ -233,6 +299,7 @@ private fun CourseDetailsScreenErrorPreview() { isError = true, ), actionHandler = {}, + applyOnWebView = {}, navigationActionClick = {} ) } diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsUiState.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsUiState.kt index 0ff03ca2f0..0963cc10e1 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsUiState.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsUiState.kt @@ -28,9 +28,12 @@ data class CourseDetailsUiState( val courseName: String = "", @ColorInt val studentColor: Int = Color.BLACK, val isLoading: Boolean = false, + val isRefreshing: Boolean = false, val isError: Boolean = false, val tabs: List = emptyList(), - val currentTab: TabType? = null + val currentTab: TabType? = null, + val syllabus: String = "", + val snackbarMessage: String? = null ) enum class TabType(@StringRes val labelRes: Int) { @@ -42,12 +45,19 @@ enum class TabType(@StringRes val labelRes: Int) { sealed class CourseDetailsAction { data object Refresh : CourseDetailsAction() + data object RefreshCourse : CourseDetailsAction() data object SendAMessage : CourseDetailsAction() data class NavigateToAssignmentDetails(val courseId: Long, val assignmentId: Long) : CourseDetailsAction() + data class NavigateToCalendarEvent(val contextType: String, val contextId: Long, val eventId: Long) : CourseDetailsAction() data class CurrentTabChanged(val newTab: TabType) : CourseDetailsAction() + data class OnLtiClicked(val url: String) : CourseDetailsAction() + data class ShowSnackbar(val message: String) : CourseDetailsAction() + data object SnackbarDismissed : CourseDetailsAction() } sealed class CourseDetailsViewModelAction { data class NavigateToComposeMessageScreen(val options: InboxComposeOptions) : CourseDetailsViewModelAction() data class NavigateToAssignmentDetails(val courseId: Long, val assignmentId: Long) : CourseDetailsViewModelAction() + data class NavigateToCalendarEvent(val contextType: String, val contextId: Long, val eventId: Long) : CourseDetailsViewModelAction() + data class OpenLtiScreen(val url: String) : CourseDetailsViewModelAction() } diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsViewModel.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsViewModel.kt index 869a6214ef..4a496cfe1c 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsViewModel.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsViewModel.kt @@ -96,22 +96,54 @@ class CourseDetailsViewModel @Inject constructor( it.copy( courseName = course.name, isLoading = false, - tabs = tabTypes + isRefreshing = false, + isError = false, + tabs = tabTypes, + syllabus = course.syllabusBody.orEmpty() ) } } catch { _uiState.update { it.copy( isLoading = false, + isRefreshing = false, isError = true ) } } } + private fun refreshCourse() { + viewModelScope.tryLaunch { + _uiState.update { + it.copy(isRefreshing = true) + } + + val course = repository.getCourse(courseId, true) + + _uiState.update { + it.copy( + isRefreshing = false, + courseName = course.name, + syllabus = course.syllabusBody.orEmpty(), + ) + } + } catch { + _uiState.update { + it.copy( + isLoading = false, + isRefreshing = false, + snackbarMessage = context.getString(R.string.courseRefreshFailed) + ) + } + } + } + fun handleAction(action: CourseDetailsAction) { when (action) { - is CourseDetailsAction.Refresh -> loadData(forceRefresh = true) + is CourseDetailsAction.Refresh -> loadData(true) + + is CourseDetailsAction.RefreshCourse -> refreshCourse() is CourseDetailsAction.SendAMessage -> { viewModelScope.launch { @@ -125,6 +157,12 @@ class CourseDetailsViewModel @Inject constructor( } } + is CourseDetailsAction.NavigateToCalendarEvent -> { + viewModelScope.launch { + _events.send(CourseDetailsViewModelAction.NavigateToCalendarEvent(action.contextType, action.contextId, action.eventId)) + } + } + is CourseDetailsAction.CurrentTabChanged -> { viewModelScope.launch { _uiState.update { @@ -132,6 +170,24 @@ class CourseDetailsViewModel @Inject constructor( } } } + + is CourseDetailsAction.OnLtiClicked -> { + viewModelScope.launch { + _events.send(CourseDetailsViewModelAction.OpenLtiScreen(action.url)) + } + } + + is CourseDetailsAction.ShowSnackbar -> { + _uiState.update { + it.copy(snackbarMessage = action.message) + } + } + + is CourseDetailsAction.SnackbarDismissed -> { + _uiState.update { + it.copy(snackbarMessage = null) + } + } } } diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsWebViewScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsWebViewScreen.kt new file mode 100644 index 0000000000..d1b6b95274 --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/CourseDetailsWebViewScreen.kt @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.instructure.parentapp.features.courses.details + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.pullrefresh.PullRefreshDefaults +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.tooling.preview.Preview +import com.instructure.pandautils.compose.composables.ComposeCanvasWebViewWrapper +import com.instructure.pandautils.views.CanvasWebView + + +@OptIn(ExperimentalMaterialApi::class) +@Composable +internal fun CourseDetailsWebViewScreen( + html: String, + isRefreshing: Boolean, + studentColor: Int, + onRefresh: () -> Unit, + applyOnWebView: (CanvasWebView) -> Unit, + onLtiButtonPressed: (String) -> Unit +) { + val pullRefreshState = rememberPullRefreshState( + refreshing = isRefreshing, + onRefresh = onRefresh, + refreshThreshold = PullRefreshDefaults.RefreshingOffset + ) + + Box( + modifier = Modifier + .pullRefresh(pullRefreshState) + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .testTag("CourseDetailsWebViewScreen") + ) { + ComposeCanvasWebViewWrapper( + html = html, + onLtiButtonPressed = onLtiButtonPressed, + applyOnWebView = applyOnWebView + ) + PullRefreshIndicator( + refreshing = isRefreshing, + state = pullRefreshState, + modifier = Modifier + .align(Alignment.TopCenter) + .testTag("pullRefreshIndicator"), + contentColor = Color(studentColor) + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun CourseDetailsWebViewScreenPreview() { + CourseDetailsWebViewScreen( + html = "WebView content", + isRefreshing = false, + studentColor = android.graphics.Color.BLACK, + onRefresh = {}, + applyOnWebView = {}, + onLtiButtonPressed = {} + ) +} diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageRepository.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageRepository.kt new file mode 100644 index 0000000000..121a2cf9f5 --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageRepository.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.instructure.parentapp.features.courses.details.frontpage + +import com.instructure.canvasapi2.apis.PageAPI +import com.instructure.canvasapi2.builders.RestParams +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.models.Page + + +class FrontPageRepository(private val pageApi: PageAPI.PagesInterface) { + + suspend fun loadFrontPage(courseId: Long, forceRefresh: Boolean): Page { + val params = RestParams(isForceReadFromNetwork = forceRefresh) + + return pageApi.getFrontPage(CanvasContext.Type.COURSE.apiString, courseId, params).dataOrThrow + } +} diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageScreen.kt new file mode 100644 index 0000000000..8d4f2d6288 --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageScreen.kt @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.instructure.parentapp.features.courses.details.frontpage + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.lifecycle.viewmodel.compose.viewModel +import com.instructure.pandautils.R +import com.instructure.pandautils.compose.composables.ErrorContent +import com.instructure.pandautils.compose.composables.Loading +import com.instructure.pandautils.views.CanvasWebView +import com.instructure.parentapp.features.courses.details.CourseDetailsWebViewScreen + + +@Composable +internal fun FrontPageScreen( + applyOnWebView: (CanvasWebView) -> Unit, + onLtiButtonPressed: (String) -> Unit, + showSnackbar: (String) -> Unit +) { + val viewModel: FrontPageViewModel = viewModel() + val uiState by remember { viewModel.uiState }.collectAsState() + val events = viewModel.events + LaunchedEffect(events) { + events.collect { action -> + when (action) { + is FrontPageViewModelAction.ShowSnackbar -> { + showSnackbar(action.message) + } + } + } + } + + FrontPageContent(uiState, viewModel::handleAction, applyOnWebView, onLtiButtonPressed) +} + +@Composable +internal fun FrontPageContent( + uiState: FrontPageUiState, + actionHandler: (FrontPageAction) -> Unit, + applyOnWebView: (CanvasWebView) -> Unit, + onLtiButtonPressed: (String) -> Unit +) { + when { + uiState.isLoading -> { + Loading( + color = Color(uiState.studentColor), + modifier = Modifier + .fillMaxSize() + .testTag("loading") + ) + } + + uiState.isError -> { + ErrorContent( + errorMessage = stringResource(id = R.string.generalUnexpectedError), + retryClick = { + actionHandler(FrontPageAction.Refresh) + }, + modifier = Modifier.fillMaxSize() + ) + } + + else -> { + CourseDetailsWebViewScreen( + html = uiState.htmlContent, + isRefreshing = uiState.isRefreshing, + studentColor = uiState.studentColor, + onRefresh = { actionHandler(FrontPageAction.Refresh) }, + applyOnWebView = applyOnWebView, + onLtiButtonPressed = onLtiButtonPressed + ) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun FrontPageScreenPreview( + @PreviewParameter(FrontPageScreenPreviewParameterProvider::class) uiState: FrontPageUiState +) { + FrontPageContent( + uiState = uiState, + actionHandler = {}, + applyOnWebView = {}, + onLtiButtonPressed = {} + ) +} + +private class FrontPageScreenPreviewParameterProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + FrontPageUiState( + studentColor = android.graphics.Color.RED, + isLoading = true, + isError = false + ), + FrontPageUiState( + studentColor = android.graphics.Color.BLUE, + isLoading = false, + isError = false, + htmlContent = "Front Page Content" + ), + FrontPageUiState( + studentColor = android.graphics.Color.GREEN, + isLoading = false, + isError = true + ) + ) +} diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageUiState.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageUiState.kt new file mode 100644 index 0000000000..2cf5615087 --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageUiState.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.instructure.parentapp.features.courses.details.frontpage + +import android.graphics.Color +import androidx.annotation.ColorInt + + +data class FrontPageUiState( + @ColorInt val studentColor: Int = Color.BLACK, + val isLoading: Boolean = true, + val isError: Boolean = false, + val isRefreshing: Boolean = false, + val htmlContent: String = "" +) + +sealed class FrontPageAction { + data object Refresh : FrontPageAction() +} + +sealed class FrontPageViewModelAction { + data class ShowSnackbar(val message: String) : FrontPageViewModelAction() +} \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageViewModel.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageViewModel.kt new file mode 100644 index 0000000000..00b0e9cb56 --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageViewModel.kt @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.instructure.parentapp.features.courses.details.frontpage + +import android.content.Context +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.instructure.canvasapi2.utils.weave.catch +import com.instructure.canvasapi2.utils.weave.tryLaunch +import com.instructure.pandautils.features.grades.COURSE_ID_KEY +import com.instructure.pandautils.utils.orDefault +import com.instructure.pandautils.utils.studentColor +import com.instructure.parentapp.R +import com.instructure.parentapp.util.ParentPrefs +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + + +@HiltViewModel +class FrontPageViewModel @Inject constructor( + @ApplicationContext private val context: Context, + savedStateHandle: SavedStateHandle, + private val repository: FrontPageRepository, + private val parentPrefs: ParentPrefs +) : ViewModel() { + + private val courseId = savedStateHandle.get(COURSE_ID_KEY).orDefault() + + private val _uiState = MutableStateFlow(FrontPageUiState()) + val uiState = _uiState.asStateFlow() + + private val _events = Channel() + val events = _events.receiveAsFlow() + + init { + loadFrontPage(false) + } + + private fun loadFrontPage(forceRefresh: Boolean) { + viewModelScope.tryLaunch { + _uiState.update { + it.copy( + studentColor = parentPrefs.currentStudent.studentColor, + isLoading = it.htmlContent.isEmpty(), + isRefreshing = it.htmlContent.isNotEmpty() + ) + } + + val frontPage = repository.loadFrontPage(courseId, forceRefresh) + + _uiState.update { + it.copy( + htmlContent = frontPage.body.orEmpty(), + isLoading = false, + isRefreshing = false, + isError = false + ) + } + } catch { + val showSnack = forceRefresh && _uiState.value.htmlContent.isNotEmpty() + + if (showSnack) { + viewModelScope.launch { + _events.send(FrontPageViewModelAction.ShowSnackbar(context.getString(R.string.frontPageRefreshFailed))) + } + } + + _uiState.update { + it.copy( + isLoading = false, + isError = !showSnack, + isRefreshing = false + ) + } + } + } + + fun handleAction(action: FrontPageAction) { + when (action) { + is FrontPageAction.Refresh -> { + loadFrontPage(true) + } + } + } +} diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/ParentGradesScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/grades/ParentGradesScreen.kt similarity index 87% rename from apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/ParentGradesScreen.kt rename to apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/grades/ParentGradesScreen.kt index e92bf4a303..b98f5a08fd 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/ParentGradesScreen.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/grades/ParentGradesScreen.kt @@ -15,7 +15,7 @@ * */ -package com.instructure.parentapp.features.courses.details +package com.instructure.parentapp.features.courses.details.grades import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -30,7 +30,7 @@ import com.instructure.pandautils.features.grades.GradesViewModelAction @Composable internal fun ParentGradesScreen( - actionHandler: (CourseDetailsAction) -> Unit + navigateToAssignmentDetails: (Long, Long) -> Unit ) { val gradesViewModel: GradesViewModel = viewModel() val gradeUiState by remember { gradesViewModel.uiState }.collectAsState() @@ -39,7 +39,7 @@ internal fun ParentGradesScreen( events.collect { action -> when (action) { is GradesViewModelAction.NavigateToAssignmentDetails -> { - actionHandler(CourseDetailsAction.NavigateToAssignmentDetails(action.courseId, action.assignmentId)) + navigateToAssignmentDetails(action.courseId, action.assignmentId) } } } diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryRepository.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryRepository.kt new file mode 100644 index 0000000000..adeb52493a --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryRepository.kt @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.parentapp.features.courses.details.summary + +import com.instructure.canvasapi2.apis.CalendarEventAPI +import com.instructure.canvasapi2.apis.CourseAPI +import com.instructure.canvasapi2.builders.RestParams +import com.instructure.canvasapi2.models.Course +import com.instructure.canvasapi2.models.ScheduleItem +import com.instructure.canvasapi2.utils.depaginate + +class SummaryRepository( + private val courseApi: CourseAPI.CoursesInterface, + private val calendarEventApi: CalendarEventAPI.CalendarEventInterface +) { + + suspend fun getCourse(id: Long): Course { + return courseApi.getCourse(id, RestParams()).dataOrThrow + } + + suspend fun getCalendarEvents(contextId: String, forceRefresh: Boolean = false): List { + val params = RestParams(isForceReadFromNetwork = forceRefresh, usePerPageQueryParam = true) + val assignmentEvents = calendarEventApi.getCalendarEvents( + allEvents = true, + type = CalendarEventAPI.CalendarEventType.ASSIGNMENT.apiName, + startDate = null, + endDate = null, + contextCodes = listOf(contextId), + restParams = params + ).depaginate { + calendarEventApi.next(it, params) + }.dataOrNull + .orEmpty() + .filterNot { it.isHidden } + + val calendarEvents = calendarEventApi.getCalendarEvents( + allEvents = true, + type = CalendarEventAPI.CalendarEventType.CALENDAR.apiName, + startDate = null, + endDate = null, + contextCodes = listOf(contextId), + restParams = params + ).depaginate { + calendarEventApi.next(it, params) + }.dataOrNull + .orEmpty() + .filterNot { it.isHidden } + + return assignmentEvents + calendarEvents + } +} \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryScreen.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryScreen.kt new file mode 100644 index 0000000000..523a05d0c5 --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryScreen.kt @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.instructure.parentapp.features.courses.details.summary + +import android.net.Uri +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.models.ScheduleItem +import com.instructure.pandautils.compose.CanvasTheme +import com.instructure.pandautils.compose.composables.EmptyContent +import com.instructure.pandautils.compose.composables.ErrorContent +import com.instructure.pandautils.compose.composables.Loading +import com.instructure.pandautils.utils.color +import com.instructure.pandautils.utils.getDisplayDate +import com.instructure.pandautils.utils.iconRes +import com.instructure.parentapp.R + +@Composable +internal fun SummaryScreen( + navigateToAssignmentDetails: (Long, Long) -> Unit, + navigateToCalendarEvent: (String, Long, Long) -> Unit, +) { + val summaryViewModel: SummaryViewModel = viewModel() + val uiState by summaryViewModel.uiState.collectAsState() + + CanvasTheme { + SummaryContent( + uiState = uiState, + onRefresh = { summaryViewModel.refresh() }, + navigateToAssignmentDetails = navigateToAssignmentDetails, + navigateToCalendarEvent = navigateToCalendarEvent) + } +} + +@OptIn(ExperimentalMaterialApi::class) +@Composable +internal fun SummaryContent( + uiState: SummaryUiState, + onRefresh: () -> Unit, + navigateToAssignmentDetails: (Long, Long) -> Unit, + navigateToCalendarEvent: (String, Long, Long) -> Unit, +) { + val pullToRefreshState = rememberPullRefreshState(refreshing = (uiState.state == ScreenState.Loading), onRefresh = { + onRefresh() + }) + + Box( + modifier = Modifier + .fillMaxSize() + .pullRefresh(pullToRefreshState) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier + .fillMaxSize() + ) { + when (uiState.state) { + is ScreenState.Loading -> { + SummaryLoadingScreen() + } + + is ScreenState.Error -> { + SummaryErrorScreen(onRefresh) + } + + is ScreenState.Empty -> { + SummaryEmptyScreen() + } + + is ScreenState.Content -> { + SummaryContentScreen(uiState.items, uiState.courseId, navigateToAssignmentDetails, navigateToCalendarEvent) + } + } + } + + PullRefreshIndicator( + refreshing = (uiState.state == ScreenState.Loading), + state = pullToRefreshState, + modifier = Modifier + .align(Alignment.TopCenter) + .testTag("pullRefreshIndicator"), + ) + } +} + +@Composable +private fun SummaryLoadingScreen() { + Loading(modifier = Modifier.testTag("Loading")) +} + +@Composable +private fun SummaryErrorScreen( + onRefresh: () -> Unit +) { + ErrorContent( + errorMessage = stringResource(R.string.failed_to_load_summary), + retryClick = onRefresh, + ) +} + +@Composable +private fun SummaryEmptyScreen() { + EmptyContent( + imageRes = R.drawable.ic_panda_nosyllabus, + emptyMessage = stringResource(R.string.no_summary_items_to_display) + ) +} + +@Composable +private fun SummaryContentScreen( + items: List, + courseId: Long, + navigateToAssignmentDetails: (Long, Long) -> Unit, + navigateToCalendarEvent: (String, Long, Long) -> Unit +) { + LazyColumn( + contentPadding = PaddingValues(bottom = 64.dp), + modifier = Modifier.fillMaxSize() + ) { + items(items) { + ScheduleItemRow(it, courseId, navigateToAssignmentDetails, navigateToCalendarEvent) + } + } +} + +@Composable +private fun ScheduleItemRow( + scheduleItem: ScheduleItem, + courseId: Long, + navigateToAssignmentDetails: (Long, Long) -> Unit, + navigateToCalendarEvent: (String, Long, Long) -> Unit +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .padding(8.dp) + .clickable { + if (scheduleItem.assignment != null) { + navigateToAssignmentDetails( + scheduleItem.courseId, + scheduleItem.assignment?.id ?: 0 + ) + } else { + val uri = Uri.parse(scheduleItem.htmlUrl) + val eventId = uri + .getQueryParameter("event_id") + ?.toLongOrNull() ?: 0 + navigateToCalendarEvent (CanvasContext.Type.COURSE.apiString, courseId, eventId) + } + } + ) { + Icon( + painter = painterResource(id = scheduleItem.iconRes), + contentDescription = "Summary Item Icon", + tint = Color(CanvasContext.emptyCourseContext(courseId).color), + modifier = Modifier + .padding(8.dp) + .size(24.dp) + ) + + Column { + Text( + text = scheduleItem.title.orEmpty(), + fontSize = 16.sp, + color = colorResource(id = R.color.textDarkest), + modifier = Modifier.padding(start = 8.dp, top = 4.dp) + ) + + Text( + text = scheduleItem.getDisplayDate(context = LocalContext.current), + fontSize = 14.sp, + color = colorResource(id = R.color.textDark), + modifier = Modifier.padding(start = 8.dp, bottom = 4.dp) + ) + } + } +} \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryUiState.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryUiState.kt new file mode 100644 index 0000000000..91060c37e6 --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryUiState.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.parentapp.features.courses.details.summary + +import com.instructure.canvasapi2.models.ScheduleItem + +data class SummaryUiState ( + val state: ScreenState = ScreenState.Loading, + val courseId: Long = 0, + val items: List = emptyList() +) + +sealed class ScreenState { + data object Loading : ScreenState() + data object Error : ScreenState() + data object Empty : ScreenState() + data object Content : ScreenState() +} \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryViewModel.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryViewModel.kt new file mode 100644 index 0000000000..2cdaba33c8 --- /dev/null +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/summary/SummaryViewModel.kt @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.parentapp.features.courses.details.summary + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.instructure.canvasapi2.utils.weave.catch +import com.instructure.canvasapi2.utils.weave.tryLaunch +import com.instructure.pandautils.features.grades.COURSE_ID_KEY +import com.instructure.pandautils.utils.orDefault +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import javax.inject.Inject + +@HiltViewModel +class SummaryViewModel @Inject constructor( + private val repository: SummaryRepository, + savedStateHandle: SavedStateHandle, +): ViewModel() { + + private val courseId = savedStateHandle.get(COURSE_ID_KEY).orDefault() + + private val _uiState = MutableStateFlow(SummaryUiState()) + val uiState = _uiState.asStateFlow() + + init { + loadSummary(false) + } + + fun refresh() { + loadSummary(true) + } + + private fun loadSummary(forceRefresh: Boolean) { + _uiState.update { it.copy(state = ScreenState.Loading) } + viewModelScope.tryLaunch { + val course = repository.getCourse(courseId) + val summary = repository.getCalendarEvents(course.contextId, forceRefresh) + if (summary.isEmpty()) { + _uiState.update { it.copy(state = ScreenState.Empty, items = summary, courseId = course.id) } + } else { + _uiState.update { it.copy(state = ScreenState.Content, items = summary, courseId = course.id) } + } + }.catch { + _uiState.update { it.copy(state = ScreenState.Error) } + } + } + +} \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/list/CourseGradeFormatter.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/list/CourseGradeFormatter.kt index 1096da8778..0227b41c9a 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/list/CourseGradeFormatter.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/list/CourseGradeFormatter.kt @@ -19,6 +19,7 @@ package com.instructure.parentapp.features.courses.list import android.content.Context import com.instructure.canvasapi2.models.Course +import com.instructure.canvasapi2.utils.convertPercentToPointBased import com.instructure.pandautils.utils.orDefault import com.instructure.parentapp.R import dagger.hilt.android.qualifiers.ApplicationContext @@ -46,7 +47,11 @@ class CourseGradeFormatter(@ApplicationContext private val context: Context) { val formattedScore = grade.currentScore?.takeIf { !restrictQuantitativeData }?.let { - percentageFormat.format(it / 100) + if (course.pointsBasedGradingScheme) { + convertPercentToPointBased(it, course.scalingFactor) + } else { + percentageFormat.format(it / 100) + } }.orEmpty() return when { diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/list/CoursesFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/list/CoursesFragment.kt index 1fd6b2e8a0..ecbcebd8fa 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/list/CoursesFragment.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/courses/list/CoursesFragment.kt @@ -24,7 +24,7 @@ import android.view.ViewGroup import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.platform.ComposeView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import com.instructure.pandautils.utils.collectOneOffEvents @@ -34,7 +34,7 @@ import javax.inject.Inject @AndroidEntryPoint -class CoursesFragment : Fragment() { +class CoursesFragment : BaseCanvasFragment() { private val viewModel: CoursesViewModel by viewModels() diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/dashboard/DashboardFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/dashboard/DashboardFragment.kt index 4e8a57e3ab..cf80adc67d 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/dashboard/DashboardFragment.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/dashboard/DashboardFragment.kt @@ -28,7 +28,7 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.core.view.GravityCompat -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle @@ -41,16 +41,21 @@ import com.google.android.material.navigation.NavigationBarView import com.google.firebase.crashlytics.FirebaseCrashlytics import com.instructure.canvasapi2.models.LaunchDefinition import com.instructure.canvasapi2.models.User +import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.canvasapi2.utils.MasqueradeHelper +import com.instructure.loginapi.login.dialog.MasqueradingDialog import com.instructure.loginapi.login.tasks.LogoutTask import com.instructure.pandautils.features.calendar.CalendarSharedEvents import com.instructure.pandautils.features.calendar.SharedCalendarAction import com.instructure.pandautils.features.help.HelpDialogFragment import com.instructure.pandautils.interfaces.NavigationCallbacks +import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.ViewStyler import com.instructure.pandautils.utils.animateCircularBackgroundColorChange import com.instructure.pandautils.utils.applyTheme import com.instructure.pandautils.utils.collectOneOffEvents import com.instructure.pandautils.utils.getDrawableCompat +import com.instructure.pandautils.utils.isTablet import com.instructure.pandautils.utils.onClick import com.instructure.pandautils.utils.setGone import com.instructure.pandautils.utils.setVisible @@ -63,6 +68,7 @@ import com.instructure.parentapp.databinding.NavigationDrawerHeaderLayoutBinding import com.instructure.parentapp.features.addstudent.AddStudentBottomSheetDialogFragment import com.instructure.parentapp.features.addstudent.AddStudentViewModel import com.instructure.parentapp.features.addstudent.AddStudentViewModelAction +import com.instructure.parentapp.features.main.MainActivity import com.instructure.parentapp.util.ParentLogoutTask import com.instructure.parentapp.util.ParentPrefs import com.instructure.parentapp.util.navigation.Navigation @@ -74,7 +80,7 @@ import javax.inject.Inject @AndroidEntryPoint -class DashboardFragment : Fragment(), NavigationCallbacks { +class DashboardFragment : BaseCanvasFragment(), NavigationCallbacks { private lateinit var binding: FragmentDashboardBinding @@ -201,7 +207,7 @@ class DashboardFragment : Fragment(), NavigationCallbacks { } } is DashboardViewModelAction.OpenLtiTool -> { - navigation.navigate(requireActivity(), navigation.ltiLaunchRoute(action.url, action.name)) + navigation.navigate(requireActivity(), navigation.ltiLaunchRoute(action.url, action.name, sessionlessLaunch = true)) } } } @@ -270,7 +276,7 @@ class DashboardFragment : Fragment(), NavigationCallbacks { inboxBadge?.height = 24.toPx inboxBadge?.gravity = Gravity.CENTER inboxBadge?.textSize = 10f - inboxBadge?.setTextColor(requireContext().getColor(R.color.white)) + inboxBadge?.setTextColor(requireContext().getColor(R.color.textLightest)) inboxBadge?.setBackgroundResource(R.drawable.bg_button_full_rounded_filled) inboxBadge?.visibility = View.GONE @@ -286,9 +292,17 @@ class DashboardFragment : Fragment(), NavigationCallbacks { R.id.help -> menuItemSelected { activity?.let { HelpDialogFragment.show(it) } } R.id.log_out -> menuItemSelected { onLogout() } R.id.switch_users -> menuItemSelected { onSwitchUsers() } + R.id.act_as_user -> menuItemSelected { MasqueradingDialog.show(requireActivity().supportFragmentManager, ApiPrefs.domain, null, !isTablet) } + R.id.stop_act_as_user -> menuItemSelected { MasqueradeHelper.stopMasquerading(MainActivity::class.java) } else -> false } } + + val actAsUserItem = binding.navView.menu.findItem(R.id.act_as_user) + actAsUserItem.isVisible = !ApiPrefs.isMasquerading && ApiPrefs.canBecomeUser == true + + val stopActAsUserItem = binding.navView.menu.findItem(R.id.stop_act_as_user) + stopActAsUserItem.isVisible = ApiPrefs.isMasquerading } private fun menuItemSelected(action: () -> Unit): Boolean { @@ -319,10 +333,13 @@ class DashboardFragment : Fragment(), NavigationCallbacks { binding.bottomNav.applyTheme(color, requireActivity().getColor(R.color.textDarkest)) ViewStyler.setStatusBarDark(requireActivity(), color) + val toolbarIconsColor = if (student != null) requireContext().getColor(R.color.textLightest) else ThemePrefs.primaryTextColor val gradientDrawable = requireContext().getDrawableCompat(R.drawable.bg_button_full_rounded_filled_with_border) as? GradientDrawable gradientDrawable?.setStroke(2.toPx, color) + gradientDrawable?.setColor(toolbarIconsColor) binding.unreadCountBadge.background = gradientDrawable binding.unreadCountBadge.setTextColor(color) + binding.navigationButton.setColorFilter(toolbarIconsColor) binding.bottomNav.getOrCreateBadge(R.id.alerts).backgroundColor = color viewModel.updateColor(color) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/login/routevalidator/RouteValidatorActivity.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/login/routevalidator/RouteValidatorActivity.kt index 8fe7a1587b..1ffcb90573 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/login/routevalidator/RouteValidatorActivity.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/login/routevalidator/RouteValidatorActivity.kt @@ -23,7 +23,7 @@ import android.net.Uri import android.os.Bundle import android.widget.Toast import androidx.activity.viewModels -import androidx.appcompat.app.AppCompatActivity +import com.instructure.pandautils.base.BaseCanvasActivity import androidx.lifecycle.lifecycleScope import com.instructure.canvasapi2.models.AccountDomain import com.instructure.pandautils.binding.viewBinding @@ -36,7 +36,7 @@ import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class RouteValidatorActivity : AppCompatActivity() { +class RouteValidatorActivity : BaseCanvasActivity() { private val binding by viewBinding(ActivityRouteValidatorBinding::inflate) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/lti/LtiLaunchFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/lti/LtiLaunchFragment.kt deleted file mode 100644 index c075e27967..0000000000 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/lti/LtiLaunchFragment.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2024 - present Instructure, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package com.instructure.parentapp.features.lti - -import android.net.Uri -import android.os.Bundle -import android.os.Handler -import android.os.Looper -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.browser.customtabs.CustomTabColorSchemeParams -import androidx.browser.customtabs.CustomTabsIntent -import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels -import androidx.lifecycle.lifecycleScope -import com.instructure.canvasapi2.utils.validOrNull -import com.instructure.pandautils.binding.viewBinding -import com.instructure.pandautils.utils.NullableStringArg -import com.instructure.pandautils.utils.ThemePrefs -import com.instructure.pandautils.utils.asChooserExcludingInstructure -import com.instructure.pandautils.utils.collectOneOffEvents -import com.instructure.pandautils.utils.setTextForVisibility -import com.instructure.pandautils.utils.studentColor -import com.instructure.pandautils.utils.toast -import com.instructure.parentapp.R -import com.instructure.parentapp.databinding.FragmentLtiLaunchBinding -import com.instructure.parentapp.util.ParentPrefs -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class LtiLaunchFragment : Fragment() { - - private val binding by viewBinding(FragmentLtiLaunchBinding::bind) - - private val viewModel: LtiLaunchViewModel by viewModels() - - var title: String? by NullableStringArg(key = LTI_TITLE) - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_lti_launch, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.loadingView.setOverrideColor(ParentPrefs.currentStudent?.studentColor ?: ThemePrefs.primaryColor) - binding.toolName.setTextForVisibility(title.validOrNull()) - - lifecycleScope.collectOneOffEvents(viewModel.events, ::handleAction) - } - - private fun handleAction(action: LtiLaunchAction) { - when (action) { - is LtiLaunchAction.LaunchCustomTab -> { - launchCustomTab(action.url) - } - is LtiLaunchAction.ShowError -> { - toast(R.string.errorOccurred) - if (activity != null) { - requireActivity().onBackPressed() - } - } - } - } - - private fun launchCustomTab(url: String) { - val uri = Uri.parse(url) - .buildUpon() - .appendQueryParameter("display", "borderless") - .appendQueryParameter("platform", "android") - .build() - - val colorSchemeParams = CustomTabColorSchemeParams.Builder() - .setToolbarColor(ThemePrefs.primaryColor) - .build() - - var intent = CustomTabsIntent.Builder() - .setDefaultColorSchemeParams(colorSchemeParams) - .setShowTitle(true) - .build() - .intent - - intent.data = uri - - // Exclude Instructure apps from chooser options - intent = intent.asChooserExcludingInstructure() - - requireContext().startActivity(intent) - Handler(Looper.getMainLooper()).postDelayed({ - if (activity == null) return@postDelayed - requireActivity().onBackPressed() - }, 500) - } - - companion object { - const val LTI_URL = "lti_url" - const val LTI_TITLE = "lti_title" - } -} \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/lti/LtiLaunchViewModel.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/lti/LtiLaunchViewModel.kt deleted file mode 100644 index 8730dae52f..0000000000 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/lti/LtiLaunchViewModel.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2024 - present Instructure, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package com.instructure.parentapp.features.lti - -import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.instructure.canvasapi2.utils.weave.catch -import com.instructure.canvasapi2.utils.weave.tryLaunch -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.coroutines.launch -import javax.inject.Inject - -@HiltViewModel -class LtiLaunchViewModel @Inject constructor( - savedStateHandle: SavedStateHandle, - private val repository: LtiLaunchRepository -) : ViewModel() { - - private val ltiUrl: String? = savedStateHandle.get(LtiLaunchFragment.LTI_URL) - - private val _events = Channel() - val events = _events.receiveAsFlow() - - init { - loadLtiAuthenticatedUrl() - } - - private fun loadLtiAuthenticatedUrl() { - viewModelScope.tryLaunch { - ltiUrl?.let { - val ltiTool = repository.getLtiFromAuthenticationUrl(it) - ltiTool.url?.let { url -> - _events.send(LtiLaunchAction.LaunchCustomTab(url)) - } ?: _events.send(LtiLaunchAction.ShowError) - } - } catch { - viewModelScope.launch { - _events.send(LtiLaunchAction.ShowError) - } - } - } -} \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/lti/LtiLaunchRepository.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/lti/ParentLtiLaunchFragmentBehavior.kt similarity index 60% rename from apps/parent/src/main/java/com/instructure/parentapp/features/lti/LtiLaunchRepository.kt rename to apps/parent/src/main/java/com/instructure/parentapp/features/lti/ParentLtiLaunchFragmentBehavior.kt index 1cb12a7556..c45f67c6c3 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/lti/LtiLaunchRepository.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/lti/ParentLtiLaunchFragmentBehavior.kt @@ -16,14 +16,10 @@ */ package com.instructure.parentapp.features.lti -import com.instructure.canvasapi2.apis.LaunchDefinitionsAPI -import com.instructure.canvasapi2.builders.RestParams -import com.instructure.canvasapi2.models.LTITool +import com.instructure.pandautils.features.lti.LtiLaunchFragmentBehavior +import com.instructure.pandautils.utils.studentColor +import com.instructure.parentapp.util.ParentPrefs -class LtiLaunchRepository( - private val launchDefinitionsApi: LaunchDefinitionsAPI.LaunchDefinitionsInterface -) { - suspend fun getLtiFromAuthenticationUrl(url: String): LTITool { - return launchDefinitionsApi.getLtiFromAuthenticationUrl(url, RestParams(isForceReadFromNetwork = true)).dataOrThrow - } +class ParentLtiLaunchFragmentBehavior(parentPrefs: ParentPrefs) : LtiLaunchFragmentBehavior { + override val toolbarColor: Int = parentPrefs.currentStudent.studentColor } \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/main/MainActivity.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/main/MainActivity.kt index 133de6ac91..1f4bae41df 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/main/MainActivity.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/main/MainActivity.kt @@ -23,16 +23,22 @@ import android.content.res.Configuration import android.net.Uri import android.os.Bundle import android.util.Log -import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment +import com.instructure.canvasapi2.apis.OAuthAPI +import com.instructure.canvasapi2.builders.RestParams +import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.canvasapi2.utils.MasqueradeHelper +import com.instructure.loginapi.login.dialog.MasqueradingDialog +import com.instructure.pandautils.base.BaseCanvasActivity import com.instructure.pandautils.binding.viewBinding import com.instructure.pandautils.features.inbox.list.OnUnreadCountInvalidated import com.instructure.pandautils.interfaces.NavigationCallbacks import com.instructure.pandautils.utils.ColorKeeper import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.ThemePrefs +import com.instructure.pandautils.utils.loadUrlIntoHeadlessWebView import com.instructure.parentapp.R import com.instructure.parentapp.databinding.ActivityMainBinding import com.instructure.parentapp.features.dashboard.InboxCountUpdater @@ -44,7 +50,7 @@ import javax.inject.Inject @AndroidEntryPoint -class MainActivity : AppCompatActivity(), OnUnreadCountInvalidated { +class MainActivity : BaseCanvasActivity(), OnUnreadCountInvalidated, MasqueradingDialog.OnMasqueradingSet { private val binding by viewBinding(ActivityMainBinding::inflate) @@ -54,6 +60,9 @@ class MainActivity : AppCompatActivity(), OnUnreadCountInvalidated { @Inject lateinit var inboxCountUpdater: InboxCountUpdater + @Inject + lateinit var oAuthApi: OAuthAPI.OAuthInterface + private lateinit var navController: NavController override fun onCreate(savedInstanceState: Bundle?) { @@ -61,6 +70,31 @@ class MainActivity : AppCompatActivity(), OnUnreadCountInvalidated { setContentView(binding.root) setupTheme() setupNavigation() + handleQrMasquerading() + + if (ApiPrefs.isFirstMasqueradingStart) { + loadAuthenticatedSession() + ApiPrefs.isFirstMasqueradingStart = false + } + } + + private fun loadAuthenticatedSession() { + lifecycleScope.launch { + oAuthApi.getAuthenticatedSession( + ApiPrefs.fullDomain, + RestParams(isForceReadFromNetwork = true) + ).dataOrNull?.sessionUrl?.let { + loadUrlIntoHeadlessWebView(this@MainActivity, it) + } + } + } + + private fun handleQrMasquerading() { + val masqueradingUserId: Long = intent.getLongExtra(Const.QR_CODE_MASQUERADE_ID, 0L) + if (masqueradingUserId != 0L) { + MasqueradeHelper.startMasquerading(masqueradingUserId, ApiPrefs.domain, MainActivity::class.java) + finish() + } } private fun setupTheme() { @@ -80,7 +114,8 @@ class MainActivity : AppCompatActivity(), OnUnreadCountInvalidated { val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment navController = navHostFragment.navController - navController.graph = navigation.crateMainNavGraph(navController) + val masqueradingUserId: Long = intent.getLongExtra(Const.QR_CODE_MASQUERADE_ID, 0L) + navController.graph = navigation.crateMainNavGraph(navController, masqueradingUserId) navController.currentBackStackEntry?.savedStateHandle?.getLiveData(SplashFragment.INITIAL_DATA_LOADED_KEY)?.observe(this) { // If the initial data has been loaded, we can navigate to courses, remove splash from backstack @@ -116,6 +151,14 @@ class MainActivity : AppCompatActivity(), OnUnreadCountInvalidated { } } + override fun onStartMasquerading(domain: String, userId: Long) { + MasqueradeHelper.startMasquerading(userId, domain, MainActivity::class.java) + } + + override fun onStopMasquerading() { + MasqueradeHelper.stopMasquerading(MainActivity::class.java) + } + companion object { fun createIntent(context: Context, uri: Uri): Intent { val intent = Intent(context, MainActivity::class.java) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/managestudents/ManageStudentsFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/managestudents/ManageStudentsFragment.kt index 114c4cd6b6..a5399be8a4 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/managestudents/ManageStudentsFragment.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/managestudents/ManageStudentsFragment.kt @@ -24,7 +24,7 @@ import android.view.ViewGroup import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.platform.ComposeView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope @@ -43,7 +43,7 @@ import javax.inject.Inject @AndroidEntryPoint -class ManageStudentsFragment : Fragment() { +class ManageStudentsFragment : BaseCanvasFragment() { @Inject lateinit var navigation: Navigation diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/notaparent/NotAParentFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/notaparent/NotAParentFragment.kt index e616c8f91c..4d2f7b0898 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/notaparent/NotAParentFragment.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/notaparent/NotAParentFragment.kt @@ -25,14 +25,14 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.compose.ui.platform.ComposeView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.instructure.loginapi.login.tasks.LogoutTask import com.instructure.parentapp.util.ParentLogoutTask import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class NotAParentFragment : Fragment() { +class NotAParentFragment : BaseCanvasFragment() { override fun onCreateView( inflater: LayoutInflater, diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/settings/ParentSettingsBehaviour.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/settings/ParentSettingsBehaviour.kt index bba51876eb..7546e05b80 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/settings/ParentSettingsBehaviour.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/settings/ParentSettingsBehaviour.kt @@ -13,16 +13,22 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - */ package com.instructure.parentapp.features.settings + */ +package com.instructure.parentapp.features.settings import com.instructure.pandautils.features.settings.SettingsBehaviour import com.instructure.pandautils.features.settings.SettingsItem import com.instructure.parentapp.R +import com.instructure.parentapp.features.dashboard.SelectedStudentHolder -class ParentSettingsBehaviour : SettingsBehaviour { +class ParentSettingsBehaviour(private val selectedStudentHolder: SelectedStudentHolder) : SettingsBehaviour { override val settingsItems: Map> get() = mapOf( R.string.preferences to listOf(SettingsItem.APP_THEME), R.string.legal to listOf(SettingsItem.ABOUT, SettingsItem.LEGAL) ) + + override suspend fun applyAppSpecificColorSettings() { + selectedStudentHolder.selectedStudentColorChanged() + } } \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/settings/ParentSettingsRouter.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/settings/ParentSettingsRouter.kt index aff1ffda29..ba84050d74 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/settings/ParentSettingsRouter.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/settings/ParentSettingsRouter.kt @@ -18,20 +18,4 @@ package com.instructure.parentapp.features.settings import com.instructure.pandautils.features.settings.SettingsRouter -class ParentSettingsRouter : SettingsRouter { - override fun navigateToProfileSettings() { - throw IllegalStateException("Profile settings item not available") - } - - override fun navigateToPushNotificationsSettings() { - throw IllegalStateException("Push settings item not available") - } - - override fun navigateToEmailNotificationsSettings() { - throw IllegalStateException("Email settings item not available") - } - - override fun navigateToPairWithObserver() { - throw IllegalStateException("Pair with observer item not available") - } -} \ No newline at end of file +class ParentSettingsRouter : SettingsRouter \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashFragment.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashFragment.kt index 72fd396258..610e1a8d14 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashFragment.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashFragment.kt @@ -31,12 +31,12 @@ import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.res.colorResource import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController -import com.instructure.canvasapi2.utils.LocaleUtils -import com.instructure.loginapi.login.view.CanvasLoadingView +import com.instructure.pandautils.utils.LocaleUtils +import com.instructure.pandautils.views.CanvasLoadingView import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.collectOneOffEvents import com.instructure.parentapp.R @@ -46,7 +46,7 @@ import javax.inject.Inject @AndroidEntryPoint -class SplashFragment : Fragment() { +class SplashFragment : BaseCanvasFragment() { private val viewModel: SplashViewModel by viewModels() diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashRepository.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashRepository.kt index 50318bb742..735084a137 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashRepository.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashRepository.kt @@ -56,4 +56,9 @@ class SplashRepository( .orEmpty() .mapNotNull { it.observedUser } } + + suspend fun getBecomeUserPermission(): Boolean { + val params = RestParams(isForceReadFromNetwork = true) + return userApi.getBecomeUserPermission(params).dataOrNull?.becomeUser ?: false + } } \ No newline at end of file diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashViewModel.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashViewModel.kt index e67060e5ab..87a86cc977 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashViewModel.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/splash/SplashViewModel.kt @@ -18,6 +18,7 @@ package com.instructure.parentapp.features.splash import android.content.Context +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.instructure.canvasapi2.models.User @@ -25,6 +26,7 @@ import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryLaunch import com.instructure.pandautils.utils.ColorKeeper +import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.ThemePrefs import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext @@ -39,12 +41,15 @@ class SplashViewModel @Inject constructor( @ApplicationContext private val context: Context, private val repository: SplashRepository, private val apiPrefs: ApiPrefs, - private val colorKeeper: ColorKeeper + private val colorKeeper: ColorKeeper, + savedStateHandle: SavedStateHandle ) : ViewModel() { private val _events = Channel() val events = _events.receiveAsFlow() + private val qrMasqueradeId = savedStateHandle.get(Const.QR_CODE_MASQUERADE_ID) ?: 0L + init { loadInitialData() } @@ -60,8 +65,16 @@ class SplashViewModel @Inject constructor( val theme = repository.getTheme() theme?.let { _events.send(SplashAction.ApplyTheme(it)) } + if (apiPrefs.canBecomeUser == null && qrMasqueradeId == 0L) { + if (apiPrefs.domain.startsWith("siteadmin", true)) { + apiPrefs.canBecomeUser = true + } else { + apiPrefs.canBecomeUser = repository.getBecomeUserPermission() + } + } + val students = repository.getStudents() - if (students.isEmpty()) { + if (students.isEmpty() && apiPrefs.canBecomeUser == false) { _events.send(SplashAction.NavigateToNotAParentScreen) } else { _events.send(SplashAction.InitialDataLoadingFinished) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/util/BaseAppManager.kt b/apps/parent/src/main/java/com/instructure/parentapp/util/BaseAppManager.kt index 58d284cfe6..3ef9313a3e 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/util/BaseAppManager.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/util/BaseAppManager.kt @@ -25,17 +25,25 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics import com.instructure.canvasapi2.AppManager import com.instructure.canvasapi2.utils.Analytics import com.instructure.canvasapi2.utils.AnalyticsEventConstants +import com.instructure.canvasapi2.utils.MasqueradeHelper import com.instructure.canvasapi2.utils.RemoteConfigUtils +import com.instructure.loginapi.login.tasks.LogoutTask +import com.instructure.pandautils.base.AppConfig +import com.instructure.pandautils.base.AppConfigProvider import com.instructure.pandautils.utils.AppTheme +import com.instructure.pandautils.utils.AppType import com.instructure.pandautils.utils.ColorKeeper import com.instructure.pandautils.utils.ThemePrefs import com.instructure.parentapp.BuildConfig import com.instructure.parentapp.R +import com.instructure.parentapp.features.main.MainActivity abstract class BaseAppManager : AppManager() { override fun onCreate() { super.onCreate() + AppConfigProvider.appConfig = AppConfig(AppType.PARENT, MainActivity::class.java) + MasqueradeHelper.masqueradeLogoutTask = Runnable { ParentLogoutTask(LogoutTask.Type.LOGOUT).execute() } val appTheme = AppTheme.fromIndex(ThemePrefs.appTheme) AppCompatDelegate.setDefaultNightMode(appTheme.nightModeType) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/util/navigation/Navigation.kt b/apps/parent/src/main/java/com/instructure/parentapp/util/navigation/Navigation.kt index 97b5cbfb6c..d04f725581 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/util/navigation/Navigation.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/util/navigation/Navigation.kt @@ -36,7 +36,7 @@ import com.instructure.parentapp.features.calendar.ParentCalendarFragment import com.instructure.parentapp.features.courses.details.CourseDetailsFragment import com.instructure.parentapp.features.courses.list.CoursesFragment import com.instructure.parentapp.features.dashboard.DashboardFragment -import com.instructure.parentapp.features.lti.LtiLaunchFragment +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.parentapp.features.managestudents.ManageStudentsFragment import com.instructure.parentapp.features.notaparent.NotAParentFragment import com.instructure.parentapp.features.splash.SplashFragment @@ -52,7 +52,8 @@ class Navigation(apiPrefs: ApiPrefs) { private val courseAnnouncementDetails = "$baseUrl/courses/{$COURSE_ID}/discussion_topics/{$announcementId}" private val globalAnnouncementDetails = "$baseUrl/account_notifications/{$announcementId}" - val splash = "$baseUrl/splash" + val splash = "$baseUrl/splash/{${Const.QR_CODE_MASQUERADE_ID}}" + val notAParent = "$baseUrl/not-a-parent" val courses = "$baseUrl/courses" val calendar = "$baseUrl/calendar" @@ -81,8 +82,9 @@ class Navigation(apiPrefs: ApiPrefs) { private val updateToDo = "$baseUrl/update-todo/{${CreateUpdateToDoFragment.PLANNER_ITEM}}" private val alertSettings = "$baseUrl/alert-settings/{${Const.USER}}" - private val ltiLaunch = "$baseUrl/lti-launch/{${LtiLaunchFragment.LTI_URL}}/{${LtiLaunchFragment.LTI_TITLE}}" + private val ltiLaunch = "$baseUrl/lti-launch/{${LtiLaunchFragment.LTI_URL}}/{${LtiLaunchFragment.LTI_TITLE}}/{${LtiLaunchFragment.SESSION_LESS_LAUNCH}}" + private fun splashRoute(qrCodeMasqueradeId: Long) = "$baseUrl/splash/$qrCodeMasqueradeId" fun courseDetailsRoute(id: Long) = "$baseUrl/courses/$id" fun calendarEventRoute(contextTypeString: String, contextId: Long, eventId: Long) = "$baseUrl/$contextTypeString/$contextId/calendar_events/$eventId" @@ -97,13 +99,18 @@ class Navigation(apiPrefs: ApiPrefs) { fun globalAnnouncementRoute(alertId: Long) = "$baseUrl/account_notifications/$alertId" - fun ltiLaunchRoute(url: String, title: String) = "$baseUrl/lti-launch/${Uri.encode(url)}/${Uri.encode(title)}" + fun ltiLaunchRoute(url: String, title: String, sessionlessLaunch: Boolean) = "$baseUrl/lti-launch/${Uri.encode(url)}/${Uri.encode(title)}/$sessionlessLaunch" - fun crateMainNavGraph(navController: NavController): NavGraph { + fun crateMainNavGraph(navController: NavController, qrCodeMasqueradeId: Long): NavGraph { return navController.createGraph( - splash + splashRoute(qrCodeMasqueradeId) ) { - fragment(splash) + fragment(splash) { + argument(Const.QR_CODE_MASQUERADE_ID) { + type = NavType.LongType + nullable = false + } + } fragment(notAParent) fragment(courses) { deepLink { @@ -239,6 +246,11 @@ class Navigation(apiPrefs: ApiPrefs) { type = NavType.StringType nullable = false } + argument(LtiLaunchFragment.SESSION_LESS_LAUNCH) { + type = NavType.BoolType + nullable = false + defaultValue = false + } } } } diff --git a/apps/parent/src/main/res/layout/activity_route_validator.xml b/apps/parent/src/main/res/layout/activity_route_validator.xml index 47dd4fd893..e235d52fde 100644 --- a/apps/parent/src/main/res/layout/activity_route_validator.xml +++ b/apps/parent/src/main/res/layout/activity_route_validator.xml @@ -16,7 +16,8 @@ + android:layout_height="match_parent" + android:background="@color/backgroundLightest"> - + android:layout_height="match_parent"> + android:layout_marginBottom="12dp" + app:visible="@{viewModel.data.selectedStudent != null}"> + + - - - - - - - - - - - diff --git a/apps/parent/src/main/res/menu/nav_drawer.xml b/apps/parent/src/main/res/menu/nav_drawer.xml index c8a5e1de55..c77ca10ea1 100644 --- a/apps/parent/src/main/res/menu/nav_drawer.xml +++ b/apps/parent/src/main/res/menu/nav_drawer.xml @@ -61,5 +61,17 @@ android:contentDescription="" android:icon="@drawable/ic_navigation_logout" android:title="@string/navigationDrawerLogOut" /> + + diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/calendar/ParentCalendarRepositoryTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/calendar/ParentCalendarRepositoryTest.kt index 8735704971..7e06f28796 100644 --- a/apps/parent/src/test/java/com/instructure/parentapp/features/calendar/ParentCalendarRepositoryTest.kt +++ b/apps/parent/src/test/java/com/instructure/parentapp/features/calendar/ParentCalendarRepositoryTest.kt @@ -23,6 +23,7 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.models.Enrollment +import com.instructure.canvasapi2.models.EnvironmentSettings import com.instructure.canvasapi2.models.Plannable import com.instructure.canvasapi2.models.PlannableType import com.instructure.canvasapi2.models.ScheduleItem @@ -292,23 +293,14 @@ class ParentCalendarRepositoryTest { } @Test - fun `Return 20 for calendar filter limit when context limit is increased`() = runTest { - coEvery { featuresApi.getAccountSettingsFeatures(any()) } returns DataResult.Success(mapOf("calendar_contexts_limit" to true)) + fun `Return context limit from api when request is success`() = runTest { + coEvery { featuresApi.getAccountSettingsFeatures(any()) } returns DataResult.Success(EnvironmentSettings(calendarContextsLimit = 20)) val result = calendarRepository.getCalendarFilterLimit() assertEquals(20, result) } - @Test - fun `Return 10 for calendar filter limit when context limit is not increased`() = runTest { - coEvery { featuresApi.getAccountSettingsFeatures(any()) } returns DataResult.Success(mapOf("calendar_contexts_limit" to false)) - - val result = calendarRepository.getCalendarFilterLimit() - - assertEquals(10, result) - } - @Test fun `Return 10 for calendar filter limit when features request fails`() = runTest { coEvery { featuresApi.getAccountSettingsFeatures(any()) } returns DataResult.Fail() diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/CourseDetailsViewModelTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/CourseDetailsViewModelTest.kt index 8ad64e5104..7d44331791 100644 --- a/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/CourseDetailsViewModelTest.kt +++ b/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/CourseDetailsViewModelTest.kt @@ -85,6 +85,7 @@ class CourseDetailsViewModelTest { every { apiPrefs.fullDomain } returns "https://domain.com" every { context.getString(R.string.regardingHiddenMessage, any(), any()) } returns "https://domain.com/courses/1" every { context.getString(R.string.regardingHiddenMessage, any(), "") } returns "Regarding: User 1" + every { context.getString(R.string.courseRefreshFailed) } returns "Failed to refresh course" } @After @@ -128,7 +129,8 @@ class CourseDetailsViewModelTest { studentColor = 1, isLoading = false, isError = false, - tabs = listOf(TabType.GRADES, TabType.SYLLABUS) + tabs = listOf(TabType.GRADES, TabType.SYLLABUS), + syllabus = "Syllabus body" ) Assert.assertEquals(expected, viewModel.uiState.value) @@ -152,7 +154,8 @@ class CourseDetailsViewModelTest { studentColor = 1, isLoading = false, isError = false, - tabs = listOf(TabType.GRADES, TabType.SYLLABUS, TabType.SUMMARY) + tabs = listOf(TabType.GRADES, TabType.SYLLABUS, TabType.SUMMARY), + syllabus = "Syllabus body" ) Assert.assertEquals(expected, viewModel.uiState.value) @@ -174,7 +177,7 @@ class CourseDetailsViewModelTest { } @Test - fun `Refresh course details`() = runTest { + fun `Refresh course and tabs`() = runTest { coEvery { repository.getCourse(1, any()) } returns Course(id = 1, name = "Course 1") coEvery { repository.getCourseTabs(1, any()) } returns listOf(Tab("tab1")) @@ -203,7 +206,70 @@ class CourseDetailsViewModelTest { val expectedAfterRefresh = expected.copy( courseName = "Course 2", - tabs = listOf(TabType.GRADES, TabType.SYLLABUS, TabType.SUMMARY) + tabs = listOf(TabType.GRADES, TabType.SYLLABUS, TabType.SUMMARY), + syllabus = "Syllabus body" + ) + + Assert.assertEquals(expectedAfterRefresh, viewModel.uiState.value) + } + + @Test + fun `Refresh course`() = runTest { + coEvery { repository.getCourse(1, any()) } returns Course(id = 1, name = "Course 1") + coEvery { repository.getCourseTabs(1, any()) } returns listOf(Tab("tab1")) + + createViewModel() + + val expected = CourseDetailsUiState( + courseName = "Course 1", + studentColor = 1, + isLoading = false, + isError = false, + tabs = listOf(TabType.GRADES) + ) + + Assert.assertEquals(expected, viewModel.uiState.value) + + coEvery { repository.getCourse(1, any()) } returns Course( + id = 1, + name = "Course 2", + syllabusBody = "Syllabus body" + ) + + viewModel.handleAction(CourseDetailsAction.RefreshCourse) + + val expectedAfterRefresh = expected.copy( + courseName = "Course 2", + syllabus = "Syllabus body" + ) + + Assert.assertEquals(expectedAfterRefresh, viewModel.uiState.value) + } + + + @Test + fun `Error refreshing course`() = runTest { + coEvery { repository.getCourse(1, any()) } returns Course(id = 1, name = "Course 1") + coEvery { repository.getCourseTabs(1, any()) } returns listOf(Tab("tab1")) + + createViewModel() + + val expected = CourseDetailsUiState( + courseName = "Course 1", + studentColor = 1, + isLoading = false, + isError = false, + tabs = listOf(TabType.GRADES) + ) + + Assert.assertEquals(expected, viewModel.uiState.value) + + coEvery { repository.getCourse(1, any()) } throws Exception() + + viewModel.handleAction(CourseDetailsAction.RefreshCourse) + + val expectedAfterRefresh = expected.copy( + snackbarMessage = "Failed to refresh course" ) Assert.assertEquals(expectedAfterRefresh, viewModel.uiState.value) @@ -239,6 +305,21 @@ class CourseDetailsViewModelTest { Assert.assertEquals(expected, events.last()) } + @Test + fun `Navigate to LTI screen`() = runTest { + createViewModel() + + val events = mutableListOf() + backgroundScope.launch(testDispatcher) { + viewModel.events.toList(events) + } + + viewModel.handleAction(CourseDetailsAction.OnLtiClicked("ltiUrl")) + + val expected = CourseDetailsViewModelAction.OpenLtiScreen("ltiUrl") + Assert.assertEquals(expected, events.last()) + } + private fun createViewModel() { viewModel = CourseDetailsViewModel(context, savedStateHandle, repository, parentPrefs, apiPrefs) } diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageRepositoryTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageRepositoryTest.kt new file mode 100644 index 0000000000..f6819a1d29 --- /dev/null +++ b/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageRepositoryTest.kt @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.instructure.parentapp.features.courses.details.frontpage + +import com.instructure.canvasapi2.apis.PageAPI +import com.instructure.canvasapi2.builders.RestParams +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.models.Page +import com.instructure.canvasapi2.utils.DataResult +import io.mockk.coEvery +import io.mockk.mockk +import kotlinx.coroutines.test.runTest +import org.junit.Assert +import org.junit.Test + + +class FrontPageRepositoryTest { + + private val pageApi = mockk(relaxed = true) + + private val repository = FrontPageRepository(pageApi) + + @Test + fun `Get front page successfully returns data`() = runTest { + val expected = Page(id = 1L) + + coEvery { + pageApi.getFrontPage( + CanvasContext.Type.COURSE.apiString, + 1L, + RestParams(isForceReadFromNetwork = false) + ) + } returns DataResult.Success(expected) + + val result = repository.loadFrontPage(1L, false) + Assert.assertEquals(expected, result) + } + + @Test(expected = IllegalStateException::class) + fun `Get front page throws exception when fails`() = runTest { + coEvery { + pageApi.getFrontPage( + CanvasContext.Type.COURSE.apiString, + 1L, + RestParams(isForceReadFromNetwork = true) + ) + } returns DataResult.Fail() + + repository.loadFrontPage(1L, true) + } +} diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageViewModelTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageViewModelTest.kt new file mode 100644 index 0000000000..88441e15ef --- /dev/null +++ b/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/frontpage/FrontPageViewModelTest.kt @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.instructure.parentapp.features.courses.details.frontpage + +import android.content.Context +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.SavedStateHandle +import com.instructure.canvasapi2.models.Page +import com.instructure.canvasapi2.models.User +import com.instructure.pandautils.utils.ColorKeeper +import com.instructure.pandautils.utils.ThemedColor +import com.instructure.parentapp.R +import com.instructure.parentapp.util.ParentPrefs +import com.instructure.parentapp.util.navigation.Navigation +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkObject +import io.mockk.unmockkAll +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Assert +import org.junit.Before +import org.junit.Rule +import org.junit.Test + + +@OptIn(ExperimentalCoroutinesApi::class) +class FrontPageViewModelTest { + + @get:Rule + val instantExecutorRule = InstantTaskExecutorRule() + + private val lifecycleOwner: LifecycleOwner = mockk(relaxed = true) + private val lifecycleRegistry = LifecycleRegistry(lifecycleOwner) + private val testDispatcher = UnconfinedTestDispatcher() + + private val context: Context = mockk(relaxed = true) + private val savedStateHandle: SavedStateHandle = mockk(relaxed = true) + private val repository: FrontPageRepository = mockk(relaxed = true) + private val parentPrefs: ParentPrefs = mockk(relaxed = true) + + private lateinit var viewModel: FrontPageViewModel + + @Before + fun setup() { + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) + Dispatchers.setMain(testDispatcher) + mockkObject(ColorKeeper) + every { ColorKeeper.getOrGenerateUserColor(any()) } returns ThemedColor(1, 1) + coEvery { savedStateHandle.get(Navigation.COURSE_ID) } returns 1 + every { parentPrefs.currentStudent } returns User(shortName = "User 1") + every { context.getString(R.string.frontPageRefreshFailed) } returns "Failed to refresh front page" + } + + @After + fun tearDown() { + Dispatchers.resetMain() + unmockkAll() + } + + @Test + fun `Load front page`() = runTest { + coEvery { repository.loadFrontPage(1, false) } returns Page(id = 1L, body = "Front Page") + + createViewModel() + + val expected = FrontPageUiState( + studentColor = 1, + isLoading = false, + isError = false, + htmlContent = "Front Page" + ) + + Assert.assertEquals(expected, viewModel.uiState.value) + } + + @Test + fun `Error loading front page`() = runTest { + coEvery { repository.loadFrontPage(1, false) } throws Exception() + + createViewModel() + + val expected = FrontPageUiState( + studentColor = 1, + isLoading = false, + isError = true + ) + + Assert.assertEquals(expected, viewModel.uiState.value) + } + + @Test + fun `Refresh front page`() = runTest { + coEvery { repository.loadFrontPage(1, any()) } returns Page(id = 1L, body = "Front Page") + + createViewModel() + + val expected = FrontPageUiState( + studentColor = 1, + isLoading = false, + isError = false, + htmlContent = "Front Page" + ) + + Assert.assertEquals(expected, viewModel.uiState.value) + + coEvery { repository.loadFrontPage(1, true) } returns Page(id = 2L, body = "Front Page 2") + + viewModel.handleAction(FrontPageAction.Refresh) + + val expectedAfterRefresh = expected.copy(htmlContent = "Front Page 2") + + Assert.assertEquals(expectedAfterRefresh, viewModel.uiState.value) + } + + @Test + fun `Show snackbar when error refreshing and content is not empty`() = runTest { + coEvery { repository.loadFrontPage(1, any()) } returns Page(id = 1L, body = "Front Page") + + createViewModel() + + coEvery { repository.loadFrontPage(1, any()) } throws Exception() + viewModel.handleAction(FrontPageAction.Refresh) + + val events = mutableListOf() + backgroundScope.launch(testDispatcher) { + viewModel.events.toList(events) + } + + val expectedEvent = FrontPageViewModelAction.ShowSnackbar("Failed to refresh front page") + Assert.assertEquals(expectedEvent, events.last()) + val expectedUiState = FrontPageUiState( + studentColor = 1, + isLoading = false, + isError = false, + isRefreshing = false, + htmlContent = "Front Page" + ) + Assert.assertEquals(expectedUiState, viewModel.uiState.value) + } + + @Test + fun `Show error when error refreshing and content is not empty`() = runTest { + coEvery { repository.loadFrontPage(1, any()) } returns Page(id = 1L, body = "") + + createViewModel() + + coEvery { repository.loadFrontPage(1, any()) } throws Exception() + viewModel.handleAction(FrontPageAction.Refresh) + + val expectedUiState = FrontPageUiState( + studentColor = 1, + isLoading = false, + isError = true, + isRefreshing = false + ) + Assert.assertEquals(expectedUiState, viewModel.uiState.value) + } + + private fun createViewModel() { + viewModel = FrontPageViewModel(context, savedStateHandle, repository, parentPrefs) + } +} diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/summary/SummaryRepositoryTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/summary/SummaryRepositoryTest.kt new file mode 100644 index 0000000000..31f78b1db7 --- /dev/null +++ b/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/summary/SummaryRepositoryTest.kt @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.parentapp.features.courses.details.summary + +import com.instructure.canvasapi2.apis.CalendarEventAPI +import com.instructure.canvasapi2.apis.CourseAPI +import com.instructure.canvasapi2.models.Course +import com.instructure.canvasapi2.models.ScheduleItem +import com.instructure.canvasapi2.utils.DataResult +import com.instructure.canvasapi2.utils.LinkHeaders +import io.mockk.coEvery +import io.mockk.mockk +import junit.framework.TestCase.assertEquals +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class SummaryRepositoryTest { + private val courseApi: CourseAPI.CoursesInterface = mockk(relaxed = true) + private val calendarEventApi: CalendarEventAPI.CalendarEventInterface = mockk(relaxed = true) + val repository = SummaryRepository(courseApi, calendarEventApi) + + @Test + fun `getCourse should return course on successful call`() = runTest { + val course: Course = mockk(relaxed = true) + coEvery { courseApi.getCourse(any(), any()) } returns DataResult.Success(course) + + val result = repository.getCourse(1) + + assertEquals(course, result) + } + + @Test(expected = IllegalStateException::class) + fun `getCourse should throw exception on failed call`() = runTest { + coEvery { courseApi.getCourse(any(), any()) } returns DataResult.Fail() + + repository.getCourse(1) + } + + @Test + fun `getCalendarEvents should return list of schedule items on successful call`() = runTest { + val calendarItems: List = listOf(mockk(relaxed = true)) + val assignmentItems: List = listOf(mockk(relaxed = true)) + coEvery { calendarEventApi.getCalendarEvents(any(), CalendarEventAPI.CalendarEventType.CALENDAR.apiName, any(), any(), any(), any()) } returns DataResult.Success(calendarItems) + coEvery { calendarEventApi.getCalendarEvents(any(), CalendarEventAPI.CalendarEventType.ASSIGNMENT.apiName, any(), any(), any(), any()) } returns DataResult.Success(assignmentItems) + + val result = repository.getCalendarEvents("1") + + assertEquals(assignmentItems + calendarItems, result) + } + + @Test + fun `getCalendarEvents should filter out hidden elements`() = runTest { + val calendarItems: List = listOf(ScheduleItem(itemId = "1", isHidden = true), ScheduleItem(itemId = "2", isHidden = false)) + val assignmentItems: List = listOf(ScheduleItem(itemId = "3", isHidden = true), ScheduleItem(itemId = "4", isHidden = false)) + val expected = (assignmentItems + calendarItems).filterNot { it.isHidden } + coEvery { calendarEventApi.getCalendarEvents(any(), CalendarEventAPI.CalendarEventType.CALENDAR.apiName, any(), any(), any(), any()) } returns DataResult.Success(calendarItems) + coEvery { calendarEventApi.getCalendarEvents(any(), CalendarEventAPI.CalendarEventType.ASSIGNMENT.apiName, any(), any(), any(), any()) } returns DataResult.Success(assignmentItems) + + val result = repository.getCalendarEvents("1") + + assertEquals(expected, result) + } + + @Test + fun `getCalendarEvents should depaginate elements`() = runTest { + val items: List = listOf( + ScheduleItem(itemId = "1"), + ScheduleItem(itemId = "2"), + ScheduleItem(itemId = "3"), + ScheduleItem(itemId = "4") + ) + coEvery { + calendarEventApi.getCalendarEvents( + any(), + CalendarEventAPI.CalendarEventType.ASSIGNMENT.apiName, + any(), + any(), + any(), + any() + ) + } returns DataResult.Success(listOf(items[0]), linkHeaders = LinkHeaders(nextUrl = "next1")) + coEvery { + calendarEventApi.getCalendarEvents( + any(), + CalendarEventAPI.CalendarEventType.CALENDAR.apiName, + any(), + any(), + any(), + any() + ) + } returns DataResult.Success(listOf(items[2]), linkHeaders = LinkHeaders(nextUrl = "next2")) + + coEvery { calendarEventApi.next("next1", any()) } returns DataResult.Success(listOf(items[1])) + coEvery { calendarEventApi.next("next2", any()) } returns DataResult.Success(listOf(items[3])) + + val result = repository.getCalendarEvents("1") + + assertEquals(items, result) + } + + @Test + fun `getCalendarEvents should return empty list of schedule items on failed call`() = runTest { + coEvery { calendarEventApi.getCalendarEvents(any(), CalendarEventAPI.CalendarEventType.CALENDAR.apiName, any(), any(), any(), any()) } returns DataResult.Fail() + coEvery { calendarEventApi.getCalendarEvents(any(), CalendarEventAPI.CalendarEventType.ASSIGNMENT.apiName, any(), any(), any(), any()) } returns DataResult.Fail() + + val result = repository.getCalendarEvents("1") + + assertEquals(emptyList(), result) + } +} \ No newline at end of file diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/summary/SummaryViewModelTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/summary/SummaryViewModelTest.kt new file mode 100644 index 0000000000..2a4613683c --- /dev/null +++ b/apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/summary/SummaryViewModelTest.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.parentapp.features.courses.details.summary + +import androidx.lifecycle.SavedStateHandle +import com.instructure.pandautils.features.grades.COURSE_ID_KEY +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.unmockkAll +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Before +import org.junit.Test + +@OptIn(ExperimentalCoroutinesApi::class) +class SummaryViewModelTest { + private val testDispatcher = UnconfinedTestDispatcher() + private val savedStateHandle: SavedStateHandle = mockk(relaxed = true) + private val repository: SummaryRepository = mockk(relaxed = true) + + @Before + fun setup() { + every { savedStateHandle.get(COURSE_ID_KEY) } returns 1 + Dispatchers.setMain(testDispatcher) + } + + @After + fun tearDown() { + Dispatchers.resetMain() + unmockkAll() + } + + @Test + fun `ViewModel should load data on init`() { + val viewModel = SummaryViewModel(repository, savedStateHandle) + coVerify(exactly = 1) { repository.getCourse(any()) } + coVerify(exactly = 1) { repository.getCalendarEvents(any(), false) } + } + + @Test + fun `ViewModel should load data with force refresh on refresh`() { + val viewModel = SummaryViewModel(repository, savedStateHandle) + viewModel.refresh() + coVerify(exactly = 2) { repository.getCourse(any()) } + coVerify(exactly = 1) { repository.getCalendarEvents(any(), false) } + coVerify(exactly = 1) { repository.getCalendarEvents(any(), true) } + } +} \ No newline at end of file diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/lti/LtiLaunchRepositoryTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/lti/LtiLaunchRepositoryTest.kt deleted file mode 100644 index 05ab5f04d3..0000000000 --- a/apps/parent/src/test/java/com/instructure/parentapp/features/lti/LtiLaunchRepositoryTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2024 - present Instructure, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package com.instructure.parentapp.features.lti - -import com.instructure.canvasapi2.apis.LaunchDefinitionsAPI -import com.instructure.canvasapi2.models.LTITool -import com.instructure.canvasapi2.utils.DataResult -import io.mockk.coEvery -import io.mockk.mockk -import kotlinx.coroutines.test.runTest -import org.junit.Assert.assertEquals -import org.junit.Test - -class LtiLaunchRepositoryTest { - - private val launchDefinitionsApi: LaunchDefinitionsAPI.LaunchDefinitionsInterface = mockk(relaxed = true) - - private val repository = LtiLaunchRepository(launchDefinitionsApi) - - @Test - fun `Get lti from authentication url throws exception when fails`() = runTest { - val url = "https://www.instructure.com" - val result = runCatching { repository.getLtiFromAuthenticationUrl(url) } - assert(result.isFailure) - } - - @Test - fun `Get lti from authentication url returns data when successful`() = runTest { - val url = "https://www.instructure.com" - val expected = LTITool() - coEvery { launchDefinitionsApi.getLtiFromAuthenticationUrl(url, any()) } returns DataResult.Success(expected) - - val result = repository.getLtiFromAuthenticationUrl(url) - - assertEquals(expected, result) - } -} \ No newline at end of file diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/lti/LtiLaunchViewModelTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/lti/LtiLaunchViewModelTest.kt deleted file mode 100644 index 19e8745f60..0000000000 --- a/apps/parent/src/test/java/com/instructure/parentapp/features/lti/LtiLaunchViewModelTest.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2024 - present Instructure, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package com.instructure.parentapp.features.lti - -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import androidx.lifecycle.SavedStateHandle -import com.instructure.canvasapi2.models.LTITool -import io.mockk.coEvery -import io.mockk.every -import io.mockk.mockk -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.toList -import kotlinx.coroutines.launch -import kotlinx.coroutines.test.UnconfinedTestDispatcher -import kotlinx.coroutines.test.resetMain -import kotlinx.coroutines.test.runTest -import kotlinx.coroutines.test.setMain -import org.junit.After -import org.junit.Assert.assertEquals -import org.junit.Before -import org.junit.Rule -import org.junit.Test - -@OptIn(ExperimentalCoroutinesApi::class) -class LtiLaunchViewModelTest { - - @get:Rule - val instantExecutorRule = InstantTaskExecutorRule() - - private val savedStateHandle: SavedStateHandle = mockk(relaxed = true) - private val repository: LtiLaunchRepository = mockk(relaxed = true) - private val testDispatcher = UnconfinedTestDispatcher() - - private lateinit var viewModel: LtiLaunchViewModel - - @Before - fun setup() { - every { savedStateHandle.get(LtiLaunchFragment.LTI_URL) } returns "url" - Dispatchers.setMain(testDispatcher) - } - - @After - fun tearDown() { - Dispatchers.resetMain() - } - - @Test - fun `Launch custom tab when lti tool url is successful`() = runTest { - val ltiTool = LTITool(url = "url") - coEvery { repository.getLtiFromAuthenticationUrl("url") } returns ltiTool - - viewModel = LtiLaunchViewModel(savedStateHandle, repository) - - val events = mutableListOf() - - backgroundScope.launch(testDispatcher) { - viewModel.events.toList(events) - } - - assertEquals(events[0], LtiLaunchAction.LaunchCustomTab("url")) - } - - @Test - fun `Show error when lti tool url is null`() = runTest { - val ltiTool = LTITool(url = null) - coEvery { repository.getLtiFromAuthenticationUrl("url") } returns ltiTool - - viewModel = LtiLaunchViewModel(savedStateHandle, repository) - - val events = mutableListOf() - - backgroundScope.launch(testDispatcher) { - viewModel.events.toList(events) - } - - assertEquals(events[0], LtiLaunchAction.ShowError) - } - - @Test - fun `Show error when lti request fails`() = runTest { - coEvery { repository.getLtiFromAuthenticationUrl("url") } throws Exception() - - viewModel = LtiLaunchViewModel(savedStateHandle, repository) - - val events = mutableListOf() - - backgroundScope.launch(testDispatcher) { - viewModel.events.toList(events) - } - - assertEquals(events[0], LtiLaunchAction.ShowError) - } -} \ No newline at end of file diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/settings/ParentSettingsBehaviourTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/settings/ParentSettingsBehaviourTest.kt index a7deac8c56..4eca4b6ceb 100644 --- a/apps/parent/src/test/java/com/instructure/parentapp/features/settings/ParentSettingsBehaviourTest.kt +++ b/apps/parent/src/test/java/com/instructure/parentapp/features/settings/ParentSettingsBehaviourTest.kt @@ -16,16 +16,22 @@ */ package com.instructure.parentapp.features.settings +import com.instructure.canvasapi2.models.User import com.instructure.pandautils.features.settings.SettingsItem -import org.junit.Test import com.instructure.parentapp.R +import com.instructure.parentapp.features.dashboard.TestSelectStudentHolder import junit.framework.TestCase.assertEquals +import kotlinx.coroutines.flow.MutableStateFlow +import org.junit.Test class ParentSettingsBehaviourTest { + private val selectedStudentFlow = MutableStateFlow(null) + private val selectedStudentHolder = TestSelectStudentHolder(selectedStudentFlow) + @Test fun `Settings behaviour has the correct items`() { - val settingsBehaviour = ParentSettingsBehaviour() + val settingsBehaviour = ParentSettingsBehaviour(selectedStudentHolder) val expected = mapOf( R.string.preferences to listOf(SettingsItem.APP_THEME), diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/splash/SplashRepositoryTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/splash/SplashRepositoryTest.kt index f27d515db4..0e755f579a 100644 --- a/apps/parent/src/test/java/com/instructure/parentapp/features/splash/SplashRepositoryTest.kt +++ b/apps/parent/src/test/java/com/instructure/parentapp/features/splash/SplashRepositoryTest.kt @@ -20,6 +20,8 @@ package com.instructure.parentapp.features.splash import com.instructure.canvasapi2.apis.EnrollmentAPI import com.instructure.canvasapi2.apis.ThemeAPI import com.instructure.canvasapi2.apis.UserAPI +import com.instructure.canvasapi2.builders.RestParams +import com.instructure.canvasapi2.models.BecomeUserPermission import com.instructure.canvasapi2.models.CanvasColor import com.instructure.canvasapi2.models.CanvasTheme import com.instructure.canvasapi2.models.Enrollment @@ -29,7 +31,10 @@ import com.instructure.canvasapi2.utils.LinkHeaders import io.mockk.coEvery import io.mockk.mockk import kotlinx.coroutines.test.runTest -import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue import org.junit.Test @@ -49,7 +54,7 @@ class SplashRepositoryTest { coEvery { enrollmentApi.firstPageObserveeEnrollmentsParent(any()) } returns DataResult.Success(enrollments) val result = repository.getStudents() - Assert.assertEquals(expected, result) + assertEquals(expected, result) } @Test @@ -66,7 +71,7 @@ class SplashRepositoryTest { coEvery { enrollmentApi.getNextPage("page_2_url", any()) } returns DataResult.Success(enrollments2) val result = repository.getStudents() - Assert.assertEquals(page1 + page2, result) + assertEquals(page1 + page2, result) } @Test @@ -74,7 +79,7 @@ class SplashRepositoryTest { coEvery { enrollmentApi.firstPageObserveeEnrollmentsParent(any()) } returns DataResult.Fail() val result = repository.getStudents() - Assert.assertTrue(result.isEmpty()) + assertTrue(result.isEmpty()) } @Test @@ -84,7 +89,7 @@ class SplashRepositoryTest { coEvery { userApi.getSelf(any()) } returns DataResult.Success(expected) val result = repository.getSelf() - Assert.assertEquals(expected, result) + assertEquals(expected, result) } @Test @@ -92,7 +97,7 @@ class SplashRepositoryTest { coEvery { userApi.getSelf(any()) } returns DataResult.Fail() val result = repository.getSelf() - Assert.assertNull(result) + assertNull(result) } @Test @@ -102,7 +107,7 @@ class SplashRepositoryTest { coEvery { userApi.getColors(any()) } returns DataResult.Success(expected) val result = repository.getColors() - Assert.assertEquals(expected, result) + assertEquals(expected, result) } @Test @@ -110,7 +115,7 @@ class SplashRepositoryTest { coEvery { userApi.getColors(any()) } returns DataResult.Fail() val result = repository.getColors() - Assert.assertNull(result) + assertNull(result) } @Test @@ -120,7 +125,7 @@ class SplashRepositoryTest { coEvery { themeApi.getTheme(any()) } returns DataResult.Success(expected) val result = repository.getTheme() - Assert.assertEquals(expected, result) + assertEquals(expected, result) } @Test @@ -128,6 +133,22 @@ class SplashRepositoryTest { coEvery { themeApi.getTheme(any()) } returns DataResult.Fail() val result = repository.getTheme() - Assert.assertNull(result) + assertNull(result) + } + + @Test + fun `GetBecomeUserPermission returns true when call succeeds and returns true`() = runTest { + coEvery { userApi.getBecomeUserPermission(any()) } returns DataResult.Success(BecomeUserPermission(true)) + + val result = repository.getBecomeUserPermission() + assertTrue(result) + } + + @Test + fun `GetBecomeUserPermission returns false when call fails`() = runTest { + coEvery { userApi.getBecomeUserPermission(any()) } returns DataResult.Fail() + + val result = repository.getBecomeUserPermission() + assertFalse(result) } } diff --git a/apps/parent/src/test/java/com/instructure/parentapp/features/splash/SplashViewModelTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/features/splash/SplashViewModelTest.kt index ec0f8c6f4e..abf190c7bb 100644 --- a/apps/parent/src/test/java/com/instructure/parentapp/features/splash/SplashViewModelTest.kt +++ b/apps/parent/src/test/java/com/instructure/parentapp/features/splash/SplashViewModelTest.kt @@ -22,17 +22,19 @@ import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.SavedStateHandle import com.instructure.canvasapi2.models.CanvasColor import com.instructure.canvasapi2.models.CanvasTheme import com.instructure.canvasapi2.models.User import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.ContextKeeper import com.instructure.pandautils.utils.ColorKeeper -import com.instructure.pandautils.utils.ThemePrefs +import com.instructure.pandautils.utils.Const import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every import io.mockk.mockk +import io.mockk.verify import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.toList @@ -42,7 +44,7 @@ import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.After -import org.junit.Assert +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule import org.junit.Test @@ -62,11 +64,13 @@ class SplashViewModelTest { private val repository: SplashRepository = mockk(relaxed = true) private val apiPrefs: ApiPrefs = mockk(relaxed = true) private val colorKeeper: ColorKeeper = mockk(relaxed = true) + private val savedStateHandle = mockk(relaxed = true) private lateinit var viewModel: SplashViewModel @Before fun setup() { + every { savedStateHandle.get(Const.QR_CODE_MASQUERADE_ID) } returns 0L lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) Dispatchers.setMain(testDispatcher) ContextKeeper.appContext = context @@ -101,8 +105,8 @@ class SplashViewModelTest { viewModel.events.toList(events) } - Assert.assertEquals(SplashAction.InitialDataLoadingFinished, events.last()) - Assert.assertEquals(SplashAction.ApplyTheme(theme), events.first()) + assertEquals(SplashAction.InitialDataLoadingFinished, events.last()) + assertEquals(SplashAction.ApplyTheme(theme), events.first()) } @Test @@ -116,11 +120,11 @@ class SplashViewModelTest { viewModel.events.toList(events) } - Assert.assertEquals(SplashAction.InitialDataLoadingFinished, events.last()) + assertEquals(SplashAction.InitialDataLoadingFinished, events.last()) } @Test - fun `No observed students`() = runTest { + fun `No observed students navigates to not a parent screen`() = runTest { val user = User(id = 1L) coEvery { repository.getSelf() } returns user @@ -139,7 +143,31 @@ class SplashViewModelTest { viewModel.events.toList(events) } - Assert.assertEquals(SplashAction.NavigateToNotAParentScreen, events.last()) + assertEquals(SplashAction.NavigateToNotAParentScreen, events.last()) + } + + @Test + fun `No observed students finishes data loading and navigates to app if the user can masquerade`() = runTest { + every { apiPrefs.canBecomeUser } returns true + val user = User(id = 1L) + coEvery { repository.getSelf() } returns user + + val colors = CanvasColor() + coEvery { repository.getColors() } returns colors + + val theme = CanvasTheme("", "", "", "", "", "", "", "") + coEvery { repository.getTheme() } returns theme + + coEvery { repository.getStudents() } returns emptyList() + + createViewModel() + + val events = mutableListOf() + backgroundScope.launch(testDispatcher) { + viewModel.events.toList(events) + } + + assertEquals(SplashAction.InitialDataLoadingFinished, events.last()) } @Test @@ -157,7 +185,68 @@ class SplashViewModelTest { viewModel.events.toList(events) } - Assert.assertEquals(SplashAction.LocaleChanged, events.first()) + assertEquals(SplashAction.LocaleChanged, events.first()) + } + + @Test + fun `Set canBecomeUser when the domain is siteadmin`() = runTest { + every { apiPrefs.domain } returns "siteadmin.whatever.com" + every { apiPrefs.canBecomeUser } returns null + coEvery { repository.getBecomeUserPermission() } returns false + + createViewModel() + + backgroundScope.launch(testDispatcher) { + viewModel.events.toList() + } + + verify { apiPrefs.canBecomeUser = true } + } + + @Test + fun `Set canBecomeUser by the result of the canBecomeUserApiCall`() = runTest { + every { apiPrefs.domain } returns "whatever.com" + every { apiPrefs.canBecomeUser } returns null + coEvery { repository.getBecomeUserPermission() } returns true + + createViewModel() + + backgroundScope.launch(testDispatcher) { + viewModel.events.toList() + } + + verify { apiPrefs.canBecomeUser = true } + } + + @Test + fun `Do not request permission and set canBecomeUser when masquerading from a QR code`() = runTest { + every { apiPrefs.domain } returns "whatever.com" + every { apiPrefs.canBecomeUser } returns null + every { savedStateHandle.get(Const.QR_CODE_MASQUERADE_ID) } returns 1L + + createViewModel() + + backgroundScope.launch(testDispatcher) { + viewModel.events.toList() + } + + coVerify(exactly = 0) { repository.getBecomeUserPermission() } + verify(exactly = 0) { apiPrefs.canBecomeUser = any() } + } + + @Test + fun `Do not request permission and set canBecomeUser when it is already set`() = runTest { + every { apiPrefs.domain } returns "whatever.com" + every { apiPrefs.canBecomeUser } returns true + + createViewModel() + + backgroundScope.launch(testDispatcher) { + viewModel.events.toList() + } + + coVerify(exactly = 0) { repository.getBecomeUserPermission() } + verify(exactly = 0) { apiPrefs.canBecomeUser = any() } } private fun createViewModel() { @@ -165,7 +254,8 @@ class SplashViewModelTest { context = context, repository = repository, apiPrefs = apiPrefs, - colorKeeper = colorKeeper + colorKeeper = colorKeeper, + savedStateHandle = savedStateHandle ) } } diff --git a/apps/student/build.gradle b/apps/student/build.gradle index 451ec4425e..8a9e1cd401 100644 --- a/apps/student/build.gradle +++ b/apps/student/build.gradle @@ -14,15 +14,13 @@ * along with this program. If not, see . * */ - -import com.instructure.android.buildtools.transform.* - apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'dagger.hilt.android.plugin' -apply plugin: 'com.heapanalytics.android' +apply plugin: 'org.jetbrains.kotlin.plugin.compose' +apply plugin: 'io.heap.gradle' def updatePriority = 2 def coverageEnabled = project.hasProperty('coverage') @@ -40,8 +38,8 @@ android { applicationId "com.instructure.candroid" minSdkVersion Versions.MIN_SDK targetSdkVersion Versions.TARGET_SDK - versionCode = 268 - versionName = '7.6.1' + versionCode = 269 + versionName = '7.7.0' vectorDrawables.useSupportLibrary = true testInstrumentationRunner 'com.instructure.student.espresso.StudentHiltTestRunner' @@ -50,6 +48,7 @@ android { /* Add private data */ PrivateData.merge(project, "student") + buildConfigField "String", "TRANSLATION_TAGS", "\"${LocaleScanner.getAvailableLanguageTags(project)}\"" buildConfigField "String", "PSPDFKIT_LICENSE_KEY", "\"$pspdfkitLicenseKey\"" testBuildType = "debug" @@ -111,10 +110,6 @@ android { } buildConfigField "String", "HEAP_APP_ID", "\"$heapStagingId\"" - - ext { - heapEnabled = true - } } debugMinify { @@ -140,10 +135,6 @@ android { } buildConfigField "String", "HEAP_APP_ID", "\"$heapProductionId\"" - - ext { - heapEnabled = true - } } } @@ -209,15 +200,7 @@ android { javaMaxHeapSize '4g' } - registerTransform( - new ProjectTransformer( - android, - new MasqueradeUITransformer('com.instructure.student.activity.NavigationActivity.class'), - new PageViewTransformer(), - new ScreenViewTransformer("student"), - new LocaleTransformer(project) - ) - ) + compileOptions { sourceCompatibility 1.8 @@ -334,7 +317,7 @@ dependencies { implementation Libs.ANDROIDX_WORK_MANAGER implementation Libs.ANDROIDX_WORK_MANAGER_KTX - implementation Libs.HEAP + implementation Libs.HEAP_CORE /* ROOM */ implementation Libs.ROOM diff --git a/apps/student/src/androidTest/java/com/instructure/student/di/TestApplicationModule.kt b/apps/student/src/androidTest/java/com/instructure/student/di/TestApplicationModule.kt new file mode 100644 index 0000000000..eb2b6bf2c9 --- /dev/null +++ b/apps/student/src/androidTest/java/com/instructure/student/di/TestApplicationModule.kt @@ -0,0 +1,29 @@ +package com.instructure.student.di + +import com.instructure.pandautils.utils.LogoutHelper +import com.instructure.student.espresso.fakes.FakeEnabledTabs +import com.instructure.student.router.EnabledTabs +import com.instructure.student.util.StudentLogoutHelper +import dagger.Module +import dagger.Provides +import dagger.hilt.components.SingletonComponent +import dagger.hilt.testing.TestInstallIn +import javax.inject.Singleton + +@Module +@TestInstallIn( + components = [SingletonComponent::class], + replaces = [ApplicationModule::class] +) +class TestApplicationModule { + @Provides + fun provideLogoutHelper(): LogoutHelper { + return StudentLogoutHelper() + } + + @Provides + @Singleton + fun provideEnabledTabs(): EnabledTabs { + return FakeEnabledTabs() + } +} \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/espresso/fakes/FakeEnabledTabs.kt b/apps/student/src/androidTest/java/com/instructure/student/espresso/fakes/FakeEnabledTabs.kt new file mode 100644 index 0000000000..0f53d6aa6f --- /dev/null +++ b/apps/student/src/androidTest/java/com/instructure/student/espresso/fakes/FakeEnabledTabs.kt @@ -0,0 +1,12 @@ +package com.instructure.student.espresso.fakes + +import com.instructure.interactions.router.Route +import com.instructure.student.router.EnabledTabs + +class FakeEnabledTabs: EnabledTabs { + override suspend fun initTabs() {} + + override fun isPathTabNotEnabled(route: Route?): Boolean { + return false + } +} \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/AssignmentsE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/AssignmentsE2ETest.kt index b106acbd6c..dd3447c0fd 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/AssignmentsE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/AssignmentsE2ETest.kt @@ -25,6 +25,7 @@ import com.instructure.canvas.espresso.E2E import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.SecondaryFeatureCategory +import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.TestCategory import com.instructure.canvas.espresso.TestMetaData import com.instructure.canvas.espresso.checkToastText @@ -40,9 +41,10 @@ import com.instructure.dataseeding.util.days import com.instructure.dataseeding.util.fromNow import com.instructure.dataseeding.util.iso8601 import com.instructure.espresso.retryWithIncreasingDelay +import com.instructure.pandautils.utils.toFormattedString import com.instructure.student.R import com.instructure.student.ui.pages.AssignmentListPage -import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.StudentComposeTest import com.instructure.student.ui.utils.ViewUtils import com.instructure.student.ui.utils.seedData import com.instructure.student.ui.utils.tokenLogin @@ -50,9 +52,10 @@ import com.instructure.student.ui.utils.uploadTextFile import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Rule import org.junit.Test +import java.util.Calendar @HiltAndroidTest -class AssignmentsE2ETest: StudentTest() { +class AssignmentsE2ETest: StudentComposeTest() { override fun displaysPageObjects() = Unit @@ -68,19 +71,21 @@ class AssignmentsE2ETest: StudentTest() { @E2E @Test @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.E2E, SecondaryFeatureCategory.ASSIGNMENT_REMINDER) - fun testAssignmentReminderE2E() { + fun testAssignmentCustomReminderE2E() { Log.d(PREPARATION_TAG,"Seeding data.") val data = seedData(students = 1, teachers = 1, courses = 1) val student = data.studentsList[0] val teacher = data.teachersList[0] val course = data.coursesList[0] + val futureDueDate = 2.days.fromNow + val pastDueDate = 2.days.ago Log.d(PREPARATION_TAG,"Seeding 'Text Entry' assignment for '${course.name}' course with 2 days ahead due date.") - val testAssignment = AssignmentsApi.createAssignment(course.id, teacher.token, dueAt = 2.days.fromNow.iso8601, pointsPossible = 15.0, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY)) + val testAssignment = AssignmentsApi.createAssignment(course.id, teacher.token, dueAt = futureDueDate.iso8601, pointsPossible = 15.0, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY)) Log.d(PREPARATION_TAG,"Seeding 'Text Entry' assignment for '${course.name}' course with 2 days past due date.") - val alreadyPastAssignment = AssignmentsApi.createAssignment(course.id, teacher.token, dueAt = 2.days.ago.iso8601, pointsPossible = 15.0, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY)) + val alreadyPastAssignment = AssignmentsApi.createAssignment(course.id, teacher.token, dueAt = pastDueDate.iso8601, pointsPossible = 15.0, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY)) Log.d(STEP_TAG, "Login with user: '${student.name}', login id: '${student.loginId}'.") tokenLogin(student) @@ -97,74 +102,164 @@ class AssignmentsE2ETest: StudentTest() { Log.d(STEP_TAG, "Assert that the corresponding views are displayed on the Assignment Details Page. Assert that the reminder section is displayed as well.") assignmentDetailsPage.assertPageObjects() - assignmentDetailsPage.assertReminderSectionDisplayed() + reminderPage.assertReminderSectionDisplayed() Log.d(STEP_TAG, "Click on the '+' button (Add reminder) to pick up a new reminder.") - assignmentDetailsPage.clickAddReminder() + reminderPage.clickAddReminder() Log.d(STEP_TAG, "Select '1 Hour Before' and assert that the reminder has been picked up and displayed on the Assignment Details Page.") - assignmentDetailsPage.selectTimeOption("1 Hour Before") - assignmentDetailsPage.assertReminderDisplayedWithText("1 Hour Before") + val reminderDateOneHour = futureDueDate.apply { add(Calendar.HOUR, -1) } + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderDateOneHour) + reminderPage.selectTime(reminderDateOneHour) + reminderPage.assertReminderDisplayedWithText(reminderDateOneHour.time.toFormattedString()) Log.d(STEP_TAG, "Click on the '+' button (Add reminder) to pick up a new reminder.") - assignmentDetailsPage.clickAddReminder() + reminderPage.clickAddReminder() Log.d(STEP_TAG, "Select '1 Hour Before' again, and assert that a toast message is occurring which warns that we cannot pick up the same time reminder twice.") - assignmentDetailsPage.selectTimeOption("1 Hour Before") + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderDateOneHour) + reminderPage.selectTime(reminderDateOneHour) checkToastText(R.string.reminderAlreadySet, activityRule.activity) Log.d(STEP_TAG, "Remove the '1 Hour Before' reminder, confirm the deletion dialog and assert that the '1 Hour Before' reminder is not displayed any more.") - assignmentDetailsPage.removeReminderWithText("1 Hour Before") - assignmentDetailsPage.assertReminderNotDisplayedWithText("1 Hour Before") + reminderPage.removeReminderWithText(reminderDateOneHour.time.toFormattedString()) + reminderPage.assertReminderNotDisplayedWithText(reminderDateOneHour.time.toFormattedString()) + futureDueDate.apply { add(Calendar.HOUR, 1) } Log.d(STEP_TAG, "Click on the '+' button (Add reminder) to pick up a new reminder.") - assignmentDetailsPage.clickAddReminder() + reminderPage.clickAddReminder() - Log.d(STEP_TAG, "Select 'Custom' reminder.") - assignmentDetailsPage.clickCustom() + Log.d(STEP_TAG, "Select '1 Week Before' and assert that a toast message is occurring which warns that we cannot pick up a reminder which has already passed (for example cannot pick '1 Week Before' reminder for an assignment which ends tomorrow).") + val reminderDateOneWeek = futureDueDate.apply { add(Calendar.WEEK_OF_YEAR, -1) } + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderDateOneWeek) + reminderPage.selectTime(reminderDateOneWeek) + reminderPage.assertReminderNotDisplayedWithText(reminderDateOneWeek.time.toFormattedString()) + checkToastText(R.string.reminderInPast, activityRule.activity) + futureDueDate.apply { add(Calendar.WEEK_OF_YEAR, 1) } + + Log.d(STEP_TAG, "Click on the '+' button (Add reminder) to pick up a new reminder.") + reminderPage.clickAddReminder() + + Log.d(STEP_TAG, "Select '1 Day Before' and assert that the reminder has been picked up and displayed on the Assignment Details Page.") + val reminderDateOneDay = futureDueDate.apply { add(Calendar.DAY_OF_MONTH, -1) } + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderDateOneDay) + reminderPage.selectTime(reminderDateOneDay) + reminderPage.assertReminderDisplayedWithText(reminderDateOneDay.time.toFormattedString()) + + Log.d(STEP_TAG, "Click on the '+' button (Add reminder) to pick up a new reminder.") + reminderPage.clickAddReminder() - Log.d(STEP_TAG, "Assert that the 'Done' button is disabled by default.") - assignmentDetailsPage.assertDoneButtonIsDisabled() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderDateOneDay) + reminderPage.selectTime(reminderDateOneDay) - Log.d(STEP_TAG, "Fill the quantity text input with '15' and assert that the 'Done' button is still disabled since there is no option selected yet.") - assignmentDetailsPage.fillQuantity("15") - assignmentDetailsPage.assertDoneButtonIsDisabled() + Log.d(STEP_TAG, "Assert that a toast message is occurring which warns that we cannot pick up the same time reminder twice. (Because 1 days and 24 hours is the same)") + checkToastText(R.string.reminderAlreadySet, activityRule.activity) - Log.d(STEP_TAG, "Select the 'Hours Before' option, and click on 'Done' button, since it will be enabled because both the quantity and option are filled and selected.") - assignmentDetailsPage.clickHoursBefore() - assignmentDetailsPage.clickDone() + futureDueDate.apply { add(Calendar.DAY_OF_MONTH, 1) } + + Log.d(STEP_TAG, "Navigate back to Assignment List Page.") + Espresso.pressBack() - Log.d(STEP_TAG, "Assert that the '15 Hours Before' reminder is displayed on the Assignment Details Page.") - assignmentDetailsPage.assertReminderDisplayedWithText("15 Hours Before") + Log.d(STEP_TAG,"Click on assignment '${alreadyPastAssignment.name}'.") + assignmentListPage.clickAssignment(alreadyPastAssignment) + + Log.d(STEP_TAG, "Assert that the reminder section is NOT displayed, because the '${alreadyPastAssignment.name}' assignment has already passed..") + reminderPage.assertReminderSectionDisplayed() + } + + @E2E + @Test + @Stub + @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.E2E, SecondaryFeatureCategory.ASSIGNMENT_REMINDER) + fun testAssignmentBeforeReminderE2E() { + + Log.d(PREPARATION_TAG,"Seeding data.") + val data = seedData(students = 1, teachers = 1, courses = 1) + val student = data.studentsList[0] + val teacher = data.teachersList[0] + val course = data.coursesList[0] + val futureDueDate = 2.days.fromNow + val pastDueDate = 2.days.ago + + Log.d(PREPARATION_TAG,"Seeding 'Text Entry' assignment for '${course.name}' course with 2 days ahead due date.") + val testAssignment = AssignmentsApi.createAssignment(course.id, teacher.token, dueAt = futureDueDate.iso8601, pointsPossible = 15.0, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY)) + + Log.d(PREPARATION_TAG,"Seeding 'Text Entry' assignment for '${course.name}' course with 2 days past due date.") + val alreadyPastAssignment = AssignmentsApi.createAssignment(course.id, teacher.token, dueAt = pastDueDate.iso8601, pointsPossible = 15.0, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY)) + + Log.d(STEP_TAG, "Login with user: '${student.name}', login id: '${student.loginId}'.") + tokenLogin(student) + dashboardPage.waitForRender() + + Log.d(STEP_TAG,"Select course: '${course.name}'.") + dashboardPage.selectCourse(course) + + Log.d(STEP_TAG,"Navigate to course Assignments Page.") + courseBrowserPage.selectAssignments() + + Log.d(STEP_TAG,"Click on assignment '${testAssignment.name}'.") + assignmentListPage.clickAssignment(testAssignment) + + Log.d(STEP_TAG, "Assert that the corresponding views are displayed on the Assignment Details Page. Assert that the reminder section is displayed as well.") + assignmentDetailsPage.assertPageObjects() + reminderPage.assertReminderSectionDisplayed() + + Log.d(STEP_TAG, "Click on the '+' button (Add reminder) to pick up a new reminder.") + reminderPage.clickAddReminder() + + Log.d(STEP_TAG, "Select '1 Hour Before' and assert that the reminder has been picked up and displayed on the Assignment Details Page.") + val reminderDateOneHour = futureDueDate.apply { add(Calendar.HOUR, -1) } + reminderPage.clickBeforeReminderOption("1 Hour Before") + reminderPage.assertReminderDisplayedWithText(reminderDateOneHour.time.toFormattedString()) Log.d(STEP_TAG, "Click on the '+' button (Add reminder) to pick up a new reminder.") - assignmentDetailsPage.clickAddReminder() + reminderPage.clickAddReminder() + + Log.d(STEP_TAG, "Select '1 Hour Before' again, and assert that a toast message is occurring which warns that we cannot pick up the same time reminder twice.") + reminderPage.clickBeforeReminderOption("1 Hour Before") + checkToastText(R.string.reminderAlreadySet, activityRule.activity) + + Log.d(STEP_TAG, "Remove the '1 Hour Before' reminder, confirm the deletion dialog and assert that the '1 Hour Before' reminder is not displayed any more.") + reminderPage.removeReminderWithText(reminderDateOneHour.time.toFormattedString()) + reminderPage.assertReminderNotDisplayedWithText(reminderDateOneHour.time.toFormattedString()) + futureDueDate.apply { add(Calendar.HOUR, 1) } + + Log.d(STEP_TAG, "Click on the '+' button (Add reminder) to pick up a new reminder.") + reminderPage.clickAddReminder() Log.d(STEP_TAG, "Select '1 Week Before' and assert that a toast message is occurring which warns that we cannot pick up a reminder which has already passed (for example cannot pick '1 Week Before' reminder for an assignment which ends tomorrow).") - assignmentDetailsPage.selectTimeOption("1 Week Before") - assignmentDetailsPage.assertReminderNotDisplayedWithText("1 Week Before") + val reminderDateOneWeek = futureDueDate.apply { add(Calendar.WEEK_OF_YEAR, -1) } + reminderPage.clickBeforeReminderOption("1 Week Before") + reminderPage.assertReminderNotDisplayedWithText(reminderDateOneWeek.time.toFormattedString()) + composeTestRule.waitForIdle() checkToastText(R.string.reminderInPast, activityRule.activity) + composeTestRule.waitForIdle() + futureDueDate.apply { add(Calendar.WEEK_OF_YEAR, 1) } Log.d(STEP_TAG, "Click on the '+' button (Add reminder) to pick up a new reminder.") - assignmentDetailsPage.clickAddReminder() + reminderPage.clickAddReminder() Log.d(STEP_TAG, "Select '1 Day Before' and assert that the reminder has been picked up and displayed on the Assignment Details Page.") - assignmentDetailsPage.selectTimeOption("1 Day Before") - assignmentDetailsPage.assertReminderDisplayedWithText("1 Day Before") + val reminderDateOneDay = futureDueDate.apply { add(Calendar.DAY_OF_MONTH, -1) } + reminderPage.clickBeforeReminderOption("1 Day Before") + reminderPage.assertReminderDisplayedWithText(reminderDateOneDay.time.toFormattedString()) Log.d(STEP_TAG, "Click on the '+' button (Add reminder) to pick up a new reminder.") - assignmentDetailsPage.clickAddReminder() - - Log.d(STEP_TAG, "Select 'Custom' reminder.") - assignmentDetailsPage.clickCustom() + reminderPage.clickAddReminder() - Log.d(STEP_TAG, "Fill the quantity text input with '24' and select 'Hours Before' as option. Click on 'Done'.") - assignmentDetailsPage.fillQuantity("24") - assignmentDetailsPage.clickHoursBefore() - assignmentDetailsPage.clickDone() + reminderPage.clickBeforeReminderOption("1 Day Before") Log.d(STEP_TAG, "Assert that a toast message is occurring which warns that we cannot pick up the same time reminder twice. (Because 1 days and 24 hours is the same)") + composeTestRule.waitForIdle() checkToastText(R.string.reminderAlreadySet, activityRule.activity) + composeTestRule.waitForIdle() + + futureDueDate.apply { add(Calendar.DAY_OF_MONTH, 1) } Log.d(STEP_TAG, "Navigate back to Assignment List Page.") Espresso.pressBack() @@ -173,7 +268,7 @@ class AssignmentsE2ETest: StudentTest() { assignmentListPage.clickAssignment(alreadyPastAssignment) Log.d(STEP_TAG, "Assert that the reminder section is NOT displayed, because the '${alreadyPastAssignment.name}' assignment has already passed..") - assignmentDetailsPage.assertReminderSectionNotDisplayed() + reminderPage.assertReminderSectionDisplayed() } @E2E diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/DiscussionsE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/DiscussionsE2ETest.kt index 90febc40bd..d45362e7a0 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/DiscussionsE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/DiscussionsE2ETest.kt @@ -22,6 +22,7 @@ import androidx.test.espresso.Espresso import com.instructure.canvas.espresso.E2E import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority +import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.TestCategory import com.instructure.canvas.espresso.TestMetaData import com.instructure.dataseeding.api.DiscussionTopicsApi @@ -42,6 +43,7 @@ class DiscussionsE2ETest: StudentTest() { @E2E @Test @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.E2E) + @Stub("There is a known issue with the API on beta, so this would always fail. Remove stubbing when VICE-4849 is done.") fun testDiscussionsE2E() { Log.d(PREPARATION_TAG,"Seeding data.") diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ModulesE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ModulesE2ETest.kt index 08ef0e00c8..f3f8ecc723 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ModulesE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ModulesE2ETest.kt @@ -21,6 +21,7 @@ import androidx.test.espresso.Espresso import com.instructure.canvas.espresso.E2E import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority +import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.TestCategory import com.instructure.canvas.espresso.TestMetaData import com.instructure.dataseeding.api.AssignmentsApi @@ -50,6 +51,7 @@ class ModulesE2ETest: StudentTest() { @E2E @Test @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.E2E) + @Stub("There is a known issue with the API on beta, so this would always fail. Remove stubbing when LX-2147 is done.") fun testModulesE2E() { Log.d(PREPARATION_TAG, "Seeding data.") diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PushNotificationsE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PushNotificationsE2ETest.kt index 4503ae6bb8..90472a9c3b 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PushNotificationsE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PushNotificationsE2ETest.kt @@ -7,12 +7,12 @@ import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.TestCategory import com.instructure.canvas.espresso.TestMetaData import com.instructure.student.BuildConfig -import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.StudentComposeTest import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Test @HiltAndroidTest -class PushNotificationsE2ETest : StudentTest() { +class PushNotificationsE2ETest : StudentComposeTest() { override fun displaysPageObjects() = Unit @@ -40,7 +40,7 @@ class PushNotificationsE2ETest : StudentTest() { leftSideNavigationDrawerPage.clickSettingsMenu() Log.d(STEP_TAG, "Open Push Notifications Page.") - settingsPage.openPushNotificationsPage() + settingsPage.clickOnSettingsItem("Push Notifications") Log.d(ASSERTION_TAG, "Assert that the toolbar title is 'Push Notifications' on the Push Notifications Page.") pushNotificationsPage.assertToolbarTitle() diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/SettingsE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/SettingsE2ETest.kt index 0417003bff..c701efcb60 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/SettingsE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/SettingsE2ETest.kt @@ -18,6 +18,8 @@ package com.instructure.student.ui.e2e import android.content.Intent import android.util.Log +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick import androidx.test.espresso.Espresso import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.Intents.intended @@ -32,22 +34,29 @@ import com.instructure.dataseeding.api.ConversationsApi import com.instructure.dataseeding.api.CoursesApi import com.instructure.dataseeding.api.EnrollmentsApi import com.instructure.espresso.ViewUtils +import com.instructure.pandautils.utils.AppTheme import com.instructure.student.BuildConfig import com.instructure.student.R import com.instructure.student.ui.utils.IntentActionMatcher -import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.StudentComposeTest import com.instructure.student.ui.utils.seedData import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.junit.After import org.junit.Assert import org.junit.Test @HiltAndroidTest -class SettingsE2ETest : StudentTest() { +class SettingsE2ETest : StudentComposeTest() { override fun displaysPageObjects() = Unit override fun enableAndConfigureAccessibilityChecks() = Unit + @After + fun tearDown() { + Intents.release() + } + @E2E @Test @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.E2E) @@ -66,7 +75,7 @@ class SettingsE2ETest : StudentTest() { settingsPage.assertPageObjects() Log.d(STEP_TAG, "Open Profile Settings Page.") - settingsPage.openProfileSettings() + settingsPage.clickOnSettingsItem("Profile Settings") profileSettingsPage.assertPageObjects() val newUserName = "John Doe" @@ -82,7 +91,7 @@ class SettingsE2ETest : StudentTest() { Log.d(STEP_TAG, "Navigate to Settings Page again and open Panda Avatar Creator.") leftSideNavigationDrawerPage.clickSettingsMenu() settingsPage.assertPageObjects() - settingsPage.openProfileSettings() + settingsPage.clickOnSettingsItem("Profile Settings") profileSettingsPage.assertPageObjects() profileSettingsPage.launchPandaAvatarCreator() @@ -126,13 +135,9 @@ class SettingsE2ETest : StudentTest() { leftSideNavigationDrawerPage.clickSettingsMenu() settingsPage.assertPageObjects() - Log.d(STEP_TAG,"Navigate to Settings Page and open App Theme Settings.") - settingsPage.openAppThemeSettings() Log.d(STEP_TAG,"Select Dark App Theme and assert that the App Theme Title and Status has the proper text color (which is used in Dark mode).") - settingsPage.selectAppTheme("Dark") - settingsPage.assertAppThemeTitleTextColor("#FFFFFFFF") //Currently, this color is used in the Dark mode for the AppTheme Title text. - settingsPage.assertAppThemeStatusTextColor("#FF919CA8") //Currently, this color is used in the Dark mode for the AppTheme Status text. + settingsPage.selectAppTheme(AppTheme.DARK) Log.d(STEP_TAG,"Navigate back to Dashboard. Assert that the 'Courses' label has the proper text color (which is used in Dark mode).") Espresso.pressBack() @@ -146,12 +151,9 @@ class SettingsE2ETest : StudentTest() { Log.d(STEP_TAG,"Navigate to Settings Page and open App Theme Settings again.") Espresso.pressBack() leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openAppThemeSettings() Log.d(STEP_TAG,"Select Light App Theme and assert that the App Theme Title and Status has the proper text color (which is used in Light mode).") - settingsPage.selectAppTheme("Light") - settingsPage.assertAppThemeTitleTextColor("#FF273540") //Currently, this color is used in the Light mode for the AppTheme Title texts. - settingsPage.assertAppThemeStatusTextColor("#FF6A7883") //Currently, this color is used in the Light mode for the AppTheme Status text. + settingsPage.selectAppTheme(AppTheme.LIGHT) Log.d(STEP_TAG,"Navigate back to Dashboard. Assert that the 'Courses' label has the proper text color (which is used in Light mode).") Espresso.pressBack() @@ -176,7 +178,7 @@ class SettingsE2ETest : StudentTest() { settingsPage.assertPageObjects() Log.d(STEP_TAG, "Click on 'Legal' link to open Legal Page. Assert that Legal Page has opened.") - settingsPage.openLegalPage() + settingsPage.clickOnSettingsItem("Legal") legalPage.assertPageObjects() } @@ -198,7 +200,7 @@ class SettingsE2ETest : StudentTest() { settingsPage.assertPageObjects() Log.d(STEP_TAG, "Click on 'About' link to open About Page. Assert that About Page has opened.") - settingsPage.openAboutPage() + settingsPage.clickOnSettingsItem("About") aboutPage.assertPageObjects() Log.d(STEP_TAG,"Check that domain is equal to: ${student.domain} (student's domain).") @@ -236,7 +238,7 @@ class SettingsE2ETest : StudentTest() { RemoteConfigParam.values().forEach {param -> initialValues.put(param.rc_name, RemoteConfigUtils.getString(param))} Log.d(STEP_TAG, "Navigate to Remote Config Settings Page.") - settingsPage.openRemoteConfigParams() + settingsPage.clickOnSettingsItem("Remote Config Params") RemoteConfigParam.values().forEach { param -> @@ -256,7 +258,7 @@ class SettingsE2ETest : StudentTest() { Espresso.pressBack() Log.d(STEP_TAG, "Navigate to Remote Config Settings Page.") - settingsPage.openRemoteConfigParams() + settingsPage.clickOnSettingsItem("Remote Config Params") Log.d(STEP_TAG, "Assert that all fields have maintained their initial value.") RemoteConfigParam.values().forEach { param -> @@ -282,21 +284,17 @@ class SettingsE2ETest : StudentTest() { Log.d(STEP_TAG, "Navigate to User Settings Page.") leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.assertPageObjects() Log.d(STEP_TAG, "Click on 'Subscribe to Calendar'.") - settingsPage.openSubscribeToCalendar() + settingsPage.clickOnSettingsItem("Subscribe to Calendar Feed") Log.d(STEP_TAG, "Click on the 'SUBSCRIBE' button of the pop-up dialog.") - settingsPage.clickOnSubscribe() + settingsPage.clickOnSubscribeButton() Log.d(STEP_TAG, "Assert that the proper intents has launched, so the NavigationActivity has been launched with an Intent from SettingsActivity.") val calendarDataMatcherString = "https://calendar.google.com/calendar/r?cid=webcal://" val intentActionMatcher = IntentActionMatcher(Intent.ACTION_VIEW, calendarDataMatcherString) intended(intentActionMatcher) - - Log.d(PREPARATION_TAG, "Release Intents.") - Intents.release() } @E2E diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/GradesElementaryE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/GradesElementaryE2ETest.kt index 6714978284..d27a66e9c1 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/GradesElementaryE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/GradesElementaryE2ETest.kt @@ -32,7 +32,7 @@ import com.instructure.dataseeding.model.SubmissionType import com.instructure.dataseeding.util.days import com.instructure.dataseeding.util.fromNow import com.instructure.dataseeding.util.iso8601 -import com.instructure.espresso.page.getStringFromResource +import com.instructure.espresso.pages.getStringFromResource import com.instructure.student.R import com.instructure.student.ui.pages.ElementaryDashboardPage import com.instructure.student.ui.utils.StudentTest diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/HomeroomE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/HomeroomE2ETest.kt index 830e9ee26c..08edf28a3b 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/HomeroomE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/HomeroomE2ETest.kt @@ -31,7 +31,7 @@ import com.instructure.dataseeding.model.SubmissionType import com.instructure.dataseeding.util.ago import com.instructure.dataseeding.util.days import com.instructure.dataseeding.util.iso8601 -import com.instructure.espresso.page.getStringFromResource +import com.instructure.espresso.pages.getStringFromResource import com.instructure.student.R import com.instructure.student.ui.pages.ElementaryDashboardPage import com.instructure.student.ui.utils.StudentTest diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ScheduleE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ScheduleE2ETest.kt index d2dd8fb9c2..64a4bbf090 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ScheduleE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ScheduleE2ETest.kt @@ -21,7 +21,6 @@ import androidx.test.espresso.Espresso import com.instructure.canvas.espresso.E2E import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority -import com.instructure.canvas.espresso.ReleaseExclude import com.instructure.canvas.espresso.SecondaryFeatureCategory import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.TestCategory @@ -30,8 +29,8 @@ import com.instructure.canvasapi2.utils.toApiString import com.instructure.dataseeding.api.AssignmentsApi import com.instructure.dataseeding.model.GradingType import com.instructure.dataseeding.model.SubmissionType -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.withAncestor +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.withAncestor import com.instructure.student.R import com.instructure.student.ui.pages.ElementaryDashboardPage import com.instructure.student.ui.utils.StudentTest @@ -42,7 +41,9 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.Timeout import java.lang.Thread.sleep -import java.util.* +import java.util.Calendar +import java.util.Locale +import java.util.TimeZone @HiltAndroidTest class ScheduleE2ETest : StudentTest() { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineSyncProgressE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineSyncProgressE2ETest.kt index 9bb2940fa9..ae2b88bb63 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineSyncProgressE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineSyncProgressE2ETest.kt @@ -23,6 +23,7 @@ import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.OfflineE2E import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.SecondaryFeatureCategory +import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.TestCategory import com.instructure.canvas.espresso.TestMetaData import com.instructure.student.ui.e2e.offline.utils.OfflineTestUtils @@ -40,6 +41,7 @@ class OfflineSyncProgressE2ETest : StudentTest() { override fun enableAndConfigureAccessibilityChecks() = Unit + @Stub @OfflineE2E @Test @TestMetaData(Priority.MANDATORY, FeatureCategory.SYNC_PROGRESS, TestCategory.E2E, SecondaryFeatureCategory.OFFLINE_MODE) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineSyncSettingsE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineSyncSettingsE2ETest.kt index 6efa56db19..550911fe82 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineSyncSettingsE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineSyncSettingsE2ETest.kt @@ -24,6 +24,7 @@ import com.instructure.canvas.espresso.SecondaryFeatureCategory import com.instructure.canvas.espresso.TestCategory import com.instructure.canvas.espresso.TestMetaData import com.instructure.pandautils.R +import com.instructure.student.ui.utils.StudentComposeTest import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.ViewUtils import com.instructure.student.ui.utils.seedData @@ -33,7 +34,7 @@ import org.junit.After import org.junit.Test @HiltAndroidTest -class OfflineSyncSettingsE2ETest : StudentTest() { +class OfflineSyncSettingsE2ETest : StudentComposeTest() { override fun displaysPageObjects() = Unit @@ -57,11 +58,10 @@ class OfflineSyncSettingsE2ETest : StudentTest() { Log.d(STEP_TAG, "Assert that the Offline Sync Settings related information is displayed properly on the Settings Page ('Daily' is the default status).") settingsPage.assertOfflineContentDisplayed() - settingsPage.assertOfflineContentTitle() - settingsPage.assertOfflineSyncSettingsStatus(R.string.daily) + settingsPage.assertOfflineSyncSettingsStatus("Daily") Log.d(STEP_TAG, "Open Offline Sync Settings page and wait for it to be loaded.") - settingsPage.openOfflineSyncSettingsPage() + settingsPage.clickOnSyncSettingsItem() offlineSyncSettingsPage.assertPageObjects() Log.d(STEP_TAG, "Assert that further settings, such as the toolbar title is displayed and correct, and both the Auto Content Sync and Wi-Fi Only Sync toggles are displayed and checked by default.") @@ -126,10 +126,10 @@ class OfflineSyncSettingsE2ETest : StudentTest() { leftSideNavigationDrawerPage.clickSettingsMenu() Log.d(STEP_TAG, "Assert that the Offline Sync Settings frequency text is 'Weekly' (because we set it previously).") - settingsPage.assertOfflineSyncSettingsStatus(R.string.weekly) + settingsPage.assertOfflineSyncSettingsStatus("Weekly") Log.d(STEP_TAG, "Open Offline Sync Settings page and wait for it to be loaded.") - settingsPage.openOfflineSyncSettingsPage() + settingsPage.clickOnSyncSettingsItem() offlineSyncSettingsPage.assertPageObjects() Log.d(STEP_TAG, "Assert that the Offline Sync Settings frequency text is 'Weekly' (because we set it previously) and the 'Sync Content Wi-Fi Only' switch is switched off.") diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/utils/OfflineTestUtils.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/utils/OfflineTestUtils.kt index c7dbd9c204..34036b067a 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/utils/OfflineTestUtils.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/utils/OfflineTestUtils.kt @@ -17,7 +17,12 @@ package com.instructure.student.ui.e2e.offline.utils import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.hasDescendant +import androidx.test.espresso.matcher.ViewMatchers.hasSibling +import androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA +import androidx.test.espresso.matcher.ViewMatchers.withChild +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiScrollable @@ -25,7 +30,7 @@ import androidx.test.uiautomator.UiSelector import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click import com.instructure.espresso.matchers.WaitForViewMatcher.waitForView -import com.instructure.espresso.page.plus +import com.instructure.espresso.pages.plus import com.instructure.student.R import org.hamcrest.CoreMatchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AssignmentDetailsInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AssignmentDetailsInteractionTest.kt index 5e2e572fb5..91220934a3 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AssignmentDetailsInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AssignmentDetailsInteractionTest.kt @@ -15,6 +15,10 @@ */ package com.instructure.student.ui.interaction +import androidx.compose.ui.platform.ComposeView +import androidx.test.espresso.matcher.ViewMatchers +import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils +import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.SecondaryFeatureCategory @@ -30,17 +34,19 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.CourseSettings import com.instructure.canvasapi2.utils.toApiString import com.instructure.dataseeding.model.SubmissionType +import com.instructure.pandautils.utils.toFormattedString import com.instructure.student.R -import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.StudentComposeTest import com.instructure.student.ui.utils.routeTo import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.hamcrest.Matchers import org.junit.Assert.assertNotNull import org.junit.Test import java.util.Calendar @HiltAndroidTest -class AssignmentDetailsInteractionTest : StudentTest() { +class AssignmentDetailsInteractionTest : StudentComposeTest() { override fun displaysPageObjects() = Unit @Test @@ -389,7 +395,7 @@ class AssignmentDetailsInteractionTest : StudentTest() { @Test @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) - fun testReminderSectionIsNotVisibleWhenThereIsNoFutureDueDate() { + fun testReminderSectionIsVisibleWhenThereIsNoFutureDueDate() { val data = setUpData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { @@ -399,27 +405,25 @@ class AssignmentDetailsInteractionTest : StudentTest() { assignmentListPage.clickAssignment(assignment) - assignmentDetailsPage.assertReminderSectionNotDisplayed() + reminderPage.assertReminderSectionDisplayed() } @Test @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) - fun testReminderSectionIsVisibleWhenThereIsFutureDueDate() { + fun testReminderSectionIsVisibleWhenThereIsNoDueDate() { val data = setUpData() val course = data.courses.values.first() - val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { - add(Calendar.DAY_OF_MONTH, 1) - }.time.toApiString()) + val assignment = data.addAssignment(course.id, name = "Test Assignment") goToAssignmentList() assignmentListPage.clickAssignment(assignment) - assignmentDetailsPage.assertReminderSectionDisplayed() + reminderPage.assertReminderSectionDisplayed() } @Test - @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) - fun testAddReminder() { + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + fun testReminderSectionIsVisibleWhenThereIsFutureDueDate() { val data = setUpData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { @@ -428,58 +432,65 @@ class AssignmentDetailsInteractionTest : StudentTest() { goToAssignmentList() assignmentListPage.clickAssignment(assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Hour Before") - assignmentDetailsPage.assertReminderDisplayedWithText("1 Hour Before") + reminderPage.assertReminderSectionDisplayed() } @Test @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) - fun testRemoveReminder() { + fun testAddReminder() { + val reminderCalendar = Calendar.getInstance().apply { + add(Calendar.DAY_OF_MONTH, 1) + } val data = setUpData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { - add(Calendar.DAY_OF_MONTH, 1) + add(Calendar.DAY_OF_MONTH, 2) }.time.toApiString()) goToAssignmentList() assignmentListPage.clickAssignment(assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Hour Before") - - assignmentDetailsPage.assertReminderDisplayedWithText("1 Hour Before") + reminderPage.clickAddReminder() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderCalendar) + reminderPage.selectTime(reminderCalendar) - assignmentDetailsPage.removeReminderWithText("1 Hour Before") - - assignmentDetailsPage.assertReminderNotDisplayedWithText("1 Hour Before") + reminderPage.assertReminderDisplayedWithText(reminderCalendar.time.toFormattedString()) } @Test @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) - fun testAddCustomReminder() { + fun testRemoveReminder() { + val reminderCalendar = Calendar.getInstance().apply { + add(Calendar.DAY_OF_MONTH, 1) + } val data = setUpData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { - add(Calendar.DAY_OF_MONTH, 1) + add(Calendar.DAY_OF_MONTH, 2) }.time.toApiString()) goToAssignmentList() assignmentListPage.clickAssignment(assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.clickCustom() - assignmentDetailsPage.assertDoneButtonIsDisabled() - assignmentDetailsPage.fillQuantity("15") - assignmentDetailsPage.assertDoneButtonIsDisabled() - assignmentDetailsPage.clickHoursBefore() - assignmentDetailsPage.clickDone() + reminderPage.clickAddReminder() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderCalendar) + reminderPage.selectTime(reminderCalendar) + + + reminderPage.assertReminderDisplayedWithText(reminderCalendar.time.toFormattedString()) - assignmentDetailsPage.assertReminderDisplayedWithText("15 Hours Before") + reminderPage.removeReminderWithText(reminderCalendar.time.toFormattedString()) + + reminderPage.assertReminderNotDisplayedWithText(reminderCalendar.time.toFormattedString()) } @Test @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) fun testAddReminderInPastShowsError() { + val reminderCalendar = Calendar.getInstance().apply { + add(Calendar.DAY_OF_MONTH, -1) + } val data = setUpData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { @@ -488,8 +499,10 @@ class AssignmentDetailsInteractionTest : StudentTest() { goToAssignmentList() assignmentListPage.clickAssignment(assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Hour Before") + reminderPage.clickAddReminder() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderCalendar) + reminderPage.selectTime(reminderCalendar) checkToastText(R.string.reminderInPast, activityRule.activity) } @@ -497,41 +510,27 @@ class AssignmentDetailsInteractionTest : StudentTest() { @Test @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) fun testAddReminderForTheSameTimeShowsError() { - val data = setUpData() - val course = data.courses.values.first() - val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { + val reminderCalendar = Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, 1) - }.time.toApiString()) - goToAssignmentList() - - assignmentListPage.clickAssignment(assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Hour Before") - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Hour Before") - - checkToastText(R.string.reminderAlreadySet, activityRule.activity) - } - - @Test - @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) - fun testAddReminderForTheSameTimeWithDifferentMeasureOfTimeShowsError() { + } val data = setUpData() val course = data.courses.values.first() val assignment = data.addAssignment(course.id, name = "Test Assignment", dueAt = Calendar.getInstance().apply { - add(Calendar.DAY_OF_MONTH, 10) + add(Calendar.DAY_OF_MONTH, 2) }.time.toApiString()) goToAssignmentList() assignmentListPage.clickAssignment(assignment) - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.selectTimeOption("1 Week Before") - assignmentDetailsPage.clickAddReminder() - assignmentDetailsPage.clickCustom() - assignmentDetailsPage.fillQuantity("7") - assignmentDetailsPage.clickDaysBefore() - assignmentDetailsPage.clickDone() + reminderPage.clickAddReminder() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderCalendar) + reminderPage.selectTime(reminderCalendar) + + reminderPage.clickAddReminder() + reminderPage.clickCustomReminderOption() + reminderPage.selectDate(reminderCalendar) + reminderPage.selectTime(reminderCalendar) checkToastText(R.string.reminderAlreadySet, activityRule.activity) } @@ -599,4 +598,21 @@ class AssignmentDetailsInteractionTest : StudentTest() { return assignment } + + override fun enableAndConfigureAccessibilityChecks() { + extraAccessibilitySupressions = Matchers.allOf( + AccessibilityCheckResultUtils.matchesCheck( + SpeakableTextPresentCheck::class.java + ), + AccessibilityCheckResultUtils.matchesViews( + ViewMatchers.withParent( + ViewMatchers.withClassName( + Matchers.equalTo(ComposeView::class.java.name) + ) + ) + ) + ) + + super.enableAndConfigureAccessibilityChecks() + } } diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/BookmarkInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/BookmarkInteractionTest.kt index ec8cac9747..830186bac2 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/BookmarkInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/BookmarkInteractionTest.kt @@ -15,7 +15,11 @@ */ package com.instructure.student.ui.interaction +import androidx.compose.ui.platform.ComposeView import androidx.test.espresso.Espresso +import androidx.test.espresso.matcher.ViewMatchers +import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils +import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.TestCategory @@ -29,6 +33,7 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.hamcrest.Matchers import org.junit.Test @HiltAndroidTest @@ -124,4 +129,21 @@ class BookmarkInteractionTest : StudentTest() { return data } + override fun enableAndConfigureAccessibilityChecks() { + extraAccessibilitySupressions = Matchers.allOf( + AccessibilityCheckResultUtils.matchesCheck( + SpeakableTextPresentCheck::class.java + ), + AccessibilityCheckResultUtils.matchesViews( + ViewMatchers.withParent( + ViewMatchers.withClassName( + Matchers.equalTo(ComposeView::class.java.name) + ) + ) + ) + ) + + super.enableAndConfigureAccessibilityChecks() + } + } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CourseGradesInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CourseGradesInteractionTest.kt index 4120a6e084..e7ec64c5ad 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CourseGradesInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CourseGradesInteractionTest.kt @@ -45,7 +45,7 @@ class CourseGradesInteractionTest : StudentTest() { val data = setUpData(courseCount = 1, favoriteCourseCount = 1) setUpCustomGrade("A", 100.0, data, false) goToGrades(data) - courseGradesPage.assertTotalGrade(ViewMatchers.withText("100% (A)")) + courseGradesPage.assertTotalGrade(ViewMatchers.withText("100% A")) } @Test diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ElementaryGradesInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ElementaryGradesInteractionTest.kt index bad0d87003..cc901a0597 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ElementaryGradesInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ElementaryGradesInteractionTest.kt @@ -25,7 +25,7 @@ import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.addCourseWithEnrollment import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvasapi2.models.Enrollment -import com.instructure.espresso.page.getStringFromResource +import com.instructure.espresso.pages.getStringFromResource import com.instructure.student.R import com.instructure.student.ui.pages.ElementaryDashboardPage import com.instructure.student.ui.utils.StudentTest diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/HomeroomInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/HomeroomInteractionTest.kt index 8fe96b8638..868f47f911 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/HomeroomInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/HomeroomInteractionTest.kt @@ -27,7 +27,7 @@ import com.instructure.canvas.espresso.mockCanvas.addDiscussionTopicToCourse import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.Enrollment -import com.instructure.espresso.page.getStringFromResource +import com.instructure.espresso.pages.getStringFromResource import com.instructure.student.R import com.instructure.student.ui.pages.ElementaryDashboardPage import com.instructure.student.ui.utils.StudentTest diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ModuleInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ModuleInteractionTest.kt index 5564b86d71..bcd26beb0d 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ModuleInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ModuleInteractionTest.kt @@ -16,8 +16,12 @@ package com.instructure.student.ui.interaction import android.text.Html +import androidx.compose.ui.platform.ComposeView import androidx.test.espresso.Espresso +import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.web.webdriver.Locator +import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils +import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.SecondaryFeatureCategory @@ -53,6 +57,7 @@ import com.instructure.student.ui.pages.WebViewTextCheck import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.hamcrest.Matchers import org.junit.Test import java.net.URLEncoder @@ -649,4 +654,21 @@ class ModuleInteractionTest : StudentTest() { return data } + override fun enableAndConfigureAccessibilityChecks() { + extraAccessibilitySupressions = Matchers.allOf( + AccessibilityCheckResultUtils.matchesCheck( + SpeakableTextPresentCheck::class.java + ), + AccessibilityCheckResultUtils.matchesViews( + ViewMatchers.withParent( + ViewMatchers.withClassName( + Matchers.equalTo(ComposeView::class.java.name) + ) + ) + ) + ) + + super.enableAndConfigureAccessibilityChecks() + } + } diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/OfflineContentInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/OfflineContentInteractionTest.kt index d429d3b65d..e71b9f2b54 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/OfflineContentInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/OfflineContentInteractionTest.kt @@ -18,7 +18,11 @@ package com.instructure.student.ui.interaction import android.text.format.Formatter +import androidx.compose.ui.platform.ComposeView import androidx.test.espresso.Espresso +import androidx.test.espresso.matcher.ViewMatchers +import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils +import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck import com.google.android.material.checkbox.MaterialCheckBox import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority @@ -32,14 +36,16 @@ import com.instructure.canvasapi2.models.Tab import com.instructure.dataseeding.util.Randomizer import com.instructure.pandautils.R import com.instructure.pandautils.utils.StorageUtils +import com.instructure.student.ui.utils.StudentComposeTest import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.hamcrest.Matchers import org.junit.Test import javax.inject.Inject @HiltAndroidTest -class OfflineContentInteractionTest : StudentTest() { +class OfflineContentInteractionTest : StudentComposeTest() { @Inject lateinit var storageUtils: StorageUtils @@ -367,11 +373,28 @@ class OfflineContentInteractionTest : StudentTest() { tokenLogin(data.domain, token, student) dashboardPage.waitForRender() leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openOfflineSyncSettingsPage() + settingsPage.clickOnSyncSettingsItem() offlineSyncSettingsPage.clickWifiOnlySwitch() offlineSyncSettingsPage.clickTurnOff() Espresso.pressBack() Espresso.pressBack() dashboardPage.openGlobalManageOfflineContentPage() } + + override fun enableAndConfigureAccessibilityChecks() { + extraAccessibilitySupressions = Matchers.allOf( + AccessibilityCheckResultUtils.matchesCheck( + SpeakableTextPresentCheck::class.java + ), + AccessibilityCheckResultUtils.matchesViews( + ViewMatchers.withParent( + ViewMatchers.withClassName( + Matchers.equalTo(ComposeView::class.java.name) + ) + ) + ) + ) + + super.enableAndConfigureAccessibilityChecks() + } } diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PdfInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PdfInteractionTest.kt index 1535862916..08c288d8d7 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PdfInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PdfInteractionTest.kt @@ -16,11 +16,15 @@ */ package com.instructure.student.ui.interaction +import androidx.compose.ui.platform.ComposeView +import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.web.sugar.Web import androidx.test.espresso.web.webdriver.DriverAtoms import androidx.test.espresso.web.webdriver.Locator import androidx.test.platform.app.InstrumentationRegistry +import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils +import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck import com.instructure.annotations.FileCaching.FileCache import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority @@ -43,6 +47,7 @@ import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.routeTo import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.hamcrest.Matchers import org.junit.Test import java.io.File import java.io.FileOutputStream @@ -106,6 +111,7 @@ class PdfInteractionTest : StudentTest() { // Annotation toolbar icon needs to be present val data = getToCourse() val course = data.courses.values.first() + val student = data.students[0] data.addFileToCourse( courseId = course.id, @@ -114,7 +120,7 @@ class PdfInteractionTest : StudentTest() { val uniqueFileName = OpenMediaAsyncTaskLoader.makeFilenameUnique(pdfFileName, data.folderFiles.values.first().first().url!!) - cacheFile(uniqueFileName) + cacheFile(student.id.toString(), uniqueFileName) courseBrowserPage.selectFiles() fileListPage.selectItem(pdfFileName) @@ -148,9 +154,9 @@ class PdfInteractionTest : StudentTest() { url = url ) - val uniqueFileName = OpenMediaAsyncTaskLoader.makeFilenameUnique(pdfFileName, url) + val uniqueFileName = OpenMediaAsyncTaskLoader.makeFilenameUnique(pdfFileName, url, fileId.toString()) - cacheFile(uniqueFileName) + cacheFile(student.id.toString(), uniqueFileName) val pdfUrlElementId = "testLinkElement" val assignmentDescriptionHtml = """pdf baby!!!""" @@ -252,7 +258,7 @@ class PdfInteractionTest : StudentTest() { FileCache.putInputStream("https://mock-data.instructure.com$pdfUrl", inputStream) } - private fun cacheFile(fileName: String) { + private fun cacheFile(userid: String, fileName: String) { // We need to copy the file from our assets directory to the cache dirctory, so OpenMediaAsyncTaskLoader // will find it and assume it was downloaded previously var inputStream : InputStream? = null @@ -260,7 +266,7 @@ class PdfInteractionTest : StudentTest() { try { inputStream = InstrumentationRegistry.getInstrumentation().context.resources.assets.open(pdfFileName) - val dir = File(InstrumentationRegistry.getInstrumentation().getTargetContext().externalCacheDir, "attachments") + val dir = File(InstrumentationRegistry.getInstrumentation().getTargetContext().filesDir, "pdfs-$userid") dir.mkdirs() val file = File(dir, fileName) outputStream = FileOutputStream(file) @@ -275,4 +281,21 @@ class PdfInteractionTest : StudentTest() { } } + override fun enableAndConfigureAccessibilityChecks() { + extraAccessibilitySupressions = Matchers.allOf( + AccessibilityCheckResultUtils.matchesCheck( + SpeakableTextPresentCheck::class.java + ), + AccessibilityCheckResultUtils.matchesViews( + ViewMatchers.withParent( + ViewMatchers.withClassName( + Matchers.equalTo(ComposeView::class.java.name) + ) + ) + ) + ) + + super.enableAndConfigureAccessibilityChecks() + } + } diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PickerSubmissionUploadInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PickerSubmissionUploadInteractionTest.kt index 333abfc1da..9f27366f37 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PickerSubmissionUploadInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PickerSubmissionUploadInteractionTest.kt @@ -20,9 +20,13 @@ import android.app.Activity import android.app.Instrumentation import android.content.Intent import android.net.Uri +import androidx.compose.ui.platform.ComposeView import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.IntentMatchers +import androidx.test.espresso.matcher.ViewMatchers import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils +import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.Stub @@ -35,6 +39,7 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.hamcrest.Matchers import org.hamcrest.core.AllOf import org.junit.Before import org.junit.Test @@ -171,4 +176,21 @@ class PickerSubmissionUploadInteractionTest : StudentTest() { return data } + + override fun enableAndConfigureAccessibilityChecks() { + extraAccessibilitySupressions = Matchers.allOf( + AccessibilityCheckResultUtils.matchesCheck( + SpeakableTextPresentCheck::class.java + ), + AccessibilityCheckResultUtils.matchesViews( + ViewMatchers.withParent( + ViewMatchers.withClassName( + Matchers.equalTo(ComposeView::class.java.name) + ) + ) + ) + ) + + super.enableAndConfigureAccessibilityChecks() + } } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ProfileSettingsInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ProfileSettingsInteractionTest.kt index cb58b48fd2..b2e05bcc1a 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ProfileSettingsInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ProfileSettingsInteractionTest.kt @@ -1,7 +1,11 @@ package com.instructure.student.ui.interaction +import androidx.compose.ui.platform.ComposeView import androidx.test.espresso.Espresso +import androidx.test.espresso.matcher.ViewMatchers import androidx.test.rule.GrantPermissionRule +import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils +import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.TestCategory @@ -10,15 +14,16 @@ import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.addUserPermissions import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.student.R -import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.StudentComposeTest import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.hamcrest.Matchers import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test @HiltAndroidTest -class ProfileSettingsInteractionTest : StudentTest() { +class ProfileSettingsInteractionTest : StudentComposeTest() { override fun displaysPageObjects() = Unit // Not used for interaction tests @@ -43,7 +48,7 @@ class ProfileSettingsInteractionTest : StudentTest() { tokenLogin(data.domain, token, student) leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openProfileSettings() + settingsPage.clickOnSettingsItem("Profile Settings") profileSettingsPage.changeUserNameTo(newUserName) Espresso.pressBack() // to settings page @@ -62,7 +67,7 @@ class ProfileSettingsInteractionTest : StudentTest() { tokenLogin(data.domain, token, student) leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openProfileSettings() + settingsPage.clickOnSettingsItem("Profile Settings") profileSettingsPage.assertSettingsDisabled() // No permissions granted } @@ -86,7 +91,7 @@ class ProfileSettingsInteractionTest : StudentTest() { // Navigate to avatar creation page leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openProfileSettings() + settingsPage.clickOnSettingsItem("Profile Settings") profileSettingsPage.launchPandaAvatarCreator() // Select head @@ -115,4 +120,21 @@ class ProfileSettingsInteractionTest : StudentTest() { ) } + + override fun enableAndConfigureAccessibilityChecks() { + extraAccessibilitySupressions = Matchers.allOf( + AccessibilityCheckResultUtils.matchesCheck( + SpeakableTextPresentCheck::class.java + ), + AccessibilityCheckResultUtils.matchesViews( + ViewMatchers.withParent( + ViewMatchers.withClassName( + Matchers.equalTo(ComposeView::class.java.name) + ) + ) + ) + ) + + super.enableAndConfigureAccessibilityChecks() + } } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ScheduleInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ScheduleInteractionTest.kt index c8ba13f4eb..658635db59 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ScheduleInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ScheduleInteractionTest.kt @@ -28,7 +28,7 @@ import com.instructure.canvas.espresso.mockCanvas.addTodo import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.utils.toApiString -import com.instructure.espresso.page.getStringFromResource +import com.instructure.espresso.pages.getStringFromResource import com.instructure.pandautils.utils.date.DateTimeProvider import com.instructure.student.R import com.instructure.student.ui.pages.ElementaryDashboardPage @@ -38,7 +38,7 @@ import com.instructure.student.ui.utils.tokenLoginElementary import dagger.hilt.android.testing.HiltAndroidTest import junit.framework.AssertionFailedError import org.junit.Test -import java.util.* +import java.util.Calendar import javax.inject.Inject @HiltAndroidTest diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SettingsInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SettingsInteractionTest.kt index 762fb310e1..451f701398 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SettingsInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SettingsInteractionTest.kt @@ -29,6 +29,7 @@ import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.student.ui.utils.StudentComposeTest import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest @@ -37,7 +38,7 @@ import org.junit.Before import org.junit.Test @HiltAndroidTest -class SettingsInteractionTest : StudentTest() { +class SettingsInteractionTest : StudentComposeTest() { override fun displaysPageObjects() = Unit // Not used for interaction tests private lateinit var course: Course @@ -59,7 +60,7 @@ class SettingsInteractionTest : StudentTest() { setUpAndSignIn() leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openLegalPage() + settingsPage.clickOnSettingsItem("Legal") Intents.init() try { @@ -80,7 +81,7 @@ class SettingsInteractionTest : StudentTest() { setUpAndSignIn() leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openLegalPage() + settingsPage.clickOnSettingsItem("Legal") legalPage.openTermsOfUse() legalPage.assertTermsOfUseDisplayed() } @@ -93,7 +94,7 @@ class SettingsInteractionTest : StudentTest() { setUpAndSignIn() leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openLegalPage() + settingsPage.clickOnSettingsItem("Legal") legalPage.openPrivacyPolicy() canvasWebViewPage.acceptCookiePolicyIfNecessary() canvasWebViewPage.checkWebViewURL("https://www.instructure.com/policies/product-privacy-policy") @@ -109,7 +110,7 @@ class SettingsInteractionTest : StudentTest() { ApiPrefs.canGeneratePairingCode = true leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openPairObserverPage() + settingsPage.clickOnSettingsItem("Pair with Observer") pairObserverPage.hasCode("1") pairObserverPage.refresh() diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/StudentSmartSearchInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/StudentSmartSearchInteractionTest.kt new file mode 100644 index 0000000000..a69b1d21f6 --- /dev/null +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/StudentSmartSearchInteractionTest.kt @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.instructure.student.ui.interaction + +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.performImeAction +import androidx.compose.ui.test.performTextInput +import androidx.compose.ui.test.requestFocus +import com.instructure.canvas.espresso.common.interaction.SmartSearchInteractionTest +import com.instructure.canvas.espresso.mockCanvas.MockCanvas +import com.instructure.canvas.espresso.mockCanvas.init +import com.instructure.canvasapi2.models.DiscussionTopicHeader +import com.instructure.canvasapi2.models.Page +import com.instructure.canvasapi2.models.Tab +import com.instructure.espresso.ModuleItemInteractions +import com.instructure.student.BuildConfig +import com.instructure.student.activity.LoginActivity +import com.instructure.student.ui.pages.DashboardPage +import com.instructure.student.ui.pages.DiscussionDetailsPage +import com.instructure.student.ui.pages.PageDetailsPage +import com.instructure.student.ui.utils.StudentActivityTestRule +import com.instructure.student.ui.utils.tokenLogin +import dagger.hilt.android.testing.HiltAndroidTest + +@HiltAndroidTest +class StudentSmartSearchInteractionTest : SmartSearchInteractionTest() { + + override val isTesting = BuildConfig.IS_TESTING + + override val activityRule = StudentActivityTestRule(LoginActivity::class.java) + + private val dashboardPage = DashboardPage() + private val discussionDetailsPage = DiscussionDetailsPage(ModuleItemInteractions()) + private val pageDetailsPage = PageDetailsPage(ModuleItemInteractions()) + + override fun initData(): MockCanvas { + val data = MockCanvas.init( + studentCount = 1, + teacherCount = 1, + courseCount = 1, + favoriteCourseCount = 1 + ) + + val course = data.courses.values.first() + data.courseTabs[course.id]?.add( + Tab(position = 3, label = "Smart Search", visibility = "public", tabId = Tab.SEARCH_ID) + ) + data.courseTabs[course.id]?.add( + Tab(position = 4, label = "Announcements", visibility = "public", tabId = Tab.ANNOUNCEMENTS_ID) + ) + data.courseTabs[course.id]?.add( + Tab(position = 5, label = "Discussions", visibility = "public", tabId = Tab.DISCUSSIONS_ID) + ) + data.courseTabs[course.id]?.add( + Tab(position = 6, label = "Pages", visibility = "public", tabId = Tab.PAGES_ID) + ) + return data + } + + override fun goToSmartSearch(data: MockCanvas, query: String) { + val student = data.students[0] + val token = data.tokenFor(student)!! + tokenLogin(data.domain, token, student) + + val course = data.courses.values.first() + + dashboardPage.selectCourse(course) + composeTestRule.onNodeWithTag("searchButton").performClick() + + composeTestRule.onNodeWithTag("searchField") + .requestFocus() + .performClick() + .performTextInput(query) + + composeTestRule.onNodeWithTag("searchField").performImeAction() + + } + + override fun assertDiscussionPage(discussionTopic: DiscussionTopicHeader) { + discussionDetailsPage.assertToolbarDiscussionTitle(discussionTopic.title.orEmpty()) + } + + override fun assertPage(page: Page) { + pageDetailsPage.assertToolbarTitle(page.id.toString()) + } + + +} \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SubmissionDetailsInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SubmissionDetailsInteractionTest.kt index 30203de91a..379ff39588 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SubmissionDetailsInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SubmissionDetailsInteractionTest.kt @@ -17,7 +17,11 @@ package com.instructure.student.ui.interaction import android.os.SystemClock.sleep +import androidx.compose.ui.platform.ComposeView +import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.web.webdriver.Locator +import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils +import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.Stub @@ -40,8 +44,9 @@ import com.instructure.student.ui.pages.WebViewTextCheck import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.hamcrest.Matchers import org.junit.Test -import java.util.* +import java.util.Date @HiltAndroidTest class SubmissionDetailsInteractionTest : StudentTest() { @@ -290,4 +295,21 @@ class SubmissionDetailsInteractionTest : StudentTest() { return data } + + override fun enableAndConfigureAccessibilityChecks() { + extraAccessibilitySupressions = Matchers.allOf( + AccessibilityCheckResultUtils.matchesCheck( + SpeakableTextPresentCheck::class.java + ), + AccessibilityCheckResultUtils.matchesViews( + ViewMatchers.withParent( + ViewMatchers.withClassName( + Matchers.equalTo(ComposeView::class.java.name) + ) + ) + ) + ) + + super.enableAndConfigureAccessibilityChecks() + } } diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SyncSettingsInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SyncSettingsInteractionTest.kt index 2a5c54cd5f..83f3fc40a1 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SyncSettingsInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SyncSettingsInteractionTest.kt @@ -24,13 +24,14 @@ import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.TestCategory import com.instructure.canvas.espresso.TestMetaData import com.instructure.pandautils.R +import com.instructure.student.ui.utils.StudentComposeTest import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Test @HiltAndroidTest -class SyncSettingsInteractionTest : StudentTest() { +class SyncSettingsInteractionTest : StudentComposeTest() { override fun displaysPageObjects() = Unit @@ -104,6 +105,6 @@ class SyncSettingsInteractionTest : StudentTest() { tokenLogin(data.domain, token, student) dashboardPage.waitForRender() leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openOfflineSyncSettingsPage() + settingsPage.clickOnSyncSettingsItem() } } diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/TodoInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/TodoInteractionTest.kt index 4e0d5abc4a..0a0e53ca76 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/TodoInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/TodoInteractionTest.kt @@ -15,7 +15,11 @@ */ package com.instructure.student.ui.interaction +import androidx.compose.ui.platform.ComposeView import androidx.test.espresso.Espresso +import androidx.test.espresso.matcher.ViewMatchers +import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils +import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.StubLandscape @@ -35,6 +39,7 @@ import com.instructure.dataseeding.util.iso8601 import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.hamcrest.Matchers import org.junit.Test @HiltAndroidTest @@ -124,4 +129,21 @@ class TodoInteractionTest : StudentTest() { return data } + override fun enableAndConfigureAccessibilityChecks() { + extraAccessibilitySupressions = Matchers.allOf( + AccessibilityCheckResultUtils.matchesCheck( + SpeakableTextPresentCheck::class.java + ), + AccessibilityCheckResultUtils.matchesViews( + ViewMatchers.withParent( + ViewMatchers.withClassName( + Matchers.equalTo(ComposeView::class.java.name) + ) + ) + ) + ) + + super.enableAndConfigureAccessibilityChecks() + } + } diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AboutPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AboutPage.kt index 7218029b17..07815ca49d 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AboutPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AboutPage.kt @@ -20,9 +20,9 @@ import androidx.test.espresso.Espresso.onView import androidx.test.espresso.matcher.ViewMatchers.withId import com.instructure.espresso.OnViewWithText import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AllCoursesPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AllCoursesPage.kt index d14942bad9..93fdff93bb 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AllCoursesPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AllCoursesPage.kt @@ -19,19 +19,27 @@ package com.instructure.student.ui.pages import android.view.View import androidx.appcompat.widget.AppCompatImageView import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.Visibility +import androidx.test.espresso.matcher.ViewMatchers.hasDescendant +import androidx.test.espresso.matcher.ViewMatchers.hasSibling +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom +import androidx.test.espresso.matcher.ViewMatchers.isNotClickable +import androidx.test.espresso.matcher.ViewMatchers.withContentDescription +import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility +import androidx.test.espresso.matcher.ViewMatchers.withParent +import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.canvasapi2.models.Course import com.instructure.dataseeding.model.CourseApiModel import com.instructure.espresso.DoesNotExistAssertion import com.instructure.espresso.ViewAlphaAssertion import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeUp import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AnnotationCommentListPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AnnotationCommentListPage.kt index af8e4ec2e3..ebea45fe2a 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AnnotationCommentListPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AnnotationCommentListPage.kt @@ -21,8 +21,8 @@ import com.instructure.canvas.espresso.scrollRecyclerView import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.waitForView +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.waitForView import com.instructure.espresso.replaceText import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AnnouncementListPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AnnouncementListPage.kt index 26c6b09593..ad41429951 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AnnouncementListPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AnnouncementListPage.kt @@ -20,10 +20,10 @@ import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import com.instructure.espresso.Searchable import com.instructure.espresso.assertDisplayed import com.instructure.espresso.matchers.WaitForViewMatcher -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.student.R class AnnouncementListPage(searchable: Searchable) : DiscussionListPage(searchable) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AssignmentListPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AssignmentListPage.kt index 0b5d5d880a..1fa8e11ee0 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AssignmentListPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AssignmentListPage.kt @@ -38,16 +38,16 @@ import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeDown import com.instructure.espresso.waitForCheck diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/BookmarkPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/BookmarkPage.kt index d6550170a6..43a8f23289 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/BookmarkPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/BookmarkPage.kt @@ -19,15 +19,19 @@ package com.instructure.student.ui.pages import androidx.appcompat.widget.AppCompatButton import androidx.test.espresso.Espresso import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.hasSibling +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.canvas.espresso.CanvasTest import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvas.espresso.scrollRecyclerView import com.instructure.espresso.assertDisplayed import com.instructure.espresso.clearText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.waitForView +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.waitForView import com.instructure.espresso.typeText import com.instructure.student.R import org.hamcrest.Matchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CanvasWebViewPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CanvasWebViewPage.kt index cc2a97e5eb..94337587cb 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CanvasWebViewPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CanvasWebViewPage.kt @@ -31,14 +31,14 @@ import androidx.test.espresso.web.webdriver.Locator import com.instructure.canvas.espresso.withElementRepeat import com.instructure.espresso.assertVisible import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.student.R import com.instructure.student.ui.utils.TypeInRCETextEditor import org.hamcrest.Matchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ConferenceDetailsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ConferenceDetailsPage.kt index e18d491a3c..5cb4866206 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ConferenceDetailsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ConferenceDetailsPage.kt @@ -18,13 +18,13 @@ package com.instructure.student.ui.pages import androidx.test.espresso.matcher.ViewMatchers.hasSibling import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.student.R import org.hamcrest.CoreMatchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ConferenceListPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ConferenceListPage.kt index 2d7c19a8f8..bbf5928b45 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ConferenceListPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ConferenceListPage.kt @@ -20,13 +20,13 @@ import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.matcher.ViewMatchers.hasSibling import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.student.R import org.hamcrest.CoreMatchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseBrowserPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseBrowserPage.kt index 87cbc0de71..133434b02b 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseBrowserPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseBrowserPage.kt @@ -19,14 +19,18 @@ package com.instructure.student.ui.pages import android.view.View import android.widget.LinearLayout import androidx.constraintlayout.widget.ConstraintLayout -import androidx.test.espresso.Espresso.onView import androidx.test.espresso.PerformException import androidx.test.espresso.UiController import androidx.test.espresso.ViewAction import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast +import androidx.test.espresso.matcher.ViewMatchers.isEnabled +import androidx.test.espresso.matcher.ViewMatchers.withChild +import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.canvas.espresso.scrollRecyclerView import com.instructure.canvas.espresso.withCustomConstraints import com.instructure.canvasapi2.models.Course @@ -36,8 +40,10 @@ import com.instructure.espresso.TextViewColorAssertion import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertHasText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.plus +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withId import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeUp import com.instructure.pandautils.views.SwipeRefreshLayoutAppBar diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseGradesPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseGradesPage.kt index dd17e17206..f3558572a8 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseGradesPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseGradesPage.kt @@ -39,15 +39,15 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasText import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.typeText import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DashboardPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DashboardPage.kt index fcd4dae3bb..19e983bc18 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DashboardPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DashboardPage.kt @@ -54,19 +54,19 @@ import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click import com.instructure.espresso.matchers.WaitForViewMatcher import com.instructure.espresso.matchers.WaitForViewMatcher.waitForViewToBeCompletelyDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithId +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.replaceText import com.instructure.espresso.retry import com.instructure.espresso.scrollTo diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DiscussionDetailsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DiscussionDetailsPage.kt index db61d656e4..29328dd39c 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DiscussionDetailsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DiscussionDetailsPage.kt @@ -23,13 +23,13 @@ import androidx.test.espresso.web.sugar.Web.onWebView import androidx.test.espresso.web.webdriver.Locator import com.instructure.espresso.ModuleItemInteractions import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.waitForWebElement import com.instructure.student.R import org.junit.Assert diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DiscussionListPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DiscussionListPage.kt index 1da5850b9e..2ab775e082 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DiscussionListPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/DiscussionListPage.kt @@ -35,15 +35,15 @@ import com.instructure.espresso.Searchable import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeDown import com.instructure.espresso.waitForCheck diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ElementaryCoursePage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ElementaryCoursePage.kt index aa2142c13a..051bea9195 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ElementaryCoursePage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ElementaryCoursePage.kt @@ -16,17 +16,13 @@ package com.instructure.student.ui.pages -import androidx.test.espresso.Espresso -import androidx.test.espresso.matcher.ViewMatchers import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.assertHasText import com.instructure.espresso.matchers.WaitForViewMatcher -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.student.R -import org.hamcrest.Matchers class ElementaryCoursePage : BasePage(R.id.elementaryCoursePage) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ElementaryDashboardPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ElementaryDashboardPage.kt index e70ea4f77e..f3beb20912 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ElementaryDashboardPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ElementaryDashboardPage.kt @@ -24,13 +24,13 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.assertSelected import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.waitForCheck import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/FileChooserPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/FileChooserPage.kt index 6ae46f177b..88893ce75f 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/FileChooserPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/FileChooserPage.kt @@ -28,12 +28,12 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasText import com.instructure.espresso.click import com.instructure.espresso.matchers.WaitForViewMatcher.waitForViewToBeClickable -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/FileListPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/FileListPage.kt index 786d1e2406..828d5e6e8f 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/FileListPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/FileListPage.kt @@ -21,7 +21,13 @@ import androidx.test.espresso.Espresso import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.swipeDown import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.hasChildCount +import androidx.test.espresso.matcher.ViewMatchers.hasSibling +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast +import androidx.test.espresso.matcher.ViewMatchers.withChild +import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvas.espresso.scrollRecyclerView import com.instructure.canvas.espresso.withCustomConstraints @@ -31,13 +37,13 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.clearText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithId +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId import com.instructure.espresso.scrollTo import com.instructure.espresso.typeText import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/GoToQuizPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/GoToQuizPage.kt index 9d6cc3af2c..d96827de3c 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/GoToQuizPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/GoToQuizPage.kt @@ -20,12 +20,12 @@ import com.instructure.espresso.ModuleItemInteractions import com.instructure.espresso.OnViewWithText import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.student.R class GoToQuizPage(val moduleItemInteractions: ModuleItemInteractions) : BasePage() { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/GradesPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/GradesPage.kt index 1bb0b641b4..6cc917bd84 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/GradesPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/GradesPage.kt @@ -23,13 +23,13 @@ import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.scrollTo -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.scrollTo +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeDown import com.instructure.espresso.swipeUp diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/HelpPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/HelpPage.kt index 224a53087f..05dd581001 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/HelpPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/HelpPage.kt @@ -31,8 +31,8 @@ import com.instructure.espresso.OnViewWithText import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click import com.instructure.espresso.matchers.WaitForViewMatcher.waitForView -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.plus +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.plus import com.instructure.espresso.scrollTo import com.instructure.espresso.typeText import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/HomeroomPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/HomeroomPage.kt index 86c3a2a0db..2757d43af7 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/HomeroomPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/HomeroomPage.kt @@ -29,17 +29,17 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasText import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.scrollTo -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.scrollTo +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeDown import com.instructure.espresso.swipeUp diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ImportantDatesPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ImportantDatesPage.kt index 8958de26f9..d7a588fe1e 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ImportantDatesPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ImportantDatesPage.kt @@ -26,13 +26,13 @@ import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasChild import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeDown import com.instructure.espresso.swipeUp diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/InboxConversationPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/InboxConversationPage.kt index 9873583e3e..26f6167def 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/InboxConversationPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/InboxConversationPage.kt @@ -24,26 +24,36 @@ import android.view.View import android.widget.ImageView import androidx.appcompat.widget.AppCompatButton import androidx.appcompat.widget.MenuPopupWindow -import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers -import androidx.test.espresso.matcher.ViewMatchers.* -import com.instructure.canvas.espresso.* +import androidx.test.espresso.matcher.ViewMatchers.hasChildCount +import androidx.test.espresso.matcher.ViewMatchers.hasSibling +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast +import androidx.test.espresso.matcher.ViewMatchers.withContentDescription +import androidx.test.espresso.matcher.ViewMatchers.withHint +import androidx.test.espresso.matcher.ViewMatchers.withParent +import com.instructure.canvas.espresso.containsTextCaseInsensitive +import com.instructure.canvas.espresso.explicitClick +import com.instructure.canvas.espresso.scrollRecyclerView +import com.instructure.canvas.espresso.stringContainsTextCaseInsensitive +import com.instructure.canvas.espresso.withCustomConstraints import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertGone import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithContentDescription -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithHint -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithContentDescription +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithHint +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.replaceText import com.instructure.espresso.swipeUp import com.instructure.pandautils.utils.ColorUtils diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LeftSideNavigationDrawerPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LeftSideNavigationDrawerPage.kt index 552231af27..87b3aec9d9 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LeftSideNavigationDrawerPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LeftSideNavigationDrawerPage.kt @@ -19,13 +19,13 @@ import com.instructure.espresso.assertContainsText import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithId +import com.instructure.espresso.pages.withId import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeDown import com.instructure.espresso.swipeUp diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LegalPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LegalPage.kt index aa180b2594..3f7bb3674f 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LegalPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LegalPage.kt @@ -23,7 +23,7 @@ import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R import org.hamcrest.Matchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LoginLandingPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LoginLandingPage.kt deleted file mode 100644 index 150ef99490..0000000000 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/LoginLandingPage.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2018 - present Instructure, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.instructure.student.ui.pages - -import androidx.test.espresso.assertion.ViewAssertions.doesNotExist -import androidx.test.espresso.matcher.ViewMatchers.hasSibling -import androidx.test.espresso.matcher.ViewMatchers.withChild -import com.instructure.canvasapi2.models.User -import com.instructure.dataseeding.model.CanvasUserApiModel -import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.assertNotDisplayed -import com.instructure.espresso.click -import com.instructure.espresso.page.* -import com.instructure.student.R -import org.hamcrest.CoreMatchers.allOf - -@Suppress("unused") -class LoginLandingPage : BasePage() { - - private val canvasLogoImageView by OnViewWithId(R.id.canvasLogo) - private val findMySchoolButton by OnViewWithId(R.id.findMySchool) - private val findAnotherSchoolButton by OnViewWithId(R.id.findAnotherSchool, autoAssert = false) - private val lastSavedSchoolButton by OnViewWithId(R.id.openRecentSchool, autoAssert = false) - private val canvasNetworkTextView by OnViewWithId(R.id.canvasNetwork) - private val previousLoginWrapper by OnViewWithId(R.id.previousLoginWrapper, autoAssert = false) - private val previousLoginTitleText by OnViewWithId(R.id.previousLoginTitleText, autoAssert = false) - private val previousLoginDivider by OnViewWithId(R.id.previousLoginDivider, autoAssert = false) - private val previousLoginRecyclerView by OnViewWithId(R.id.previousLoginRecyclerView, autoAssert = false) - private val canvasWordmarkView by OnViewWithId(R.id.canvasWordmark, autoAssert = false) - private val appDescriptionTypeTextView by OnViewWithId(R.id.appDescriptionType, autoAssert = false) - private val qrCodeButton by OnViewWithId(R.id.qrLogin, autoAssert = false) - - fun clickFindMySchoolButton() { - findMySchoolButton.click() - } - - fun clickFindAnotherSchoolButton() { - findAnotherSchoolButton.click() - } - - fun clickOnLastSavedSchoolButton() { - lastSavedSchoolButton.click() - } - - fun clickCanvasNetworkButton() { - canvasNetworkTextView.click() - } - - fun clickQRCodeButton() { - qrCodeButton.click() - } - - fun assertDisplaysCanvasWordmark() { - canvasWordmarkView.assertDisplayed() - } - - fun assertDisplaysAppDescriptionType() { - appDescriptionTypeTextView.assertDisplayed() - } - - fun assertDisplaysPreviousLogins() { - previousLoginTitleText.assertDisplayed() - } - - fun assertNotDisplaysPreviousLogins() { - previousLoginTitleText.assertNotDisplayed() - } - - fun assertPreviousLoginUserDisplayed(userName: String) { - onView(withText(userName)).assertDisplayed() - } - - fun assertPreviousLoginUserNotExist(userName: String) { - onView(withText(userName)).check(doesNotExist()) - } - - fun removeUserFromPreviousLogins(userName: String) { - onView(allOf(withId(R.id.removePreviousUser), hasSibling(withChild(withText(userName))))).click() - } - - fun loginWithPreviousUser(previousUser: CanvasUserApiModel) { - onViewWithText(previousUser.name).click() - } - - fun loginWithPreviousUser(previousUser: User) { - onViewWithText(previousUser.name).click() - } -} diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ModuleProgressionPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ModuleProgressionPage.kt index c2b3e8aac6..2029024574 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ModuleProgressionPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ModuleProgressionPage.kt @@ -23,12 +23,10 @@ import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withParent import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.assertGone import com.instructure.espresso.assertHasText import com.instructure.espresso.assertInvisible -import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.not diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ModulesPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ModulesPage.kt index cc01ea9911..73b01949a2 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ModulesPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ModulesPage.kt @@ -36,14 +36,14 @@ import com.instructure.espresso.RecyclerViewItemCountAssertion import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.waitForCheck import com.instructure.pandautils.utils.color diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/NewMessagePage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/NewMessagePage.kt index 6801a10cf7..43b7508323 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/NewMessagePage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/NewMessagePage.kt @@ -38,14 +38,14 @@ import com.instructure.espresso.RecyclerViewItemCountAssertion import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.typeText import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/NotificationPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/NotificationPage.kt index f189dec280..0dbaf0d4e0 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/NotificationPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/NotificationPage.kt @@ -22,12 +22,16 @@ import androidx.test.espresso.matcher.ViewMatchers.hasSibling import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvas.espresso.refresh import com.instructure.canvas.espresso.scrollRecyclerView -import com.instructure.espresso.* -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.RecyclerViewItemCountGreaterThanAssertion +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.click +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText +import com.instructure.espresso.scrollTo +import com.instructure.espresso.waitForCheck import com.instructure.student.R import org.hamcrest.CoreMatchers.allOf import org.hamcrest.Matchers diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PageDetailsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PageDetailsPage.kt index 81b06aaf67..ebe0cac98f 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PageDetailsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PageDetailsPage.kt @@ -22,7 +22,12 @@ import androidx.test.espresso.web.assertion.WebViewAssertions.webMatches import androidx.test.espresso.web.model.Atoms import androidx.test.espresso.web.sugar.Web.onWebView import com.instructure.espresso.ModuleItemInteractions -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withText import com.instructure.student.R import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.containsString @@ -34,4 +39,8 @@ class PageDetailsPage(val moduleItemInteractions: ModuleItemInteractions) : Base .check(webMatches(Atoms.getCurrentUrl(), containsString(pageUrl))) } + fun assertToolbarTitle(pageName: String) { + onView(withText(pageName) + withAncestor(withId(R.id.toolbar))).assertDisplayed() + } + } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PageListPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PageListPage.kt index 430678fc1f..5c17880ea7 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PageListPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PageListPage.kt @@ -28,11 +28,11 @@ import com.instructure.espresso.RecyclerViewItemCountAssertion import com.instructure.espresso.Searchable import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId import com.instructure.espresso.waitForCheck import com.instructure.student.R import org.hamcrest.Matcher diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PairObserverPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PairObserverPage.kt index 28a7f380c1..40752b166d 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PairObserverPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PairObserverPage.kt @@ -17,7 +17,10 @@ package com.instructure.student.ui.pages import com.instructure.espresso.click -import com.instructure.espresso.page.* +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withId import com.instructure.student.R open class PairObserverPage : BasePage(R.id.pairObserverPage) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PandaAvatarPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PandaAvatarPage.kt index bdf9bd9301..13b9527fdf 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PandaAvatarPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PandaAvatarPage.kt @@ -4,14 +4,13 @@ import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.canvas.espresso.stringContainsTextCaseInsensitive import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent import com.instructure.espresso.scrollTo import com.instructure.student.R import org.hamcrest.Matchers.allOf -import org.hamcrest.Matchers.containsString class PandaAvatarPage : BasePage(R.id.panda_create_layout) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PeopleListPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PeopleListPage.kt index 6254ddc991..c352afeb7b 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PeopleListPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PeopleListPage.kt @@ -29,13 +29,13 @@ import com.instructure.dataseeding.model.CanvasUserApiModel import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.student.R import org.hamcrest.Matcher import org.hamcrest.Matchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PersonDetailsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PersonDetailsPage.kt index c955c7fd1a..bded04d061 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PersonDetailsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PersonDetailsPage.kt @@ -23,9 +23,9 @@ import com.instructure.canvasapi2.models.User import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertContainsText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withId import com.instructure.student.R import org.hamcrest.Matchers diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PickerSubmissionUploadPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PickerSubmissionUploadPage.kt index d743d3d1fc..e94c7ac959 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PickerSubmissionUploadPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PickerSubmissionUploadPage.kt @@ -21,8 +21,8 @@ import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.espresso.OnViewWithId import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.waitForViewWithText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.waitForViewWithText import com.instructure.student.R import org.hamcrest.core.AllOf.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ProfileSettingsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ProfileSettingsPage.kt index fa6d671d36..ae9c0d6310 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ProfileSettingsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ProfileSettingsPage.kt @@ -11,7 +11,7 @@ import com.instructure.canvas.espresso.CanvasTest import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.espresso.OnViewWithId import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R import org.hamcrest.Matchers.not diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PushNotificationsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PushNotificationsPage.kt index d5e0139481..66938e948f 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PushNotificationsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/PushNotificationsPage.kt @@ -19,13 +19,13 @@ package com.instructure.student.ui.pages import androidx.test.espresso.matcher.ViewMatchers import com.instructure.espresso.WaitForViewWithText import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeUp import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/QRLoginPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/QRLoginPage.kt index f7fe46b346..bef31969b8 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/QRLoginPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/QRLoginPage.kt @@ -17,9 +17,8 @@ import com.instructure.espresso.OnViewWithContentDescription import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.OnViewWithStringContentDescription import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R class QRLoginPage : BasePage() { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/QuizListPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/QuizListPage.kt index fab2457607..47434461d1 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/QuizListPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/QuizListPage.kt @@ -19,7 +19,9 @@ package com.instructure.student.ui.pages import android.view.View import androidx.test.espresso.action.ViewActions.swipeDown import androidx.test.espresso.assertion.ViewAssertions.doesNotExist -import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast +import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.canvas.espresso.scrollRecyclerView import com.instructure.canvas.espresso.withCustomConstraints import com.instructure.canvasapi2.models.Quiz @@ -28,7 +30,12 @@ import com.instructure.espresso.RecyclerViewItemCountAssertion import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.* +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.student.R import org.hamcrest.Matcher import org.hamcrest.Matchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/RemoteConfigSettingsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/RemoteConfigSettingsPage.kt index 5edda4a5ef..44aeebfdce 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/RemoteConfigSettingsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/RemoteConfigSettingsPage.kt @@ -26,7 +26,7 @@ import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvas.espresso.scrollRecyclerView import com.instructure.canvasapi2.utils.RemoteConfigParam import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.pandautils.R import org.hamcrest.Matcher import org.hamcrest.Matchers diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ResourcesPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ResourcesPage.kt index bd6caa932d..c68635b6bc 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ResourcesPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ResourcesPage.kt @@ -26,14 +26,14 @@ import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeDown import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SchedulePage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SchedulePage.kt index 2fc890500e..91be2de04e 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SchedulePage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SchedulePage.kt @@ -21,8 +21,26 @@ import androidx.test.espresso.NoMatchingViewException import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers.hasSibling -import com.instructure.espresso.* -import com.instructure.espresso.page.* +import com.instructure.espresso.OnViewWithId +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.assertNotDisplayed +import com.instructure.espresso.click +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText +import com.instructure.espresso.scrollTo +import com.instructure.espresso.swipeDown +import com.instructure.espresso.swipeLeft +import com.instructure.espresso.swipeRight +import com.instructure.espresso.swipeUp import com.instructure.pandautils.binding.BindableViewHolder import com.instructure.student.R import org.hamcrest.Matcher diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SettingsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SettingsPage.kt index 512939d935..e69de29bb2 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SettingsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SettingsPage.kt @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2019 - present Instructure, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.instructure.student.ui.pages - -import androidx.test.espresso.matcher.ViewMatchers.hasSibling -import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.TextViewColorAssertion -import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.assertNotDisplayed -import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText -import com.instructure.espresso.scrollTo -import com.instructure.student.R - -class SettingsPage : BasePage(R.id.settingsFragment) { - private val profileSettingLabel by OnViewWithId(R.id.profileSettings) - private val accountPreferencesLabel by OnViewWithId(R.id.accountPreferences) - private val pushNotificationsLabel by OnViewWithId(R.id.pushNotifications) - - // The pairObserverLabel may not be present if the corresponding remote-config flag is disabled. - private val pairObserverLabel by OnViewWithId(R.id.pairObserver, autoAssert = false) - private val aboutLabel by OnViewWithId(R.id.about) - private val legalLabel by OnViewWithId(R.id.legal) - private val subscribeCalendarLabel by OnViewWithId(R.id.subscribeToCalendar, autoAssert = false) - private val remoteConfigLabel by OnViewWithId(R.id.remoteConfigParams) - private val appThemeTitle by OnViewWithId(R.id.appThemeTitle) - private val appThemeStatus by OnViewWithId(R.id.appThemeStatus) - private val offlineContent by OnViewWithId(R.id.offlineSyncSettingsContainer) - - fun openAboutPage() { - aboutLabel.scrollTo().click() - } - - fun openLegalPage() { - legalLabel.scrollTo().click() - } - - fun openRemoteConfigParams() { - remoteConfigLabel.scrollTo().click() - } - - fun openPairObserverPage() { - pairObserverLabel.scrollTo().click() - } - - fun openProfileSettings() { - profileSettingLabel.scrollTo().click() - } - - fun openPushNotificationsPage() { - pushNotificationsLabel.scrollTo().click() - } - - - fun openSubscribeToCalendar() { - subscribeCalendarLabel.scrollTo().click() - } - - fun clickOnSubscribe() { - onView(withText(R.string.subscribeButton)).click() - } - - fun openAppThemeSettings() { - appThemeTitle.scrollTo().click() - } - - fun selectAppTheme(appTheme: String) - { - onView(withText(appTheme) + withParent(R.id.select_dialog_listview)).click() - } - - fun assertAppThemeTitleTextColor(expectedTextColor: String) { - appThemeTitle.check(TextViewColorAssertion(expectedTextColor)) - } - - fun assertAppThemeStatusTextColor(expectedTextColor: String) { - appThemeStatus.check(TextViewColorAssertion(expectedTextColor)) - } - - //OfflineMethod - fun openOfflineSyncSettingsPage() { - offlineContent.scrollTo().click() - } - - //OfflineMethod - fun assertOfflineContentDisplayed() { - offlineContent.scrollTo().assertDisplayed() - } - - //OfflineMethod - fun assertOfflineContentNotDisplayed() { - offlineContent.assertNotDisplayed() - } - - //OfflineMethod - fun assertOfflineContentTitle() { - onView(withId(R.id.offlineContentTitle) + withText(R.string.offlineContent)).assertDisplayed() - } - - //OfflineMethod - fun assertOfflineSyncSettingsStatus(expectedStatus: Int) { - onView(withId(R.id.offlineSyncSettingsStatus) + withText(expectedStatus) + withParent(R.id.offlineSyncSettingsContainer) + - hasSibling(withId(R.id.offlineSyncSettingsTitle) + withText(R.string.offlineSyncSettingsTitle))).assertDisplayed() - } - -} diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ShareExtensionStatusPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ShareExtensionStatusPage.kt index 83d8ba9a25..4ff20bb011 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ShareExtensionStatusPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ShareExtensionStatusPage.kt @@ -19,9 +19,9 @@ package com.instructure.student.ui.pages import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertHasText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withId import com.instructure.student.R class ShareExtensionStatusPage : BasePage() { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ShareExtensionTargetPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ShareExtensionTargetPage.kt index bd94dbda59..745a3c5bcf 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ShareExtensionTargetPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/ShareExtensionTargetPage.kt @@ -20,8 +20,17 @@ import androidx.test.espresso.Espresso.onData import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.matcher.RootMatchers.isDialog import androidx.test.espresso.matcher.ViewMatchers -import com.instructure.espresso.* -import com.instructure.espresso.page.* +import com.instructure.espresso.WaitForViewWithId +import com.instructure.espresso.WaitForViewWithStringTextIgnoreCase +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.assertHasText +import com.instructure.espresso.click +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withText import com.instructure.student.R import org.hamcrest.Matchers.anything diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/StudentAssignmentDetailsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/StudentAssignmentDetailsPage.kt index d8dee9a60c..b6ca2381e4 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/StudentAssignmentDetailsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/StudentAssignmentDetailsPage.kt @@ -26,12 +26,12 @@ import com.instructure.espresso.ModuleItemInteractions import com.instructure.espresso.assertDisplayed import com.instructure.espresso.clearText import com.instructure.espresso.click -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.typeText import com.instructure.student.R import org.hamcrest.Matchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SubmissionDetailsEmptyContentPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SubmissionDetailsEmptyContentPage.kt index 3500562c7c..986d7204e8 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SubmissionDetailsEmptyContentPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SubmissionDetailsEmptyContentPage.kt @@ -15,7 +15,7 @@ */ package com.instructure.student.ui.pages -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R open class SubmissionDetailsEmptyContentPage : BasePage(R.id.submissionDetailsEmptyContent) \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SubmissionDetailsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SubmissionDetailsPage.kt index d969b499f7..c199b85167 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SubmissionDetailsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SubmissionDetailsPage.kt @@ -40,16 +40,16 @@ import com.instructure.dataseeding.model.CanvasUserApiModel import com.instructure.espresso.OnViewWithStringTextIgnoreCase import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithId +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.replaceText import com.instructure.student.R import com.instructure.student.ui.pages.renderPages.SubmissionCommentsRenderPage diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SyllabusPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SyllabusPage.kt index 00114048ff..2d6d70a6f5 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SyllabusPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/SyllabusPage.kt @@ -29,10 +29,10 @@ import com.instructure.canvas.espresso.matchToolbarText import com.instructure.canvas.espresso.scrollRecyclerView import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor import com.instructure.espresso.swipeDown import com.instructure.student.R import org.hamcrest.Matchers diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/TextSubmissionUploadPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/TextSubmissionUploadPage.kt index bb5e6e1d91..be20f767d8 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/TextSubmissionUploadPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/TextSubmissionUploadPage.kt @@ -20,7 +20,7 @@ import com.instructure.canvas.espresso.explicitClick import com.instructure.espresso.OnViewWithId import com.instructure.espresso.OnViewWithText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R class TextSubmissionUploadPage : BasePage(R.id.textSubmissionUpload) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/TodoPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/TodoPage.kt index 656df2e5e9..63633e9573 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/TodoPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/TodoPage.kt @@ -25,13 +25,13 @@ import com.instructure.dataseeding.model.QuizApiModel import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.student.R import org.hamcrest.Matchers diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/UrlSubmissionUploadPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/UrlSubmissionUploadPage.kt index 7ca89f0e01..546adfc0ce 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/UrlSubmissionUploadPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/UrlSubmissionUploadPage.kt @@ -16,19 +16,14 @@ package com.instructure.student.ui.pages import android.view.View -import androidx.test.espresso.PerformException import androidx.test.espresso.UiController import androidx.test.espresso.ViewAction -import androidx.test.espresso.ViewAssertion import androidx.test.espresso.matcher.ViewMatchers -import androidx.test.espresso.util.HumanReadables -import com.instructure.espresso.* -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.OnViewWithId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.replaceText import com.instructure.student.R import org.hamcrest.Matcher -import java.lang.System.currentTimeMillis -import java.lang.Thread.sleep -import java.util.concurrent.TimeoutException open class UrlSubmissionUploadPage : BasePage(R.id.urlSubmissionUpload) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/ManageOfflineContentPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/ManageOfflineContentPage.kt index a64ec38b56..8b97db034c 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/ManageOfflineContentPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/ManageOfflineContentPage.kt @@ -18,12 +18,12 @@ package com.instructure.student.ui.pages.offline import androidx.test.espresso.Espresso +import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.Visibility +import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.hasSibling import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility -import androidx.test.espresso.contrib.RecyclerViewActions -import androidx.test.espresso.matcher.ViewMatchers.* import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvas.espresso.hasCheckedState import com.instructure.canvas.espresso.withRotation @@ -36,14 +36,14 @@ import com.instructure.espresso.actions.ForceClick import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click import com.instructure.espresso.matchers.WaitForViewMatcher -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.pandautils.R import com.instructure.pandautils.binding.BindableViewHolder diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/NativeDiscussionDetailsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/NativeDiscussionDetailsPage.kt index 8cc3233183..5feb94d297 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/NativeDiscussionDetailsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/NativeDiscussionDetailsPage.kt @@ -43,12 +43,12 @@ import com.instructure.espresso.assertGone import com.instructure.espresso.assertHasText import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForViewWithId +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.student.R import com.instructure.student.ui.pages.WebViewTextCheck diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/OfflineSyncSettingsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/OfflineSyncSettingsPage.kt index d27445850e..a6b572413e 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/OfflineSyncSettingsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/OfflineSyncSettingsPage.kt @@ -25,15 +25,15 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasText import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.pandautils.R class OfflineSyncSettingsPage : BasePage(R.id.syncSettingsPage) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/SyncProgressPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/SyncProgressPage.kt index dfb0cd3307..0ba0a64766 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/SyncProgressPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/offline/SyncProgressPage.kt @@ -26,14 +26,14 @@ import com.instructure.espresso.assertContainsText import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertVisibility import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.pandautils.R import com.instructure.student.ui.utils.getView diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/ConferenceDetailsRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/ConferenceDetailsRenderPage.kt index 81cf77ed4f..8e88eab39f 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/ConferenceDetailsRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/ConferenceDetailsRenderPage.kt @@ -18,11 +18,16 @@ package com.instructure.student.ui.pages.renderPages import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.withAlpha -import com.instructure.espresso.* -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.scrollTo -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.OnViewWithId +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.assertGone +import com.instructure.espresso.assertHasText +import com.instructure.espresso.assertInvisible +import com.instructure.espresso.assertVisible +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.scrollTo +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.student.R import com.instructure.student.mobius.conferences.conference_details.ui.ConferenceRecordingViewState import com.instructure.student.ui.pages.ConferenceDetailsPage diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/ConferenceListRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/ConferenceListRenderPage.kt index befba656b3..f19a7fe535 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/ConferenceListRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/ConferenceListRenderPage.kt @@ -18,12 +18,20 @@ package com.instructure.student.ui.pages.renderPages import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import com.instructure.canvas.espresso.scrollRecyclerView -import com.instructure.espresso.* -import com.instructure.espresso.page.* +import com.instructure.espresso.OnViewWithId +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.assertGone +import com.instructure.espresso.assertHasText +import com.instructure.espresso.assertVisible +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.scrollTo +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.student.R import com.instructure.student.mobius.conferences.conference_list.ui.ConferenceListItemViewState import com.instructure.student.ui.pages.ConferenceListPage -import com.instructure.student.ui.pages.SyllabusPage import com.instructure.student.ui.utils.assertIsRefreshing import org.hamcrest.Matchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/DiscussionSubmissionViewRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/DiscussionSubmissionViewRenderPage.kt index 9ec5ec6810..617e49be5d 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/DiscussionSubmissionViewRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/DiscussionSubmissionViewRenderPage.kt @@ -20,13 +20,10 @@ import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.web.assertion.WebViewAssertions.webMatches import androidx.test.espresso.web.model.Atoms.getCurrentUrl import androidx.test.espresso.web.sugar.Web.onWebView -import androidx.test.espresso.web.webdriver.DriverAtoms.findElement -import androidx.test.espresso.web.webdriver.DriverAtoms.webClick -import androidx.test.espresso.web.webdriver.Locator import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.espresso.waitForCheck import com.instructure.student.R import org.hamcrest.CoreMatchers.containsString diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/MediaSubmissionViewRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/MediaSubmissionViewRenderPage.kt index e5b4063b04..4b3fc4f8d7 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/MediaSubmissionViewRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/MediaSubmissionViewRenderPage.kt @@ -18,7 +18,7 @@ package com.instructure.student.ui.pages.renderPages import com.instructure.espresso.OnViewWithId import com.instructure.espresso.WaitForViewWithId -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R class MediaSubmissionViewRenderPage : BasePage(R.id.mediaSubmissionView) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/PairObserverRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/PairObserverRenderPage.kt index a008bce279..936ace9e9a 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/PairObserverRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/PairObserverRenderPage.kt @@ -20,10 +20,10 @@ import com.instructure.canvas.espresso.waitForMatcherWithSleeps import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertGone -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.student.R import com.instructure.student.ui.pages.PairObserverPage import org.hamcrest.Matchers.allOf diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/PickerSubmissionUploadRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/PickerSubmissionUploadRenderPage.kt index c75c41a01a..a62722b976 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/PickerSubmissionUploadRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/PickerSubmissionUploadRenderPage.kt @@ -20,7 +20,7 @@ import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R class PickerSubmissionUploadRenderPage : BasePage(R.id.pickerSubmissionUploadPage) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/QuizSubmissionViewRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/QuizSubmissionViewRenderPage.kt index d1f7f0422c..9fe66746ad 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/QuizSubmissionViewRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/QuizSubmissionViewRenderPage.kt @@ -23,7 +23,7 @@ import androidx.test.espresso.web.sugar.Web.onWebView import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.espresso.waitForCheck import com.instructure.student.R import org.hamcrest.CoreMatchers.containsString diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionCommentsRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionCommentsRenderPage.kt index 394559aabc..1181ff028e 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionCommentsRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionCommentsRenderPage.kt @@ -31,10 +31,10 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertGone import com.instructure.espresso.assertVisible import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText import com.instructure.espresso.scrollTo import com.instructure.student.R import com.instructure.student.mobius.assignmentDetails.submissionDetails.drawer.comments.CommentItemState diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionDetailsRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionDetailsRenderPage.kt index 16aca79ad0..4148f928ad 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionDetailsRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionDetailsRenderPage.kt @@ -18,13 +18,29 @@ package com.instructure.student.ui.pages.renderPages import android.view.View import androidx.test.espresso.Espresso.onData -import androidx.test.espresso.action.* +import androidx.test.espresso.action.CoordinatesProvider +import androidx.test.espresso.action.GeneralLocation +import androidx.test.espresso.action.GeneralSwipeAction +import androidx.test.espresso.action.Press +import androidx.test.espresso.action.Swipe import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.BoundedMatcher import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withChild -import com.instructure.espresso.* -import com.instructure.espresso.page.* +import com.instructure.espresso.OnViewWithId +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.assertGone +import com.instructure.espresso.assertNotDisplayed +import com.instructure.espresso.assertVisible +import com.instructure.espresso.click +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText +import com.instructure.espresso.scrollTo +import com.instructure.espresso.waitForCheck import com.instructure.student.R import com.instructure.student.ui.pages.SubmissionDetailsPage import com.sothree.slidinguppanel.SlidingUpPanelLayout diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionFilesRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionFilesRenderPage.kt index 8be16aa0a4..a6a543b040 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionFilesRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionFilesRenderPage.kt @@ -16,7 +16,7 @@ package com.instructure.student.ui.pages.renderPages import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R class SubmissionFilesRenderPage : BasePage(R.id.submissionFilesPage) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionRubricRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionRubricRenderPage.kt index 27f746ba57..847a739cfe 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionRubricRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SubmissionRubricRenderPage.kt @@ -16,7 +16,7 @@ package com.instructure.student.ui.pages.renderPages import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R class SubmissionRubricRenderPage : BasePage(R.id.submissionRubricPage) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SyllabusRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SyllabusRenderPage.kt index 54ed6bec6f..9fed82a8b4 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SyllabusRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/SyllabusRenderPage.kt @@ -23,8 +23,16 @@ import androidx.test.espresso.web.sugar.Web.onWebView import androidx.test.espresso.web.webdriver.DriverAtoms.findElement import androidx.test.espresso.web.webdriver.DriverAtoms.getText import androidx.test.espresso.web.webdriver.Locator -import com.instructure.espresso.* -import com.instructure.espresso.page.* +import com.instructure.espresso.OnViewWithId +import com.instructure.espresso.WaitForViewWithId +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.assertNotDisplayed +import com.instructure.espresso.click +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.student.R import com.instructure.student.ui.pages.SyllabusPage import org.hamcrest.CoreMatchers diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/TextSubmissionUploadRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/TextSubmissionUploadRenderPage.kt index 715613fc4f..9d472b72d2 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/TextSubmissionUploadRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/TextSubmissionUploadRenderPage.kt @@ -16,7 +16,7 @@ package com.instructure.student.ui.pages.renderPages import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R class TextSubmissionUploadRenderPage : BasePage(R.id.textSubmissionUpload) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/TextSubmissionViewRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/TextSubmissionViewRenderPage.kt index 78e8ef8577..81ac7b5e4a 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/TextSubmissionViewRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/TextSubmissionViewRenderPage.kt @@ -20,12 +20,14 @@ import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.web.assertion.WebViewAssertions.webMatches import androidx.test.espresso.web.model.Atoms.getCurrentUrl import androidx.test.espresso.web.sugar.Web.onWebView -import androidx.test.espresso.web.webdriver.DriverAtoms.* +import androidx.test.espresso.web.webdriver.DriverAtoms.findElement +import androidx.test.espresso.web.webdriver.DriverAtoms.getText +import androidx.test.espresso.web.webdriver.DriverAtoms.webClick import androidx.test.espresso.web.webdriver.Locator import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.espresso.waitForCheck import com.instructure.student.R import org.hamcrest.CoreMatchers.containsString diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UploadStatusSubmissionViewRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UploadStatusSubmissionViewRenderPage.kt index cbed29420b..72f2bdc737 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UploadStatusSubmissionViewRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UploadStatusSubmissionViewRenderPage.kt @@ -16,9 +16,8 @@ package com.instructure.student.ui.pages.renderPages import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.OnViewWithText import com.instructure.espresso.assertVisible -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R class UploadStatusSubmissionViewRenderPage : BasePage(R.id.uploadStatusSubmissionPage) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UrlSubmissionUploadRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UrlSubmissionUploadRenderPage.kt index 2aea428816..2bfd8d4f25 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UrlSubmissionUploadRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UrlSubmissionUploadRenderPage.kt @@ -16,7 +16,7 @@ package com.instructure.student.ui.pages.renderPages import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R class UrlSubmissionUploadRenderPage : BasePage(R.id.urlSubmissionUpload) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UrlSubmissionViewRenderPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UrlSubmissionViewRenderPage.kt index a550e30f6d..f955fc1916 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UrlSubmissionViewRenderPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/renderPages/UrlSubmissionViewRenderPage.kt @@ -17,7 +17,7 @@ package com.instructure.student.ui.pages.renderPages import com.instructure.espresso.OnViewWithId import com.instructure.espresso.OnViewWithText -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.student.R class UrlSubmissionViewRenderPage : BasePage(R.id.urlSubmission) { diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/QuizSubmissionViewRenderTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/QuizSubmissionViewRenderTest.kt index 30deffe789..a4aae64f24 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/QuizSubmissionViewRenderTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/QuizSubmissionViewRenderTest.kt @@ -16,7 +16,7 @@ package com.instructure.student.ui.renderTests import com.instructure.espresso.assertNotDisplayed -import com.instructure.espresso.page.onViewWithId +import com.instructure.espresso.pages.onViewWithId import com.instructure.student.R import com.instructure.student.espresso.StudentRenderTest import com.instructure.student.mobius.assignmentDetails.submissionDetails.content.QuizSubmissionViewFragment diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SubmissionRubricRenderTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SubmissionRubricRenderTest.kt index 654d0437b3..94113bba32 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SubmissionRubricRenderTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SubmissionRubricRenderTest.kt @@ -32,7 +32,7 @@ import com.instructure.espresso.assertHasText import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.assertVisible import com.instructure.espresso.click -import com.instructure.espresso.page.onViewWithText +import com.instructure.espresso.pages.onViewWithText import com.instructure.pandautils.features.assignments.details.mobius.gradeCell.GradeCellViewState import com.instructure.student.espresso.StudentRenderTest import com.instructure.student.mobius.assignmentDetails.submissionDetails.drawer.rubric.RatingData diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/views/GradeCellRenderTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/views/GradeCellRenderTest.kt index 17151a2d39..de93fbe0c3 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/views/GradeCellRenderTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/views/GradeCellRenderTest.kt @@ -22,7 +22,7 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertGone import com.instructure.espresso.assertHasText import com.instructure.espresso.assertNotDisplayed -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.pandautils.features.assignments.details.mobius.gradeCell.GradeCellView import com.instructure.pandautils.features.assignments.details.mobius.gradeCell.GradeCellViewState import com.instructure.student.R diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentComposeTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentComposeTest.kt index b4b871784e..f61501d67c 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentComposeTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentComposeTest.kt @@ -19,12 +19,14 @@ package com.instructure.student.ui.utils import androidx.compose.ui.test.junit4.createAndroidComposeRule +import com.instructure.canvas.espresso.common.pages.ReminderPage import com.instructure.canvas.espresso.common.pages.compose.CalendarEventCreateEditPage import com.instructure.canvas.espresso.common.pages.compose.CalendarEventDetailsPage import com.instructure.canvas.espresso.common.pages.compose.CalendarFilterPage import com.instructure.canvas.espresso.common.pages.compose.CalendarScreenPage import com.instructure.canvas.espresso.common.pages.compose.CalendarToDoCreateUpdatePage import com.instructure.canvas.espresso.common.pages.compose.CalendarToDoDetailsPage +import com.instructure.canvas.espresso.common.pages.compose.SettingsPage import com.instructure.student.activity.LoginActivity import org.junit.Rule @@ -39,4 +41,6 @@ abstract class StudentComposeTest : StudentTest() { val calendarToDoCreateUpdatePage = CalendarToDoCreateUpdatePage(composeTestRule) val calendarToDoDetailsPage = CalendarToDoDetailsPage(composeTestRule) val calendarFilterPage = CalendarFilterPage(composeTestRule) + val settingsPage = SettingsPage(composeTestRule) + val reminderPage = ReminderPage(composeTestRule) } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentTest.kt index efdc4c2a85..71d00083bf 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentTest.kt @@ -36,6 +36,9 @@ import com.instructure.canvas.espresso.common.pages.InboxPage import com.instructure.espresso.InstructureActivityTestRule import com.instructure.espresso.ModuleItemInteractions import com.instructure.espresso.Searchable +import com.instructure.espresso.pages.common.LoginFindSchoolPage +import com.instructure.espresso.pages.common.LoginLandingPage +import com.instructure.espresso.pages.common.LoginSignInPage import com.instructure.espresso.swipeRight import com.instructure.pandautils.utils.Const import com.instructure.student.BuildConfig @@ -67,9 +70,6 @@ import com.instructure.student.ui.pages.ImportantDatesPage import com.instructure.student.ui.pages.InboxConversationPage import com.instructure.student.ui.pages.LeftSideNavigationDrawerPage import com.instructure.student.ui.pages.LegalPage -import com.instructure.student.ui.pages.LoginFindSchoolPage -import com.instructure.student.ui.pages.LoginLandingPage -import com.instructure.student.ui.pages.LoginSignInPage import com.instructure.student.ui.pages.ModuleProgressionPage import com.instructure.student.ui.pages.ModulesPage import com.instructure.student.ui.pages.NewMessagePage @@ -89,7 +89,6 @@ import com.instructure.student.ui.pages.QuizTakingPage import com.instructure.student.ui.pages.RemoteConfigSettingsPage import com.instructure.student.ui.pages.ResourcesPage import com.instructure.student.ui.pages.SchedulePage -import com.instructure.student.ui.pages.SettingsPage import com.instructure.student.ui.pages.ShareExtensionStatusPage import com.instructure.student.ui.pages.ShareExtensionTargetPage import com.instructure.student.ui.pages.StudentAssignmentDetailsPage @@ -164,7 +163,6 @@ abstract class StudentTest : CanvasTest() { val quizTakingPage = QuizTakingPage() val goToQuizPage = GoToQuizPage(ModuleItemInteractions(R.id.moduleName, R.id.next_item, R.id.prev_item)) val remoteConfigSettingsPage = RemoteConfigSettingsPage() - val settingsPage = SettingsPage() val pushNotificationsPage = PushNotificationsPage() val submissionDetailsPage = SubmissionDetailsPage() val textSubmissionUploadPage = TextSubmissionUploadPage() @@ -185,7 +183,7 @@ abstract class StudentTest : CanvasTest() { // A no-op interaction to afford us an easy, harmless way to get a11y checking to trigger. fun meaninglessSwipe() { - Espresso.onView(ViewMatchers.withId(R.id.action_bar_root)).swipeRight(); + Espresso.onView(ViewMatchers.withId(R.id.action_bar_root)).swipeRight() } // Get the number of files/avatars in our panda avatars folder diff --git a/apps/student/src/main/AndroidManifest.xml b/apps/student/src/main/AndroidManifest.xml index 360bcc3e0e..ec123b370f 100644 --- a/apps/student/src/main/AndroidManifest.xml +++ b/apps/student/src/main/AndroidManifest.xml @@ -117,10 +117,6 @@ android:theme="@style/PSPDFKitTheme" android:windowSoftInputMode="adjustNothing" /> - - diff --git a/apps/student/src/main/java/com/instructure/student/activity/BaseRouterActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/BaseRouterActivity.kt index 0bd5ea46d0..5b7ba7ef95 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/BaseRouterActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/BaseRouterActivity.kt @@ -177,7 +177,7 @@ abstract class BaseRouterActivity : CallbackActivity(), FullScreenInteractions { if (it.isLocked || it.isLockedForUser) { Toast.makeText(context, String.format(context.getString(R.string.fileLocked), if (it.displayName == null) getString(R.string.file) else it.displayName), Toast.LENGTH_LONG).show() } else { - openMedia(canvasContext, it.contentType.orEmpty(), it.url.orEmpty(), it.displayName.orEmpty()) + openMedia(canvasContext, it.contentType.orEmpty(), it.url.orEmpty(), it.displayName.orEmpty(), fileID) } } } @@ -195,7 +195,7 @@ abstract class BaseRouterActivity : CallbackActivity(), FullScreenInteractions { if (it.isLocked || it.isLockedForUser) { Toast.makeText(context, String.format(context.getString(R.string.fileLocked), if (it.displayName == null) getString(R.string.file) else it.displayName), Toast.LENGTH_LONG).show() } else { - openMedia(CanvasContext.emptyUserContext(), it.contentType.orEmpty(), it.url.orEmpty(), it.displayName.orEmpty()) + openMedia(CanvasContext.emptyUserContext(), it.contentType.orEmpty(), it.url.orEmpty(), it.displayName.orEmpty(), fileID) } } } @@ -204,14 +204,14 @@ abstract class BaseRouterActivity : CallbackActivity(), FullScreenInteractions { FileFolderManager.getFileFolderFromURL("files/$fileID", true, fileFolderCanvasCallback) } - fun openMedia(canvasContext: CanvasContext?, url: String) { - openMediaBundle = OpenMediaAsyncTaskLoader.createBundle(url, null, canvasContext) + fun openMedia(canvasContext: CanvasContext?, url: String, fileID: String?) { + openMediaBundle = OpenMediaAsyncTaskLoader.createBundle(url, null, fileID, canvasContext) LoaderUtils.restartLoaderWithBundle>( LoaderManager.getInstance(this), openMediaBundle, loaderCallbacks, R.id.openMediaLoaderID) } - fun openMedia(canvasContext: CanvasContext?, mime: String, url: String, filename: String) { - openMediaBundle = OpenMediaAsyncTaskLoader.createBundle(canvasContext, mime, url, filename) + fun openMedia(canvasContext: CanvasContext?, mime: String, url: String, filename: String, fileID: String?) { + openMediaBundle = OpenMediaAsyncTaskLoader.createBundle(canvasContext, mime, url, filename, fileID) LoaderUtils.restartLoaderWithBundle>( LoaderManager.getInstance(this), openMediaBundle, loaderCallbacks, R.id.openMediaLoaderID) } diff --git a/apps/student/src/main/java/com/instructure/student/activity/BookmarkShortcutActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/BookmarkShortcutActivity.kt index 5b08990801..4db6f66447 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/BookmarkShortcutActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/BookmarkShortcutActivity.kt @@ -19,7 +19,7 @@ package com.instructure.student.activity import android.content.Intent import android.graphics.BitmapFactory import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity +import com.instructure.pandautils.base.BaseCanvasActivity import com.instructure.canvasapi2.models.Bookmark import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.pandautils.analytics.SCREEN_VIEW_BOOKMARK_SHORTCUT @@ -34,7 +34,7 @@ import com.instructure.student.util.Analytics import com.instructure.student.util.ShortcutUtils @ScreenView(SCREEN_VIEW_BOOKMARK_SHORTCUT) -class BookmarkShortcutActivity : AppCompatActivity() { +class BookmarkShortcutActivity : BaseCanvasActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/apps/student/src/main/java/com/instructure/student/activity/CallbackActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/CallbackActivity.kt index 9d64ef0107..eaba1a72eb 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/CallbackActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/CallbackActivity.kt @@ -19,7 +19,6 @@ package com.instructure.student.activity import android.os.Bundle import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.heapanalytics.android.Heap import com.instructure.canvasapi2.StatusCallback import com.instructure.canvasapi2.managers.FeaturesManager import com.instructure.canvasapi2.managers.LaunchDefinitionsManager @@ -40,7 +39,7 @@ import com.instructure.canvasapi2.utils.APIHelper import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.ApiType import com.instructure.canvasapi2.utils.LinkHeaders -import com.instructure.canvasapi2.utils.LocaleUtils +import com.instructure.pandautils.utils.LocaleUtils import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.pageview.PandataInfo import com.instructure.canvasapi2.utils.pageview.PandataManager @@ -59,9 +58,12 @@ import com.instructure.pandautils.utils.toast import com.instructure.student.BuildConfig import com.instructure.student.R import com.instructure.student.fragment.NotificationListFragment +import com.instructure.student.router.EnabledTabs import com.instructure.student.service.StudentPageViewService import com.instructure.student.util.StudentPrefs import dagger.hilt.android.AndroidEntryPoint +import io.heap.autocapture.ViewAutocaptureSDK +import io.heap.core.Heap import kotlinx.coroutines.Job import retrofit2.Call import retrofit2.Response @@ -73,6 +75,9 @@ abstract class CallbackActivity : ParentActivity(), OnUnreadCountInvalidated, No @Inject lateinit var featureFlagProvider: FeatureFlagProvider + @Inject + lateinit var enabledTabs: EnabledTabs + private var loadInitialDataJob: Job? = null abstract fun gotLaunchDefinitions(launchDefinitions: List?) @@ -90,6 +95,9 @@ abstract class CallbackActivity : ParentActivity(), OnUnreadCountInvalidated, No loadInitialDataJob = tryWeave { setupHeapTracking() + // Get enabled tabs + enabledTabs.initTabs() + // Determine if user can masquerade if (ApiPrefs.canBecomeUser == null) { if (ApiPrefs.domain.startsWith("siteadmin", true)) { @@ -168,7 +176,13 @@ abstract class CallbackActivity : ParentActivity(), OnUnreadCountInvalidated, No private suspend fun setupHeapTracking() { val featureFlagsResult = FeaturesManager.getEnvironmentFeatureFlagsAsync(true).await().dataOrNull val sendUsageMetrics = featureFlagsResult?.get(FeaturesManager.SEND_USAGE_METRICS) ?: false - Heap.setTrackingEnabled(sendUsageMetrics) + if (sendUsageMetrics) { + Heap.startRecording(context.applicationContext, BuildConfig.HEAP_APP_ID) + ViewAutocaptureSDK.register() + } else { + Heap.stopRecording() + ViewAutocaptureSDK.deregister() + } } private suspend fun getUnreadMessageCount() { diff --git a/apps/student/src/main/java/com/instructure/student/activity/CandroidPSPDFActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/CandroidPSPDFActivity.kt index 2a1e341052..d9511eb8e3 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/CandroidPSPDFActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/CandroidPSPDFActivity.kt @@ -37,6 +37,7 @@ import com.instructure.pandautils.utils.NetworkStateProvider import com.instructure.pandautils.utils.ViewStyler import com.instructure.student.R import com.instructure.student.features.shareextension.StudentShareExtensionActivity +import com.pspdfkit.annotations.AnnotationType import com.pspdfkit.document.processor.PdfProcessorTask import com.pspdfkit.document.sharing.DefaultDocumentSharingController import com.pspdfkit.document.sharing.DocumentSharingIntentHelper @@ -48,7 +49,9 @@ import com.pspdfkit.ui.toolbar.ContextualToolbar import com.pspdfkit.ui.toolbar.ContextualToolbarMenuItem import com.pspdfkit.ui.toolbar.ToolbarCoordinatorLayout import dagger.hilt.android.AndroidEntryPoint -import java.util.* +import java.io.File +import java.util.EnumSet +import java.util.Locale import javax.inject.Inject @ScreenView(SCREEN_VIEW_PSPDFKIT) @@ -93,6 +96,24 @@ class CandroidPSPDFActivity : PdfActivity(), ToolbarCoordinatorLayout.OnContextu } } + + override fun onDestroy() { + val path = filesDir.path + intent.data?.path?.replace("/files", "") + document?.let { + val annotations = it.annotationProvider.getAllAnnotationsOfType( + EnumSet.allOf(AnnotationType::class.java) + ) + if (annotations.isEmpty()) { + val file = File(path) + if (file.exists()) { + file.delete() + } + } + } + + super.onDestroy() + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setOnContextualToolbarLifecycleListener(this) diff --git a/apps/student/src/main/java/com/instructure/student/activity/InterwebsToApplication.kt b/apps/student/src/main/java/com/instructure/student/activity/InterwebsToApplication.kt index 9f175cbc9a..1e0a3407f4 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/InterwebsToApplication.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/InterwebsToApplication.kt @@ -26,7 +26,7 @@ import android.util.Log import android.view.View import android.view.Window import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity +import com.instructure.pandautils.base.BaseCanvasActivity import com.instructure.canvasapi2.managers.OAuthManager import com.instructure.canvasapi2.models.AccountDomain import com.instructure.canvasapi2.utils.Analytics @@ -47,7 +47,8 @@ import com.instructure.pandautils.utils.Utils.generateUserAgent import com.instructure.student.R import com.instructure.student.databinding.InterwebsToApplicationBinding import com.instructure.student.databinding.LoadingCanvasViewBinding -import com.instructure.pandautils.features.assignments.details.reminder.AlarmScheduler +import com.instructure.pandautils.features.reminder.AlarmScheduler +import com.instructure.student.router.EnabledTabs import com.instructure.student.router.RouteMatcher import com.instructure.student.tasks.StudentLogoutTask import com.instructure.student.util.LoggingUtility @@ -57,7 +58,7 @@ import kotlinx.coroutines.delay import javax.inject.Inject @AndroidEntryPoint -class InterwebsToApplication : AppCompatActivity() { +class InterwebsToApplication : BaseCanvasActivity() { private val binding by viewBinding(InterwebsToApplicationBinding::inflate) private lateinit var loadingBinding: LoadingCanvasViewBinding @@ -71,6 +72,9 @@ class InterwebsToApplication : AppCompatActivity() { @Inject lateinit var alarmScheduler: AlarmScheduler + @Inject + lateinit var enabledTabs: EnabledTabs + private var loadingJob: Job? = null public override fun onCreate(savedInstanceState: Bundle?) { @@ -101,6 +105,9 @@ class InterwebsToApplication : AppCompatActivity() { loadingJob = tryWeave { val host = data.host.orEmpty() // example: "mobiledev.instructure.com" + RouteMatcher.enabledTabs = enabledTabs + enabledTabs.initTabs() + // Do some logging LoggingUtility.log(Log.WARN, data.toString()) @@ -200,6 +207,7 @@ class InterwebsToApplication : AppCompatActivity() { // Allow the UI to show delay(700) RouteMatcher.routeUrl(this@InterwebsToApplication, url, domain) + finish() } } catch { diff --git a/apps/student/src/main/java/com/instructure/student/activity/NavigationActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/NavigationActivity.kt index 709f6b6fb0..64a02a37ba 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/NavigationActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/NavigationActivity.kt @@ -60,7 +60,6 @@ import com.instructure.canvasapi2.models.StorageQuotaExceededError import com.instructure.canvasapi2.models.User import com.instructure.canvasapi2.utils.APIHelper import com.instructure.canvasapi2.utils.ApiPrefs -import com.instructure.canvasapi2.utils.LocaleUtils import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.MasqueradeHelper import com.instructure.canvasapi2.utils.Pronouns @@ -80,13 +79,16 @@ import com.instructure.loginapi.login.dialog.MasqueradingDialog import com.instructure.loginapi.login.tasks.LogoutTask import com.instructure.pandautils.analytics.OfflineAnalyticsManager import com.instructure.pandautils.binding.viewBinding -import com.instructure.pandautils.features.assignments.details.reminder.AlarmScheduler +import com.instructure.pandautils.features.reminder.AlarmScheduler +import com.instructure.pandautils.utils.LocaleUtils import com.instructure.pandautils.features.calendar.CalendarFragment import com.instructure.pandautils.features.calendarevent.details.EventFragment import com.instructure.pandautils.features.help.HelpDialogFragment import com.instructure.pandautils.features.inbox.list.InboxFragment +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.features.notification.preferences.PushNotificationPreferencesFragment import com.instructure.pandautils.features.offline.sync.OfflineSyncHelper +import com.instructure.pandautils.features.settings.SettingsFragment import com.instructure.pandautils.features.themeselector.ThemeSelectorBottomSheet import com.instructure.pandautils.interfaces.NavigationCallbacks import com.instructure.pandautils.models.PushNotification @@ -136,7 +138,6 @@ import com.instructure.student.fragment.DashboardFragment import com.instructure.student.fragment.InboxComposeMessageFragment import com.instructure.student.fragment.InboxConversationFragment import com.instructure.student.fragment.InboxRecipientsFragment -import com.instructure.student.fragment.LtiLaunchFragment import com.instructure.student.fragment.NotificationListFragment import com.instructure.student.fragment.ToDoListFragment import com.instructure.student.mobius.assignmentDetails.submission.picker.PickerSubmissionUploadEffectHandler @@ -145,6 +146,7 @@ import com.instructure.student.navigation.AccountMenuItem import com.instructure.student.navigation.NavigationBehavior import com.instructure.student.navigation.NavigationMenuItem import com.instructure.student.navigation.OptionsMenuItem +import com.instructure.student.router.EnabledTabs import com.instructure.student.router.RouteMatcher import com.instructure.student.router.RouteResolver import com.instructure.student.tasks.StudentLogoutTask @@ -215,6 +217,9 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. @Inject lateinit var offlineAnalyticsManager: OfflineAnalyticsManager + @Inject + lateinit var enabledCourseTabs: EnabledTabs + private var routeJob: WeaveJob? = null private var debounceJob: Job? = null private var drawerItemSelectedJob: Job? = null @@ -281,7 +286,11 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. R.id.navigationDrawerItem_stopMasquerading -> { MasqueradeHelper.stopMasquerading(startActivityClass) } - R.id.navigationDrawerSettings -> startActivity(SettingsActivity.createIntent(applicationContext, featureFlagProvider.offlineEnabled())) + R.id.navigationDrawerSettings -> { + val route = SettingsFragment.makeRoute(featureFlagProvider.offlineEnabled()) + val fragment = SettingsFragment.newInstance(route) + addFragment(fragment, route) + } } } } @@ -343,6 +352,7 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. super.onCreate(savedInstanceState) RouteMatcher.offlineDb = offlineDatabase RouteMatcher.networkStateProvider = networkStateProvider + RouteMatcher.enabledTabs = enabledCourseTabs navigationDrawerBinding = NavigationDrawerBinding.bind(binding.root) canvasLoadingBinding = LoadingCanvasViewBinding.bind(binding.root) setContentView(binding.root) @@ -912,7 +922,7 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. when { RouteContext.FILE == route.routeContext && route.secondaryClass != CourseModuleProgressionFragment::class.java -> { if (route.queryParamsHash.containsKey(RouterParams.VERIFIER) && route.queryParamsHash.containsKey(RouterParams.DOWNLOAD_FRD)) { - if(route.uri != null) openMedia(CanvasContext.getGenericContext(CanvasContext.Type.COURSE, contextId, ""), route.uri.toString()) + if(route.uri != null) openMedia(CanvasContext.getGenericContext(CanvasContext.Type.COURSE, contextId, ""), route.uri.toString(), null) } route.paramsHash[RouterParams.FILE_ID]?.let { handleSpecificFile(contextId, it) } diff --git a/apps/student/src/main/java/com/instructure/student/activity/SettingsActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/SettingsActivity.kt deleted file mode 100644 index edaed771de..0000000000 --- a/apps/student/src/main/java/com/instructure/student/activity/SettingsActivity.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2016 - present Instructure, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package com.instructure.student.activity - -import android.content.Context -import android.content.Intent -import android.content.res.Configuration -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment -import com.instructure.interactions.FragmentInteractions -import com.instructure.pandautils.analytics.SCREEN_VIEW_SETTINGS -import com.instructure.pandautils.analytics.ScreenView -import com.instructure.pandautils.binding.viewBinding -import com.instructure.pandautils.utils.NetworkStateProvider -import com.instructure.pandautils.utils.setVisible -import com.instructure.student.R -import com.instructure.student.databinding.ActivitySettingsBinding -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject - -private const val OFFLINE_ENABLED = "offlineEnabled" - -@ScreenView(SCREEN_VIEW_SETTINGS) -@AndroidEntryPoint -class SettingsActivity : AppCompatActivity(){ - - @Inject - lateinit var networkStateProvider: NetworkStateProvider - - private val binding by viewBinding(ActivitySettingsBinding::inflate) - - var offlineEnabled: Boolean = false - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - offlineEnabled = intent.getBooleanExtra(OFFLINE_ENABLED, false) - setContentView(binding.root) - networkStateProvider.isOnlineLiveData.observe(this) { isOnline -> - binding.offlineIndicator.root.setVisible(!isOnline) - } - } - - private val currentFragment: Fragment? get() = supportFragmentManager.fragments.last() - - override fun onConfigurationChanged(newConfig: Configuration) { - super.onConfigurationChanged(newConfig) - applyThemeForAllFragments() - } - - private fun applyThemeForAllFragments() { - supportFragmentManager.fragments.forEach { - (it as? FragmentInteractions)?.applyTheme() - } - } - - fun addFragment(fragment: Fragment) { - val ft = supportFragmentManager.beginTransaction() - currentFragment?.let { ft.hide(it) } - ft.add(R.id.fragmentContainer, fragment, fragment.javaClass.name) - ft.addToBackStack(fragment.javaClass.name) - ft.commitAllowingStateLoss() - } - - companion object { - fun createIntent(context: Context, offlineEnabled: Boolean): Intent { - return Intent(context, SettingsActivity::class.java).apply { - putExtra(OFFLINE_ENABLED, offlineEnabled) - } - } - } -} diff --git a/apps/student/src/main/java/com/instructure/student/activity/StudentViewStarterActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/StudentViewStarterActivity.kt index 135dd7252c..a239d14896 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/StudentViewStarterActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/StudentViewStarterActivity.kt @@ -16,7 +16,7 @@ package com.instructure.student.activity import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity +import com.instructure.pandautils.base.BaseCanvasActivity import androidx.core.content.ContextCompat import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.MasqueradeHelper @@ -30,7 +30,7 @@ import com.instructure.student.databinding.ActivityStudentViewStarterBinding // The sole purpose of this activity is to capture the intent from the Teacher app that signals the Student app // to start the Student view @ScreenView(SCREEN_VIEW_STUDENT_VIEW) -class StudentViewStarterActivity : AppCompatActivity() { +class StudentViewStarterActivity : BaseCanvasActivity() { private val binding by viewBinding(ActivityStudentViewStarterBinding::inflate) diff --git a/apps/student/src/main/java/com/instructure/student/activity/VideoViewActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/VideoViewActivity.kt index ac391875ef..01b15b7f99 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/VideoViewActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/VideoViewActivity.kt @@ -22,7 +22,7 @@ import android.net.Uri import android.os.Bundle import android.os.Handler import androidx.annotation.OptIn -import androidx.appcompat.app.AppCompatActivity +import com.instructure.pandautils.base.BaseCanvasActivity import androidx.media3.common.C import androidx.media3.common.MediaItem import androidx.media3.common.util.UnstableApi @@ -55,7 +55,7 @@ import com.instructure.student.util.Const @OptIn(UnstableApi::class) @ScreenView(SCREEN_VIEW_VIDEO_VIEW) -class VideoViewActivity : AppCompatActivity() { +class VideoViewActivity : BaseCanvasActivity() { private val binding by viewBinding(ActivityVideoViewBinding::inflate) diff --git a/apps/student/src/main/java/com/instructure/student/activity/WidgetSetupActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/WidgetSetupActivity.kt index 9ae8c38975..854414036b 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/WidgetSetupActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/WidgetSetupActivity.kt @@ -21,14 +21,14 @@ import android.appwidget.AppWidgetManager import android.content.Intent import android.os.Bundle import android.view.View -import androidx.appcompat.app.AppCompatActivity +import com.instructure.pandautils.base.BaseCanvasActivity import com.instructure.pandautils.binding.viewBinding import com.instructure.student.R import com.instructure.student.databinding.ActivityWidgetSetupBinding import com.instructure.student.util.StudentPrefs import com.instructure.student.widget.WidgetUpdater.updateWidgets -class WidgetSetupActivity : AppCompatActivity() { +class WidgetSetupActivity : BaseCanvasActivity() { private val binding by viewBinding(ActivityWidgetSetupBinding::inflate) diff --git a/apps/student/src/main/java/com/instructure/student/di/ApplicationModule.kt b/apps/student/src/main/java/com/instructure/student/di/ApplicationModule.kt index 38d3f681b2..04cdd7f71e 100644 --- a/apps/student/src/main/java/com/instructure/student/di/ApplicationModule.kt +++ b/apps/student/src/main/java/com/instructure/student/di/ApplicationModule.kt @@ -18,12 +18,16 @@ package com.instructure.student.di +import com.instructure.canvasapi2.apis.CourseAPI import com.instructure.pandautils.utils.LogoutHelper +import com.instructure.student.router.EnabledTabs +import com.instructure.student.router.EnabledTabsImpl import com.instructure.student.util.StudentLogoutHelper import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) @@ -33,4 +37,10 @@ class ApplicationModule { fun provideLogoutHelper(): LogoutHelper { return StudentLogoutHelper() } + + @Provides + @Singleton + fun provideEnabledTabs(courseApi: CourseAPI.CoursesInterface): EnabledTabs { + return EnabledTabsImpl(courseApi) + } } \ No newline at end of file diff --git a/apps/student/src/main/java/com/instructure/student/di/DiscussionModule.kt b/apps/student/src/main/java/com/instructure/student/di/DiscussionModule.kt index d93219c4f0..46ff2e9746 100644 --- a/apps/student/src/main/java/com/instructure/student/di/DiscussionModule.kt +++ b/apps/student/src/main/java/com/instructure/student/di/DiscussionModule.kt @@ -1,8 +1,10 @@ package com.instructure.student.di import androidx.fragment.app.FragmentActivity +import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragmentBehavior import com.instructure.pandautils.features.discussion.router.DiscussionRouter import com.instructure.pandautils.utils.NetworkStateProvider +import com.instructure.student.features.discussion.details.StudentDiscussionDetailsWebViewFragmentBehavior import com.instructure.student.features.discussion.routing.StudentDiscussionRouter import dagger.Module import dagger.Provides @@ -17,4 +19,9 @@ class DiscussionModule { fun provideDiscussionRouter(fragmentActivity: FragmentActivity, networkStateProvider: NetworkStateProvider): DiscussionRouter { return StudentDiscussionRouter(fragmentActivity, networkStateProvider) } -} \ No newline at end of file + + @Provides + fun provideDiscussionWebViewFragmentBehavior(): DiscussionDetailsWebViewFragmentBehavior { + return StudentDiscussionDetailsWebViewFragmentBehavior() + } +} diff --git a/apps/student/src/main/java/com/instructure/student/di/LoginModule.kt b/apps/student/src/main/java/com/instructure/student/di/LoginModule.kt index 2cc049cb0d..d325fcb0fb 100644 --- a/apps/student/src/main/java/com/instructure/student/di/LoginModule.kt +++ b/apps/student/src/main/java/com/instructure/student/di/LoginModule.kt @@ -20,7 +20,7 @@ import androidx.fragment.app.FragmentActivity import com.instructure.loginapi.login.LoginNavigation import com.instructure.loginapi.login.features.acceptableusepolicy.AcceptableUsePolicyRouter import com.instructure.pandautils.room.offline.DatabaseProvider -import com.instructure.pandautils.features.assignments.details.reminder.AlarmScheduler +import com.instructure.pandautils.features.reminder.AlarmScheduler import com.instructure.student.features.login.StudentAcceptableUsePolicyRouter import com.instructure.student.features.login.StudentLoginNavigation import dagger.Module diff --git a/apps/student/src/main/java/com/instructure/student/di/feature/LtiLaunchModule.kt b/apps/student/src/main/java/com/instructure/student/di/feature/LtiLaunchModule.kt new file mode 100644 index 0000000000..f6266ceca4 --- /dev/null +++ b/apps/student/src/main/java/com/instructure/student/di/feature/LtiLaunchModule.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.instructure.student.di.feature + +import androidx.fragment.app.Fragment +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.pandautils.features.lti.LtiLaunchFragmentBehavior +import com.instructure.pandautils.utils.Const +import com.instructure.student.features.lti.StudentLtiLaunchFragmentBehavior +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.FragmentComponent + +@Module +@InstallIn(FragmentComponent::class) +class LtiLaunchModule { + + @Provides + fun provideLtiLaunchFragmentBehavior(fragment: Fragment): LtiLaunchFragmentBehavior { + val canvasContext = fragment.arguments?.getParcelable(Const.CANVAS_CONTEXT) ?: CanvasContext.emptyUserContext() + return StudentLtiLaunchFragmentBehavior(canvasContext) + } +} \ No newline at end of file diff --git a/apps/student/src/main/java/com/instructure/student/di/feature/SettingsModule.kt b/apps/student/src/main/java/com/instructure/student/di/feature/SettingsModule.kt index ec2906477d..b2337c95be 100644 --- a/apps/student/src/main/java/com/instructure/student/di/feature/SettingsModule.kt +++ b/apps/student/src/main/java/com/instructure/student/di/feature/SettingsModule.kt @@ -15,24 +15,37 @@ */ package com.instructure.student.di.feature +import android.content.Context +import androidx.fragment.app.FragmentActivity +import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.pandautils.features.settings.SettingsBehaviour import com.instructure.pandautils.features.settings.SettingsRouter +import com.instructure.student.features.settings.StudentSettingsBehaviour +import com.instructure.student.features.settings.StudentSettingsRouter import dagger.Module import dagger.Provides import dagger.hilt.InstallIn +import dagger.hilt.android.components.ActivityComponent +import dagger.hilt.android.components.FragmentComponent +import dagger.hilt.android.components.ViewModelComponent +import dagger.hilt.android.qualifiers.ActivityContext import dagger.hilt.components.SingletonComponent @Module -@InstallIn(SingletonComponent::class) -class SettingsModule { - +@InstallIn(FragmentComponent::class) +class SettingsRouterModule{ @Provides - fun provideSettingsRouter(): SettingsRouter { - throw NotImplementedError("Not implemented") + fun provideSettingsRouter(activity: FragmentActivity): SettingsRouter { + return StudentSettingsRouter(activity) } +} + +@Module +@InstallIn(ViewModelComponent::class) +class SettingsModule { @Provides - fun provideSettingsBehavior(): SettingsBehaviour { - throw NotImplementedError("Not implemented") + fun provideSettingsBehavior(apiPrefs: ApiPrefs): SettingsBehaviour { + return StudentSettingsBehaviour(apiPrefs) } } \ No newline at end of file diff --git a/apps/student/src/main/java/com/instructure/student/di/feature/SmartSearchModule.kt b/apps/student/src/main/java/com/instructure/student/di/feature/SmartSearchModule.kt new file mode 100644 index 0000000000..a151908ff4 --- /dev/null +++ b/apps/student/src/main/java/com/instructure/student/di/feature/SmartSearchModule.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.instructure.student.di.feature + +import androidx.fragment.app.FragmentActivity +import com.instructure.pandautils.features.smartsearch.SmartSearchRouter +import com.instructure.student.features.smartsearch.StudentSmartSearchRouter +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.FragmentComponent + +@Module +@InstallIn(FragmentComponent::class) +class SmartSearchModule { + + @Provides + fun provideSmartSearchRouter(activity: FragmentActivity): SmartSearchRouter { + return StudentSmartSearchRouter(activity) + } +} \ No newline at end of file diff --git a/apps/student/src/main/java/com/instructure/student/dialog/AskInstructorDialogStyled.kt b/apps/student/src/main/java/com/instructure/student/dialog/AskInstructorDialogStyled.kt index 795617dfc4..5487f28aa2 100644 --- a/apps/student/src/main/java/com/instructure/student/dialog/AskInstructorDialogStyled.kt +++ b/apps/student/src/main/java/com/instructure/student/dialog/AskInstructorDialogStyled.kt @@ -29,7 +29,7 @@ import android.view.ViewGroup import android.widget.* import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.AppCompatEditText -import androidx.fragment.app.DialogFragment +import com.instructure.pandautils.base.BaseCanvasDialogFragment import com.instructure.canvasapi2.apis.UserAPI import com.instructure.canvasapi2.managers.CourseManager.getAllFavoriteCourses import com.instructure.canvasapi2.managers.InboxManager.createConversation @@ -51,7 +51,7 @@ import com.instructure.student.R import com.instructure.student.dialog.FatalErrorDialogStyled.Companion.newInstance @ScreenView(SCREEN_VIEW_ASK_INSTRUCTOR) -class AskInstructorDialogStyled : DialogFragment() { +class AskInstructorDialogStyled : BaseCanvasDialogFragment() { // Data private var courseList: List = emptyList() diff --git a/apps/student/src/main/java/com/instructure/student/dialog/BookmarkCreationDialog.kt b/apps/student/src/main/java/com/instructure/student/dialog/BookmarkCreationDialog.kt index 2f8fc8b382..d002079b9b 100644 --- a/apps/student/src/main/java/com/instructure/student/dialog/BookmarkCreationDialog.kt +++ b/apps/student/src/main/java/com/instructure/student/dialog/BookmarkCreationDialog.kt @@ -25,7 +25,6 @@ import android.view.View import android.view.inputmethod.InputMethodManager import android.widget.Toast import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatDialogFragment import androidx.appcompat.view.ContextThemeWrapper import androidx.appcompat.widget.AppCompatEditText import androidx.fragment.app.Fragment @@ -38,6 +37,7 @@ import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.interactions.bookmarks.Bookmarkable import com.instructure.pandautils.analytics.SCREEN_VIEW_BOOKMARK_CREATION import com.instructure.pandautils.analytics.ScreenView +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.ViewStyler import com.instructure.pandautils.utils.color @@ -49,7 +49,7 @@ import com.instructure.student.util.CacheControlFlags import kotlinx.coroutines.Job @ScreenView(SCREEN_VIEW_BOOKMARK_CREATION) -class BookmarkCreationDialog : AppCompatDialogFragment() { +class BookmarkCreationDialog : BaseCanvasAppCompatDialogFragment() { private var bookmarkJob: Job? = null private var bookmarkEditText: AppCompatEditText? = null diff --git a/apps/student/src/main/java/com/instructure/student/dialog/EditTextDialog.kt b/apps/student/src/main/java/com/instructure/student/dialog/EditTextDialog.kt index 1cf2d568e4..55a65fa4fb 100644 --- a/apps/student/src/main/java/com/instructure/student/dialog/EditTextDialog.kt +++ b/apps/student/src/main/java/com/instructure/student/dialog/EditTextDialog.kt @@ -21,7 +21,7 @@ import android.os.Bundle import android.view.WindowManager import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.fragment.app.FragmentManager import com.instructure.pandautils.utils.StringArg import com.instructure.pandautils.utils.ThemePrefs @@ -31,7 +31,7 @@ import com.instructure.student.databinding.DialogEditTextBinding import java.util.* import kotlin.properties.Delegates -class EditTextDialog : AppCompatDialogFragment() { +class EditTextDialog : BaseCanvasAppCompatDialogFragment() { private var mEditTextCallback: (String) -> Unit by Delegates.notNull() private var mDefaultText by StringArg() diff --git a/apps/student/src/main/java/com/instructure/student/dialog/FatalErrorDialogStyled.kt b/apps/student/src/main/java/com/instructure/student/dialog/FatalErrorDialogStyled.kt index b71d382d3f..bffc0686f2 100644 --- a/apps/student/src/main/java/com/instructure/student/dialog/FatalErrorDialogStyled.kt +++ b/apps/student/src/main/java/com/instructure/student/dialog/FatalErrorDialogStyled.kt @@ -20,7 +20,7 @@ package com.instructure.student.dialog import android.app.Dialog import android.os.Bundle import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.DialogFragment +import com.instructure.pandautils.base.BaseCanvasDialogFragment import com.instructure.pandautils.analytics.SCREEN_VIEW_FATAL_ERROR import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.ThemePrefs @@ -28,7 +28,7 @@ import com.instructure.pandautils.utils.nonNullArgs import com.instructure.student.R @ScreenView(SCREEN_VIEW_FATAL_ERROR) -class FatalErrorDialogStyled : DialogFragment() { +class FatalErrorDialogStyled : BaseCanvasDialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { diff --git a/apps/student/src/main/java/com/instructure/student/dialog/UnsavedChangesExitDialog.kt b/apps/student/src/main/java/com/instructure/student/dialog/UnsavedChangesExitDialog.kt index 64b14d06d5..ee7e4ddbd7 100644 --- a/apps/student/src/main/java/com/instructure/student/dialog/UnsavedChangesExitDialog.kt +++ b/apps/student/src/main/java/com/instructure/student/dialog/UnsavedChangesExitDialog.kt @@ -18,14 +18,14 @@ package com.instructure.student.dialog import android.app.Dialog import android.os.Bundle import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.fragment.app.FragmentManager import com.instructure.pandautils.utils.BlindSerializableArg import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.dismissExisting import com.instructure.student.R -class UnsavedChangesExitDialog : AppCompatDialogFragment() { +class UnsavedChangesExitDialog : BaseCanvasAppCompatDialogFragment() { private var callback: (() -> Unit)? by BlindSerializableArg() diff --git a/apps/student/src/main/java/com/instructure/student/dialog/WhatIfDialogStyled.kt b/apps/student/src/main/java/com/instructure/student/dialog/WhatIfDialogStyled.kt index 2ebff9c9bc..1e73a1c8a0 100644 --- a/apps/student/src/main/java/com/instructure/student/dialog/WhatIfDialogStyled.kt +++ b/apps/student/src/main/java/com/instructure/student/dialog/WhatIfDialogStyled.kt @@ -24,7 +24,7 @@ import android.view.LayoutInflater import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.AppCompatEditText -import androidx.fragment.app.DialogFragment +import com.instructure.pandautils.base.BaseCanvasDialogFragment import androidx.fragment.app.FragmentManager import com.instructure.canvasapi2.models.Assignment import com.instructure.pandautils.analytics.SCREEN_VIEW_WHAT_IF @@ -35,7 +35,7 @@ import com.instructure.student.R import kotlin.properties.Delegates @ScreenView(SCREEN_VIEW_WHAT_IF) -class WhatIfDialogStyled : DialogFragment() { +class WhatIfDialogStyled : BaseCanvasDialogFragment() { private var callback: (Double?, Double) -> Unit by Delegates.notNull() private var assignment: Assignment by ParcelableArg() diff --git a/apps/student/src/main/java/com/instructure/student/features/assignments/details/StudentAssignmentDetailsBehaviour.kt b/apps/student/src/main/java/com/instructure/student/features/assignments/details/StudentAssignmentDetailsBehaviour.kt index cdb2d9065d..2e5b61a000 100644 --- a/apps/student/src/main/java/com/instructure/student/features/assignments/details/StudentAssignmentDetailsBehaviour.kt +++ b/apps/student/src/main/java/com/instructure/student/features/assignments/details/StudentAssignmentDetailsBehaviour.kt @@ -38,6 +38,7 @@ import com.instructure.pandautils.features.assignments.details.AssignmentDetails import com.instructure.pandautils.features.assignments.details.AssignmentDetailsRouter import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.ViewStyler +import com.instructure.pandautils.utils.color import com.instructure.pandautils.utils.setVisible import com.instructure.pandautils.utils.setupAsBackButton import com.instructure.pandautils.utils.toast @@ -236,4 +237,8 @@ class StudentAssignmentDetailsBehaviour ( } return false } + + override fun getThemeColor(course: Course): Int { + return course.color + } } \ No newline at end of file diff --git a/apps/student/src/main/java/com/instructure/student/features/assignments/details/StudentAssignmentDetailsRouter.kt b/apps/student/src/main/java/com/instructure/student/features/assignments/details/StudentAssignmentDetailsRouter.kt index 042543792b..bc50fa1916 100644 --- a/apps/student/src/main/java/com/instructure/student/features/assignments/details/StudentAssignmentDetailsRouter.kt +++ b/apps/student/src/main/java/com/instructure/student/features/assignments/details/StudentAssignmentDetailsRouter.kt @@ -27,9 +27,9 @@ import com.instructure.canvasapi2.utils.Analytics import com.instructure.canvasapi2.utils.AnalyticsEventConstants import com.instructure.pandautils.features.assignments.details.AssignmentDetailsRouter import com.instructure.pandautils.features.discussion.router.DiscussionRouterFragment +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.student.activity.BaseRouterActivity import com.instructure.student.fragment.BasicQuizViewFragment -import com.instructure.student.fragment.LtiLaunchFragment import com.instructure.student.mobius.assignmentDetails.submission.annnotation.AnnotationSubmissionUploadFragment import com.instructure.student.mobius.assignmentDetails.submission.file.ui.UploadStatusSubmissionFragment import com.instructure.student.mobius.assignmentDetails.submission.picker.PickerSubmissionMode @@ -154,7 +154,8 @@ class StudentAssignmentDetailsRouter: AssignmentDetailsRouter() { title: String?, sessionLessLaunch: Boolean, isAssignmentLTI: Boolean, - ltiTool: LTITool? + ltiTool: LTITool?, + openInternally: Boolean ) { RouteMatcher.route( activity, @@ -163,8 +164,9 @@ class StudentAssignmentDetailsRouter: AssignmentDetailsRouter() { url, title, sessionLessLaunch = sessionLessLaunch, - isAssignmentLTI = isAssignmentLTI, - ltiTool = ltiTool + assignmentLti = isAssignmentLTI, + ltiTool = ltiTool, + openInternally = openInternally ) ) } @@ -178,7 +180,8 @@ class StudentAssignmentDetailsRouter: AssignmentDetailsRouter() { canvasContext, attachment.contentType.orEmpty(), attachment.url.orEmpty(), - attachment.fileName.orEmpty() + attachment.fileName.orEmpty(), + attachment.id.toString() ) } diff --git a/apps/student/src/main/java/com/instructure/student/features/assignments/details/receiver/StudentAlarmReceiverNotificationHandler.kt b/apps/student/src/main/java/com/instructure/student/features/assignments/details/receiver/StudentAlarmReceiverNotificationHandler.kt index 1a13b8072a..b3f02212be 100644 --- a/apps/student/src/main/java/com/instructure/student/features/assignments/details/receiver/StudentAlarmReceiverNotificationHandler.kt +++ b/apps/student/src/main/java/com/instructure/student/features/assignments/details/receiver/StudentAlarmReceiverNotificationHandler.kt @@ -29,10 +29,10 @@ import com.instructure.student.R import com.instructure.student.activity.NavigationActivity class StudentAlarmReceiverNotificationHandler: AlarmReceiverNotificationHandler { - override fun showNotification(context: Context, assignmentId: Long, assignmentPath: String, assignmentName: String, dueIn: String) { + override fun showNotification(context: Context, contentId: Long, htmlPath: String, title: String, message: String) { val intent = Intent(context, NavigationActivity.startActivityClass).apply { putExtra(Const.LOCAL_NOTIFICATION, true) - putExtra(PushNotification.HTML_URL, assignmentPath) + putExtra(PushNotification.HTML_URL, htmlPath) } val pendingIntent = PendingIntent.getActivity( @@ -42,14 +42,14 @@ class StudentAlarmReceiverNotificationHandler: AlarmReceiverNotificationHandler val builder = NotificationCompat.Builder(context, AlarmReceiver.CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification_canvas_logo) - .setContentTitle(context.getString(R.string.reminderNotificationTitle)) - .setContentText(context.getString(R.string.reminderNotificationDescription, dueIn, assignmentName)) + .setContentTitle(title) + .setContentText(message) .setAutoCancel(true) .setContentIntent(pendingIntent) .setPriority(NotificationCompat.PRIORITY_DEFAULT) val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - notificationManager.notify(assignmentId.toInt(), builder.build()) + notificationManager.notify(contentId.toInt(), builder.build()) } override fun createNotificationChannel(context: Context) { diff --git a/apps/student/src/main/java/com/instructure/student/features/assignments/list/AssignmentListFragment.kt b/apps/student/src/main/java/com/instructure/student/features/assignments/list/AssignmentListFragment.kt index f77c7fa268..b63e4965b1 100644 --- a/apps/student/src/main/java/com/instructure/student/features/assignments/list/AssignmentListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/assignments/list/AssignmentListFragment.kt @@ -37,6 +37,7 @@ import com.instructure.canvasapi2.models.GradingPeriod import com.instructure.canvasapi2.utils.Analytics import com.instructure.canvasapi2.utils.AnalyticsEventConstants import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.interactions.bookmarks.Bookmarkable import com.instructure.interactions.bookmarks.Bookmarker import com.instructure.interactions.router.Route @@ -84,7 +85,8 @@ class AssignmentListFragment : ParentFragment(), Bookmarkable { private val binding by viewBinding(AssignmentListLayoutBinding::bind) - private var canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private var recyclerAdapter: AssignmentListRecyclerAdapter? = null private var termAdapter: TermSpinnerAdapter? = null @@ -146,6 +148,7 @@ class AssignmentListFragment : ParentFragment(), Bookmarkable { inflater.inflate(R.layout.assignment_list_layout, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) recyclerAdapter = createRecyclerAdapter() binding.sortByTextView.setText(sortOrder.buttonTextRes) diff --git a/apps/student/src/main/java/com/instructure/student/features/calendar/StudentCalendarRouter.kt b/apps/student/src/main/java/com/instructure/student/features/calendar/StudentCalendarRouter.kt index 55257f42cc..20dc7902a0 100644 --- a/apps/student/src/main/java/com/instructure/student/features/calendar/StudentCalendarRouter.kt +++ b/apps/student/src/main/java/com/instructure/student/features/calendar/StudentCalendarRouter.kt @@ -21,6 +21,7 @@ import androidx.fragment.app.FragmentActivity import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.PlannerItem import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment import com.instructure.pandautils.features.calendar.CalendarFragment import com.instructure.pandautils.features.calendar.CalendarRouter import com.instructure.pandautils.features.calendarevent.createupdate.CreateUpdateEventFragment @@ -29,7 +30,6 @@ import com.instructure.pandautils.features.calendartodo.createupdate.CreateUpdat import com.instructure.pandautils.features.calendartodo.details.ToDoFragment import com.instructure.pandautils.features.discussion.router.DiscussionRouterFragment import com.instructure.student.activity.NavigationActivity -import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment import com.instructure.student.fragment.BasicQuizViewFragment import com.instructure.student.router.RouteMatcher diff --git a/apps/student/src/main/java/com/instructure/student/features/coursebrowser/CourseBrowserFragment.kt b/apps/student/src/main/java/com/instructure/student/features/coursebrowser/CourseBrowserFragment.kt index 684cca0837..41cb2303db 100644 --- a/apps/student/src/main/java/com/instructure/student/features/coursebrowser/CourseBrowserFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/coursebrowser/CourseBrowserFragment.kt @@ -23,7 +23,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.stringResource import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import com.google.android.material.appbar.AppBarLayout import com.instructure.canvasapi2.models.CanvasContext @@ -32,6 +35,7 @@ import com.instructure.canvasapi2.models.Group import com.instructure.canvasapi2.models.Tab import com.instructure.canvasapi2.utils.isValid import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.weave.StatusCallbackError import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave @@ -41,6 +45,10 @@ import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_COURSE_BROWSER import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.binding.viewBinding +import com.instructure.pandautils.compose.composables.SearchBar +import com.instructure.pandautils.base.BaseCanvasFragment +import com.instructure.pandautils.compose.CanvasTheme +import com.instructure.pandautils.features.smartsearch.SmartSearchFragment import com.instructure.pandautils.utils.ParcelableArg import com.instructure.pandautils.utils.ViewStyler import com.instructure.pandautils.utils.a11yManager @@ -51,6 +59,7 @@ import com.instructure.pandautils.utils.setCourseImage import com.instructure.pandautils.utils.setVisible import com.instructure.pandautils.utils.setupAsBackButton import com.instructure.pandautils.utils.toast +import com.instructure.student.BuildConfig import com.instructure.student.R import com.instructure.student.adapter.CourseBrowserAdapter import com.instructure.student.databinding.FragmentCourseBrowserBinding @@ -70,7 +79,8 @@ import javax.inject.Inject @ScreenView(SCREEN_VIEW_COURSE_BROWSER) @PageView(url = "{canvasContext}") @AndroidEntryPoint -class CourseBrowserFragment : Fragment(), FragmentInteractions, AppBarLayout.OnOffsetChangedListener { +class CourseBrowserFragment : BaseCanvasFragment(), FragmentInteractions, + AppBarLayout.OnOffsetChangedListener { @Inject lateinit var repository: CourseBrowserRepository @@ -79,18 +89,57 @@ class CourseBrowserFragment : Fragment(), FragmentInteractions, AppBarLayout.OnO private var apiCalls: Job? = null - private var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) override val navigation: Navigation? get() = if (activity is Navigation) activity as Navigation else null //region Fragment Lifecycle Overrides - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? = inflater.inflate(R.layout.fragment_course_browser, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) = with(binding) { super.onViewCreated(view, savedInstanceState) + searchBar.apply { + setContent { + CanvasTheme { + SearchBar( + icon = R.drawable.ic_smart_search, + tintColor = colorResource(R.color.textLightest), + placeholder = stringResource(R.string.smartSearchPlaceholder), + onExpand = { expanded -> + overlayToolbar.background = + if (expanded) ColorDrawable(canvasContext.color) else null + overlayToolbar.navigationIcon = + if (expanded) { + null + } else { + ContextCompat.getDrawable( + requireContext(), + R.drawable.ic_back_arrow + ) + } + ViewStyler.colorToolbarIconsAndText( + requireActivity(), + overlayToolbar, + requireContext().getColor(R.color.textLightest) + ) + }, + onSearch = { query -> + RouteMatcher.route(requireActivity(), SmartSearchFragment.makeRoute(canvasContext, query)) + }, + collapseOnSearch = true + ) + } + } + } + appBarLayout.addOnOffsetChangedListener(this@CourseBrowserFragment) collapsingToolbarLayout.isTitleEnabled = false @@ -99,7 +148,10 @@ class CourseBrowserFragment : Fragment(), FragmentInteractions, AppBarLayout.OnO (canvasContext as? Course)?.let { courseImage.setCourseImage(it, it.color, !StudentPrefs.hideCourseColorOverlay) courseBrowserSubtitle.text = it.term?.name ?: "" - binding.courseBrowserHeader.courseBrowserHeader.setTitleAndSubtitle(it.name, it.term?.name ?: "") + binding.courseBrowserHeader.courseBrowserHeader.setTitleAndSubtitle( + it.name, + it.term?.name ?: "" + ) } (canvasContext as? Group)?.let { @@ -194,7 +246,7 @@ class CourseBrowserFragment : Fragment(), FragmentInteractions, AppBarLayout.OnO ViewStyler.setStatusBarDark(requireActivity(), canvasContext.color) } - override fun getFragment(): Fragment? = this + override fun getFragment(): Fragment = this override fun title(): String = canvasContext.name ?: "" //endregion @@ -216,34 +268,39 @@ class CourseBrowserFragment : Fragment(), FragmentInteractions, AppBarLayout.OnO val tabs = repository.getTabs(canvasContext, isRefresh) + //TODO: Remove the debug flag when the search tab is ready + binding.searchBar.setVisible(BuildConfig.IS_DEBUG && tabs.find { it.tabId == Tab.SEARCH_ID } != null) + // Finds the home tab so we can reorder them if necessary - val sortedTabs = tabs.toMutableList() + val sortedTabs = tabs.filter { it.tabId != Tab.SEARCH_ID }.toMutableList() sortedTabs.sortBy { if (TabHelper.isHomeTab(it)) -1 else 1 } - courseBrowserRecyclerView.adapter = CourseBrowserAdapter(sortedTabs, canvasContext, homePageTitle) { tab -> - if (isHomeAPage && TabHelper.isHomeTab(tab, canvasContext as Course)) { - // Load Pages List - if (tabs.any { it.tabId == Tab.PAGES_ID }) { - // Do not load the pages list if the tab is hidden or locked. - val route = TabHelper.getRouteByTabId(tab, canvasContext) - route?.arguments = route?.arguments?.apply { + courseBrowserRecyclerView.adapter = + CourseBrowserAdapter(sortedTabs, canvasContext, homePageTitle) { tab -> + if (isHomeAPage && TabHelper.isHomeTab(tab, canvasContext as Course)) { + // Load Pages List + if (tabs.any { it.tabId == Tab.PAGES_ID }) { + // Do not load the pages list if the tab is hidden or locked. + val route = TabHelper.getRouteByTabId(tab, canvasContext) + route?.arguments = route?.arguments?.apply { + putString(PageDetailsFragment.PAGE_NAME, homePageTitle) + } ?: Bundle() + RouteMatcher.route(requireActivity(), route) + } + + // If the home tab is a Page and we clicked it lets route directly there. + val route = PageDetailsFragment.makeFrontPageRoute(canvasContext) + .apply { ignoreDebounce = true } + route.arguments = route.arguments.apply { putString(PageDetailsFragment.PAGE_NAME, homePageTitle) - } ?: Bundle() + } + RouteMatcher.route(requireActivity(), route) + } else { + val route = TabHelper.getRouteByTabId(tab, canvasContext) + ?.apply { ignoreDebounce = true } RouteMatcher.route(requireActivity(), route) } - - // If the home tab is a Page and we clicked it lets route directly there. - val route = PageDetailsFragment.makeFrontPageRoute(canvasContext) - .apply { ignoreDebounce = true } - route.arguments = route.arguments.apply { - putString(PageDetailsFragment.PAGE_NAME, homePageTitle) - } - RouteMatcher.route(requireActivity(), route) - } else { - val route = TabHelper.getRouteByTabId(tab, canvasContext)?.apply { ignoreDebounce = true } - RouteMatcher.route(requireActivity(), route) } - } swipeRefreshLayout.isRefreshing = false } catch { @@ -264,18 +321,24 @@ class CourseBrowserFragment : Fragment(), FragmentInteractions, AppBarLayout.OnO override fun onOffsetChanged(appBarLayout: AppBarLayout?, verticalOffset: Int) { if (view == null) return - val percentage = Math.abs(verticalOffset).div(appBarLayout?.totalScrollRange?.toFloat() ?: 1F) + val percentage = + Math.abs(verticalOffset).div(appBarLayout?.totalScrollRange?.toFloat() ?: 1F) if (percentage <= 0.3F) { val toolbarAnimation = - if (binding.courseBrowserHeader.courseBrowserHeader == null) null else ObjectAnimator.ofFloat( + ObjectAnimator.ofFloat( binding.courseBrowserHeader.courseBrowserHeader, View.ALPHA, binding.courseBrowserHeader.courseBrowserHeader.alpha, 0F ) val titleAnimation = - ObjectAnimator.ofFloat(binding.courseBrowserTitle, View.ALPHA, binding.courseBrowserTitle.alpha, 1F) + ObjectAnimator.ofFloat( + binding.courseBrowserTitle, + View.ALPHA, + binding.courseBrowserTitle.alpha, + 1F + ) val subtitleAnimation = ObjectAnimator.ofFloat( binding.courseBrowserSubtitle, View.ALPHA, @@ -301,14 +364,19 @@ class CourseBrowserFragment : Fragment(), FragmentInteractions, AppBarLayout.OnO } else if (percentage > 0.7F) { val toolbarAnimation = - if (binding.courseBrowserHeader.courseBrowserHeader == null) null else ObjectAnimator.ofFloat( + ObjectAnimator.ofFloat( binding.courseBrowserHeader.courseBrowserHeader, View.ALPHA, binding.courseBrowserHeader.courseBrowserHeader.alpha, 1F ) val titleAnimation = - ObjectAnimator.ofFloat(binding.courseBrowserTitle, View.ALPHA, binding.courseBrowserTitle.alpha, 0F) + ObjectAnimator.ofFloat( + binding.courseBrowserTitle, + View.ALPHA, + binding.courseBrowserTitle.alpha, + 0F + ) val subtitleAnimation = ObjectAnimator.ofFloat( binding.courseBrowserSubtitle, View.ALPHA, @@ -342,6 +410,7 @@ class CourseBrowserFragment : Fragment(), FragmentInteractions, AppBarLayout.OnO private fun validateRoute(route: Route) = route.canvasContext != null - fun makeRoute(canvasContext: CanvasContext?) = Route(CourseBrowserFragment::class.java, canvasContext) + fun makeRoute(canvasContext: CanvasContext?) = + Route(CourseBrowserFragment::class.java, canvasContext) } } diff --git a/apps/student/src/main/java/com/instructure/student/features/discussion/details/DiscussionDetailsFragment.kt b/apps/student/src/main/java/com/instructure/student/features/discussion/details/DiscussionDetailsFragment.kt index f9375ebec8..af9dd0ea3f 100644 --- a/apps/student/src/main/java/com/instructure/student/features/discussion/details/DiscussionDetailsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/discussion/details/DiscussionDetailsFragment.kt @@ -50,7 +50,6 @@ import com.instructure.canvasapi2.utils.NumberHelper import com.instructure.canvasapi2.utils.Pronouns import com.instructure.canvasapi2.utils.isValid import com.instructure.canvasapi2.utils.mapToAttachment -import com.instructure.canvasapi2.utils.pageview.BeforePageView import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.pageview.PageViewUrlQuery @@ -67,6 +66,7 @@ import com.instructure.pandautils.binding.viewBinding import com.instructure.pandautils.discussions.DiscussionCaching import com.instructure.pandautils.discussions.DiscussionEntryHtmlConverter import com.instructure.pandautils.discussions.DiscussionUtils +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.utils.BooleanArg import com.instructure.pandautils.utils.DiscussionEntryEvent import com.instructure.pandautils.utils.LongArg @@ -103,7 +103,6 @@ import com.instructure.student.features.modules.progression.CourseModuleProgress import com.instructure.student.fragment.DiscussionsReplyFragment import com.instructure.student.fragment.DiscussionsUpdateFragment import com.instructure.student.fragment.InternalWebviewFragment -import com.instructure.student.fragment.LtiLaunchFragment import com.instructure.student.fragment.ParentFragment import com.instructure.student.router.RouteMatcher import com.instructure.student.util.Const @@ -131,7 +130,8 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { lateinit var repository: DiscussionDetailsRepository // Bundle args - private var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private var discussionTopic: DiscussionTopic? by NullableParcelableArg(key = DISCUSSION_TOPIC) private var discussionTopicHeader: DiscussionTopicHeader by ParcelableArg(default = DiscussionTopicHeader(), key = DISCUSSION_TOPIC_HEADER) private var discussionTopicHeaderId: Long by LongArg(default = 0L, key = DISCUSSION_TOPIC_HEADER_ID) @@ -150,11 +150,11 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { //region Analytics @Suppress("unused") @PageViewUrlParam("topicId") - private fun getTopicId() = discussionTopicHeader.id + fun getTopicId() = discussionTopicHeader.id @Suppress("unused") @PageViewUrlQuery("module_item_id") - private fun pageViewModuleItemId() = getModuleItemId() + fun pageViewModuleItemId() = getModuleItemId() //endregion //region Fragment Lifecycle Overrides @@ -259,7 +259,7 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { // Show attachment val attachment = remoteFile.mapToAttachment() - openMedia(attachment.contentType, attachment.url, attachment.filename, canvasContext, localFile = attachment.isLocalFile) + openMedia(attachment.contentType, attachment.url, attachment.filename, attachment.id.toString(), canvasContext, localFile = attachment.isLocalFile) } private fun showReplyView(discussionEntryId: Long) { @@ -435,7 +435,7 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { override fun canRouteInternallyDelegate(url: String): Boolean = true override fun openMediaFromWebView(mime: String, url: String, filename: String) { - openMedia(canvasContext, url, filename) + openMedia(canvasContext, url, filename, null) } override fun onPageStartedCallback(webView: WebView, url: String) = Unit @@ -750,7 +750,10 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { } } - @BeforePageView + override fun beforePageViewPrerequisites(): List { + return listOf("discussion_loaded") + } + private fun loadDiscussionTopicHeaderViews(discussionTopicHeader: DiscussionTopicHeader) = with(binding) { if (discussionTopicHeader.assignment != null) { setupAssignmentDetails(discussionTopicHeader.assignment!!) @@ -781,12 +784,16 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { discussionTopicHeaderWebViewWrapper.webView.loadHtmlWithIframes(requireContext(), discussionTopicHeader.message, { if (view != null) loadHTMLTopic(it, discussionTopicHeader.title) - }, onLtiButtonPressed = { LtiLaunchFragment.routeLtiLaunchFragment(requireActivity(), canvasContext, it) }) + }, onLtiButtonPressed = { + RouteMatcher.route(requireActivity(), LtiLaunchFragment.makeSessionlessLtiUrlRoute(requireActivity(), canvasContext, it)) + }) attachmentIcon.setVisible(discussionTopicHeader.attachments.isNotEmpty()) attachmentIcon.onClick { viewAttachments(discussionTopicHeader.attachments) } + + completePageViewPrerequisite("discussion_loaded") } private fun loadHTMLTopic(html: String, contentDescription: String?) { @@ -802,7 +809,7 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { discussionRepliesWebViewWrapper.webView.loadHtmlWithIframes(requireContext(), html, { formattedHtml -> discussionRepliesWebViewWrapper.loadDataWithBaseUrl(CanvasWebView.getReferrer(true), formattedHtml, "text/html", "UTF-8", null) - }, onLtiButtonPressed = { LtiLaunchFragment.routeLtiLaunchFragment(requireActivity(), canvasContext, it) }) + }, onLtiButtonPressed = { RouteMatcher.route(requireActivity(), LtiLaunchFragment.makeSessionlessLtiUrlRoute(requireActivity(), canvasContext, it)) }) swipeRefreshLayout.isRefreshing = false discussionTopicRepliesTitle.setVisible(discussionTopicHeader.shouldShowReplies) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/FrontPageScreen.kt b/apps/student/src/main/java/com/instructure/student/features/discussion/details/StudentDiscussionDetailsWebViewFragmentBehavior.kt similarity index 69% rename from apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/FrontPageScreen.kt rename to apps/student/src/main/java/com/instructure/student/features/discussion/details/StudentDiscussionDetailsWebViewFragmentBehavior.kt index 3d37c364c7..e4be59ba45 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/FrontPageScreen.kt +++ b/apps/student/src/main/java/com/instructure/student/features/discussion/details/StudentDiscussionDetailsWebViewFragmentBehavior.kt @@ -15,13 +15,10 @@ * */ -package com.instructure.parentapp.features.courses.details +package com.instructure.student.features.discussion.details -import androidx.compose.material.Text -import androidx.compose.runtime.Composable +import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragmentBehavior - -@Composable -internal fun FrontPageScreen() { - Text(text = "Front Page") +class StudentDiscussionDetailsWebViewFragmentBehavior : DiscussionDetailsWebViewFragmentBehavior { + override val showBackButton = true } diff --git a/apps/student/src/main/java/com/instructure/student/features/discussion/list/DiscussionListFragment.kt b/apps/student/src/main/java/com/instructure/student/features/discussion/list/DiscussionListFragment.kt index e36dfe4a0a..49db4e1ad9 100644 --- a/apps/student/src/main/java/com/instructure/student/features/discussion/list/DiscussionListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/discussion/list/DiscussionListFragment.kt @@ -29,6 +29,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.DiscussionTopicHeader import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.weave.WeaveJob import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryLaunch @@ -71,7 +72,8 @@ open class DiscussionListFragment : ParentFragment(), Bookmarkable { @Inject lateinit var repository: DiscussionListRepository - protected var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private var recyclerAdapter: DiscussionListRecyclerAdapter? = null diff --git a/apps/student/src/main/java/com/instructure/student/features/elementary/course/ElementaryCourseFragment.kt b/apps/student/src/main/java/com/instructure/student/features/elementary/course/ElementaryCourseFragment.kt index 12ac118ccb..9fe3f2409b 100644 --- a/apps/student/src/main/java/com/instructure/student/features/elementary/course/ElementaryCourseFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/elementary/course/ElementaryCourseFragment.kt @@ -21,13 +21,14 @@ import android.os.Handler import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.viewModels import androidx.lifecycle.Observer import com.google.android.material.tabs.TabLayout import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_ELEMENTARY_COURSE import com.instructure.pandautils.analytics.ScreenView @@ -42,9 +43,10 @@ import dagger.hilt.android.AndroidEntryPoint @PageView(url = "{canvasContext}") @ScreenView(SCREEN_VIEW_ELEMENTARY_COURSE) @AndroidEntryPoint -class ElementaryCourseFragment : Fragment() { +class ElementaryCourseFragment : BaseCanvasFragment() { - private var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private var tabId: String by StringArg(key = TAB_ID) private val viewModel: ElementaryCourseViewModel by viewModels() diff --git a/apps/student/src/main/java/com/instructure/student/features/files/details/FileDetailsFragment.kt b/apps/student/src/main/java/com/instructure/student/features/files/details/FileDetailsFragment.kt index e85601d4e3..0483d15691 100644 --- a/apps/student/src/main/java/com/instructure/student/features/files/details/FileDetailsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/files/details/FileDetailsFragment.kt @@ -33,17 +33,29 @@ import com.instructure.canvasapi2.models.FileFolder import com.instructure.canvasapi2.models.ModuleObject import com.instructure.canvasapi2.utils.DateHelper import com.instructure.canvasapi2.utils.Logger -import com.instructure.canvasapi2.utils.pageview.BeforePageView import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.pageview.PageViewUrlQuery -import com.instructure.canvasapi2.utils.weave.* +import com.instructure.canvasapi2.utils.weave.catch +import com.instructure.canvasapi2.utils.weave.tryLaunch import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_FILE_DETAILS import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.binding.viewBinding import com.instructure.pandautils.features.file.download.FileDownloadWorker -import com.instructure.pandautils.utils.* +import com.instructure.pandautils.utils.Const +import com.instructure.pandautils.utils.DP +import com.instructure.pandautils.utils.LongArg +import com.instructure.pandautils.utils.ParcelableArg +import com.instructure.pandautils.utils.PermissionUtils +import com.instructure.pandautils.utils.StringArg +import com.instructure.pandautils.utils.ViewStyler +import com.instructure.pandautils.utils.getModuleItemId +import com.instructure.pandautils.utils.makeBundle +import com.instructure.pandautils.utils.setGone +import com.instructure.pandautils.utils.setVisible +import com.instructure.pandautils.utils.setupAsBackButton +import com.instructure.pandautils.utils.withArgs import com.instructure.student.R import com.instructure.student.databinding.FragmentFileDetailsBinding import com.instructure.student.events.ModuleUpdatedEvent @@ -51,7 +63,7 @@ import com.instructure.student.events.post import com.instructure.student.fragment.ParentFragment import com.instructure.student.util.StringUtilities import dagger.hilt.android.AndroidEntryPoint -import java.util.* +import java.util.Date import javax.inject.Inject @ScreenView(SCREEN_VIEW_FILE_DETAILS) @@ -67,7 +79,8 @@ class FileDetailsFragment : ParentFragment() { private val binding by viewBinding(FragmentFileDetailsBinding::bind) - private var canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private var moduleObject by ParcelableArg(key = Const.MODULE_OBJECT) private var itemId: Long by LongArg(key = Const.ITEM_ID) @@ -80,14 +93,19 @@ class FileDetailsFragment : ParentFragment() { get() = this.getModuleItemId() @PageViewUrlParam(name = "fileId") - private fun getFileIdValue(): Long = fileId + fun getFileIdValue(): Long = fileId @Suppress("unused") // For page view stats @PageViewUrlQuery(name = "module_item_id") - private fun getModuleIdValue(): Long? = moduleItemId + fun getModuleIdValue(): Long? = moduleItemId - @BeforePageView - private fun setPageViewReady() {} + private fun setPageViewReady() { + completePageViewPrerequisite("pageViewReady") + } + + override fun beforePageViewPrerequisites(): List { + return listOf("pageViewReady") + } override fun title(): String { return if (file != null && file!!.lockInfo == null) file!!.displayName ?: getString(R.string.file) else getString(R.string.file) @@ -124,7 +142,7 @@ class FileDetailsFragment : ParentFragment() { private fun setupClickListeners() { binding.openButton.setOnClickListener { file?.let { fileFolder -> - openMedia(fileFolder.contentType, fileFolder.url, fileFolder.displayName, canvasContext, fileFolder.isLocalFile) + openMedia(fileFolder.contentType, fileFolder.url, fileFolder.displayName, fileFolder.id.toString(), canvasContext, fileFolder.isLocalFile) markAsRead() } } diff --git a/apps/student/src/main/java/com/instructure/student/features/files/list/FileListFragment.kt b/apps/student/src/main/java/com/instructure/student/features/files/list/FileListFragment.kt index 52ea6555a6..e54b79328a 100644 --- a/apps/student/src/main/java/com/instructure/student/features/files/list/FileListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/files/list/FileListFragment.kt @@ -32,12 +32,15 @@ import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.PopupMenu import androidx.core.content.FileProvider -import androidx.fragment.app.DialogFragment import androidx.lifecycle.LiveData import androidx.work.WorkInfo import androidx.work.WorkManager import com.instructure.canvasapi2.managers.FileFolderManager -import com.instructure.canvasapi2.models.* +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.models.Course +import com.instructure.canvasapi2.models.CreateFolder +import com.instructure.canvasapi2.models.FileFolder +import com.instructure.canvasapi2.models.UpdateFileFolder import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.canvasapi2.utils.pageview.PageViewUrl @@ -55,7 +58,28 @@ import com.instructure.pandautils.binding.viewBinding import com.instructure.pandautils.features.file.download.FileDownloadWorker import com.instructure.pandautils.features.file.upload.FileUploadDialogFragment import com.instructure.pandautils.features.file.upload.FileUploadDialogParent -import com.instructure.pandautils.utils.* +import com.instructure.pandautils.utils.Const +import com.instructure.pandautils.utils.DP +import com.instructure.pandautils.utils.FileUploadEvent +import com.instructure.pandautils.utils.LongArg +import com.instructure.pandautils.utils.NullableParcelableArg +import com.instructure.pandautils.utils.ParcelableArg +import com.instructure.pandautils.utils.PermissionUtils +import com.instructure.pandautils.utils.ThemePrefs +import com.instructure.pandautils.utils.ViewStyler +import com.instructure.pandautils.utils.isCourse +import com.instructure.pandautils.utils.isCourseOrGroup +import com.instructure.pandautils.utils.isGroup +import com.instructure.pandautils.utils.isTablet +import com.instructure.pandautils.utils.makeBundle +import com.instructure.pandautils.utils.onClickWithRequireNetwork +import com.instructure.pandautils.utils.setGone +import com.instructure.pandautils.utils.setInvisible +import com.instructure.pandautils.utils.setMenu +import com.instructure.pandautils.utils.setVisible +import com.instructure.pandautils.utils.setupAsBackButton +import com.instructure.pandautils.utils.toast +import com.instructure.pandautils.utils.withArgs import com.instructure.student.R import com.instructure.student.databinding.FragmentFileListBinding import com.instructure.student.dialog.EditTextDialog @@ -69,7 +93,7 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import java.io.File -import java.util.* +import java.util.UUID import javax.inject.Inject @@ -90,7 +114,7 @@ class FileListFragment : ParentFragment(), Bookmarkable, FileUploadDialogParent @Suppress("unused") @PageViewUrl - private fun makePageViewUrl(): String { + fun makePageViewUrl(): String { var url = if (canvasContext.type == CanvasContext.Type.USER) "${ApiPrefs.fullDomain}/files" else "${ApiPrefs.fullDomain}/${canvasContext.contextId.replace("_", "s/")}/files" @@ -129,7 +153,7 @@ class FileListFragment : ParentFragment(), Bookmarkable, FileUploadDialogParent super.onCreate(savedInstanceState) // We only want full screen dialog style if its user files if (canvasContext.type == CanvasContext.Type.USER) { - setStyle(DialogFragment.STYLE_NORMAL, R.style.LightStatusBarDialog) + setStyle(STYLE_NORMAL, R.style.LightStatusBarDialog) } setUpCallbacks() } @@ -231,7 +255,7 @@ class FileListFragment : ParentFragment(), Bookmarkable, FileUploadDialogParent } else -> { recordFilePreviewEvent(item) - openMedia(item.contentType, item.url, item.displayName, canvasContext, localFile = item.isLocalFile) + openMedia(item.contentType, item.url, item.displayName, item.id.toString(), canvasContext, localFile = item.isLocalFile) } } } @@ -384,7 +408,7 @@ class FileListFragment : ParentFragment(), Bookmarkable, FileUploadDialogParent when (menuItem.itemId) { R.id.openAlternate -> { recordFilePreviewEvent(item) - openMedia(item.contentType, item.url, item.displayName, canvasContext, localFile = !fileListRepository.isOnline(), useOutsideApps = true) + openMedia(item.contentType, item.url, item.displayName, item.id.toString(), canvasContext, localFile = !fileListRepository.isOnline(), useOutsideApps = true) } R.id.download -> downloadItem(item) R.id.rename -> renameItem(item) diff --git a/apps/student/src/main/java/com/instructure/student/features/files/search/FileSearchFragment.kt b/apps/student/src/main/java/com/instructure/student/features/files/search/FileSearchFragment.kt index da4e0eb53d..b8e3bc7dec 100644 --- a/apps/student/src/main/java/com/instructure/student/features/files/search/FileSearchFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/files/search/FileSearchFragment.kt @@ -158,7 +158,7 @@ class FileSearchFragment : ParentFragment(), FileSearchView { override fun fileClicked(file: FileFolder) { PageViewUtils.saveSingleEvent("FilePreview", "${makePageViewUrl()}?preview=${file.id}") - openMedia(file.contentType, file.url, file.displayName, canvasContext, file.isLocalFile) + openMedia(file.contentType, file.url, file.displayName, file.id.toString(), canvasContext, file.isLocalFile) } override fun onMediaLoadingStarted() { diff --git a/apps/student/src/main/java/com/instructure/student/features/grades/GradesListFragment.kt b/apps/student/src/main/java/com/instructure/student/features/grades/GradesListFragment.kt index c87a1b80ef..fdf70b7cad 100644 --- a/apps/student/src/main/java/com/instructure/student/features/grades/GradesListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/grades/GradesListFragment.kt @@ -39,7 +39,9 @@ import com.instructure.canvasapi2.utils.AnalyticsEventConstants import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.NumberHelper import com.instructure.canvasapi2.utils.convertPercentScoreToLetterGrade +import com.instructure.canvasapi2.utils.convertPercentToPointBased import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.weave.WeaveJob import com.instructure.canvasapi2.utils.weave.weave import com.instructure.interactions.bookmarks.Bookmarkable @@ -49,6 +51,8 @@ import com.instructure.interactions.router.RouterParams import com.instructure.pandautils.analytics.SCREEN_VIEW_GRADES_LIST import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.binding.viewBinding +import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment +import com.instructure.pandautils.features.grades.GradeFormatter import com.instructure.pandautils.utils.ColorKeeper import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.ParcelableArg @@ -65,7 +69,6 @@ import com.instructure.student.R import com.instructure.student.adapter.TermSpinnerAdapter import com.instructure.student.databinding.FragmentCourseGradesBinding import com.instructure.student.dialog.WhatIfDialogStyled -import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment import com.instructure.student.fragment.ParentFragment import com.instructure.student.interfaces.AdapterToFragmentCallback import com.instructure.student.router.RouteMatcher @@ -82,9 +85,13 @@ class GradesListFragment : ParentFragment(), Bookmarkable { @Inject lateinit var repository: GradesListRepository + @Inject + lateinit var gradeFormatter: GradeFormatter + private val binding by viewBinding(FragmentCourseGradesBinding::bind) - private var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private var computeGradesJob: WeaveJob? = null @@ -98,8 +105,8 @@ class GradesListFragment : ParentFragment(), Bookmarkable { private lateinit var allTermsGradingPeriod: GradingPeriod private var recyclerAdapter: GradesListRecyclerAdapter? = null - private val course: Course - get() = canvasContext as Course + private lateinit var course: Course + private var courseGrade: CourseGrade? = null override fun title(): String = getString(R.string.grades) @@ -111,9 +118,15 @@ class GradesListFragment : ParentFragment(), Bookmarkable { allTermsGradingPeriod.title = getString(R.string.allGradingPeriods) } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_course_grades, container, false) + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? = inflater.inflate(R.layout.fragment_course_grades, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + course = canvasContext as Course recyclerAdapter = GradesListRecyclerAdapter( requireContext(), course, @@ -123,17 +136,22 @@ class GradesListFragment : ParentFragment(), Bookmarkable { adapterToGradesCallback, object : WhatIfDialogStyled.WhatIfDialogCallback { override fun onClick(assignment: Assignment, position: Int) { - WhatIfDialogStyled.show(requireFragmentManager(), assignment, course.color) { whatIf, _ -> + WhatIfDialogStyled.show( + parentFragmentManager, + assignment, + course.color + ) { whatIf, _ -> //Create dummy submission for what if grade //check to see if grade is empty for reset if (whatIf == null) { assignment.submission = null recyclerAdapter?.assignmentsHash?.get(assignment.id)?.submission = null } else { - recyclerAdapter?.assignmentsHash?.get(assignment.id)?.submission = Submission( - score = whatIf, - grade = whatIf.toString() - ) + recyclerAdapter?.assignmentsHash?.get(assignment.id)?.submission = + Submission( + score = whatIf, + grade = whatIf.toString() + ) } //Compute new overall grade @@ -144,8 +162,15 @@ class GradesListFragment : ParentFragment(), Bookmarkable { ) view.let { configureViews(it) - recyclerAdapter?.let {recyclerAdapter -> - configureRecyclerView(it, requireContext(), recyclerAdapter, R.id.swipeRefreshLayout, R.id.gradesEmptyView, R.id.listView) + recyclerAdapter?.let { recyclerAdapter -> + configureRecyclerView( + it, + requireContext(), + recyclerAdapter, + R.id.swipeRefreshLayout, + R.id.gradesEmptyView, + R.id.listView + ) } } @@ -162,7 +187,7 @@ class GradesListFragment : ParentFragment(), Bookmarkable { setupToolbarMenu(toolbar) toolbar.title = title() toolbar.setupAsBackButton(this@GradesListFragment) - ViewStyler.themeToolbarColored(requireActivity(), toolbar, course) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } } @@ -170,23 +195,35 @@ class GradesListFragment : ParentFragment(), Bookmarkable { super.onConfigurationChanged(newConfig) view?.let { recyclerAdapter?.let { recyclerAdapter -> - configureRecyclerView(it, requireContext(), recyclerAdapter, R.id.swipeRefreshLayout, R.id.gradesEmptyView, R.id.listView) } + configureRecyclerView( + it, + requireContext(), + recyclerAdapter, + R.id.swipeRefreshLayout, + R.id.gradesEmptyView, + R.id.listView + ) } + } } private fun configureViews(rootView: View) { val appBarLayout = rootView.findViewById(R.id.appbar) - val lockDrawable = ColorKeeper.getColoredDrawable(requireContext(), R.drawable.ic_lock, ContextCompat.getColor(requireContext(), R.color.textDarkest)) + val lockDrawable = ColorKeeper.getColoredDrawable( + requireContext(), + R.drawable.ic_lock, + ContextCompat.getColor(requireContext(), R.color.textDarkest) + ) binding.lockedGradeImage.setImageDrawable(lockDrawable) setupListeners() lockGrade(course.hideFinalGrades) - appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, i -> + appBarLayout.addOnOffsetChangedListener { _, i -> // workaround for Toolbar not showing with swipe to refresh if (i == 0) setRefreshingEnabled(true) else setRefreshingEnabled(false) - }) + } } private fun setupListeners() = with(binding) { @@ -196,12 +233,14 @@ class GradesListFragment : ParentFragment(), Bookmarkable { if (showWhatIfCheckBox.isChecked) { computeGrades(showTotalCheckBox.isChecked, -1) } else { - val gradeString = getGradeString( + val gradeString = gradeFormatter.getGradeString( + course, recyclerAdapter?.courseGrade, !isChecked ) txtOverallGrade.text = gradeString - txtOverallGrade.contentDescription = getContentDescriptionForMinusGradeString(gradeString, requireContext()) + txtOverallGrade.contentDescription = + getContentDescriptionForMinusGradeString(gradeString, requireContext()) } lockGrade(course.hideFinalGrades) @@ -234,7 +273,7 @@ class GradesListFragment : ParentFragment(), Bookmarkable { } } - private fun round(value: Double, places: Int): Double { + private fun round(value: Double, places: Int = 2): Double { if (places < 0) throw IllegalArgumentException() var bd = BigDecimal(value) @@ -242,40 +281,56 @@ class GradesListFragment : ParentFragment(), Bookmarkable { return bd.toDouble() } - private val adapterToGradesCallback = object : GradesListRecyclerAdapter.AdapterToGradesCallback { - override fun setTermSpinnerState(isEnabled: Boolean) { - if (!isAdded) return - binding.termSpinner.isEnabled = isEnabled - termAdapter?.let { - it.isLoading = !isEnabled - it.notifyDataSetChanged() + private val adapterToGradesCallback = + object : GradesListRecyclerAdapter.AdapterToGradesCallback { + override fun setTermSpinnerState(isEnabled: Boolean) { + if (!isAdded) return + binding.termSpinner.isEnabled = isEnabled + termAdapter?.let { + it.isLoading = !isEnabled + it.notifyDataSetChanged() + } } - } - override fun notifyGradeChanged(courseGrade: CourseGrade?, restrictQuantitativeData: Boolean, gradingScheme: List) { - Logger.d("Logging for Grades E2E, current total grade is: ${binding.txtOverallGrade.text}") - if (!isAdded) return - this@GradesListFragment.restrictQuantitativeData = restrictQuantitativeData - this@GradesListFragment.gradingScheme = gradingScheme - val gradeString = getGradeString(courseGrade, !binding.showTotalCheckBox.isChecked) - Logger.d("Logging for Grades E2E, new total grade is: $gradeString") - binding.txtOverallGrade.text = gradeString - binding.txtOverallGrade.contentDescription = getContentDescriptionForMinusGradeString(gradeString, requireContext()) - lockGrade(course.hideFinalGrades || courseGrade?.isLocked == true) - } + override fun notifyGradeChanged( + course: Course?, + courseGrade: CourseGrade?, + restrictQuantitativeData: Boolean, + gradingScheme: List + ) { + Logger.d("Logging for Grades E2E, current total grade is: ${binding.txtOverallGrade.text}") + if (!isAdded) return + this@GradesListFragment.restrictQuantitativeData = restrictQuantitativeData + this@GradesListFragment.gradingScheme = gradingScheme + this@GradesListFragment.courseGrade = courseGrade + this@GradesListFragment.course = course ?: canvasContext as Course + val gradeString = gradeFormatter.getGradeString( + course, + courseGrade, + !binding.showTotalCheckBox.isChecked + ) + Logger.d("Logging for Grades E2E, new total grade is: $gradeString") + binding.txtOverallGrade.text = gradeString + binding.txtOverallGrade.contentDescription = + getContentDescriptionForMinusGradeString(gradeString, requireContext()) + lockGrade(course?.hideFinalGrades == true || courseGrade?.isLocked == true) + } - // showWhatIfCheckBox is accessed a little too early when this fragment is loaded, so we add an elvis operator here - override val isEdit: Boolean get() = binding.showWhatIfCheckBox.isChecked + // showWhatIfCheckBox is accessed a little too early when this fragment is loaded, so we add an elvis operator here + override val isEdit: Boolean get() = binding.showWhatIfCheckBox.isChecked - override fun setIsWhatIfGrading(isWhatIfGrading: Boolean) { - binding.whatIfView.setVisible(isWhatIfGrading) - this@GradesListFragment.isWhatIfGrading = isWhatIfGrading + override fun setIsWhatIfGrading(isWhatIfGrading: Boolean) { + binding.whatIfView.setVisible(isWhatIfGrading) + this@GradesListFragment.isWhatIfGrading = isWhatIfGrading + } } - } private val adapterToFragmentCallback = object : AdapterToFragmentCallback { override fun onRowClicked(assignment: Assignment, position: Int, isOpenDetail: Boolean) { - RouteMatcher.route(requireActivity(), AssignmentDetailsFragment.makeRoute(canvasContext, assignment.id)) + RouteMatcher.route( + requireActivity(), + AssignmentDetailsFragment.makeRoute(canvasContext, assignment.id) + ) } override fun onRefreshFinished() { @@ -298,7 +353,12 @@ class GradesListFragment : ParentFragment(), Bookmarkable { termSpinner.adapter = termAdapter termSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onNothingSelected(parent: AdapterView<*>?) {} - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + override fun onItemSelected( + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long + ) { // The current item must always be set first recyclerAdapter?.currentGradingPeriod = termAdapter?.getItem(position) if (termAdapter?.getItem(position)?.title == getString(R.string.allGradingPeriods)) { @@ -338,34 +398,6 @@ class GradesListFragment : ParentFragment(), Bookmarkable { } } - private fun getGradeString( - courseGrade: CourseGrade?, - isFinal: Boolean - ): String { - if (courseGrade == null) return getString(R.string.noGradeText) - return if (isFinal) { - formatGrade(courseGrade.noFinalGrade, courseGrade.hasFinalGradeString(), courseGrade.finalGrade, courseGrade.finalScore) - } else { - formatGrade(courseGrade.noCurrentGrade, courseGrade.hasCurrentGradeString(), courseGrade.currentGrade, courseGrade.currentScore) - } - } - - private fun formatGrade(noGrade: Boolean, hasGradeString: Boolean, grade: String?, score: Double?): String { - return if (noGrade) { - getString(R.string.noGradeText) - } else { - if (restrictQuantitativeData) { - when { - hasGradeString -> grade.orEmpty() - gradingScheme.isNotEmpty() && score != null -> convertPercentScoreToLetterGrade(score / 100, gradingScheme) - else -> getString(R.string.noGradeText) - } - } else { - NumberHelper.doubleToPercentage(score) + if (hasGradeString) String.format(" (%s)", grade) else "" - } - } - } - private fun lockGrade(isLocked: Boolean) { if (isLocked || recyclerAdapter?.isAllGradingPeriodsSelected == true && !course.isTotalsForAllGradingPeriodsEnabled) { binding.txtOverallGrade.setInvisible() @@ -401,9 +433,24 @@ class GradesListFragment : ParentFragment(), Bookmarkable { } recyclerAdapter?.whatIfGrade = result - binding.txtOverallGrade.text = NumberHelper.doubleToPercentage(result) + val resultStr = if (course.pointsBasedGradingScheme) { + convertPercentToPointBased(result.orDefault(), course.scalingFactor) + } else { + NumberHelper.doubleToPercentage(result) + } - if(lastPositionChanged >= 0) recyclerAdapter?.notifyItemChanged(lastPositionChanged) + binding.txtOverallGrade.text = if (courseGrade?.hasFinalGradeString() == true) { + "$resultStr (${ + convertPercentScoreToLetterGrade( + result.orDefault() / 100.0, + course.gradingScheme + ) + })" + } else { + resultStr + } + + if (lastPositionChanged >= 0) recyclerAdapter?.notifyItemChanged(lastPositionChanged) } } @@ -426,7 +473,8 @@ class GradesListFragment : ParentFragment(), Bookmarkable { var totalPoints = 0.0 val weight = g.groupWeight for (a in g.assignments) { - val tempAssignment = recyclerAdapter?.assignmentsHash?.get(a.id).takeIf { !it?.omitFromFinalGrade.orDefault() } + val tempAssignment = recyclerAdapter?.assignmentsHash?.get(a.id) + .takeIf { !it?.omitFromFinalGrade.orDefault() } val tempSub = tempAssignment?.submission if (tempSub?.grade != null && tempAssignment.submissionTypesRaw.isNotEmpty()) { earnedPoints += tempSub.score @@ -439,7 +487,7 @@ class GradesListFragment : ParentFragment(), Bookmarkable { } } - return round(earnedScore, 2) + return round(earnedScore) } /** @@ -461,7 +509,8 @@ class GradesListFragment : ParentFragment(), Bookmarkable { val weight = g.groupWeight var assignCount = 0 for (a in g.assignments) { - val tempAssignment = recyclerAdapter?.assignmentsHash?.get(a.id).takeIf { !it?.omitFromFinalGrade.orDefault() } + val tempAssignment = recyclerAdapter?.assignmentsHash?.get(a.id) + .takeIf { !it?.omitFromFinalGrade.orDefault() } val tempSub = tempAssignment?.submission if (tempSub?.grade != null && tempAssignment.submissionTypesRaw.isNotEmpty() && Const.PENDING_REVIEW != tempSub.workflowState) { assignCount++ // Determines if a group contains assignments @@ -488,7 +537,7 @@ class GradesListFragment : ParentFragment(), Bookmarkable { earnedScore = earnedScore / totalWeight * 100//Cumulative } - return round(earnedScore, 2) + return round(earnedScore) } /** @@ -510,7 +559,8 @@ class GradesListFragment : ParentFragment(), Bookmarkable { var totalPoints = 0.0 for (g in groups) { for (a in g.assignments) { - val tempAssignment = recyclerAdapter?.assignmentsHash?.get(a.id).takeIf { !it?.omitFromFinalGrade.orDefault() } + val tempAssignment = recyclerAdapter?.assignmentsHash?.get(a.id) + .takeIf { !it?.omitFromFinalGrade.orDefault() } val tempSub = tempAssignment?.submission if (tempSub?.grade != null && tempAssignment.submissionTypesRaw.isNotEmpty() && Const.PENDING_REVIEW != tempSub.workflowState) { earnedPoints += tempSub.score @@ -522,7 +572,7 @@ class GradesListFragment : ParentFragment(), Bookmarkable { earnedScore += earnedPoints / totalPoints * 100 //Cumulative } - return round(earnedScore, 2) + return round(earnedScore) } /** @@ -544,7 +594,8 @@ class GradesListFragment : ParentFragment(), Bookmarkable { var earnedPoints = 0.0 for (g in groups) { for (a in g.assignments) { - val tempAssignment = recyclerAdapter?.assignmentsHash?.get(a.id).takeIf { !it?.omitFromFinalGrade.orDefault() } + val tempAssignment = recyclerAdapter?.assignmentsHash?.get(a.id) + .takeIf { !it?.omitFromFinalGrade.orDefault() } val tempSub = tempAssignment?.submission if (tempSub?.grade != null && tempAssignment.submissionTypesRaw.isNotEmpty()) { totalPoints += tempAssignment.pointsPossible @@ -556,7 +607,7 @@ class GradesListFragment : ParentFragment(), Bookmarkable { earnedScore += earnedPoints / totalPoints * 100 } - return round(earnedScore, 2) + return round(earnedScore) } //endregion @@ -566,8 +617,8 @@ class GradesListFragment : ParentFragment(), Bookmarkable { companion object { - fun newInstance(route: Route) : GradesListFragment? { - return if(validRoute(route)) GradesListFragment().apply { + fun newInstance(route: Route): GradesListFragment? { + return if (validRoute(route)) GradesListFragment().apply { arguments = route.arguments canvasContext = route.canvasContext!! } else null @@ -578,7 +629,12 @@ class GradesListFragment : ParentFragment(), Bookmarkable { } fun makeRoute(canvasContext: CanvasContext): Route { - return Route(null, GradesListFragment::class.java, canvasContext, canvasContext.makeBundle()) + return Route( + null, + GradesListFragment::class.java, + canvasContext, + canvasContext.makeBundle() + ) } } } diff --git a/apps/student/src/main/java/com/instructure/student/features/grades/GradesListRecyclerAdapter.kt b/apps/student/src/main/java/com/instructure/student/features/grades/GradesListRecyclerAdapter.kt index a0cd507ec8..7b10687939 100644 --- a/apps/student/src/main/java/com/instructure/student/features/grades/GradesListRecyclerAdapter.kt +++ b/apps/student/src/main/java/com/instructure/student/features/grades/GradesListRecyclerAdapter.kt @@ -83,7 +83,7 @@ open class GradesListRecyclerAdapter( interface AdapterToGradesCallback { val isEdit: Boolean - fun notifyGradeChanged(courseGrade: CourseGrade?, restrictQuantitativeData: Boolean, gradingScheme: List) + fun notifyGradeChanged(course: Course?, courseGrade: CourseGrade?, restrictQuantitativeData: Boolean, gradingScheme: List) fun setTermSpinnerState(isEnabled: Boolean) fun setIsWhatIfGrading(isWhatIfGrading: Boolean) } @@ -199,7 +199,7 @@ open class GradesListRecyclerAdapter( course.enrollments = mutableListOf(it) courseGrade = course.getCourseGradeFromEnrollment(it, false) val restrictQuantitativeData = course.settings?.restrictQuantitativeData ?: false - adapterToGradesCallback?.notifyGradeChanged(courseGrade, restrictQuantitativeData, course.gradingScheme) + adapterToGradesCallback?.notifyGradeChanged(course, courseGrade, restrictQuantitativeData, course.gradingScheme) } } } catch (e: CancellationException) { @@ -274,7 +274,7 @@ open class GradesListRecyclerAdapter( val course = canvasContext as Course? courseGrade = course!!.getCourseGradeForGradingPeriodSpecificEnrollment(enrollment = enrollment) val restrictQuantitativeData = course.settings?.restrictQuantitativeData ?: false - adapterToGradesCallback?.notifyGradeChanged(courseGrade, restrictQuantitativeData, course.gradingScheme) + adapterToGradesCallback?.notifyGradeChanged(course, courseGrade, restrictQuantitativeData, course.gradingScheme) // We need to update the course that the fragment is using course.addEnrollment(enrollment) } @@ -287,7 +287,7 @@ open class GradesListRecyclerAdapter( courseGrade = course?.getCourseGrade(true) val restrictQuantitativeData = course?.settings?.restrictQuantitativeData ?: false val gradingScheme = course?.gradingScheme ?: emptyList() - adapterToGradesCallback?.notifyGradeChanged(courseGrade, restrictQuantitativeData, gradingScheme) + adapterToGradesCallback?.notifyGradeChanged(course, courseGrade, restrictQuantitativeData, gradingScheme) } private fun updateWithAllAssignments(forceNetwork: Boolean) { diff --git a/apps/student/src/main/java/com/instructure/student/features/login/StudentAcceptableUsePolicyRouter.kt b/apps/student/src/main/java/com/instructure/student/features/login/StudentAcceptableUsePolicyRouter.kt index 4a47830da2..eeb3735a70 100644 --- a/apps/student/src/main/java/com/instructure/student/features/login/StudentAcceptableUsePolicyRouter.kt +++ b/apps/student/src/main/java/com/instructure/student/features/login/StudentAcceptableUsePolicyRouter.kt @@ -27,7 +27,7 @@ import com.instructure.pandautils.services.PushNotificationRegistrationWorker import com.instructure.student.R import com.instructure.student.activity.InternalWebViewActivity import com.instructure.student.activity.NavigationActivity -import com.instructure.pandautils.features.assignments.details.reminder.AlarmScheduler +import com.instructure.pandautils.features.reminder.AlarmScheduler import com.instructure.student.tasks.StudentLogoutTask class StudentAcceptableUsePolicyRouter( diff --git a/apps/student/src/main/java/com/instructure/student/features/login/StudentLoginNavigation.kt b/apps/student/src/main/java/com/instructure/student/features/login/StudentLoginNavigation.kt index 18fa125489..a549be2e90 100644 --- a/apps/student/src/main/java/com/instructure/student/features/login/StudentLoginNavigation.kt +++ b/apps/student/src/main/java/com/instructure/student/features/login/StudentLoginNavigation.kt @@ -25,7 +25,7 @@ import com.instructure.loginapi.login.tasks.LogoutTask import com.instructure.pandautils.room.offline.DatabaseProvider import com.instructure.pandautils.services.PushNotificationRegistrationWorker import com.instructure.student.activity.NavigationActivity -import com.instructure.pandautils.features.assignments.details.reminder.AlarmScheduler +import com.instructure.pandautils.features.reminder.AlarmScheduler import com.instructure.student.tasks.StudentLogoutTask class StudentLoginNavigation( diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/SummaryScreen.kt b/apps/student/src/main/java/com/instructure/student/features/lti/StudentLtiLaunchFragmentBehavior.kt similarity index 64% rename from apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/SummaryScreen.kt rename to apps/student/src/main/java/com/instructure/student/features/lti/StudentLtiLaunchFragmentBehavior.kt index 606d8bb59b..b547d38b0f 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/SummaryScreen.kt +++ b/apps/student/src/main/java/com/instructure/student/features/lti/StudentLtiLaunchFragmentBehavior.kt @@ -14,14 +14,12 @@ * along with this program. If not, see . * */ +package com.instructure.student.features.lti -package com.instructure.parentapp.features.courses.details +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.pandautils.features.lti.LtiLaunchFragmentBehavior +import com.instructure.pandautils.utils.color -import androidx.compose.material.Text -import androidx.compose.runtime.Composable - - -@Composable -internal fun SummaryScreen() { - Text(text = "Summary") -} +class StudentLtiLaunchFragmentBehavior(canvasContext: CanvasContext) : LtiLaunchFragmentBehavior { + override val toolbarColor: Int = canvasContext.color +} \ No newline at end of file diff --git a/apps/student/src/main/java/com/instructure/student/features/modules/list/adapter/ModuleViewHolder.kt b/apps/student/src/main/java/com/instructure/student/features/modules/list/adapter/ModuleViewHolder.kt index f95fdb3ce7..8282540c4b 100644 --- a/apps/student/src/main/java/com/instructure/student/features/modules/list/adapter/ModuleViewHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/features/modules/list/adapter/ModuleViewHolder.kt @@ -109,6 +109,7 @@ class ModuleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { // Icon val drawableResource: Int = when { + moduleItem.quizLti -> R.drawable.ic_quiz ModuleItem.Type.Assignment.toString() .equals(moduleItem.type, ignoreCase = true) -> R.drawable.ic_assignment ModuleItem.Type.Discussion.toString() diff --git a/apps/student/src/main/java/com/instructure/student/features/modules/progression/CourseModuleProgressionFragment.kt b/apps/student/src/main/java/com/instructure/student/features/modules/progression/CourseModuleProgressionFragment.kt index 0ac251eadb..25bb63d9f9 100644 --- a/apps/student/src/main/java/com/instructure/student/features/modules/progression/CourseModuleProgressionFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/modules/progression/CourseModuleProgressionFragment.kt @@ -36,6 +36,7 @@ import com.instructure.canvasapi2.models.Tab import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.isLocked import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.weave.WeaveJob import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryLaunch @@ -48,6 +49,7 @@ import com.instructure.interactions.router.RouterParams import com.instructure.pandautils.analytics.SCREEN_VIEW_COURSE_MODULE_PROGRESSION import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.binding.viewBinding +import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment import com.instructure.pandautils.features.discussion.router.DiscussionRouteHelper import com.instructure.pandautils.features.discussion.router.DiscussionRouterFragment import com.instructure.pandautils.utils.BooleanArg @@ -70,7 +72,6 @@ import com.instructure.student.R import com.instructure.student.databinding.CourseModuleProgressionBinding import com.instructure.student.events.ModuleUpdatedEvent import com.instructure.student.events.post -import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment import com.instructure.student.features.files.details.FileDetailsFragment import com.instructure.student.features.modules.list.ModuleListFragment import com.instructure.student.features.modules.util.ModuleProgressionUtility @@ -103,7 +104,8 @@ class CourseModuleProgressionFragment : ParentFragment(), Bookmarkable { private var markAsReadJob: WeaveJob? = null // Bundle Args - private var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private var groupPos: Int by IntArg(key = GROUP_POSITION) private var childPos: Int by IntArg(key = CHILD_POSITION) private var modules: ArrayList by ParcelableArrayListArg(key = MODULE_OBJECTS) diff --git a/apps/student/src/main/java/com/instructure/student/features/modules/progression/ModuleQuizDecider.kt b/apps/student/src/main/java/com/instructure/student/features/modules/progression/ModuleQuizDecider.kt index 20229f209a..ceba206ef7 100644 --- a/apps/student/src/main/java/com/instructure/student/features/modules/progression/ModuleQuizDecider.kt +++ b/apps/student/src/main/java/com/instructure/student/features/modules/progression/ModuleQuizDecider.kt @@ -36,7 +36,18 @@ import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_MODULE_QUIZ_DECIDER import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.binding.viewBinding -import com.instructure.pandautils.utils.* +import com.instructure.pandautils.utils.Const +import com.instructure.pandautils.utils.LongArg +import com.instructure.pandautils.utils.ParcelableArg +import com.instructure.pandautils.utils.StringArg +import com.instructure.pandautils.utils.ViewStyler +import com.instructure.pandautils.utils.argsWithContext +import com.instructure.pandautils.utils.onClickWithRequireNetwork +import com.instructure.pandautils.utils.setGone +import com.instructure.pandautils.utils.setVisible +import com.instructure.pandautils.utils.setupAsBackButton +import com.instructure.pandautils.utils.toast +import com.instructure.pandautils.utils.withArgs import com.instructure.pandautils.views.CanvasWebView import com.instructure.student.R import com.instructure.student.databinding.FragmentModuleQuizDeciderBinding @@ -67,7 +78,7 @@ class ModuleQuizDecider : ParentFragment() { private var webViewClientCallback = object : CanvasWebView.CanvasWebViewClientCallback { override fun openMediaFromWebView(mime: String, url: String, filename: String) { - openMedia(mime, url, filename, canvasContext) + openMedia(mime, url, filename, null, canvasContext) } override fun onPageFinishedCallback(webView: WebView, url: String) = Unit diff --git a/apps/student/src/main/java/com/instructure/student/features/modules/util/ModuleUtility.kt b/apps/student/src/main/java/com/instructure/student/features/modules/util/ModuleUtility.kt index a3066f832b..e64c3035dc 100644 --- a/apps/student/src/main/java/com/instructure/student/features/modules/util/ModuleUtility.kt +++ b/apps/student/src/main/java/com/instructure/student/features/modules/util/ModuleUtility.kt @@ -27,10 +27,10 @@ import com.instructure.canvasapi2.utils.APIHelper.expandTildeId import com.instructure.canvasapi2.utils.findWithPrevious import com.instructure.canvasapi2.utils.isLocked import com.instructure.interactions.router.Route -import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragment -import com.instructure.student.R import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment.Companion.makeRoute +import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragment +import com.instructure.student.R import com.instructure.student.features.discussion.details.DiscussionDetailsFragment import com.instructure.student.features.discussion.details.DiscussionDetailsFragment.Companion.makeRoute import com.instructure.student.features.files.details.FileDetailsFragment diff --git a/apps/student/src/main/java/com/instructure/student/features/pages/details/PageDetailsFragment.kt b/apps/student/src/main/java/com/instructure/student/features/pages/details/PageDetailsFragment.kt index d1d7df70dc..d3a7e43c58 100644 --- a/apps/student/src/main/java/com/instructure/student/features/pages/details/PageDetailsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/pages/details/PageDetailsFragment.kt @@ -30,7 +30,6 @@ import com.instructure.canvasapi2.utils.APIHelper import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.Failure import com.instructure.canvasapi2.utils.Logger -import com.instructure.canvasapi2.utils.pageview.BeforePageView import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.canvasapi2.utils.pageview.PageViewUrl import com.instructure.canvasapi2.utils.weave.awaitApi @@ -43,6 +42,7 @@ import com.instructure.interactions.router.RouterParams import com.instructure.loginapi.login.dialog.NoInternetConnectionDialog import com.instructure.pandautils.analytics.SCREEN_VIEW_PAGE_DETAILS import com.instructure.pandautils.analytics.ScreenView +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.navigation.WebViewRouter import com.instructure.pandautils.utils.BooleanArg import com.instructure.pandautils.utils.NullableStringArg @@ -59,7 +59,6 @@ import com.instructure.student.R import com.instructure.student.events.PageUpdatedEvent import com.instructure.student.fragment.EditPageDetailsFragment import com.instructure.student.fragment.InternalWebviewFragment -import com.instructure.student.fragment.LtiLaunchFragment import com.instructure.student.router.RouteMatcher import com.instructure.student.util.LockInfoHTMLHelper import dagger.hilt.android.AndroidEntryPoint @@ -92,7 +91,7 @@ class PageDetailsFragment : InternalWebviewFragment(), Bookmarkable { @PageViewUrl @Suppress("unused") - private fun makePageViewUrl(): String { + fun makePageViewUrl(): String { val url = StringBuilder(ApiPrefs.fullDomain) page.let { url.append(canvasContext.toAPIString()) @@ -230,7 +229,7 @@ class PageDetailsFragment : InternalWebviewFragment(), Bookmarkable { loadHtmlJob = canvasWebViewWrapper.webView.loadHtmlWithIframes(requireContext(), body, { canvasWebViewWrapper.loadHtml(it, page.title, baseUrl = page.htmlUrl) }) { - LtiLaunchFragment.routeLtiLaunchFragment(requireActivity(), canvasContext, it) + RouteMatcher.route(requireActivity(), LtiLaunchFragment.makeSessionlessLtiUrlRoute(requireActivity(), canvasContext, it)) } } else if (page.body == null || page.body?.endsWith("") == true) { loadHtml(resources.getString(R.string.noPageFound), "text/html", "utf-8", null) @@ -330,9 +329,13 @@ class PageDetailsFragment : InternalWebviewFragment(), Bookmarkable { } } - @BeforePageView private fun setPageObject(page: Page) { this.page = page + completePageViewPrerequisite("pageSet") + } + + override fun beforePageViewPrerequisites(): List { + return listOf("pageSet") } @Suppress("unused") diff --git a/apps/student/src/main/java/com/instructure/student/features/pages/list/PageListFragment.kt b/apps/student/src/main/java/com/instructure/student/features/pages/list/PageListFragment.kt index cb47a42ce2..13938daf88 100644 --- a/apps/student/src/main/java/com/instructure/student/features/pages/list/PageListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/pages/list/PageListFragment.kt @@ -26,6 +26,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Page import com.instructure.canvasapi2.models.Tab import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.interactions.bookmarks.Bookmarkable import com.instructure.interactions.bookmarks.Bookmarker import com.instructure.interactions.router.Route @@ -60,7 +61,8 @@ class PageListFragment : ParentFragment(), Bookmarkable { private var rootView: View? = null - private var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private var recyclerAdapter: PageListRecyclerAdapter? = null private var defaultSelectedPageTitle = PageListRecyclerAdapter.FRONT_PAGE_DETERMINER // blank string is used to determine front page diff --git a/apps/student/src/main/java/com/instructure/student/features/people/details/PeopleDetailsFragment.kt b/apps/student/src/main/java/com/instructure/student/features/people/details/PeopleDetailsFragment.kt index 3d9157bc16..e10ff8a949 100644 --- a/apps/student/src/main/java/com/instructure/student/features/people/details/PeopleDetailsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/people/details/PeopleDetailsFragment.kt @@ -75,7 +75,7 @@ class PeopleDetailsFragment : ParentFragment(), Bookmarkable { @Suppress("unused") @PageViewUrlParam(name = "userId") - private fun getUserIdForPageView() = userId + fun getUserIdForPageView() = userId @Inject lateinit var repository: PeopleDetailsRepository @@ -86,13 +86,15 @@ class PeopleDetailsFragment : ParentFragment(), Bookmarkable { private var userId by LongArg(key = Const.USER_ID) - private var canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) override fun title(): String = "" override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = layoutInflater.inflate(R.layout.fragment_people_details, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) binding.compose.backgroundTintList = ColorStateList.valueOf(ThemePrefs.buttonColor) binding.compose.setImageDrawable(ColorKeeper.getColoredDrawable(requireContext(), R.drawable.ic_send, ThemePrefs.buttonTextColor)) binding.compose.setOnClickListener { diff --git a/apps/student/src/main/java/com/instructure/student/features/people/list/PeopleListFragment.kt b/apps/student/src/main/java/com/instructure/student/features/people/list/PeopleListFragment.kt index b29741cb1d..fa683d01bf 100644 --- a/apps/student/src/main/java/com/instructure/student/features/people/list/PeopleListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/people/list/PeopleListFragment.kt @@ -25,6 +25,7 @@ import androidx.lifecycle.lifecycleScope import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.User import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.interactions.bookmarks.Bookmarkable import com.instructure.interactions.bookmarks.Bookmarker import com.instructure.interactions.router.Route @@ -51,7 +52,8 @@ class PeopleListFragment : ParentFragment(), Bookmarkable { private val binding by viewBinding(FragmentPeopleListBinding::bind) - private var canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private var recyclerAdapter: PeopleListRecyclerAdapter? = null @@ -76,6 +78,7 @@ class PeopleListFragment : ParentFragment(), Bookmarkable { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) recyclerAdapter = PeopleListRecyclerAdapter(requireContext(), lifecycleScope, repository, canvasContext, adapterToFragmentCallback) configureRecyclerView( view, diff --git a/apps/student/src/main/java/com/instructure/student/features/quiz/list/QuizListFragment.kt b/apps/student/src/main/java/com/instructure/student/features/quiz/list/QuizListFragment.kt index acf700f1d5..22d700ee0e 100644 --- a/apps/student/src/main/java/com/instructure/student/features/quiz/list/QuizListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/features/quiz/list/QuizListFragment.kt @@ -28,6 +28,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Quiz import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.interactions.bookmarks.Bookmarkable import com.instructure.interactions.bookmarks.Bookmarker import com.instructure.interactions.router.Route @@ -58,7 +59,8 @@ class QuizListFragment : ParentFragment(), Bookmarkable { private val binding by viewBinding(QuizListLayoutBinding::bind) private lateinit var recyclerBinding: PandaRecyclerRefreshLayoutBinding - private var canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private var recyclerAdapter: QuizListRecyclerAdapter? = null @@ -78,6 +80,7 @@ class QuizListFragment : ParentFragment(), Bookmarkable { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = layoutInflater.inflate(R.layout.quiz_list_layout, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) recyclerBinding = PandaRecyclerRefreshLayoutBinding.bind(binding.root) recyclerAdapter = QuizListRecyclerAdapter(requireContext(), canvasContext, adapterToFragmentCallback, quizListRepository, lifecycleScope) configureRecyclerView( diff --git a/apps/student/src/main/java/com/instructure/student/features/settings/StudentSettingsBehaviour.kt b/apps/student/src/main/java/com/instructure/student/features/settings/StudentSettingsBehaviour.kt new file mode 100644 index 0000000000..60ac269d6b --- /dev/null +++ b/apps/student/src/main/java/com/instructure/student/features/settings/StudentSettingsBehaviour.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.instructure.student.features.settings + +import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.pandautils.features.settings.SettingsBehaviour +import com.instructure.pandautils.features.settings.SettingsItem +import com.instructure.student.BuildConfig +import com.instructure.student.R + +class StudentSettingsBehaviour( + private val apiPrefs: ApiPrefs, +) : SettingsBehaviour { + override val settingsItems: Map> + get() { + val preferencesList = mutableListOf( + SettingsItem.APP_THEME, + SettingsItem.PROFILE_SETTINGS, + SettingsItem.PUSH_NOTIFICATIONS, + SettingsItem.EMAIL_NOTIFICATIONS + ) + if (apiPrefs.canGeneratePairingCode == true) { + preferencesList.add(SettingsItem.PAIR_WITH_OBSERVER) + } + if (apiPrefs.user?.calendar?.ics != null) { + preferencesList.add(SettingsItem.SUBSCRIBE_TO_CALENDAR) + } + if (apiPrefs.canvasForElementary) { + preferencesList.add(1, SettingsItem.HOMEROOM_VIEW) + } + if (BuildConfig.DEBUG) { + preferencesList.add(SettingsItem.ACCOUNT_PREFERENCES) + preferencesList.add(SettingsItem.FEATURE_FLAGS) + preferencesList.add(SettingsItem.REMOTE_CONFIG) + } + + return mapOf( + R.string.preferences to preferencesList, + R.string.offlineContent to listOf(SettingsItem.OFFLINE_SYNCHRONIZATION), + R.string.legal to listOf(SettingsItem.ABOUT, SettingsItem.LEGAL) + ) + } +} \ No newline at end of file diff --git a/apps/student/src/main/java/com/instructure/student/features/settings/StudentSettingsRouter.kt b/apps/student/src/main/java/com/instructure/student/features/settings/StudentSettingsRouter.kt new file mode 100644 index 0000000000..b4f4f28369 --- /dev/null +++ b/apps/student/src/main/java/com/instructure/student/features/settings/StudentSettingsRouter.kt @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.instructure.student.features.settings + +import androidx.fragment.app.FragmentActivity +import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.interactions.router.Route +import com.instructure.pandautils.features.notification.preferences.EmailNotificationPreferencesFragment +import com.instructure.pandautils.features.notification.preferences.PushNotificationPreferencesFragment +import com.instructure.pandautils.features.offline.sync.settings.SyncSettingsFragment +import com.instructure.pandautils.features.settings.SettingsRouter +import com.instructure.pandautils.fragments.RemoteConfigParamsFragment +import com.instructure.student.activity.NothingToSeeHereFragment +import com.instructure.student.fragment.AccountPreferencesFragment +import com.instructure.student.fragment.FeatureFlagsFragment +import com.instructure.student.fragment.ProfileSettingsFragment +import com.instructure.student.mobius.settings.pairobserver.ui.PairObserverFragment +import com.instructure.student.router.RouteMatcher + +class StudentSettingsRouter( + private val activity: FragmentActivity +) : SettingsRouter { + override fun navigateToProfileSettings() { + val fragment = if (ApiPrefs.isStudentView) { + NothingToSeeHereFragment::class.java + } else { + ProfileSettingsFragment::class.java + } + RouteMatcher.route( + activity, + Route(null, fragment) + ) + } + + override fun navigateToPushNotificationsSettings() { + RouteMatcher.route( + activity, + Route(null, PushNotificationPreferencesFragment::class.java) + ) + + } + + override fun navigateToEmailNotificationsSettings() { + RouteMatcher.route( + activity, + Route(null, EmailNotificationPreferencesFragment::class.java) + ) + } + + override fun navigateToPairWithObserver() { + RouteMatcher.route( + activity, + Route(null, PairObserverFragment::class.java) + ) + } + + override fun navigateToSyncSettings() { + RouteMatcher.route( + activity, + Route(null, SyncSettingsFragment::class.java) + ) + } + + override fun navigateToAccountPreferences() { + RouteMatcher.route( + activity, + Route(null, AccountPreferencesFragment::class.java) + ) + } + + override fun navigateToRemoteConfig() { + RouteMatcher.route( + activity, + Route(null, RemoteConfigParamsFragment::class.java) + ) + } + + override fun navigateToFeatureFlags() { + RouteMatcher.route( + activity, + Route(null, FeatureFlagsFragment::class.java) + ) + } +} \ No newline at end of file diff --git a/apps/student/src/main/java/com/instructure/student/features/smartsearch/StudentSmartSearchRouter.kt b/apps/student/src/main/java/com/instructure/student/features/smartsearch/StudentSmartSearchRouter.kt new file mode 100644 index 0000000000..2ebf978e22 --- /dev/null +++ b/apps/student/src/main/java/com/instructure/student/features/smartsearch/StudentSmartSearchRouter.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.instructure.student.features.smartsearch + +import androidx.fragment.app.FragmentActivity +import com.instructure.pandautils.features.smartsearch.SmartSearchRouter +import com.instructure.student.router.RouteMatcher + +class StudentSmartSearchRouter( + private val activity: FragmentActivity, +) : SmartSearchRouter { + override fun route(url: String) { + RouteMatcher.routeUrl(activity, url) + } +} \ No newline at end of file diff --git a/apps/student/src/main/java/com/instructure/student/fragment/AccountPreferencesFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/AccountPreferencesFragment.kt index 1a3357b3f3..2973b7707a 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/AccountPreferencesFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/AccountPreferencesFragment.kt @@ -25,8 +25,8 @@ import android.widget.BaseAdapter import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import com.instructure.canvasapi2.utils.ApiPrefs -import com.instructure.canvasapi2.utils.LocaleUtils -import com.instructure.canvasapi2.utils.cleanDisplayName +import com.instructure.pandautils.utils.LocaleUtils +import com.instructure.pandautils.utils.cleanDisplayName import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.pandautils.analytics.SCREEN_VIEW_ACCOUNT_PREFERENCES import com.instructure.pandautils.analytics.ScreenView @@ -50,10 +50,11 @@ class AccountPreferencesFragment : ParentFragment() { private val binding by viewBinding(FragmentAccountPreferencesBinding::bind) private val languages: List> by lazy { + val translationArray = BuildConfig.TRANSLATION_TAGS.split(";") listOf( ApiPrefs.ACCOUNT_LOCALE to "Account Locale", ApiPrefs.DEVICE_LOCALE to "Device Locale" - ) + LocaleUtils.getSupportedLanguageTags() + ) + translationArray .map { it to Locale.Builder().setLanguageTag(it).build().cleanDisplayName } } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/ApplicationSettingsFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/ApplicationSettingsFragment.kt deleted file mode 100644 index 8a90f88748..0000000000 --- a/apps/student/src/main/java/com/instructure/student/fragment/ApplicationSettingsFragment.kt +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2017 - present Instructure, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package com.instructure.student.fragment - -import android.annotation.SuppressLint -import android.content.Intent -import android.net.Uri -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.Fragment -import androidx.lifecycle.lifecycleScope -import com.instructure.canvasapi2.utils.* -import com.instructure.canvasapi2.utils.pageview.PageView -import com.instructure.pandautils.analytics.SCREEN_VIEW_APPLICATION_SETTINGS -import com.instructure.pandautils.analytics.ScreenView -import com.instructure.pandautils.binding.viewBinding -import com.instructure.pandautils.features.about.AboutFragment -import com.instructure.pandautils.features.legal.LegalDialogFragment -import com.instructure.pandautils.features.notification.preferences.EmailNotificationPreferencesFragment -import com.instructure.pandautils.features.notification.preferences.PushNotificationPreferencesFragment -import com.instructure.pandautils.features.offline.sync.settings.SyncSettingsFragment -import com.instructure.pandautils.fragments.RemoteConfigParamsFragment -import com.instructure.pandautils.room.offline.facade.SyncSettingsFacade -import com.instructure.pandautils.utils.* -import com.instructure.student.BuildConfig -import com.instructure.student.R -import com.instructure.student.activity.NothingToSeeHereFragment -import com.instructure.student.activity.SettingsActivity -import com.instructure.student.databinding.FragmentApplicationSettingsBinding -import com.instructure.student.mobius.settings.pairobserver.ui.PairObserverFragment -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import javax.inject.Inject - -@ScreenView(SCREEN_VIEW_APPLICATION_SETTINGS) -@PageView(url = "profile/settings") -@AndroidEntryPoint -class ApplicationSettingsFragment : ParentFragment() { - - @Inject - lateinit var syncSettingsFacade: SyncSettingsFacade - - @Inject - lateinit var featureFlagProvider: FeatureFlagProvider - - @Inject - lateinit var networkStateProvider: NetworkStateProvider - - private val binding by viewBinding(FragmentApplicationSettingsBinding::bind) - - override fun title(): String = getString(R.string.settings) - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = - inflater.inflate(R.layout.fragment_application_settings, container, false) - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - applyTheme() - setupViews() - - networkStateProvider.isOnlineLiveData.observe(this) { isOnline -> - handleOnlineState(isOnline == true) - } - } - - private fun handleOnlineState(online: Boolean) = with(binding) { - profileSettings.alpha = if (online) 1f else 0.5f - pushNotifications.alpha = if (online) 1f else 0.5f - emailNotifications.alpha = if (online) 1f else 0.5f - pairObserver.alpha = if (online) 1f else 0.5f - legal.alpha = if (online) 1f else 0.5f - } - - override fun applyTheme() = with(binding) { - toolbar.setupAsBackButton(this@ApplicationSettingsFragment) - ViewStyler.themeToolbarColored(requireActivity(), toolbar, ThemePrefs.primaryColor, ThemePrefs.primaryTextColor) - } - - @SuppressLint("SetTextI18n") - private fun setupViews() = with(binding) { - profileSettings.onClickWithRequireNetwork { - val frag = if (ApiPrefs.isStudentView) { - // Profile settings not available in Student View - NothingToSeeHereFragment.newInstance() - } else { - ProfileSettingsFragment.newInstance() - } - - addFragment(frag) - } - - // Account Preferences currently only contains the debug language selector, so we'll hide it in prod - if (BuildConfig.DEBUG) { - accountPreferences.setVisible() - accountPreferences.onClick { addFragment(AccountPreferencesFragment.newInstance()) } - } - - legal.onClickWithRequireNetwork { LegalDialogFragment().show(requireFragmentManager(), null) } - pinAndFingerprint.setGone() // TODO: Wire up once implemented - - if (ApiPrefs.canGeneratePairingCode == true) { - pairObserver.setVisible() - pairObserver.onClickWithRequireNetwork { - addFragment(PairObserverFragment.newInstance()) - } - } - - pushNotifications.onClickWithRequireNetwork { - addFragment(PushNotificationPreferencesFragment.newInstance()) - } - - emailNotifications.onClickWithRequireNetwork { - addFragment(EmailNotificationPreferencesFragment.newInstance()) - } - - about.onClick { - AboutFragment.newInstance().show(childFragmentManager, null) - } - - setUpSyncSettings() - - if (ApiPrefs.canvasForElementary) { - elementaryViewSwitch.isChecked = ApiPrefs.elementaryDashboardEnabledOverride - elementaryViewLayout.setVisible() - ViewStyler.themeSwitch(requireContext(), elementaryViewSwitch, ThemePrefs.brandColor) - elementaryViewSwitch.setOnCheckedChangeListener { _, isChecked -> - ApiPrefs.elementaryDashboardEnabledOverride = isChecked - - val analyticsBundle = Bundle().apply { - putBoolean(AnalyticsParamConstants.MANUAL_C4E_STATE, isChecked) - } - Analytics.logEvent(AnalyticsEventConstants.CHANGED_C4E_MODE, analyticsBundle) - } - } - - setUpAppThemeSelector() - setUpSubscribeToCalendarFeed() - - if (BuildConfig.DEBUG) { - featureFlags.setVisible() - featureFlags.onClick { - addFragment(FeatureFlagsFragment()) - } - - remoteConfigParams.setVisible() - remoteConfigParams.onClick { - addFragment(RemoteConfigParamsFragment()) - } - } - } - - private fun addFragment(fragment: Fragment) { - (activity as? SettingsActivity)?.addFragment(fragment) - } - - private fun setUpAppThemeSelector() { - val initialAppTheme = AppTheme.fromIndex(ThemePrefs.appTheme) - binding.appThemeStatus.setText(initialAppTheme.themeNameRes) - - binding.appThemeContainer.onClick { - AppThemeSelector.showAppThemeSelectorDialog(requireContext(), binding.appThemeStatus) - } - } - - private fun setUpSyncSettings() { - lifecycleScope.launch { - val offlineEnabled = (activity as? SettingsActivity)?.offlineEnabled ?: false - if (offlineEnabled) { - syncSettingsFacade.getSyncSettingsListenable().observe(viewLifecycleOwner) { syncSettings -> - if (syncSettings == null) { - binding.offlineSyncSettingsContainer.setGone() - } else { - binding.offlineSyncSettingsStatus.text = if (syncSettings.autoSyncEnabled) { - getString(syncSettings.syncFrequency.readable) - } else { - getString(R.string.syncSettings_manualDescription) - } - } - } - - binding.offlineSyncSettingsContainer.onClick { - addFragment(SyncSettingsFragment.newInstance()) - } - } else { - binding.offlineContentDivider.setGone() - binding.offlineContentTitle.setGone() - binding.offlineSyncSettingsContainer.setGone() - } - } - } - - private fun setUpSubscribeToCalendarFeed() { - val calendarFeed = ApiPrefs.user?.calendar?.ics - if (!calendarFeed.isNullOrEmpty()) { - binding.subscribeToCalendar.apply { - setVisible() - onClick { - AlertDialog.Builder(requireContext()) - .setMessage(R.string.subscribeToCalendarMessage) - .setPositiveButton(R.string.subscribeButton) { dialog, _ -> - dialog.dismiss() - openCalendarLink(calendarFeed) - } - .setNegativeButton(R.string.cancel, { dialog, _ -> dialog.dismiss() }) - .showThemed() - } - } - } - } - - private fun openCalendarLink(calendarLink: String) { - val webcalLink = calendarLink.replace("https://", "webcal://") - val googleCalendarLink = "https://calendar.google.com/calendar/r?cid=$webcalLink" - val intent = Intent(Intent.ACTION_VIEW) - intent.setData(Uri.parse(googleCalendarLink)) - startActivity(intent) - } -} diff --git a/apps/student/src/main/java/com/instructure/student/fragment/AssignmentBasicFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/AssignmentBasicFragment.kt index 4d3093f698..9591f8f08f 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/AssignmentBasicFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/AssignmentBasicFragment.kt @@ -30,7 +30,16 @@ import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_ASSIGNMENT_BASIC import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.binding.viewBinding -import com.instructure.pandautils.utils.* +import com.instructure.pandautils.features.lti.LtiLaunchFragment +import com.instructure.pandautils.utils.Const +import com.instructure.pandautils.utils.OnBackStackChangedEvent +import com.instructure.pandautils.utils.ParcelableArg +import com.instructure.pandautils.utils.ViewStyler +import com.instructure.pandautils.utils.argsWithContext +import com.instructure.pandautils.utils.loadHtmlWithIframes +import com.instructure.pandautils.utils.setGone +import com.instructure.pandautils.utils.setupAsBackButton +import com.instructure.pandautils.utils.withArgs import com.instructure.pandautils.views.CanvasWebView import com.instructure.student.R import com.instructure.student.databinding.FragmentAssignmentBasicBinding @@ -39,7 +48,9 @@ import kotlinx.coroutines.Job import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode -import java.util.* +import java.util.Calendar +import java.util.Date +import java.util.Locale @ScreenView(SCREEN_VIEW_ASSIGNMENT_BASIC) class AssignmentBasicFragment : ParentFragment() { @@ -142,7 +153,7 @@ class AssignmentBasicFragment : ParentFragment() { loadHtmlJob = assignmentWebViewWrapper.webView.loadHtmlWithIframes(requireContext(), description, { assignmentWebViewWrapper.loadHtml(it, assignment.name) }, { - LtiLaunchFragment.routeLtiLaunchFragment(requireActivity(), canvasContext, it) + RouteMatcher.route(requireActivity(), LtiLaunchFragment.makeSessionlessLtiUrlRoute(requireActivity(), canvasContext, it)) }) } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/BasicQuizViewFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/BasicQuizViewFragment.kt index 8ee29fb316..3c67fd9a3f 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/BasicQuizViewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/BasicQuizViewFragment.kt @@ -57,7 +57,7 @@ class BasicQuizViewFragment : InternalWebviewFragment() { private var apiURL: String? by NullableStringArg() private var quiz: Quiz? by NullableParcelableArg() @get:PageViewUrlParam("quizId") - private var quizId: Long by LongArg() + var quizId: Long by LongArg() override fun title(): String = getString(R.string.quizzes) diff --git a/apps/student/src/main/java/com/instructure/student/fragment/BookmarksFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/BookmarksFragment.kt index 872a8233b5..ef4ed3995a 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/BookmarksFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/BookmarksFragment.kt @@ -29,7 +29,6 @@ import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.AppCompatEditText import androidx.appcompat.widget.PopupMenu -import androidx.fragment.app.DialogFragment import com.instructure.canvasapi2.StatusCallback import com.instructure.canvasapi2.managers.BookmarkManager import com.instructure.canvasapi2.models.Bookmark @@ -65,7 +64,7 @@ class BookmarksFragment : ParentFragment() { //region Fragment Lifecycle Overrides override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setStyle(DialogFragment.STYLE_NORMAL, R.style.LightStatusBarDialog) + setStyle(STYLE_NORMAL, R.style.LightStatusBarDialog) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { diff --git a/apps/student/src/main/java/com/instructure/student/fragment/CourseSettingsFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/CourseSettingsFragment.kt index 46b1307898..639c1089e4 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/CourseSettingsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/CourseSettingsFragment.kt @@ -43,7 +43,7 @@ class CourseSettingsFragment : ParentFragment() { @Suppress("unused") @PageViewUrl - private fun makePageViewUrl() = "courses/${course.id}/settings" + fun makePageViewUrl() = "courses/${course.id}/settings" override fun title(): String = getString(R.string.settings) @@ -58,6 +58,7 @@ class CourseSettingsFragment : ParentFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) = with(binding) { + super.onViewCreated(view, savedInstanceState) courseName.text = course.name courseCode.text = course.courseCode license.text = course.license?.prettyString diff --git a/apps/student/src/main/java/com/instructure/student/fragment/CreateAnnouncementFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/CreateAnnouncementFragment.kt index f784d4fc7f..dffbaf3583 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/CreateAnnouncementFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/CreateAnnouncementFragment.kt @@ -30,6 +30,7 @@ import com.instructure.canvasapi2.models.DiscussionTopicHeader import com.instructure.canvasapi2.models.postmodels.DiscussionTopicPostBody import com.instructure.canvasapi2.utils.NetworkUtils import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave @@ -55,7 +56,8 @@ class CreateAnnouncementFragment : ParentFragment() { /* The announcement to be edited. This will be null if we're creating a new announcement */ private var editAnnouncement by NullableParcelableArg(key = DISCUSSION_TOPIC_HEADER) - private var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) /* Menu buttons. We don't cache these because the toolbar is reconstructed on configuration change. */ private val mSaveMenuButton get() = binding.createAnnouncementToolbar.menu.findItem(R.id.menuSaveAnnouncement) diff --git a/apps/student/src/main/java/com/instructure/student/fragment/CreateDiscussionFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/CreateDiscussionFragment.kt index 373a741eed..cdd2a1998c 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/CreateDiscussionFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/CreateDiscussionFragment.kt @@ -32,6 +32,7 @@ import com.instructure.canvasapi2.models.postmodels.DiscussionTopicPostBody import com.instructure.canvasapi2.models.postmodels.FileSubmitObject import com.instructure.canvasapi2.utils.NetworkUtils import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.weave.* import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_CREATE_DISCUSSION @@ -60,7 +61,8 @@ class CreateDiscussionFragment : ParentFragment() { private val binding by viewBinding(FragmentCreateDiscussionBinding::bind) - private var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private val sendButton: TextView? get() = view?.findViewById(R.id.menuSaveDiscussion) private val saveButton: TextView? get() = view?.findViewById(R.id.menuSave) // private val mAttachmentButton: TextView? get() = view?.findViewById(R.id.menuAddAttachment) BLOCKED COMMS 868 diff --git a/apps/student/src/main/java/com/instructure/student/fragment/EditPageDetailsFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/EditPageDetailsFragment.kt index 96e685f846..024589e5da 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/EditPageDetailsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/EditPageDetailsFragment.kt @@ -65,7 +65,7 @@ class EditPageDetailsFragment : ParentFragment() { @PageViewUrl @Suppress("unused") - private fun makePageViewUrl(): String { + fun makePageViewUrl(): String { val url = StringBuilder(ApiPrefs.fullDomain) page.let { url.append(canvasContext.toAPIString()) @@ -79,6 +79,7 @@ class EditPageDetailsFragment : ParentFragment() { inflater.inflate(R.layout.fragment_edit_page, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) setupToolbar() setupDescription() } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/FeatureFlagsFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/FeatureFlagsFragment.kt index 2e2ac230cf..367b70e22a 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/FeatureFlagsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/FeatureFlagsFragment.kt @@ -20,7 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.recyclerview.widget.RecyclerView import com.instructure.canvasapi2.utils.FeatureFlagPref import com.instructure.pandautils.binding.viewBinding @@ -32,7 +32,7 @@ import com.instructure.student.databinding.AdapterFeatureFlagBinding import com.instructure.student.databinding.FragmentFeatureFlagsBinding import com.instructure.student.util.FeatureFlagPrefs -class FeatureFlagsFragment : Fragment() { +class FeatureFlagsFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentFeatureFlagsBinding::bind) diff --git a/apps/student/src/main/java/com/instructure/student/fragment/InboxConversationFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/InboxConversationFragment.kt index f1cc98172f..32ac95d15f 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/InboxConversationFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/InboxConversationFragment.kt @@ -26,7 +26,11 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.work.WorkManager import com.instructure.canvasapi2.managers.InboxManager -import com.instructure.canvasapi2.models.* +import com.instructure.canvasapi2.models.Attachment +import com.instructure.canvasapi2.models.BasicUser +import com.instructure.canvasapi2.models.Conversation +import com.instructure.canvasapi2.models.Message +import com.instructure.canvasapi2.models.Recipient import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.canvasapi2.utils.weave.WeaveJob @@ -39,7 +43,20 @@ import com.instructure.pandautils.analytics.SCREEN_VIEW_INBOX_CONVERSATION import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.binding.viewBinding import com.instructure.pandautils.features.file.download.FileDownloadWorker -import com.instructure.pandautils.utils.* +import com.instructure.pandautils.utils.ColorUtils +import com.instructure.pandautils.utils.Const +import com.instructure.pandautils.utils.ConversationUpdatedEvent +import com.instructure.pandautils.utils.LongArg +import com.instructure.pandautils.utils.NullableStringArg +import com.instructure.pandautils.utils.ParcelableArg +import com.instructure.pandautils.utils.PermissionUtils +import com.instructure.pandautils.utils.ThemePrefs +import com.instructure.pandautils.utils.ToolbarColorizeHelper +import com.instructure.pandautils.utils.ViewStyler +import com.instructure.pandautils.utils.getDrawableCompat +import com.instructure.pandautils.utils.setupAsBackButton +import com.instructure.pandautils.utils.toast +import com.instructure.pandautils.utils.withArgs import com.instructure.student.R import com.instructure.student.adapter.InboxConversationAdapter import com.instructure.student.databinding.FragmentInboxConversationBinding @@ -113,7 +130,7 @@ class InboxConversationFragment : ParentFragment() { when (action) { AttachmentView.AttachmentAction.REMOVE -> Unit // Do nothing - AttachmentView.AttachmentAction.PREVIEW -> openMedia(attachment.contentType, attachment.url, attachment.filename, ApiPrefs.user!!) + AttachmentView.AttachmentAction.PREVIEW -> openMedia(attachment.contentType, attachment.url, attachment.filename, attachment.id.toString(), ApiPrefs.user!!) AttachmentView.AttachmentAction.DOWNLOAD -> { if (PermissionUtils.hasPermissions(requireActivity(), PermissionUtils.WRITE_EXTERNAL_STORAGE)) { @@ -174,6 +191,7 @@ class InboxConversationFragment : ParentFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) recyclerBinding = PandaRecyclerRefreshLayoutBinding.bind(binding.root) when { // Setup from conversation ID diff --git a/apps/student/src/main/java/com/instructure/student/fragment/InternalWebviewFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/InternalWebviewFragment.kt index efeacd8422..f09722105b 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/InternalWebviewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/InternalWebviewFragment.kt @@ -38,6 +38,7 @@ import com.instructure.canvasapi2.models.LTITool import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.isValid +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.weave.StatusCallbackError import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.canvasapi2.utils.weave.catch @@ -75,6 +76,7 @@ open class InternalWebviewFragment : ParentFragment() { val binding by viewBinding(FragmentWebviewBinding::bind) + @get:PageViewUrlParam("canvasContext") var canvasContext: CanvasContext by ParcelableArg( default = CanvasContext.emptyUserContext(), key = Const.CANVAS_CONTEXT @@ -145,7 +147,7 @@ open class InternalWebviewFragment : ParentFragment() { canvasWebViewWrapper.webView.canvasWebViewClientCallback = object : CanvasWebView.CanvasWebViewClientCallback { override fun openMediaFromWebView(mime: String, url: String, filename: String) { - openMedia(canvasContext, url, filename) + openMedia(canvasContext, url, filename, null) } override fun onPageFinishedCallback(webView: WebView, url: String) { diff --git a/apps/student/src/main/java/com/instructure/student/fragment/LtiLaunchFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/LtiLaunchFragment.kt deleted file mode 100644 index aa56b19cf8..0000000000 --- a/apps/student/src/main/java/com/instructure/student/fragment/LtiLaunchFragment.kt +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2017 - present Instructure, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package com.instructure.student.fragment - -import android.net.Uri -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.browser.customtabs.CustomTabColorSchemeParams -import androidx.browser.customtabs.CustomTabsIntent -import androidx.fragment.app.FragmentActivity -import com.instructure.canvasapi2.managers.AssignmentManager -import com.instructure.canvasapi2.managers.SubmissionManager -import com.instructure.canvasapi2.models.CanvasContext -import com.instructure.canvasapi2.models.Course -import com.instructure.canvasapi2.models.Group -import com.instructure.canvasapi2.models.LTITool -import com.instructure.canvasapi2.models.Tab -import com.instructure.canvasapi2.utils.ApiPrefs -import com.instructure.canvasapi2.utils.isValid -import com.instructure.canvasapi2.utils.pageview.PageView -import com.instructure.canvasapi2.utils.pageview.PageViewUrl -import com.instructure.canvasapi2.utils.validOrNull -import com.instructure.canvasapi2.utils.weave.weave -import com.instructure.interactions.router.Route -import com.instructure.pandautils.analytics.SCREEN_VIEW_LTI_LAUNCH -import com.instructure.pandautils.analytics.ScreenView -import com.instructure.pandautils.binding.viewBinding -import com.instructure.pandautils.utils.BooleanArg -import com.instructure.pandautils.utils.Const -import com.instructure.pandautils.utils.HtmlContentFormatter -import com.instructure.pandautils.utils.NullableParcelableArg -import com.instructure.pandautils.utils.NullableStringArg -import com.instructure.pandautils.utils.ParcelableArg -import com.instructure.pandautils.utils.StringArg -import com.instructure.pandautils.utils.argsWithContext -import com.instructure.pandautils.utils.asChooserExcludingInstructure -import com.instructure.pandautils.utils.color -import com.instructure.pandautils.utils.replaceWithURLQueryParameter -import com.instructure.pandautils.utils.setTextForVisibility -import com.instructure.pandautils.utils.toast -import com.instructure.pandautils.utils.withArgs -import com.instructure.student.R -import com.instructure.student.databinding.FragmentLtiLaunchBinding -import com.instructure.student.router.RouteMatcher -import kotlinx.coroutines.Job -import java.net.URLDecoder - -@ScreenView(SCREEN_VIEW_LTI_LAUNCH) -@PageView -class LtiLaunchFragment : ParentFragment() { - - private val binding by viewBinding(FragmentLtiLaunchBinding::bind) - - var canvasContext: CanvasContext by ParcelableArg(default = CanvasContext.emptyUserContext(), key = Const.CANVAS_CONTEXT) - var title: String? by NullableStringArg(key = Const.ACTION_BAR_TITLE) - private var ltiUrl: String by StringArg(key = LTI_URL) - private var ltiTab: Tab? by NullableParcelableArg(key = Const.TAB) - private var ltiTool: LTITool? by NullableParcelableArg(key = Const.LTI_TOOL, default = null) - private var sessionLessLaunch: Boolean by BooleanArg(key = Const.SESSIONLESS_LAUNCH) - private var isAssignmentLTI: Boolean by BooleanArg(key = Const.ASSIGNMENT_LTI) - - /* Tracks whether we have automatically started launching the LTI tool in a chrome custom tab. Because this fragment - re-runs certain logic in onResume, tracking the launch helps us know to pop this fragment instead of erroneously - launching again when the user returns to the app. */ - private var customTabLaunched: Boolean = false - - private var ltiUrlLaunchJob: Job? = null - - @Suppress("unused") - @PageViewUrl - private fun makePageViewUrl() = - ltiTab?.externalUrl ?: ApiPrefs.fullDomain + canvasContext.toAPIString() + "/external_tools" - - override fun title(): String = title.validOrNull() ?: ltiTab?.label?.validOrNull() ?: ltiUrl.validOrNull() ?: "" - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_lti_launch, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.loadingView.setOverrideColor(canvasContext.color) - binding.toolName.setTextForVisibility(title().validOrNull()) - } - - override fun applyTheme() = Unit - - override fun onResume() { - super.onResume() - // If onResume() is called after the custom tab has launched, it means the user is returning and we should close this fragment - if (customTabLaunched) { - activity?.supportFragmentManager?.popBackStack() - return - } - - try { - when { - ltiTab != null -> loadSessionlessLtiUrl(ltiTab!!.ltiUrl) - ltiUrl.isNotBlank() -> { - var url = ltiUrl // Replace deep link scheme - .replaceFirst("canvas-courses://", "${ApiPrefs.protocol}://") - .replaceFirst("canvas-student://", "${ApiPrefs.protocol}://") - .replaceWithURLQueryParameter(HtmlContentFormatter.hasKalturaUrl(ltiUrl)) - - when { - sessionLessLaunch -> { - // This is specific for Studio and Gauge - val id = url.substringAfterLast("/external_tools/").substringBefore("?") - url = when { - (id.toIntOrNull() != null) -> when (canvasContext) { - is Course -> "${ApiPrefs.fullDomain}/api/v1/courses/${canvasContext.id}/external_tools/sessionless_launch?id=$id" - is Group -> "${ApiPrefs.fullDomain}/api/v1/groups/${canvasContext.id}/external_tools/sessionless_launch?id=$id" - else -> "${ApiPrefs.fullDomain}/api/v1/accounts/self/external_tools/sessionless_launch?id=$id" - } - else -> when (canvasContext) { - is Course -> "${ApiPrefs.fullDomain}/api/v1/courses/${canvasContext.id}/external_tools/sessionless_launch?url=$url" - is Group -> "${ApiPrefs.fullDomain}/api/v1/groups/${canvasContext.id}/external_tools/sessionless_launch?url=$url" - else -> "${ApiPrefs.fullDomain}/api/v1/accounts/self/external_tools/sessionless_launch?url=$url" - } - } - loadSessionlessLtiUrl(url) - } - isAssignmentLTI -> loadSessionlessLtiUrl(url) - else -> launchCustomTab(url) - } - } - else -> displayError() - } - } catch (e: Exception) { - // If it gets here we're in trouble and won't know what the tab is, so just display an error message - displayError() - } - } - - private fun loadSessionlessLtiUrl(ltiUrl: String) { - ltiUrlLaunchJob = weave { - val tool = getLtiTool(ltiUrl) - tool?.url?.let { launchCustomTab(it) } ?: displayError() - } - } - - private fun launchCustomTab(url: String) { - val uri = Uri.parse(url) - .buildUpon() - .appendQueryParameter("display", "borderless") - .appendQueryParameter("platform", "android") - .build() - - val colorSchemeParams = CustomTabColorSchemeParams.Builder() - .setToolbarColor(canvasContext.color) - .build() - - var intent = CustomTabsIntent.Builder() - .setDefaultColorSchemeParams(colorSchemeParams) - .setShowTitle(true) - .build() - .intent - - intent.data = uri - - // Exclude Instructure apps from chooser options - intent = intent.asChooserExcludingInstructure() - - context?.startActivity(intent) - - customTabLaunched = true - } - - private fun displayError() { - toast(R.string.errorOccurred) - if (activity != null) { - requireActivity().onBackPressed() - } - } - - private suspend fun getLtiTool(url: String): LTITool? { - return ltiTool?.let { - AssignmentManager.getExternalToolLaunchUrlAsync(it.courseId, it.id, it.assignmentId).await().dataOrNull - } ?: SubmissionManager.getLtiFromAuthenticationUrlAsync(url, true).await().dataOrNull - } - - override fun onDestroy() { - super.onDestroy() - ltiUrlLaunchJob?.cancel() - } - - companion object { - const val LTI_URL = "ltiUrl" - - fun makeLTIBundle(ltiUrl: String, title: String, sessionLessLaunch: Boolean): Bundle { - val args = Bundle() - args.putString(LTI_URL, ltiUrl) - args.putBoolean(Const.SESSIONLESS_LAUNCH, sessionLessLaunch) - args.putString(Const.ACTION_BAR_TITLE, title) - return args - } - - fun makeRoute(canvasContext: CanvasContext, ltiTab: Tab): Route { - val bundle = Bundle().apply { putParcelable(Const.TAB, ltiTab) } - return Route(LtiLaunchFragment::class.java, canvasContext, bundle) - } - - /** - * The ltiTool param is used specifically for launching assignment based lti tools, where its possible to have - * a tool "collision". As such, we need to pre-fetch the correct tool to use here. - */ - fun makeRoute( - canvasContext: CanvasContext, - url: String, - title: String? = null, - sessionLessLaunch: Boolean = false, - isAssignmentLTI: Boolean = false, - ltiTool: LTITool? = null - ): Route { - val bundle = Bundle().apply { - putString(LTI_URL, url) - putBoolean(Const.SESSIONLESS_LAUNCH, sessionLessLaunch) - putBoolean(Const.ASSIGNMENT_LTI, isAssignmentLTI) - putString(Const.ACTION_BAR_TITLE, title) // For 'title' property in InternalWebViewFragment - putParcelable(Const.LTI_TOOL, ltiTool) - } - return Route(LtiLaunchFragment::class.java, canvasContext, bundle) - } - - fun validateRoute(route: Route): Boolean { - route.canvasContext ?: return false - return route.arguments.getParcelable(Const.TAB) != null || route.arguments.getString(LTI_URL).isValid() - } - - fun newInstance(route: Route): LtiLaunchFragment? { - if (!validateRoute(route)) return null - return LtiLaunchFragment().withArgs(route.argsWithContext) - } - - fun routeLtiLaunchFragment(activity: FragmentActivity, canvasContext: CanvasContext?, url: String) { - val args = makeLTIBundle(URLDecoder.decode(url, "utf-8"), activity.getString(R.string.utils_externalToolTitle), true) - RouteMatcher.route(activity, Route(LtiLaunchFragment::class.java, canvasContext, args)) - } - } -} diff --git a/apps/student/src/main/java/com/instructure/student/fragment/MasteryPathOptionsFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/MasteryPathOptionsFragment.kt index 070f21feac..f30d8c32f9 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/MasteryPathOptionsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/MasteryPathOptionsFragment.kt @@ -74,6 +74,7 @@ class MasteryPathOptionsFragment : ParentFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) mRecyclerAdapter = MasteryPathOptionsRecyclerAdapter( requireContext(), assignments.toTypedArray(), diff --git a/apps/student/src/main/java/com/instructure/student/fragment/NotificationListFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/NotificationListFragment.kt index aa6ebc7f38..48fa2e3a05 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/NotificationListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/NotificationListFragment.kt @@ -110,6 +110,7 @@ class NotificationListFragment : ParentFragment(), Bookmarkable, FragmentManager = layoutInflater.inflate(R.layout.fragment_list_notification, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) recyclerBinding = PandaRecyclerRefreshLayoutBinding.bind(binding.root) recyclerAdapter = NotificationListRecyclerAdapter(requireContext(), canvasContext, adapterToFragmentCallback) recyclerAdapter?.let { diff --git a/apps/student/src/main/java/com/instructure/student/fragment/ParentFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/ParentFragment.kt index 24f868fa74..864080d9e7 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/ParentFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/ParentFragment.kt @@ -35,7 +35,6 @@ import android.view.inputmethod.InputMethodManager import android.widget.Toast import androidx.annotation.MenuRes import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import androidx.loader.app.LoaderManager import androidx.loader.content.Loader @@ -53,6 +52,7 @@ import com.instructure.interactions.bookmarks.Bookmarkable import com.instructure.pandarecycler.BaseRecyclerAdapter import com.instructure.pandarecycler.PandaRecyclerView import com.instructure.pandarecycler.interfaces.EmptyViewInterface +import com.instructure.pandautils.base.BaseCanvasDialogFragment import com.instructure.pandautils.interfaces.NavigationCallbacks import com.instructure.pandautils.loaders.OpenMediaAsyncTaskLoader import com.instructure.pandautils.utils.Const @@ -70,7 +70,7 @@ import com.instructure.student.util.onMainThread import java.io.File import java.io.FileOutputStream -abstract class ParentFragment : DialogFragment(), FragmentInteractions, NavigationCallbacks { +abstract class ParentFragment : BaseCanvasDialogFragment(), FragmentInteractions, NavigationCallbacks { private var openMediaBundle: Bundle? = null private var openMediaCallbacks: LoaderManager.LoaderCallbacks? = null @@ -372,13 +372,13 @@ abstract class ParentFragment : DialogFragment(), FragmentInteractions, Navigati return recyclerView } - fun openMedia(mime: String?, url: String?, filename: String?, canvasContext: CanvasContext, localFile: Boolean = false, useOutsideApps: Boolean = false) { + fun openMedia(mime: String?, url: String?, filename: String?, fileId: String?, canvasContext: CanvasContext, localFile: Boolean = false, useOutsideApps: Boolean = false) { val owner = activity ?: return openMediaBundle = if (localFile) { - OpenMediaAsyncTaskLoader.createLocalBundle(canvasContext, mime, url, filename, useOutsideApps) + OpenMediaAsyncTaskLoader.createLocalBundle(canvasContext, mime, url, filename, fileId, useOutsideApps) } else { - OpenMediaAsyncTaskLoader.createBundle(canvasContext, mime, url, filename, useOutsideApps) + OpenMediaAsyncTaskLoader.createBundle(canvasContext, mime, url, filename, fileId, useOutsideApps) } onMainThread { @@ -391,10 +391,10 @@ abstract class ParentFragment : DialogFragment(), FragmentInteractions, Navigati } } - fun openMedia(canvasContext: CanvasContext, url: String, filename: String?) { + fun openMedia(canvasContext: CanvasContext, url: String, filename: String?, fileId: String?) { val owner = activity ?: return onMainThread { - openMediaBundle = OpenMediaAsyncTaskLoader.createBundle(url, filename, canvasContext) + openMediaBundle = OpenMediaAsyncTaskLoader.createBundle(url, filename, fileId, canvasContext) LoaderUtils.restartLoaderWithBundle>(LoaderManager.getInstance(owner), openMediaBundle, loaderCallbacks, R.id.openMediaLoaderID) } } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/StudioWebViewFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/StudioWebViewFragment.kt index f092a5661f..5d18d56b01 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/StudioWebViewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/StudioWebViewFragment.kt @@ -67,7 +67,7 @@ class StudioWebViewFragment : InternalWebviewFragment() { getCanvasWebView()?.canvasWebViewClientCallback = object : CanvasWebView.CanvasWebViewClientCallback { override fun openMediaFromWebView(mime: String, url: String, filename: String) { - openMedia(mime, url, filename, canvasContext) + openMedia(mime, url, filename, null, canvasContext) } override fun onPageFinishedCallback(webView: WebView, url: String) { diff --git a/apps/student/src/main/java/com/instructure/student/fragment/ToDoListFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/ToDoListFragment.kt index ce3412b950..a2bbe2bc19 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/ToDoListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/ToDoListFragment.kt @@ -92,6 +92,7 @@ class ToDoListFragment : ParentFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) recyclerViewBinding = PandaRecyclerRefreshLayoutBinding.bind(binding.root) with (binding.toolbar) { inflateMenu(R.menu.fragment_list_todo) diff --git a/apps/student/src/main/java/com/instructure/student/fragment/UnknownItemFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/UnknownItemFragment.kt index 7562850bac..3402496a7b 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/UnknownItemFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/UnknownItemFragment.kt @@ -56,6 +56,7 @@ class UnknownItemFragment : ParentFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = layoutInflater.inflate(R.layout.unknown_item, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) streamItem.getMessage(requireContext()).let { binding.message.setVisible(it.isValid()).text = it } streamItem.notificationCategory.let { binding.notificationCategory.setVisible(it.isValid()).text = it } streamItem.updatedDate.let { diff --git a/apps/student/src/main/java/com/instructure/student/fragment/ViewImageFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/ViewImageFragment.kt index bce47bc595..0f11b2b3db 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/ViewImageFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/ViewImageFragment.kt @@ -24,7 +24,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.palette.graphics.Palette import com.bumptech.glide.Glide import com.bumptech.glide.load.DataSource @@ -40,7 +40,7 @@ import com.instructure.student.R import com.instructure.student.databinding.FragmentViewImageBinding import org.greenrobot.eventbus.EventBus -class ViewImageFragment : Fragment(), ShareableFile { +class ViewImageFragment : BaseCanvasFragment(), ShareableFile { private val binding by viewBinding(FragmentViewImageBinding::bind) diff --git a/apps/student/src/main/java/com/instructure/student/fragment/ViewUnsupportedFileFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/ViewUnsupportedFileFragment.kt index 9b0e33f11b..abb06c8b44 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/ViewUnsupportedFileFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/ViewUnsupportedFileFragment.kt @@ -22,7 +22,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.annotation.DrawableRes -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions import com.instructure.interactions.router.Route @@ -34,7 +34,7 @@ import com.instructure.student.databinding.FragmentUnsupportedFileTypeBinding import org.greenrobot.eventbus.EventBus //TODO: make this generic enough teacher and student can use most/all of the code -class ViewUnsupportedFileFragment : Fragment() { +class ViewUnsupportedFileFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentUnsupportedFileTypeBinding::bind) diff --git a/apps/student/src/main/java/com/instructure/student/holders/CourseViewHolder.kt b/apps/student/src/main/java/com/instructure/student/holders/CourseViewHolder.kt index b49c9320a2..0e2ef1d3d8 100644 --- a/apps/student/src/main/java/com/instructure/student/holders/CourseViewHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/holders/CourseViewHolder.kt @@ -27,11 +27,13 @@ import androidx.appcompat.widget.PopupMenu import androidx.recyclerview.widget.RecyclerView import com.instructure.canvasapi2.models.CourseGrade import com.instructure.canvasapi2.utils.NumberHelper +import com.instructure.canvasapi2.utils.convertPercentToPointBased import com.instructure.pandautils.features.dashboard.DashboardCourseItem import com.instructure.pandautils.utils.ColorKeeper import com.instructure.pandautils.utils.color import com.instructure.pandautils.utils.getContentDescriptionForMinusGradeString import com.instructure.pandautils.utils.onClickWithRequireNetwork +import com.instructure.pandautils.utils.orDefault import com.instructure.pandautils.utils.setCourseImage import com.instructure.pandautils.utils.setGone import com.instructure.pandautils.utils.setVisible @@ -113,7 +115,15 @@ class CourseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { } else { gradeTextView.setVisible() lockedGradeImage.setGone() - setGradeView(gradeTextView, courseGrade, course.color, root.context, course.settings?.restrictQuantitativeData ?: false) + setGradeView( + gradeTextView, + courseGrade, + course.color, + root.context, + course.settings?.restrictQuantitativeData ?: false, + course.pointsBasedGradingScheme, + course.scalingFactor + ) } } else { gradeLayout.setGone() @@ -125,7 +135,9 @@ class CourseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { courseGrade: CourseGrade, color: Int, context: Context, - restrictQuantitativeData: Boolean + restrictQuantitativeData: Boolean, + pointBased: Boolean, + scalingFactor: Double ) { if(courseGrade.noCurrentGrade) { textView.text = context.getString(R.string.noGradeText) @@ -135,12 +147,23 @@ class CourseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { textView.text = context.getString(R.string.noGradeText) } else { textView.text = "${courseGrade.currentGrade.orEmpty()}" - textView.contentDescription = getContentDescriptionForMinusGradeString(courseGrade.currentGrade.orEmpty(), context) + textView.contentDescription = getContentDescriptionForMinusGradeString( + courseGrade.currentGrade.orEmpty(), + context + ) } } else { - val scoreString = NumberHelper.doubleToPercentage(courseGrade.currentScore, 2) - textView.text = if(courseGrade.hasCurrentGradeString()) "${courseGrade.currentGrade} $scoreString" else scoreString - textView.contentDescription = getContentDescriptionForMinusGradeString(courseGrade.currentGrade ?: "", context) + val scoreString = if (pointBased) { + convertPercentToPointBased(courseGrade.currentScore.orDefault(), scalingFactor) + } else { + NumberHelper.doubleToPercentage(courseGrade.currentScore, 2) + } + textView.text = + if (courseGrade.hasCurrentGradeString()) "${courseGrade.currentGrade} $scoreString" else scoreString + textView.contentDescription = getContentDescriptionForMinusGradeString( + courseGrade.currentGrade ?: "", + context + ) } } textView.setTextColor(color) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/annnotation/AnnotationSubmissionUploadFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/annnotation/AnnotationSubmissionUploadFragment.kt index 0b407516a8..d1d16c0c43 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/annnotation/AnnotationSubmissionUploadFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/annnotation/AnnotationSubmissionUploadFragment.kt @@ -21,7 +21,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.viewModels import com.instructure.canvasapi2.models.CanvasContext import com.instructure.interactions.router.Route @@ -41,7 +41,7 @@ import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @AndroidEntryPoint -class AnnotationSubmissionUploadFragment : Fragment() { +class AnnotationSubmissionUploadFragment : BaseCanvasFragment() { @Inject lateinit var submissionHelper: SubmissionHelper @@ -66,11 +66,17 @@ class AnnotationSubmissionUploadFragment : Fragment() { viewModel.loadAnnotatedPdfUrl(submissionId) - viewModel.pdfUrl.observe(viewLifecycleOwner, { + viewModel.pdfUrl.observe(viewLifecycleOwner) { binding.annotationSubmissionViewContainer.addView( - PdfStudentSubmissionView(requireActivity(), it, childFragmentManager, studentAnnotationSubmit = true) + PdfStudentSubmissionView( + activity = requireActivity(), + pdfUrl = it, + fragmentManager = childFragmentManager, + studentAnnotationSubmit = true, + courseId = canvasContext.id + ) ) - }) + } setUpToolbar(binding.annotationSubmissionToolbar) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/picker/ui/PickerBadExtensionDialog.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/picker/ui/PickerBadExtensionDialog.kt index e419fa448c..24622f086c 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/picker/ui/PickerBadExtensionDialog.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/picker/ui/PickerBadExtensionDialog.kt @@ -20,7 +20,7 @@ import android.app.Dialog import android.content.DialogInterface import android.os.Bundle import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.DialogFragment +import com.instructure.pandautils.base.BaseCanvasDialogFragment import androidx.fragment.app.FragmentManager import com.instructure.pandautils.utils.StringArrayArg import com.instructure.pandautils.utils.ThemePrefs @@ -28,7 +28,7 @@ import com.instructure.pandautils.utils.dismissExisting import com.instructure.student.R import java.util.Locale -class PickerBadExtensionDialog : DialogFragment() { +class PickerBadExtensionDialog : BaseCanvasDialogFragment() { private var extensions by StringArrayArg() diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/SubmissionDetailsModels.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/SubmissionDetailsModels.kt index 1538308c69..19e28ee3ce 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/SubmissionDetailsModels.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/SubmissionDetailsModels.kt @@ -36,7 +36,7 @@ sealed class SubmissionDetailsEvent { data class DataLoaded( val assignment: DataResult, val rootSubmissionResult: DataResult, - val ltiUrlResult: DataResult?, + val ltiTool: DataResult?, val isStudioEnabled: Boolean, val quizResult: DataResult?, val studioLTIToolResult: DataResult?, @@ -93,7 +93,7 @@ sealed class SubmissionDetailsContentType { data class NoSubmissionContent(val canvasContext: CanvasContext, val assignment: Assignment, val isStudioEnabled: Boolean, val quiz: Quiz? = null, val studioLTITool: LTITool? = null, val isObserver: Boolean = false, val ltiTool: LTITool? = null) : SubmissionDetailsContentType() object NoneContent : SubmissionDetailsContentType() - data class ExternalToolContent(val canvasContext: CanvasContext, val url: String) : SubmissionDetailsContentType() + data class ExternalToolContent(val canvasContext: CanvasContext, val ltiTool: LTITool?, val title: String, val ltiType: LtiType = LtiType.EXTERNAL_TOOL) : SubmissionDetailsContentType() object OnPaperContent : SubmissionDetailsContentType() data class UnsupportedContent(val assignmentId: Long) : SubmissionDetailsContentType() data class OtherAttachmentContent(val attachment: Attachment) : SubmissionDetailsContentType() diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/SubmissionDetailsUpdate.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/SubmissionDetailsUpdate.kt index ccbdb0847b..87f4072511 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/SubmissionDetailsUpdate.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/SubmissionDetailsUpdate.kt @@ -19,9 +19,14 @@ package com.instructure.student.mobius.assignmentDetails.submissionDetails import android.net.Uri import android.webkit.MimeTypeMap -import com.instructure.canvasapi2.models.* +import com.instructure.canvasapi2.models.Assignment +import com.instructure.canvasapi2.models.Attachment +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.models.LTITool +import com.instructure.canvasapi2.models.LtiType +import com.instructure.canvasapi2.models.Quiz +import com.instructure.canvasapi2.models.Submission import com.instructure.canvasapi2.utils.ApiPrefs -import com.instructure.canvasapi2.utils.validOrNull import com.instructure.pandautils.utils.AssignmentUtils2 import com.instructure.student.mobius.common.ui.UpdateInit import com.instructure.student.util.Const @@ -76,7 +81,7 @@ class SubmissionDetailsUpdate : UpdateInit SubmissionDetailsContentType.OnPaperContent Assignment.SubmissionType.EXTERNAL_TOOL.apiString in assignment?.submissionTypesRaw.orEmpty() -> { if (assignment?.isAllowedToSubmit == true) - SubmissionDetailsContentType.ExternalToolContent(canvasContext, ltiUrl?.url ?: "") + SubmissionDetailsContentType.ExternalToolContent(canvasContext, ltiTool, assignment.name.orEmpty(), assignment.ltiToolType()) else SubmissionDetailsContentType.LockedContent } - submission?.submissionType == null -> SubmissionDetailsContentType.NoSubmissionContent(canvasContext, assignment!!, isStudioEnabled!!, quiz, studioLTITool, isObserver, ltiUrl) + submission?.submissionType == null -> SubmissionDetailsContentType.NoSubmissionContent(canvasContext, assignment!!, isStudioEnabled!!, quiz, studioLTITool, isObserver, ltiTool) submission.workflowState != "submitted" && AssignmentUtils2.getAssignmentState(assignment, submission) in listOf(AssignmentUtils2.ASSIGNMENT_STATE_MISSING, AssignmentUtils2.ASSIGNMENT_STATE_GRADED_MISSING) -> SubmissionDetailsContentType.NoSubmissionContent(canvasContext, assignment!!, isStudioEnabled!!, quiz) else -> when (Assignment.getSubmissionTypeFromAPIString(submission.submissionType)) { // LTI submission Assignment.SubmissionType.BASIC_LTI_LAUNCH -> SubmissionDetailsContentType.ExternalToolContent( - canvasContext, - submission.previewUrl.validOrNull() ?: assignment?.url?.validOrNull() ?: assignment?.htmlUrl ?: "" + canvasContext, + ltiTool, + title = assignment?.name.orEmpty(), + assignment?.ltiToolType() ?: LtiType.EXTERNAL_TOOL ) // Text submission @@ -193,7 +200,9 @@ class SubmissionDetailsUpdate : UpdateInit getAttachmentContent(submission.attachments[0]) + Assignment.SubmissionType.ONLINE_UPLOAD -> submission.attachments.firstOrNull()?.let { + getAttachmentContent(submission.attachments[0]) + } ?: SubmissionDetailsContentType.UnsupportedContent(assignment?.id ?: -1) // URL Submission Assignment.SubmissionType.ONLINE_URL -> SubmissionDetailsContentType.UrlContent(submission.url!!, submission.attachments.firstOrNull()?.url) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/AnnotationSubmissionViewFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/AnnotationSubmissionViewFragment.kt index 7f9ec7e045..559db7aa9f 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/AnnotationSubmissionViewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/AnnotationSubmissionViewFragment.kt @@ -20,7 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.viewModels import com.instructure.pandautils.utils.LongArg import com.instructure.student.databinding.FragmentAnnotationSubmissionViewBinding @@ -28,10 +28,11 @@ import com.instructure.student.mobius.assignmentDetails.submission.annnotation.A import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class AnnotationSubmissionViewFragment : Fragment() { +class AnnotationSubmissionViewFragment : BaseCanvasFragment() { private var submissionId by LongArg() private var submissionAttempt by LongArg() + private var courseId by LongArg() private val viewModel: AnnotationSubmissionViewModel by viewModels() @@ -52,6 +53,7 @@ class AnnotationSubmissionViewFragment : Fragment() { PdfStudentSubmissionView( requireActivity(), it, + courseId, childFragmentManager, studentAnnotationView = true, ) @@ -62,10 +64,11 @@ class AnnotationSubmissionViewFragment : Fragment() { } companion object { - fun newInstance(submissionId: Long, submissionAttempt: Long): AnnotationSubmissionViewFragment { + fun newInstance(submissionId: Long, submissionAttempt: Long, courseId: Long): AnnotationSubmissionViewFragment { return AnnotationSubmissionViewFragment().apply { this.submissionId = submissionId this.submissionAttempt = submissionAttempt + this.courseId = courseId } } } diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/DiscussionSubmissionViewFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/DiscussionSubmissionViewFragment.kt index 95cf94f8ef..c34db61c70 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/DiscussionSubmissionViewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/DiscussionSubmissionViewFragment.kt @@ -22,7 +22,7 @@ import android.view.View import android.view.ViewGroup import android.webkit.WebChromeClient import android.webkit.WebView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.instructure.canvasapi2.managers.OAuthManager import com.instructure.canvasapi2.models.AuthenticatedSession import com.instructure.canvasapi2.utils.ApiPrefs @@ -43,7 +43,7 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job import kotlinx.coroutines.launch -class DiscussionSubmissionViewFragment : Fragment() { +class DiscussionSubmissionViewFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentDiscussionSubmissionViewBinding::bind) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/LtiSubmissionViewFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/LtiSubmissionViewFragment.kt index 755c40efd6..586102e115 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/LtiSubmissionViewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/LtiSubmissionViewFragment.kt @@ -20,24 +20,31 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.models.LTITool +import com.instructure.canvasapi2.models.LtiType import com.instructure.pandautils.binding.viewBinding +import com.instructure.pandautils.features.lti.LtiLaunchFragment +import com.instructure.pandautils.utils.NullableParcelableArg import com.instructure.pandautils.utils.ParcelableArg +import com.instructure.pandautils.utils.SerializableArg import com.instructure.pandautils.utils.StringArg import com.instructure.pandautils.utils.ViewStyler import com.instructure.pandautils.utils.onClickWithRequireNetwork import com.instructure.student.R import com.instructure.student.databinding.FragmentLtiSubmissionViewBinding -import com.instructure.student.fragment.LtiLaunchFragment import com.instructure.student.mobius.assignmentDetails.submissionDetails.SubmissionDetailsContentType.ExternalToolContent import com.instructure.student.router.RouteMatcher -class LtiSubmissionViewFragment : Fragment() { +class LtiSubmissionViewFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentLtiSubmissionViewBinding::bind) private var canvasContext: CanvasContext by ParcelableArg() private var url: String by StringArg() + private var ltiType: LtiType by SerializableArg(LtiType.EXTERNAL_TOOL) + private var title: String by StringArg() + private var ltiTool: LTITool? by NullableParcelableArg() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_lti_submission_view, container, false) @@ -46,16 +53,36 @@ class LtiSubmissionViewFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) ViewStyler.themeButton(binding.viewLtiButton) + setUpViews() binding.viewLtiButton.onClickWithRequireNetwork { - val route = LtiLaunchFragment.makeRoute(canvasContext = canvasContext, url = url) - RouteMatcher.route(requireActivity(), route) + RouteMatcher.route( + requireActivity(), + LtiLaunchFragment.makeRoute( + canvasContext, + url, + title, + sessionLessLaunch = false, + assignmentLti = true, + ltiTool = ltiTool, + openInternally = ltiType.openInternally + ) + ) } } + private fun setUpViews() { + binding.viewLtiButton.text = getString(ltiType.openButtonRes) + binding.ltiSubmissionTitle.text = getString(ltiType.ltiTitleRes) + binding.ltiSubmissionSubtitle.text = getString(ltiType.ltiDescriptionRes) + } + companion object { fun newInstance(data: ExternalToolContent) = LtiSubmissionViewFragment().apply { canvasContext = data.canvasContext - url = data.url + url = data.ltiTool?.url.orEmpty() + ltiTool = data.ltiTool + title = data.title + ltiType = data.ltiType } } } diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/MediaSubmissionViewFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/MediaSubmissionViewFragment.kt index 258b2c8ac7..38fb698e1a 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/MediaSubmissionViewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/MediaSubmissionViewFragment.kt @@ -22,7 +22,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.annotation.OptIn -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.media3.common.util.UnstableApi import androidx.media3.datasource.HttpDataSource import androidx.media3.exoplayer.source.UnrecognizedInputFormatException @@ -49,7 +49,7 @@ import com.instructure.student.mobius.assignmentDetails.submissionDetails.Submis import com.instructure.student.router.RouteMatcher @OptIn(UnstableApi::class) -class MediaSubmissionViewFragment : Fragment() { +class MediaSubmissionViewFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentMediaSubmissionViewBinding::bind) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/PdfStudentSubmissionView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/PdfStudentSubmissionView.kt index 2ab33d11cc..c3243b460e 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/PdfStudentSubmissionView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/PdfStudentSubmissionView.kt @@ -61,11 +61,12 @@ import org.greenrobot.eventbus.ThreadMode class PdfStudentSubmissionView( private val activity: FragmentActivity, private val pdfUrl: String, + private val courseId: Long, private val fragmentManager: FragmentManager, private val studentAnnotationSubmit: Boolean = false, private val studentAnnotationView: Boolean = false, ) : PdfSubmissionView( - activity, studentAnnotationView + activity, studentAnnotationView, courseId ), AnnotationManager.OnAnnotationCreationModeChangeListener, AnnotationManager.OnAnnotationEditingModeChangeListener { private val binding: ViewPdfStudentSubmissionBinding diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/PdfSubmissionViewFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/PdfSubmissionViewFragment.kt index 72cf8ad4bc..8f1a121ce7 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/PdfSubmissionViewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/PdfSubmissionViewFragment.kt @@ -20,20 +20,23 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment +import com.instructure.pandautils.utils.LongArg import com.instructure.pandautils.utils.StringArg -class PdfSubmissionViewFragment : Fragment() { +class PdfSubmissionViewFragment : BaseCanvasFragment() { private var pdfUrl by StringArg() + private var courseId by LongArg() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return PdfStudentSubmissionView(requireActivity(), pdfUrl, childFragmentManager) + return PdfStudentSubmissionView(requireActivity(), pdfUrl, courseId, childFragmentManager) } companion object { - fun newInstance(url: String) = PdfSubmissionViewFragment().apply { + fun newInstance(url: String, courseId: Long) = PdfSubmissionViewFragment().apply { pdfUrl = url + this.courseId = courseId } } } diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/TextSubmissionViewFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/TextSubmissionViewFragment.kt index 26d9e6e011..b4ad476a58 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/TextSubmissionViewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/TextSubmissionViewFragment.kt @@ -22,7 +22,7 @@ import android.view.View import android.view.ViewGroup import android.webkit.WebChromeClient import android.webkit.WebView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.replaceFirstAfter import com.instructure.pandautils.binding.viewBinding @@ -35,7 +35,7 @@ import com.instructure.student.activity.InternalWebViewActivity import com.instructure.student.databinding.FragmentTextSubmissionBinding import com.instructure.student.router.RouteMatcher -class TextSubmissionViewFragment : Fragment() { +class TextSubmissionViewFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentTextSubmissionBinding::bind) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/UrlSubmissionViewFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/UrlSubmissionViewFragment.kt index 55df2e2078..acb101d817 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/UrlSubmissionViewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/UrlSubmissionViewFragment.kt @@ -19,7 +19,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.bumptech.glide.Glide import com.instructure.pandautils.binding.viewBinding import com.instructure.pandautils.utils.NullableStringArg @@ -30,7 +30,7 @@ import com.instructure.student.R import com.instructure.student.activity.InternalWebViewActivity import com.instructure.student.databinding.FragmentUrlSubmissionViewBinding -class UrlSubmissionViewFragment : Fragment() { +class UrlSubmissionViewFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentUrlSubmissionViewBinding::bind) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/emptySubmission/ui/SubmissionDetailsEmptyContentView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/emptySubmission/ui/SubmissionDetailsEmptyContentView.kt index a52b0c6da9..fa6f602542 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/emptySubmission/ui/SubmissionDetailsEmptyContentView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/emptySubmission/ui/SubmissionDetailsEmptyContentView.kt @@ -33,6 +33,7 @@ import com.instructure.canvasapi2.models.Quiz import com.instructure.canvasapi2.utils.AnalyticsEventConstants import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.pandautils.features.discussion.router.DiscussionRouterFragment +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.onClickWithRequireNetwork import com.instructure.pandautils.utils.setHidden @@ -43,16 +44,15 @@ import com.instructure.student.databinding.DialogSubmissionPickerBinding import com.instructure.student.databinding.DialogSubmissionPickerMediaBinding import com.instructure.student.databinding.FragmentSubmissionDetailsEmptyContentBinding import com.instructure.student.fragment.BasicQuizViewFragment -import com.instructure.student.fragment.LtiLaunchFragment import com.instructure.student.fragment.StudioWebViewFragment -import com.instructure.student.mobius.assignmentDetails.submissionDetails.content.emptySubmission.SubmissionDetailsEmptyContentEvent -import com.instructure.student.mobius.assignmentDetails.submissionDetails.content.emptySubmission.ui.SubmissionDetailsEmptyContentViewState.Loaded -import com.instructure.student.mobius.assignmentDetails.submissionDetails.ui.SubmissionTypesVisibilities import com.instructure.student.mobius.assignmentDetails.submission.annnotation.AnnotationSubmissionUploadFragment import com.instructure.student.mobius.assignmentDetails.submission.picker.PickerSubmissionMode import com.instructure.student.mobius.assignmentDetails.submission.picker.ui.PickerSubmissionUploadFragment import com.instructure.student.mobius.assignmentDetails.submission.text.ui.TextSubmissionUploadFragment import com.instructure.student.mobius.assignmentDetails.submission.url.ui.UrlSubmissionUploadFragment +import com.instructure.student.mobius.assignmentDetails.submissionDetails.content.emptySubmission.SubmissionDetailsEmptyContentEvent +import com.instructure.student.mobius.assignmentDetails.submissionDetails.content.emptySubmission.ui.SubmissionDetailsEmptyContentViewState.Loaded +import com.instructure.student.mobius.assignmentDetails.submissionDetails.ui.SubmissionTypesVisibilities import com.instructure.student.mobius.common.ui.MobiusView import com.instructure.student.router.RouteMatcher import com.spotify.mobius.functions.Consumer @@ -145,7 +145,7 @@ class SubmissionDetailsEmptyContentView( canvasContext, ltiTool?.url ?: "", title, - isAssignmentLTI = true, + assignmentLti = true, ltiTool = ltiTool )) } diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/emptySubmission/ui/SubmissionMessageFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/emptySubmission/ui/SubmissionMessageFragment.kt index d4e2bdecea..989e04d1d9 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/emptySubmission/ui/SubmissionMessageFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/emptySubmission/ui/SubmissionMessageFragment.kt @@ -20,7 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.bumptech.glide.Glide import com.instructure.pandautils.binding.viewBinding import com.instructure.pandautils.utils.IntArg @@ -29,7 +29,7 @@ import com.instructure.pandautils.utils.setVisible import com.instructure.student.R import com.instructure.student.databinding.FragmentSubmissionMessageBinding -class SubmissionMessageFragment : Fragment() { +class SubmissionMessageFragment : BaseCanvasFragment() { private var titleRes by IntArg() private var subtitleRes by IntArg() private var messageRes by IntArg() diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/datasource/SubmissionDetailsNetworkDataSource.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/datasource/SubmissionDetailsNetworkDataSource.kt index 5fddf526b1..299f3e73f0 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/datasource/SubmissionDetailsNetworkDataSource.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/datasource/SubmissionDetailsNetworkDataSource.kt @@ -20,6 +20,7 @@ package com.instructure.student.mobius.assignmentDetails.submissionDetails.datas import com.instructure.canvasapi2.apis.* import com.instructure.canvasapi2.builders.RestParams import com.instructure.canvasapi2.models.* +import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.DataResult import com.instructure.canvasapi2.utils.depaginate @@ -40,7 +41,7 @@ class SubmissionDetailsNetworkDataSource( } override suspend fun getSingleSubmission(courseId: Long, assignmentId: Long, studentId: Long, forceNetwork: Boolean): DataResult { - val params = RestParams(isForceReadFromNetwork = forceNetwork) + val params = RestParams(isForceReadFromNetwork = forceNetwork, domain = ApiPrefs.overrideDomains[courseId]) return submissionApi.getSingleSubmission(courseId, assignmentId, studentId, params) } diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/comments/ui/SubmissionCommentsView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/comments/ui/SubmissionCommentsView.kt index 9d4941bd1e..4ddd1f4cc2 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/comments/ui/SubmissionCommentsView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/comments/ui/SubmissionCommentsView.kt @@ -27,15 +27,21 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.Attachment import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Submission -import com.instructure.pandautils.utils.* +import com.instructure.pandautils.utils.ThemePrefs +import com.instructure.pandautils.utils.ViewStyler +import com.instructure.pandautils.utils.onClick +import com.instructure.pandautils.utils.onClickWithRequireNetwork +import com.instructure.pandautils.utils.onTextChanged +import com.instructure.pandautils.utils.setGone +import com.instructure.pandautils.utils.setVisible import com.instructure.student.R import com.instructure.student.activity.BaseRouterActivity import com.instructure.student.databinding.DialogCommentFilePickerBinding import com.instructure.student.databinding.FragmentSubmissionCommentsBinding -import com.instructure.student.mobius.assignmentDetails.submissionDetails.drawer.comments.SubmissionCommentsEvent -import com.instructure.student.mobius.assignmentDetails.submissionDetails.drawer.comments.SubmissionCommentsViewState import com.instructure.student.mobius.assignmentDetails.submission.picker.PickerSubmissionMode import com.instructure.student.mobius.assignmentDetails.submission.picker.ui.PickerSubmissionUploadFragment +import com.instructure.student.mobius.assignmentDetails.submissionDetails.drawer.comments.SubmissionCommentsEvent +import com.instructure.student.mobius.assignmentDetails.submissionDetails.drawer.comments.SubmissionCommentsViewState import com.instructure.student.mobius.common.ui.MobiusView import com.instructure.student.room.StudentDb import com.instructure.student.router.RouteMatcher @@ -164,7 +170,7 @@ class SubmissionCommentsView( } fun openMedia(canvasContext: CanvasContext, contentType: String, url: String, fileName: String) { - (activity as? BaseRouterActivity)?.openMedia(canvasContext, contentType, url, fileName) + (activity as? BaseRouterActivity)?.openMedia(canvasContext, contentType, url, fileName, null) } fun showPermissionDeniedToast() { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/rubric/ui/SubmissionRubricDescriptionFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/rubric/ui/SubmissionRubricDescriptionFragment.kt index c86c64f07c..0e12c066bd 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/rubric/ui/SubmissionRubricDescriptionFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/rubric/ui/SubmissionRubricDescriptionFragment.kt @@ -22,7 +22,7 @@ import android.view.View import android.view.ViewGroup import android.webkit.WebChromeClient import android.webkit.WebView -import androidx.fragment.app.DialogFragment +import com.instructure.pandautils.base.BaseCanvasDialogFragment import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.interactions.router.Route import com.instructure.pandautils.binding.viewBinding @@ -33,7 +33,7 @@ import com.instructure.student.activity.InternalWebViewActivity import com.instructure.student.databinding.FragmentSubmissionRubricDescriptionBinding import com.instructure.student.router.RouteMatcher -class SubmissionRubricDescriptionFragment : DialogFragment() { +class SubmissionRubricDescriptionFragment : BaseCanvasDialogFragment() { private val binding by viewBinding(FragmentSubmissionRubricDescriptionBinding::bind) @@ -49,6 +49,7 @@ class SubmissionRubricDescriptionFragment : DialogFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) with (binding) { toolbar.title = title toolbar.setupAsBackButton(this@SubmissionRubricDescriptionFragment) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsDrawerPagerAdapter.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsDrawerPagerAdapter.kt index c930519733..3b444906ed 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsDrawerPagerAdapter.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsDrawerPagerAdapter.kt @@ -20,9 +20,6 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentStatePagerAdapter import androidx.viewpager.widget.PagerAdapter -import com.instructure.canvasapi2.utils.Analytics -import com.instructure.canvasapi2.utils.AnalyticsEventConstants -import com.instructure.canvasapi2.utils.AnalyticsParamConstants import com.instructure.student.mobius.assignmentDetails.submissionDetails.drawer.comments.ui.SubmissionCommentsFragment import com.instructure.student.mobius.assignmentDetails.submissionDetails.drawer.files.ui.SubmissionFilesFragment import com.instructure.student.mobius.assignmentDetails.submissionDetails.drawer.rubric.ui.SubmissionRubricFragment diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsFragment.kt index dfc4725241..206f8bec7d 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsFragment.kt @@ -19,10 +19,7 @@ package com.instructure.student.mobius.assignmentDetails.submissionDetails.ui import android.view.LayoutInflater import android.view.ViewGroup import com.instructure.canvasapi2.models.Course -import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam -import com.instructure.pandautils.analytics.SCREEN_VIEW_SUBMISSION_DETAILS -import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.BooleanArg import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.LongArg @@ -37,11 +34,10 @@ import com.instructure.student.mobius.assignmentDetails.submissionDetails.Submis import com.instructure.student.mobius.assignmentDetails.submissionDetails.SubmissionDetailsUpdate import com.instructure.student.mobius.common.ui.MobiusFragment -@ScreenView(SCREEN_VIEW_SUBMISSION_DETAILS) -@PageView(url = "{canvasContext}/assignments/{assignmentId}/submissions") abstract class SubmissionDetailsFragment : MobiusFragment() { + @get:PageViewUrlParam("canvasContext") val canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) @get:PageViewUrlParam(name = "assignmentId") diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsRepositoryFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsRepositoryFragment.kt index f2ccef6e4c..0fd2c3f8bc 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsRepositoryFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsRepositoryFragment.kt @@ -20,8 +20,11 @@ import android.os.Bundle import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.interactions.router.Route import com.instructure.interactions.router.RouterParams +import com.instructure.pandautils.analytics.SCREEN_VIEW_SUBMISSION_DETAILS +import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.makeBundle import com.instructure.pandautils.utils.withArgs @@ -35,6 +38,8 @@ import com.instructure.student.room.entities.CreateSubmissionEntity import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject +@ScreenView(SCREEN_VIEW_SUBMISSION_DETAILS) +@PageView(url = "{canvasContext}/assignments/{assignmentId}/submissions") @AndroidEntryPoint class SubmissionDetailsRepositoryFragment : SubmissionDetailsFragment() { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsView.kt index a9d2e562dc..121f848612 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/ui/SubmissionDetailsView.kt @@ -317,7 +317,7 @@ class SubmissionDetailsView( DiscussionSubmissionViewFragment.newInstance(type.previewUrl.orEmpty()), isOnline ) - is SubmissionDetailsContentType.PdfContent -> getFragmentWithOnlineCheck(PdfSubmissionViewFragment.newInstance(type.url), isOnline) + is SubmissionDetailsContentType.PdfContent -> getFragmentWithOnlineCheck(PdfSubmissionViewFragment.newInstance(type.url, canvasContext.id), isOnline) is SubmissionDetailsContentType.ExternalToolContent -> LtiSubmissionViewFragment.newInstance(type) is SubmissionDetailsContentType.MediaContent -> getFragmentWithOnlineCheck(MediaSubmissionViewFragment.newInstance(type), isOnline) is SubmissionDetailsContentType.OtherAttachmentContent -> ViewUnsupportedFileFragment.newInstance( @@ -350,7 +350,8 @@ class SubmissionDetailsView( is SubmissionDetailsContentType.StudentAnnotationContent -> getFragmentWithOnlineCheck( AnnotationSubmissionViewFragment.newInstance( type.subissionId, - type.submissionAttempt + type.submissionAttempt, + canvasContext.id ), isOnline ) is SubmissionDetailsContentType.UnsupportedContent -> { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsFragment.kt index 59ead89e2e..3002ea53ff 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsFragment.kt @@ -20,18 +20,23 @@ import android.view.LayoutInflater import android.view.ViewGroup import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Conference -import com.instructure.pandautils.analytics.SCREEN_VIEW_CONFERENCE_DETAILS -import com.instructure.pandautils.analytics.ScreenView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.ParcelableArg import com.instructure.student.databinding.FragmentConferenceDetailsBinding import com.instructure.student.mobius.common.ui.MobiusFragment -import com.instructure.student.mobius.conferences.conference_details.* +import com.instructure.student.mobius.conferences.conference_details.ConferenceDetailsEffect +import com.instructure.student.mobius.conferences.conference_details.ConferenceDetailsEffectHandler +import com.instructure.student.mobius.conferences.conference_details.ConferenceDetailsEvent +import com.instructure.student.mobius.conferences.conference_details.ConferenceDetailsModel +import com.instructure.student.mobius.conferences.conference_details.ConferenceDetailsPresenter +import com.instructure.student.mobius.conferences.conference_details.ConferenceDetailsRepository +import com.instructure.student.mobius.conferences.conference_details.ConferenceDetailsUpdate -@ScreenView(SCREEN_VIEW_CONFERENCE_DETAILS) abstract class ConferenceDetailsFragment : MobiusFragment() { + @get:PageViewUrlParam("canvasContext") val canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) val conference by ParcelableArg(key = Const.CONFERENCE) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsRepositoryFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsRepositoryFragment.kt index 0e41e621ed..f2323c8667 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsRepositoryFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsRepositoryFragment.kt @@ -22,6 +22,8 @@ import com.instructure.canvasapi2.models.Conference import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.interactions.router.Route +import com.instructure.pandautils.analytics.SCREEN_VIEW_CONFERENCE_DETAILS +import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.makeBundle import com.instructure.pandautils.utils.withArgs @@ -31,6 +33,7 @@ import javax.inject.Inject @AndroidEntryPoint @PageView(url = "{canvasContext}/conferences/{conferenceId}") +@ScreenView(SCREEN_VIEW_CONFERENCE_DETAILS) class ConferenceDetailsRepositoryFragment : ConferenceDetailsFragment() { @Inject diff --git a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListFragment.kt index cfefa5e6c0..2accdc1099 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListFragment.kt @@ -19,20 +19,23 @@ package com.instructure.student.mobius.conferences.conference_list.ui import android.view.LayoutInflater import android.view.ViewGroup import com.instructure.canvasapi2.models.CanvasContext -import com.instructure.canvasapi2.utils.pageview.PageView -import com.instructure.pandautils.analytics.SCREEN_VIEW_CONFERENCE_LIST -import com.instructure.pandautils.analytics.ScreenView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.ParcelableArg import com.instructure.student.databinding.FragmentConferenceListBinding import com.instructure.student.mobius.common.ui.MobiusFragment -import com.instructure.student.mobius.conferences.conference_list.* +import com.instructure.student.mobius.conferences.conference_list.ConferenceListEffect +import com.instructure.student.mobius.conferences.conference_list.ConferenceListEffectHandler +import com.instructure.student.mobius.conferences.conference_list.ConferenceListEvent +import com.instructure.student.mobius.conferences.conference_list.ConferenceListModel +import com.instructure.student.mobius.conferences.conference_list.ConferenceListPresenter +import com.instructure.student.mobius.conferences.conference_list.ConferenceListRepository +import com.instructure.student.mobius.conferences.conference_list.ConferenceListUpdate -@PageView(url = "{canvasContext}/conferences") -@ScreenView(SCREEN_VIEW_CONFERENCE_LIST) abstract class ConferenceListFragment : MobiusFragment() { + @get:PageViewUrlParam("canvasContext") val canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) override fun makeUpdate() = ConferenceListUpdate() diff --git a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListRepositoryFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListRepositoryFragment.kt index ce1ba24c32..c257e1241a 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListRepositoryFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListRepositoryFragment.kt @@ -18,13 +18,18 @@ package com.instructure.student.mobius.conferences.conference_list.ui import android.os.Bundle import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.interactions.router.Route +import com.instructure.pandautils.analytics.SCREEN_VIEW_CONFERENCE_LIST +import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.makeBundle import com.instructure.pandautils.utils.withArgs import com.instructure.student.mobius.conferences.conference_list.ConferenceListRepository import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject +@PageView(url = "{canvasContext}/conferences") +@ScreenView(SCREEN_VIEW_CONFERENCE_LIST) @AndroidEntryPoint class ConferenceListRepositoryFragment : ConferenceListFragment() { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/elementary/resources/StudentResourcesRouter.kt b/apps/student/src/main/java/com/instructure/student/mobius/elementary/resources/StudentResourcesRouter.kt index c6c5ceff05..80a84af5f4 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/elementary/resources/StudentResourcesRouter.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/elementary/resources/StudentResourcesRouter.kt @@ -17,10 +17,13 @@ package com.instructure.student.mobius.elementary.resources import androidx.fragment.app.FragmentActivity -import com.instructure.canvasapi2.models.* +import com.instructure.canvasapi2.models.Course +import com.instructure.canvasapi2.models.LTITool +import com.instructure.canvasapi2.models.Recipient +import com.instructure.canvasapi2.models.User import com.instructure.pandautils.features.elementary.resources.itemviewmodels.ResourcesRouter +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.student.fragment.InboxComposeMessageFragment -import com.instructure.student.fragment.LtiLaunchFragment import com.instructure.student.router.RouteMatcher class StudentResourcesRouter(private val activity: FragmentActivity) : ResourcesRouter { @@ -32,7 +35,7 @@ class StudentResourcesRouter(private val activity: FragmentActivity) : Resources ltiTool.url ?: ltiTool.courseNavigation?.url ?: "", ltiTool.courseNavigation?.text ?: ltiTool.name ?: "", sessionLessLaunch = true, - isAssignmentLTI = false, + assignmentLti = false, ltiTool = ltiTool) RouteMatcher.route(activity, route) } diff --git a/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusFragment.kt index 5933a5ac11..116ebd7374 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusFragment.kt @@ -17,9 +17,7 @@ package com.instructure.student.mobius.syllabus.ui import com.instructure.canvasapi2.models.Course -import com.instructure.canvasapi2.utils.pageview.PageView -import com.instructure.pandautils.analytics.SCREEN_VIEW_SYLLABUS -import com.instructure.pandautils.analytics.ScreenView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.ParcelableArg import com.instructure.student.databinding.FragmentSyllabusBinding @@ -32,10 +30,9 @@ import com.instructure.student.mobius.syllabus.SyllabusPresenter import com.instructure.student.mobius.syllabus.SyllabusRepository import com.instructure.student.mobius.syllabus.SyllabusUpdate -@ScreenView(SCREEN_VIEW_SYLLABUS) -@PageView(url = "{canvasContext}/assignments/syllabus") abstract class SyllabusFragment : MobiusFragment() { + @get:PageViewUrlParam("canvasContext") val canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) override fun makeEffectHandler() = SyllabusEffectHandler(getRepository()) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusRepositoryFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusRepositoryFragment.kt index 2e10db0c7d..a339920427 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusRepositoryFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusRepositoryFragment.kt @@ -22,7 +22,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup import com.instructure.canvasapi2.models.Course +import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.interactions.router.Route +import com.instructure.pandautils.analytics.SCREEN_VIEW_SYLLABUS +import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.navigation.WebViewRouter import com.instructure.pandautils.utils.makeBundle import com.instructure.pandautils.utils.withArgs @@ -30,6 +33,8 @@ import com.instructure.student.mobius.syllabus.SyllabusRepository import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject +@ScreenView(SCREEN_VIEW_SYLLABUS) +@PageView(url = "{canvasContext}/assignments/syllabus") @AndroidEntryPoint class SyllabusRepositoryFragment : SyllabusFragment() { diff --git a/apps/student/src/main/java/com/instructure/student/navigation/StudentWebViewRouter.kt b/apps/student/src/main/java/com/instructure/student/navigation/StudentWebViewRouter.kt index a05b3f115d..0eaea50137 100644 --- a/apps/student/src/main/java/com/instructure/student/navigation/StudentWebViewRouter.kt +++ b/apps/student/src/main/java/com/instructure/student/navigation/StudentWebViewRouter.kt @@ -20,10 +20,10 @@ import android.os.Bundle import androidx.fragment.app.FragmentActivity import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.navigation.WebViewRouter import com.instructure.student.activity.BaseRouterActivity import com.instructure.student.fragment.InternalWebviewFragment -import com.instructure.student.fragment.LtiLaunchFragment import com.instructure.student.router.RouteMatcher class StudentWebViewRouter(val activity: FragmentActivity) : WebViewRouter { @@ -42,7 +42,7 @@ class StudentWebViewRouter(val activity: FragmentActivity) : WebViewRouter { override fun openMedia(url: String, mime: String, filename: String, canvasContext: CanvasContext?) { if (canvasContext != null && activity is BaseRouterActivity) { - activity.openMedia(canvasContext, mime, url, filename) + activity.openMedia(canvasContext, mime, url, filename, null) } else { RouteMatcher.openMedia(activity, url) } @@ -53,7 +53,7 @@ class StudentWebViewRouter(val activity: FragmentActivity) : WebViewRouter { } override fun openLtiScreen(canvasContext: CanvasContext?, url: String) { - LtiLaunchFragment.routeLtiLaunchFragment(activity, canvasContext, url) + RouteMatcher.route(activity, LtiLaunchFragment.makeSessionlessLtiUrlRoute(activity, canvasContext, url)) } override fun launchInternalWebViewFragment(url: String, canvasContext: CanvasContext?) { diff --git a/apps/student/src/main/java/com/instructure/student/receivers/InitializeReceiver.kt b/apps/student/src/main/java/com/instructure/student/receivers/InitializeReceiver.kt index d5138445d8..c037404eaf 100644 --- a/apps/student/src/main/java/com/instructure/student/receivers/InitializeReceiver.kt +++ b/apps/student/src/main/java/com/instructure/student/receivers/InitializeReceiver.kt @@ -20,7 +20,7 @@ package com.instructure.student.receivers import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import com.instructure.pandautils.features.assignments.details.reminder.AlarmScheduler +import com.instructure.pandautils.features.reminder.AlarmScheduler import com.instructure.pandautils.receivers.PushExternalReceiver import com.instructure.student.R import com.instructure.student.activity.NavigationActivity diff --git a/apps/student/src/main/java/com/instructure/student/router/EnabledTabs.kt b/apps/student/src/main/java/com/instructure/student/router/EnabledTabs.kt new file mode 100644 index 0000000000..f667dcdb85 --- /dev/null +++ b/apps/student/src/main/java/com/instructure/student/router/EnabledTabs.kt @@ -0,0 +1,65 @@ +package com.instructure.student.router + +import android.net.Uri +import com.instructure.canvasapi2.apis.CourseAPI +import com.instructure.canvasapi2.builders.RestParams +import com.instructure.canvasapi2.models.Tab +import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.canvasapi2.utils.depaginate +import com.instructure.interactions.router.Route + +interface EnabledTabs { + fun isPathTabNotEnabled(route: Route?): Boolean + suspend fun initTabs() +} + +class EnabledTabsImpl( + private val courseApi: CourseAPI.CoursesInterface +): EnabledTabs { + private var enabledTabs: Map>? = null + + private fun isPathTabEnabled(courseId: Long, uri: Uri): Boolean { + val tabs = enabledTabs?.get(courseId) ?: return true + if (tabs.isEmpty()) return true + + val pathSegments = uri.pathSegments + val relativePath = uri.path?.replaceBefore("/courses/$courseId", "") + // Details urls should be accepted, like /assignments/1, but assignments/syllabus should not + return if (pathSegments.last() == Tab.SYLLABUS_ID) { // handle syllabus which has the same url scheme as assignment details + tabs.any { relativePath == it.htmlUrl } + } else if (pathSegments.size == 3) { // tab urls + tabs.any { relativePath == it.htmlUrl } + } else if (pathSegments.contains("external_tools") && pathSegments.size == 4) { // external tools + return tabs.any { relativePath == it.htmlUrl } + } else { + true + } + } + + override fun isPathTabNotEnabled(route: Route?): Boolean { + route?.uri?.let { uri -> + route.courseId?.let { courseId -> + return !isPathTabEnabled(courseId, uri) + } + if (uri.pathSegments.contains("courses")) { + val courseIdIndex = uri.pathSegments.indexOf("courses") + 1 + val courseId = uri.pathSegments[courseIdIndex] + return !isPathTabEnabled(courseId.toLong(), uri) + } + + } + return false + } + + override suspend fun initTabs() { + enabledTabs = courseApi.getFirstPageCourses(RestParams(usePerPageQueryParam = true)) + .depaginate { + courseApi.next(it, RestParams(usePerPageQueryParam = true)) + }.dataOrNull?.associate { it.id to (it.tabs ?: emptyList()) } ?: emptyMap() + enabledTabs?.forEach { entry -> + entry.value.find { tab -> tab.tabId == Tab.ASSIGNMENTS_ID }?.domain?.let { domain -> + ApiPrefs.overrideDomains[entry.key] = domain + } + } + } +} \ No newline at end of file diff --git a/apps/student/src/main/java/com/instructure/student/router/RouteMatcher.kt b/apps/student/src/main/java/com/instructure/student/router/RouteMatcher.kt index 089f4ee123..9dbbfb1496 100644 --- a/apps/student/src/main/java/com/instructure/student/router/RouteMatcher.kt +++ b/apps/student/src/main/java/com/instructure/student/router/RouteMatcher.kt @@ -18,6 +18,7 @@ package com.instructure.student.router import android.content.ActivityNotFoundException import android.content.Context +import android.content.Intent import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AlertDialog @@ -34,8 +35,13 @@ import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryLaunch -import com.instructure.interactions.router.* +import com.instructure.interactions.router.BaseRouteMatcher +import com.instructure.interactions.router.Route +import com.instructure.interactions.router.RouteContext +import com.instructure.interactions.router.RouteType +import com.instructure.interactions.router.RouterParams import com.instructure.pandautils.activities.BaseViewMediaActivity +import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment import com.instructure.pandautils.features.calendar.CalendarFragment import com.instructure.pandautils.features.discussion.router.DiscussionRouterFragment import com.instructure.pandautils.features.inbox.list.InboxFragment @@ -48,9 +54,14 @@ import com.instructure.pandautils.utils.LoaderUtils import com.instructure.pandautils.utils.NetworkStateProvider import com.instructure.pandautils.utils.RouteUtils import com.instructure.pandautils.utils.nonNullArgs +import com.instructure.pandautils.utils.orDefault +import com.instructure.pandautils.utils.toast import com.instructure.student.R -import com.instructure.student.activity.* -import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment +import com.instructure.student.activity.InternalWebViewActivity +import com.instructure.student.activity.InterwebsToApplication +import com.instructure.student.activity.NavigationActivity +import com.instructure.student.activity.NothingToSeeHereFragment +import com.instructure.student.activity.ViewMediaActivity import com.instructure.student.features.assignments.list.AssignmentListFragment import com.instructure.student.features.coursebrowser.CourseBrowserFragment import com.instructure.student.features.discussion.details.DiscussionDetailsFragment @@ -65,13 +76,26 @@ import com.instructure.student.features.pages.list.PageListFragment import com.instructure.student.features.people.details.PeopleDetailsFragment import com.instructure.student.features.people.list.PeopleListFragment import com.instructure.student.features.quiz.list.QuizListFragment -import com.instructure.student.fragment.* +import com.instructure.student.fragment.AnnouncementListFragment +import com.instructure.student.fragment.BasicQuizViewFragment +import com.instructure.student.fragment.CourseSettingsFragment +import com.instructure.student.fragment.DashboardFragment +import com.instructure.student.fragment.InboxConversationFragment +import com.instructure.student.fragment.InternalWebviewFragment +import com.instructure.student.fragment.NotificationListFragment +import com.instructure.student.fragment.ProfileSettingsFragment +import com.instructure.student.fragment.StudioWebViewFragment +import com.instructure.student.fragment.UnsupportedFeatureFragment +import com.instructure.student.fragment.UnsupportedTabFragment +import com.instructure.student.fragment.ViewHtmlFragment +import com.instructure.student.fragment.ViewImageFragment +import com.instructure.student.fragment.ViewUnsupportedFileFragment import com.instructure.student.mobius.assignmentDetails.submissionDetails.ui.SubmissionDetailsFragment import com.instructure.student.mobius.conferences.conference_list.ui.ConferenceListRepositoryFragment import com.instructure.student.mobius.syllabus.ui.SyllabusRepositoryFragment import com.instructure.student.util.FileUtils import com.instructure.student.util.onMainThread -import java.util.* +import java.util.Locale import java.util.regex.Pattern object RouteMatcher : BaseRouteMatcher() { @@ -81,6 +105,7 @@ object RouteMatcher : BaseRouteMatcher() { var offlineDb: OfflineDatabase? = null var networkStateProvider: NetworkStateProvider? = null + var enabledTabs: EnabledTabs? = null init { initRoutes() @@ -488,6 +513,14 @@ object RouteMatcher : BaseRouteMatcher() { } fun route(activity: FragmentActivity, route: Route?) { + if (enabledTabs?.isPathTabNotEnabled(route).orDefault()) { + if (activity is InterwebsToApplication) { + val intent = Intent(activity, NavigationActivity.startActivityClass) + activity.startActivity(intent) + } + activity.toast(R.string.route_not_available) + return + } if (route == null || route.routeContext == RouteContext.DO_NOT_ROUTE) { if (route?.uri != null) { // No route, no problem @@ -689,7 +722,7 @@ object RouteMatcher : BaseRouteMatcher() { if (networkStateProvider?.isOnline() == true) { openMedia(activity, fileFolder.contentType!!, fileFolder.url!!, fileFolder.displayName!!, route, fileID) } else { - openLocalMedia(activity, fileFolder.contentType, fileFolder.url, fileFolder.displayName, route.canvasContext!!) + openLocalMedia(activity, fileFolder.contentType, fileFolder.url, fileFolder.displayName, fileID, route.canvasContext!!) } } } catch { @@ -720,7 +753,7 @@ object RouteMatcher : BaseRouteMatcher() { } } else { openMediaCallbacks = null - openMediaBundle = OpenMediaAsyncTaskLoader.createBundle(mime, url, filename, route.arguments) + openMediaBundle = OpenMediaAsyncTaskLoader.createBundle(mime, url, filename, fileId, route.arguments) LoaderUtils.restartLoaderWithBundle>( LoaderManager.getInstance( activity @@ -729,11 +762,11 @@ object RouteMatcher : BaseRouteMatcher() { } } - private fun openLocalMedia(activity: FragmentActivity?, mime: String?, path: String?, filename: String?, canvasContext: CanvasContext) { + private fun openLocalMedia(activity: FragmentActivity?, mime: String?, path: String?, filename: String?, fileId: String?, canvasContext: CanvasContext) { val owner = activity ?: return onMainThread { openMediaCallbacks = null - openMediaBundle = OpenMediaAsyncTaskLoader.createLocalBundle(canvasContext, mime, path, filename, false) + openMediaBundle = OpenMediaAsyncTaskLoader.createLocalBundle(canvasContext, mime, path, filename, fileId, false) LoaderUtils.restartLoaderWithBundle>( LoaderManager.getInstance(owner), openMediaBundle, diff --git a/apps/student/src/main/java/com/instructure/student/router/RouteResolver.kt b/apps/student/src/main/java/com/instructure/student/router/RouteResolver.kt index 77ddbd1324..cfa56a3202 100644 --- a/apps/student/src/main/java/com/instructure/student/router/RouteResolver.kt +++ b/apps/student/src/main/java/com/instructure/student/router/RouteResolver.kt @@ -3,6 +3,7 @@ package com.instructure.student.router import androidx.fragment.app.Fragment import com.instructure.canvasapi2.models.CanvasContext import com.instructure.interactions.router.Route +import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment import com.instructure.pandautils.features.calendar.CalendarFragment import com.instructure.pandautils.features.calendarevent.createupdate.CreateUpdateEventFragment import com.instructure.pandautils.features.calendarevent.details.EventFragment @@ -12,14 +13,17 @@ import com.instructure.pandautils.features.dashboard.edit.EditDashboardFragment import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragment import com.instructure.pandautils.features.discussion.router.DiscussionRouterFragment import com.instructure.pandautils.features.inbox.list.InboxFragment +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.features.notification.preferences.EmailNotificationPreferencesFragment import com.instructure.pandautils.features.notification.preferences.PushNotificationPreferencesFragment import com.instructure.pandautils.features.offline.offlinecontent.OfflineContentFragment import com.instructure.pandautils.features.offline.sync.progress.SyncProgressFragment +import com.instructure.pandautils.features.offline.sync.settings.SyncSettingsFragment +import com.instructure.pandautils.features.smartsearch.SmartSearchFragment +import com.instructure.pandautils.fragments.RemoteConfigParamsFragment import com.instructure.pandautils.utils.Const import com.instructure.student.AnnotationComments.AnnotationCommentListFragment import com.instructure.student.activity.NothingToSeeHereFragment -import com.instructure.pandautils.features.assignments.details.AssignmentDetailsFragment import com.instructure.student.features.assignments.list.AssignmentListFragment import com.instructure.student.features.coursebrowser.CourseBrowserFragment import com.instructure.student.features.discussion.details.DiscussionDetailsFragment @@ -48,11 +52,11 @@ import com.instructure.student.fragment.DashboardFragment import com.instructure.student.fragment.DiscussionsReplyFragment import com.instructure.student.fragment.DiscussionsUpdateFragment import com.instructure.student.fragment.EditPageDetailsFragment +import com.instructure.student.fragment.FeatureFlagsFragment import com.instructure.student.fragment.InboxComposeMessageFragment import com.instructure.student.fragment.InboxConversationFragment import com.instructure.student.fragment.InboxRecipientsFragment import com.instructure.student.fragment.InternalWebviewFragment -import com.instructure.student.fragment.LtiLaunchFragment import com.instructure.student.fragment.NotificationListFragment import com.instructure.student.fragment.ProfileSettingsFragment import com.instructure.student.fragment.StudioWebViewFragment @@ -73,6 +77,7 @@ import com.instructure.student.mobius.assignmentDetails.submissionDetails.ui.Sub import com.instructure.student.mobius.conferences.conference_details.ui.ConferenceDetailsRepositoryFragment import com.instructure.student.mobius.conferences.conference_list.ui.ConferenceListRepositoryFragment import com.instructure.student.mobius.elementary.ElementaryDashboardFragment +import com.instructure.student.mobius.settings.pairobserver.ui.PairObserverFragment import com.instructure.student.mobius.syllabus.ui.SyllabusRepositoryFragment object RouteResolver { @@ -178,6 +183,11 @@ object RouteResolver { cls.isA() -> DiscussionRouterFragment.newInstance(route.canvasContext!!, route) cls.isA() -> OfflineContentFragment.newInstance(route) cls.isA() -> SyncProgressFragment.newInstance() + cls.isA() -> PairObserverFragment.newInstance() + cls.isA() -> SyncSettingsFragment.newInstance() + cls.isA() -> FeatureFlagsFragment() + cls.isA() -> RemoteConfigParamsFragment() + cls.isA() -> SmartSearchFragment.newInstance(route) cls.isA() -> InternalWebviewFragment.newInstance(route) // Keep this at the end else -> null } diff --git a/apps/student/src/main/java/com/instructure/student/tasks/StudentLogoutTask.kt b/apps/student/src/main/java/com/instructure/student/tasks/StudentLogoutTask.kt index c59c3905bd..6fb9f57003 100644 --- a/apps/student/src/main/java/com/instructure/student/tasks/StudentLogoutTask.kt +++ b/apps/student/src/main/java/com/instructure/student/tasks/StudentLogoutTask.kt @@ -21,7 +21,6 @@ import android.content.Intent import android.net.Uri import androidx.work.WorkManager import com.google.firebase.messaging.FirebaseMessaging -import com.heapanalytics.android.Heap import com.instructure.canvasapi2.utils.ContextKeeper import com.instructure.canvasapi2.utils.tryOrNull import com.instructure.loginapi.login.tasks.LogoutTask @@ -29,9 +28,10 @@ import com.instructure.pandautils.features.offline.sync.OfflineSyncWorker import com.instructure.pandautils.room.offline.DatabaseProvider import com.instructure.pandautils.typeface.TypefaceBehavior import com.instructure.student.activity.LoginActivity -import com.instructure.pandautils.features.assignments.details.reminder.AlarmScheduler +import com.instructure.pandautils.features.reminder.AlarmScheduler import com.instructure.student.util.StudentPrefs import com.instructure.student.widget.WidgetUpdater +import io.heap.core.Heap import java.io.File class StudentLogoutTask( @@ -46,7 +46,7 @@ class StudentLogoutTask( override fun onCleanup() { StudentPrefs.safeClearPrefs() WidgetUpdater.updateWidgets() - Heap.setTrackingEnabled(false) + Heap.stopRecording() } override fun createLoginIntent(context: Context): Intent { diff --git a/apps/student/src/main/java/com/instructure/student/util/AppManager.kt b/apps/student/src/main/java/com/instructure/student/util/AppManager.kt index b3203e6020..ef4ab6dc27 100644 --- a/apps/student/src/main/java/com/instructure/student/util/AppManager.kt +++ b/apps/student/src/main/java/com/instructure/student/util/AppManager.kt @@ -23,7 +23,7 @@ import com.instructure.canvasapi2.utils.MasqueradeHelper import com.instructure.loginapi.login.tasks.LogoutTask import com.instructure.pandautils.room.offline.DatabaseProvider import com.instructure.pandautils.typeface.TypefaceBehavior -import com.instructure.pandautils.features.assignments.details.reminder.AlarmScheduler +import com.instructure.pandautils.features.reminder.AlarmScheduler import com.instructure.student.tasks.StudentLogoutTask import dagger.hilt.android.HiltAndroidApp import javax.inject.Inject diff --git a/apps/student/src/main/java/com/instructure/student/util/BaseAppManager.kt b/apps/student/src/main/java/com/instructure/student/util/BaseAppManager.kt index fe26a2ca9f..30fb4b0caa 100644 --- a/apps/student/src/main/java/com/instructure/student/util/BaseAppManager.kt +++ b/apps/student/src/main/java/com/instructure/student/util/BaseAppManager.kt @@ -21,19 +21,21 @@ import android.webkit.WebView import androidx.appcompat.app.AppCompatDelegate import androidx.core.content.ContextCompat import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.heapanalytics.android.Heap -import com.heapanalytics.android.config.Options import com.instructure.annotations.FileCaching.FileCache import com.instructure.canvasapi2.utils.Analytics import com.instructure.canvasapi2.utils.AnalyticsEventConstants import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.RemoteConfigUtils import com.instructure.canvasapi2.utils.pageview.PageViewUploadService +import com.instructure.pandautils.base.AppConfig +import com.instructure.pandautils.base.AppConfigProvider import com.instructure.pandautils.utils.AppTheme +import com.instructure.pandautils.utils.AppType import com.instructure.pandautils.utils.ColorKeeper import com.instructure.pandautils.utils.ThemePrefs import com.instructure.student.BuildConfig import com.instructure.student.R +import com.instructure.student.activity.NavigationActivity import com.instructure.student.service.StudentPageViewService import com.pspdfkit.PSPDFKit import com.pspdfkit.exceptions.InvalidPSPDFKitLicenseException @@ -45,6 +47,7 @@ abstract class BaseAppManager : com.instructure.canvasapi2.AppManager(), Analyti override fun onCreate() { super.onCreate() + AppConfigProvider.appConfig = AppConfig(AppType.STUDENT, NavigationActivity::class.java) FileCache.versionCode = BuildConfig.VERSION_CODE @@ -81,10 +84,6 @@ abstract class BaseAppManager : com.instructure.canvasapi2.AppManager(), Analyti } PageViewUploadService.schedule(this, StudentPageViewService::class.java) - - val options = Options() - options.disableTracking() - Heap.init(this, BuildConfig.HEAP_APP_ID, options) } override fun trackButtonPressed(buttonName: String?, buttonValue: Long?) { diff --git a/apps/student/src/main/java/com/instructure/student/util/TabHelper.kt b/apps/student/src/main/java/com/instructure/student/util/TabHelper.kt index b3fd8de5ee..74b6e50eed 100644 --- a/apps/student/src/main/java/com/instructure/student/util/TabHelper.kt +++ b/apps/student/src/main/java/com/instructure/student/util/TabHelper.kt @@ -24,6 +24,7 @@ import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.ContextKeeper import com.instructure.canvasapi2.utils.validOrNull import com.instructure.interactions.router.Route +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.student.R import com.instructure.student.activity.NothingToSeeHereFragment import com.instructure.student.features.assignments.list.AssignmentListFragment @@ -37,12 +38,11 @@ import com.instructure.student.features.people.list.PeopleListFragment import com.instructure.student.features.quiz.list.QuizListFragment import com.instructure.student.fragment.AnnouncementListFragment import com.instructure.student.fragment.CourseSettingsFragment -import com.instructure.student.fragment.LtiLaunchFragment import com.instructure.student.fragment.NotificationListFragment import com.instructure.student.fragment.UnsupportedTabFragment import com.instructure.student.mobius.conferences.conference_list.ui.ConferenceListRepositoryFragment import com.instructure.student.mobius.syllabus.ui.SyllabusRepositoryFragment -import java.util.* +import java.util.Locale object TabHelper { diff --git a/apps/student/src/main/res/layout/activity_settings.xml b/apps/student/src/main/res/layout/activity_settings.xml deleted file mode 100644 index 7a115143d5..0000000000 --- a/apps/student/src/main/res/layout/activity_settings.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - diff --git a/apps/student/src/main/res/layout/activity_student_view_starter.xml b/apps/student/src/main/res/layout/activity_student_view_starter.xml index ce779a49cb..6ad182ea3a 100644 --- a/apps/student/src/main/res/layout/activity_student_view_starter.xml +++ b/apps/student/src/main/res/layout/activity_student_view_starter.xml @@ -23,7 +23,7 @@ android:orientation="vertical" android:background="@color/backgroundLightest"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/student/src/main/res/layout/fragment_course_browser.xml b/apps/student/src/main/res/layout/fragment_course_browser.xml index 68b938a9ea..1db95041a2 100644 --- a/apps/student/src/main/res/layout/fragment_course_browser.xml +++ b/apps/student/src/main/res/layout/fragment_course_browser.xml @@ -80,12 +80,12 @@ android:ellipsize="end" android:gravity="center" android:maxLines="3" - android:textColor="@color/textLightest" - android:textSize="24sp" android:shadowColor="@color/shadowColor" android:shadowDx="1" android:shadowDy="1" android:shadowRadius="4" + android:textColor="@color/textLightest" + android:textSize="24sp" tools:text="Title of Course" /> @@ -99,12 +99,12 @@ android:gravity="center" android:lines="1" android:maxLines="1" - android:textColor="@color/textLightest" - android:textSize="16sp" android:shadowColor="@color/shadowColor" android:shadowDx="1" android:shadowDy="1" android:shadowRadius="4" + android:textColor="@color/textLightest" + android:textSize="16sp" tools:text="Subtitle" /> @@ -120,6 +120,13 @@ app:popupTheme="@style/ToolBarPopupStyle" app:theme="@style/ToolBarStyle"> + + - - - - - - - - - diff --git a/apps/student/src/main/res/layout/fragment_lti_submission_view.xml b/apps/student/src/main/res/layout/fragment_lti_submission_view.xml index 5fdaa035c6..60157e789f 100644 --- a/apps/student/src/main/res/layout/fragment_lti_submission_view.xml +++ b/apps/student/src/main/res/layout/fragment_lti_submission_view.xml @@ -35,6 +35,7 @@ app:srcCompat="@drawable/ic_panda_online_submissions" /> - . + * + */ +package com.instructure.student.router + +import android.net.Uri +import com.instructure.canvasapi2.apis.CourseAPI +import com.instructure.canvasapi2.models.Course +import com.instructure.canvasapi2.models.Tab +import com.instructure.canvasapi2.utils.DataResult +import com.instructure.interactions.router.Route +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import junit.framework.TestCase.assertFalse +import junit.framework.TestCase.assertTrue +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before +import org.junit.Test + +class EnabledTabsTest { + private val mockUri: Uri = mockk(relaxed = true) + private val courseApi: CourseAPI.CoursesInterface = mockk(relaxed = true) + private val enabledTabs = EnabledTabsImpl(courseApi) + + @Before + fun setup() { + mockkStatic(Uri::class) + every { Uri.parse(any()) } returns mockUri + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `isPathTabNotEnabled should return false when route is null`() = runTest { + + val result = enabledTabs.isPathTabNotEnabled(null) + + assertFalse(result) + } + + @Test + fun `isPathTabNotEnabled should return false when uri not contains uri or path`() = runTest { + val route = Route(uri = null, routePath = null, courseId = null) + + val result = enabledTabs.isPathTabNotEnabled(route) + + assertFalse(result) + } + + @Test + fun `isPathTabNotEnabled should return false when enabled tabs is null`() = runTest { + val route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com" + every { mockUri.pathSegments } returns emptyList() + coEvery { courseApi.getFirstPageCourses(any()) } returns DataResult.Fail() + enabledTabs.initTabs() + + val result = enabledTabs.isPathTabNotEnabled(route) + + assertFalse(result) + } + + @Test + fun `isPathTabNotEnabled should return false when enabled tabs is empty`() = runTest { + val route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com" + every { mockUri.pathSegments } returns emptyList() + coEvery { courseApi.getFirstPageCourses(any()) } returns DataResult.Success(emptyList()) + enabledTabs.initTabs() + + val result = enabledTabs.isPathTabNotEnabled(route) + + assertFalse(result) + } + + @Test + fun `isPathTabNotEnabled should return false when uri not contains courseId`() = runTest { + val route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com" + every { mockUri.pathSegments } returns emptyList() + + val result = enabledTabs.isPathTabNotEnabled(route) + + assertFalse(result) + } + + @Test + fun `isPathTabNotEnabled should return false value for valid details urls`() = runTest { + coEvery { courseApi.getFirstPageCourses(any()) } returns DataResult.Success( + listOf( + Course(id = 1, tabs = listOf(Tab(tabId = "assignment", htmlUrl = "/courses/1/assignments"))), + ) + ) + enabledTabs.initTabs() + + val route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com/courses/1/assignments/1" + every { mockUri.pathSegments } returns listOf("courses", "1", "assignments", "1") + + val result = enabledTabs.isPathTabNotEnabled(route) + + assertFalse(result) + } + + @Test + fun `isPathTabNotEnabled handle home urls correctly`() = runTest { + coEvery { courseApi.getFirstPageCourses(any()) } returns DataResult.Success( + listOf( + Course(id = 1, tabs = listOf(Tab(tabId = "home", htmlUrl = "/courses/1"))), + ) + ) + enabledTabs.initTabs() + + val route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com/courses/1" + every { mockUri.pathSegments } returns listOf("courses", "1") + + val result = enabledTabs.isPathTabNotEnabled(route) + + assertFalse(result) + } + + @Test + fun `isPathTabNotEnabled handle syllabus urls correctly with disabled tab`() = runTest { + coEvery { courseApi.getFirstPageCourses(any()) } returns DataResult.Success( + listOf( + Course(id = 1, tabs = listOf(Tab(tabId = "assignments", htmlUrl = "/courses/1/assignments"))), + ) + ) + enabledTabs.initTabs() + + val route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com/courses/1/assignments/syllabus" + every { mockUri.pathSegments } returns listOf("courses", "1", "assignments", "syllabus") + + val result = enabledTabs.isPathTabNotEnabled(route) + + assertTrue(result) + } + + @Test + fun `isPathTabNotEnabled handle syllabus urls correctly with enabled tab`() = runTest { + coEvery { courseApi.getFirstPageCourses(any()) } returns DataResult.Success( + listOf( + Course(id = 1, tabs = listOf(Tab(tabId = "syllabus", htmlUrl = "/courses/1/assignments/syllabus"))), + ) + ) + enabledTabs.initTabs() + + val route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com/courses/1/assignments/syllabus" + every { mockUri.pathSegments } returns listOf("courses", "1", "assignments", "syllabus") + + val result = enabledTabs.isPathTabNotEnabled(route) + + assertFalse(result) + } + + @Test + fun `isPathTabNotEnabled can handle cross-course navigation`() = runTest { + coEvery { courseApi.getFirstPageCourses(any()) } returns DataResult.Success( + listOf( + Course(id = 1, tabs = listOf(Tab(tabId = "assignments", htmlUrl = "/courses/1/assignments"))), + Course(id = 2, tabs = listOf(Tab(tabId = "syllabus", htmlUrl = "/courses/2/assignments/syllabus"))), + ) + ) + enabledTabs.initTabs() + + // Check course 1 disabled tab + var route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com/courses/1/assignments/syllabus" + every { mockUri.pathSegments } returns listOf("courses", "1", "assignments", "syllabus") + var result = enabledTabs.isPathTabNotEnabled(route) + assertTrue(result) + + // Check course 1 enabled tab + route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com/courses/1/assignments" + every { mockUri.pathSegments } returns listOf("courses", "1", "assignments") + result = enabledTabs.isPathTabNotEnabled(route) + assertFalse(result) + + // Check course 2 disabled tab + route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com/courses/2/assignments" + every { mockUri.pathSegments } returns listOf("courses", "2", "assignments") + result = enabledTabs.isPathTabNotEnabled(route) + assertTrue(result) + + // Check course 2 enabled tab + route = Route(uri = mockUri) + every { mockUri.path } returns "http://www.google.com/courses/2/assignments/syllabus" + every { mockUri.pathSegments } returns listOf("courses", "2", "assignments", "syllabus") + result = enabledTabs.isPathTabNotEnabled(route) + assertFalse(result) + } +} \ No newline at end of file diff --git a/apps/student/src/test/java/com/instructure/student/test/assignment/details/submissionDetails/SubmissionDetailsEffectHandlerTest.kt b/apps/student/src/test/java/com/instructure/student/test/assignment/details/submissionDetails/SubmissionDetailsEffectHandlerTest.kt index d7642fc82b..2707d6ad55 100644 --- a/apps/student/src/test/java/com/instructure/student/test/assignment/details/submissionDetails/SubmissionDetailsEffectHandlerTest.kt +++ b/apps/student/src/test/java/com/instructure/student/test/assignment/details/submissionDetails/SubmissionDetailsEffectHandlerTest.kt @@ -110,7 +110,7 @@ class SubmissionDetailsEffectHandlerTest : Assert() { SubmissionDetailsEvent.DataLoaded( assignment = DataResult.Fail(Failure.Network(errorMessage)), rootSubmissionResult = DataResult.Fail(Failure.Network(errorMessage)), - ltiUrlResult = DataResult.Fail(null), + ltiTool = DataResult.Fail(null), isStudioEnabled = false, quizResult = null, studioLTIToolResult = DataResult.Fail(null), @@ -147,7 +147,7 @@ class SubmissionDetailsEffectHandlerTest : Assert() { SubmissionDetailsEvent.DataLoaded( assignment = DataResult.Fail(Failure.Authorization(errorMessage)), rootSubmissionResult = DataResult.Fail(Failure.Authorization(errorMessage)), - ltiUrlResult = DataResult.Fail(null), + ltiTool = DataResult.Fail(null), isStudioEnabled = false, quizResult = null, studioLTIToolResult = DataResult.Fail(null), @@ -197,7 +197,7 @@ class SubmissionDetailsEffectHandlerTest : Assert() { SubmissionDetailsEvent.DataLoaded( assignment = DataResult.Success(assignment), rootSubmissionResult = DataResult.Success(submission), - ltiUrlResult = DataResult.Success(ltiTool), + ltiTool = DataResult.Success(ltiTool), isStudioEnabled = false, quizResult = null, studioLTIToolResult = DataResult.Fail(null), @@ -246,7 +246,7 @@ class SubmissionDetailsEffectHandlerTest : Assert() { SubmissionDetailsEvent.DataLoaded( assignment = DataResult.Success(assignment), rootSubmissionResult = DataResult.Success(submission), - ltiUrlResult = DataResult.Success(ltiTool), + ltiTool = DataResult.Success(ltiTool), isStudioEnabled = false, quizResult = null, studioLTIToolResult = DataResult.Fail(null), @@ -288,7 +288,7 @@ class SubmissionDetailsEffectHandlerTest : Assert() { SubmissionDetailsEvent.DataLoaded( assignment = DataResult.Success(assignment), rootSubmissionResult = DataResult.Success(submission), - ltiUrlResult = DataResult.Success(ltiTool), + ltiTool = DataResult.Success(ltiTool), isStudioEnabled = false, quizResult = null, studioLTIToolResult = DataResult.Fail(null), @@ -332,7 +332,7 @@ class SubmissionDetailsEffectHandlerTest : Assert() { SubmissionDetailsEvent.DataLoaded( assignment = DataResult.Success(assignment), rootSubmissionResult = DataResult.Success(submission), - ltiUrlResult = DataResult.Fail(null), + ltiTool = DataResult.Fail(null), isStudioEnabled = false, quizResult = DataResult.Success(quiz), studioLTIToolResult = DataResult.Fail(null), @@ -380,7 +380,7 @@ class SubmissionDetailsEffectHandlerTest : Assert() { SubmissionDetailsEvent.DataLoaded( assignment = DataResult.Success(assignment), rootSubmissionResult = DataResult.Success(submission), - ltiUrlResult = DataResult.Fail(null), + ltiTool = DataResult.Fail(null), isStudioEnabled = true, quizResult = null, studioLTIToolResult = DataResult.Success(studioLTITool), diff --git a/apps/student/src/test/java/com/instructure/student/test/assignment/details/submissionDetails/SubmissionDetailsUpdateTest.kt b/apps/student/src/test/java/com/instructure/student/test/assignment/details/submissionDetails/SubmissionDetailsUpdateTest.kt index 0686b245e1..c0304f38ab 100644 --- a/apps/student/src/test/java/com/instructure/student/test/assignment/details/submissionDetails/SubmissionDetailsUpdateTest.kt +++ b/apps/student/src/test/java/com/instructure/student/test/assignment/details/submissionDetails/SubmissionDetailsUpdateTest.kt @@ -18,11 +18,21 @@ package com.instructure.student.test.assignment.details.submissionDetails import android.net.Uri import android.webkit.MimeTypeMap import android.webkit.URLUtil -import com.instructure.canvasapi2.models.* +import com.instructure.canvasapi2.models.Assignment +import com.instructure.canvasapi2.models.Attachment +import com.instructure.canvasapi2.models.Course +import com.instructure.canvasapi2.models.LTITool +import com.instructure.canvasapi2.models.MediaComment +import com.instructure.canvasapi2.models.Quiz +import com.instructure.canvasapi2.models.Submission import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.DataResult import com.instructure.canvasapi2.utils.Failure -import com.instructure.student.mobius.assignmentDetails.submissionDetails.* +import com.instructure.student.mobius.assignmentDetails.submissionDetails.SubmissionDetailsContentType +import com.instructure.student.mobius.assignmentDetails.submissionDetails.SubmissionDetailsEffect +import com.instructure.student.mobius.assignmentDetails.submissionDetails.SubmissionDetailsEvent +import com.instructure.student.mobius.assignmentDetails.submissionDetails.SubmissionDetailsModel +import com.instructure.student.mobius.assignmentDetails.submissionDetails.SubmissionDetailsUpdate import com.instructure.student.test.util.matchesEffects import com.instructure.student.test.util.matchesFirstEffects import com.instructure.student.util.Const @@ -34,7 +44,12 @@ import com.spotify.mobius.test.NextMatchers.hasModel import com.spotify.mobius.test.NextMatchers.hasNothing import com.spotify.mobius.test.UpdateSpec import com.spotify.mobius.test.UpdateSpec.assertThatNext -import io.mockk.* +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkObject +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import io.mockk.unmockkObject import org.junit.After import org.junit.Assert import org.junit.Before @@ -57,7 +72,7 @@ class SubmissionDetailsUpdateTest : Assert() { @Before fun setup() { course = Course() - assignment = Assignment(id = 1234L, courseId = course.id) + assignment = Assignment(id = 1234L, courseId = course.id, name = "Assignment") submission = Submission(id = 30L, attempt = 1L, assignmentId = assignment.id) initModel = SubmissionDetailsModel(assignmentId = assignment.id, canvasContext = course, isStudioEnabled = isStudioEnabled, assignmentEnhancementsEnabled = true) ltiTool = LTITool(url = "https://www.instructure.com") @@ -294,7 +309,7 @@ class SubmissionDetailsUpdateTest : Assert() { verifyGetSubmissionContentType( assignment.copy(submissionTypesRaw = listOf(Assignment.SubmissionType.EXTERNAL_TOOL.apiString)), submission, - SubmissionDetailsContentType.ExternalToolContent(course, ltiTool.url!!), + SubmissionDetailsContentType.ExternalToolContent(course, ltiTool, assignment.name!!), ltiTool ) } @@ -373,34 +388,8 @@ class SubmissionDetailsUpdateTest : Assert() { verifyGetSubmissionContentType( assignment, submission.copy(previewUrl = url, submissionType = Assignment.SubmissionType.BASIC_LTI_LAUNCH.apiString), - SubmissionDetailsContentType.ExternalToolContent(initModel.canvasContext, url) - ) - } - - @Test - fun `BASIC_LTI_LAUNCH without a preview url results in SubmissionDetailsContentType of ExternalToolContent`() { - verifyGetSubmissionContentType( - assignment.copy(url = url), - submission.copy(previewUrl = null, submissionType = Assignment.SubmissionType.BASIC_LTI_LAUNCH.apiString), - SubmissionDetailsContentType.ExternalToolContent(initModel.canvasContext, url) - ) - } - - @Test - fun `BASIC_LTI_LAUNCH without a preview url or an assignment url results in SubmissionDetailsContentType of ExternalToolContent`() { - verifyGetSubmissionContentType( - assignment.copy(url = null, htmlUrl = url), - submission.copy(previewUrl = null, submissionType = Assignment.SubmissionType.BASIC_LTI_LAUNCH.apiString), - SubmissionDetailsContentType.ExternalToolContent(initModel.canvasContext, url) - ) - } - - @Test - fun `BASIC_LTI_LAUNCH without a preview url or an assignment url or an assignment html url results in SubmissionDetailsContentType of ExternalToolContent`() { - verifyGetSubmissionContentType( - assignment.copy(url = null, htmlUrl = null), - submission.copy(previewUrl = null, submissionType = Assignment.SubmissionType.BASIC_LTI_LAUNCH.apiString), - SubmissionDetailsContentType.ExternalToolContent(initModel.canvasContext, "") + SubmissionDetailsContentType.ExternalToolContent(initModel.canvasContext, ltiTool, assignment.name!!), + lti = ltiTool ) } diff --git a/apps/teacher/build.gradle b/apps/teacher/build.gradle index 8e42c1c34f..2c97c7c8c5 100644 --- a/apps/teacher/build.gradle +++ b/apps/teacher/build.gradle @@ -13,17 +13,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - -import com.instructure.android.buildtools.transform.* - apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-parcelize' apply plugin: 'kotlin-kapt' apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'dagger.hilt.android.plugin' -apply plugin: 'com.heapanalytics.android' +apply plugin: 'io.heap.gradle' def updatePriority = 2 def coverageEnabled = project.hasProperty('coverage') @@ -39,8 +35,8 @@ android { defaultConfig { minSdkVersion Versions.MIN_SDK targetSdkVersion Versions.TARGET_SDK - versionCode = 71 - versionName = '1.34.0' + versionCode = 72 + versionName = '1.35.0' vectorDrawables.useSupportLibrary = true testInstrumentationRunner 'com.instructure.teacher.ui.espresso.TeacherHiltTestRunner' testInstrumentationRunnerArguments disableAnalytics: 'true' @@ -110,10 +106,6 @@ android { } buildConfigField "String", "HEAP_APP_ID", "\"$heapStagingId\"" - - ext { - heapEnabled = true - } } debugMinify { @@ -140,10 +132,6 @@ android { buildConfigField "String", "HEAP_APP_ID", "\"$heapProductionId\"" - ext { - heapEnabled = true - } - firebaseCrashlytics { nativeSymbolUploadEnabled true strippedNativeLibsDir 'build/intermediates/stripped_native_libs/release/out/lib' @@ -196,15 +184,7 @@ android { unitTests.includeAndroidResources = true } - registerTransform( - new ProjectTransformer( - android, - new MasqueradeUITransformer('com.instructure.teacher.activities.LoginActivity.class'), - new PageViewTransformer(), - new LocaleTransformer(project), - new ScreenViewTransformer("teacher") - ) - ) + compileOptions { sourceCompatibility 1.8 @@ -314,7 +294,7 @@ dependencies { implementation Libs.ANDROIDX_WORK_MANAGER implementation Libs.ANDROIDX_WORK_MANAGER_KTX - implementation Libs.HEAP + implementation Libs.HEAP_CORE implementation Libs.CAMERA_VIEW diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/AnnouncementsListPageTest.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/AnnouncementsListPageTest.kt index 33c7c1d89c..8419f5ccce 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/AnnouncementsListPageTest.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/AnnouncementsListPageTest.kt @@ -30,7 +30,7 @@ import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvas.espresso.mockCanvas.utils.Randomizer import com.instructure.canvasapi2.models.CanvasContextPermission import com.instructure.canvasapi2.models.Tab -import com.instructure.espresso.page.getStringFromResource +import com.instructure.espresso.pages.getStringFromResource import com.instructure.teacher.R import com.instructure.teacher.ui.utils.TeacherTest import com.instructure.teacher.ui.utils.tokenLogin diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/AssigneeListPageTest.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/AssigneeListPageTest.kt index 925dede26e..fe1780012d 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/AssigneeListPageTest.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/AssigneeListPageTest.kt @@ -22,7 +22,7 @@ import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.CanvasContextPermission import com.instructure.espresso.assertContainsText -import com.instructure.espresso.page.onViewWithId +import com.instructure.espresso.pages.onViewWithId import com.instructure.teacher.R import com.instructure.teacher.ui.utils.TeacherTest import com.instructure.teacher.ui.utils.tokenLogin diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/AssignmentE2ETest.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/AssignmentE2ETest.kt index 59e7197913..60f61b130c 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/AssignmentE2ETest.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/AssignmentE2ETest.kt @@ -32,7 +32,7 @@ import com.instructure.dataseeding.util.days import com.instructure.dataseeding.util.fromNow import com.instructure.dataseeding.util.iso8601 import com.instructure.espresso.assertContainsText -import com.instructure.espresso.page.onViewWithId +import com.instructure.espresso.pages.onViewWithId import com.instructure.teacher.R import com.instructure.teacher.ui.utils.TeacherTest import com.instructure.teacher.ui.utils.seedAssignmentSubmission diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/LoginE2ETest.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/LoginE2ETest.kt index 4774333430..e424864198 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/LoginE2ETest.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/LoginE2ETest.kt @@ -199,7 +199,6 @@ class LoginE2ETest : TeacherTest() { loginSignInPage.assertLoginErrorMessage(INVALID_CREDENTIALS_ERROR_MESSAGE) } - private fun loginWithUser(user: CanvasUserApiModel, lastSchoolSaved: Boolean = false) { if(lastSchoolSaved) { diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/PushNotificationsE2ETest.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/PushNotificationsE2ETest.kt index d1ea4269f2..6d81618d9d 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/PushNotificationsE2ETest.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/PushNotificationsE2ETest.kt @@ -7,12 +7,12 @@ import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.TestCategory import com.instructure.canvas.espresso.TestMetaData import com.instructure.teacher.BuildConfig -import com.instructure.teacher.ui.utils.TeacherTest +import com.instructure.teacher.ui.utils.TeacherComposeTest import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Test @HiltAndroidTest -class PushNotificationsE2ETest : TeacherTest() { +class PushNotificationsE2ETest : TeacherComposeTest() { override fun displaysPageObjects() = Unit @@ -41,7 +41,7 @@ class PushNotificationsE2ETest : TeacherTest() { settingsPage.assertPageObjects() Log.d(STEP_TAG, "Open Push Notifications Page.") - settingsPage.openPushNotificationsPage() + settingsPage.clickOnSettingsItem("Push Notifications") Log.d(ASSERTION_TAG, "Assert that the toolbar title is 'Push Notifications' on the Push Notifications Page.") pushNotificationsPage.assertToolbarTitle() diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/SettingsE2ETest.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/SettingsE2ETest.kt index bcd86e014d..52b07e2286 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/SettingsE2ETest.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/SettingsE2ETest.kt @@ -30,9 +30,10 @@ import com.instructure.dataseeding.api.ConversationsApi import com.instructure.dataseeding.api.CoursesApi import com.instructure.dataseeding.api.EnrollmentsApi import com.instructure.espresso.ViewUtils +import com.instructure.pandautils.utils.AppTheme import com.instructure.teacher.BuildConfig import com.instructure.teacher.ui.pages.PersonContextPage -import com.instructure.teacher.ui.utils.TeacherTest +import com.instructure.teacher.ui.utils.TeacherComposeTest import com.instructure.teacher.ui.utils.openLeftSideMenu import com.instructure.teacher.ui.utils.seedData import com.instructure.teacher.ui.utils.tokenLogin @@ -40,7 +41,7 @@ import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Test @HiltAndroidTest -class SettingsE2ETest : TeacherTest() { +class SettingsE2ETest : TeacherComposeTest() { override fun displaysPageObjects() = Unit @@ -85,10 +86,9 @@ class SettingsE2ETest : TeacherTest() { Log.d(STEP_TAG, "Navigate to User Settings Page.") leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.assertPageObjects() Log.d(STEP_TAG, "Open Profile Settings Page.") - settingsPage.openProfileSettingsPage() + settingsPage.clickOnSettingsItem("Profile Settings") profileSettingsPage.assertPageObjects() Log.d(STEP_TAG, "Assert that the '$testPronoun' pronouns are displayed on the Profile Settings Page.") @@ -141,10 +141,9 @@ class SettingsE2ETest : TeacherTest() { Log.d(STEP_TAG, "Navigate to User Settings Page.") leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.assertPageObjects() Log.d(STEP_TAG, "Open Profile Settings Page.") - settingsPage.openProfileSettingsPage() + settingsPage.clickOnSettingsItem("Profile Settings") profileSettingsPage.assertPageObjects() Log.d(STEP_TAG, "Click on Edit Pencil Icon on the toolbar.") @@ -159,9 +158,8 @@ class SettingsE2ETest : TeacherTest() { try { Log.d(STEP_TAG, "Check if the user has landed on Settings Page. If yes, navigate back to Profile Settings Page.") //Sometimes in Bitrise it's working different than locally, because in Bitrise sometimes the user has been navigated to Settings Page after saving a new name, - settingsPage.assertPageObjects() - settingsPage.openProfileSettingsPage() - } catch (e: NoMatchingViewException) { + settingsPage.clickOnSettingsItem("Profile Settings") + } catch (e: IllegalStateException) { Log.d(STEP_TAG, "Did not throw the user back to the Settings Page, so the scenario can be continued.") } @@ -208,15 +206,11 @@ class SettingsE2ETest : TeacherTest() { Log.d(STEP_TAG, "Navigate to User Settings Page.") leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.assertPageObjects() - - Log.d(STEP_TAG,"Navigate to Settings Page and open App Theme Settings.") - settingsPage.openAppThemeSettings() Log.d(STEP_TAG,"Select Dark App Theme and assert that the App Theme Title and Status has the proper text color (which is used in Dark mode).") - settingsPage.selectAppTheme("Dark") - settingsPage.assertAppThemeTitleTextColor("#FFFFFFFF") //Currently, this color is used in the Dark mode for the AppTheme Title text. - settingsPage.assertAppThemeStatusTextColor("#FF919CA8") //Currently, this color is used in the Dark mode for the AppTheme Status text. + settingsPage.selectAppTheme(AppTheme.DARK) + //settingsPage.assertAppThemeTitleTextColor("#FFFFFFFF") //Currently, this color is used in the Dark mode for the AppTheme Title text. + //settingsPage.assertAppThemeStatusTextColor("#FF919CA8") //Currently, this color is used in the Dark mode for the AppTheme Status text. Log.d(STEP_TAG,"Navigate back to Dashboard. Assert that the 'Courses' label has the proper text color (which is used in Dark mode).") Espresso.pressBack() @@ -230,12 +224,11 @@ class SettingsE2ETest : TeacherTest() { Log.d(STEP_TAG,"Navigate to Settings Page and open App Theme Settings again.") Espresso.pressBack() leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.openAppThemeSettings() Log.d(STEP_TAG,"Select Light App Theme and assert that the App Theme Title and Status has the proper text color (which is used in Light mode).") - settingsPage.selectAppTheme("Light") - settingsPage.assertAppThemeTitleTextColor("#FF273540") //Currently, this color is used in the Light mode for the AppTheme Title texts. - settingsPage.assertAppThemeStatusTextColor("#FF6A7883") //Currently, this color is used in the Light mode for the AppTheme Status text. + settingsPage.selectAppTheme(AppTheme.LIGHT) + //settingsPage.assertAppThemeTitleTextColor("#FF273540") //Currently, this color is used in the Light mode for the AppTheme Title texts. + //settingsPage.assertAppThemeStatusTextColor("#FF6A7883") //Currently, this color is used in the Light mode for the AppTheme Status text. Log.d(STEP_TAG,"Navigate back to Dashboard. Assert that the 'Courses' label has the proper text color (which is used in Light mode).") Espresso.pressBack() @@ -257,10 +250,9 @@ class SettingsE2ETest : TeacherTest() { Log.d(STEP_TAG,"Navigate to User Settings Page.") leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.assertPageObjects() Log.d(STEP_TAG,"Open Legal Page and assert that all the corresponding buttons are displayed.") - settingsPage.openLegalPage() + settingsPage.clickOnSettingsItem("Legal") legalPage.assertPageObjects() } @@ -279,10 +271,9 @@ class SettingsE2ETest : TeacherTest() { Log.d(STEP_TAG, "Navigate to Settings Page on the left-side menu.") leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.assertPageObjects() Log.d(STEP_TAG, "Click on 'About' link to open About Page. Assert that About Page has opened.") - settingsPage.openAboutPage() + settingsPage.clickOnSettingsItem("About") aboutPage.assertPageObjects() Log.d(STEP_TAG,"Check that domain is equal to: '${teacher.domain}' (teacher's domain).") @@ -313,10 +304,9 @@ class SettingsE2ETest : TeacherTest() { Log.d(STEP_TAG,"Navigate to User Settings Page.") leftSideNavigationDrawerPage.clickSettingsMenu() - settingsPage.assertPageObjects() Log.d(STEP_TAG,"Open Legal Page and assert that all the corresponding buttons are displayed.") - settingsPage.openRateAppDialog() + settingsPage.clickOnSettingsItem("Rate on the Play Store") Log.d(STEP_TAG,"Assert that the five starts are displayed.") settingsPage.assertFiveStarRatingDisplayed() @@ -344,7 +334,7 @@ class SettingsE2ETest : TeacherTest() { RemoteConfigParam.values().forEach { param -> initialValues[param.rc_name] = RemoteConfigUtils.getString(param) } Log.d(STEP_TAG,"Navigate to Remote Config Params Page.") - settingsPage.openRemoteConfigParamsPage() + settingsPage.clickOnSettingsItem("Remote Config Params") Log.d(STEP_TAG,"Click on each EditText, which brings up the soft keyboard, then dismiss it.") RemoteConfigParam.values().forEach { param -> @@ -359,10 +349,9 @@ class SettingsE2ETest : TeacherTest() { Log.d(STEP_TAG,"Navigate back to Settings Page.") Espresso.pressBack() - settingsPage.assertPageObjects() Log.d(STEP_TAG,"Navigate to Remote Config Params page again.") - settingsPage.openRemoteConfigParamsPage() + settingsPage.clickOnSettingsItem("Remote Config Params") Log.d(STEP_TAG,"Assert that all fields have maintained their initial value.") RemoteConfigParam.values().forEach { param -> diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AboutPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AboutPage.kt index 8bc5a8729d..c808ef9688 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AboutPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AboutPage.kt @@ -20,9 +20,9 @@ import androidx.test.espresso.Espresso.onView import androidx.test.espresso.matcher.ViewMatchers.withId import com.instructure.espresso.OnViewWithText import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AddMessagePage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AddMessagePage.kt index e8622a4785..34d11c6fe5 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AddMessagePage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AddMessagePage.kt @@ -24,8 +24,8 @@ import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasChild import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.waitForViewWithText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.waitForViewWithText import com.instructure.espresso.replaceText import com.instructure.espresso.scrollTo import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AllCoursesListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AllCoursesListPage.kt index 904f4f1a1a..e830633f7f 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AllCoursesListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AllCoursesListPage.kt @@ -20,8 +20,19 @@ package com.instructure.teacher.ui.pages import android.view.View import com.instructure.canvasapi2.models.Course import com.instructure.dataseeding.model.CourseApiModel -import com.instructure.espresso.* -import com.instructure.espresso.page.* +import com.instructure.espresso.OnViewWithContentDescription +import com.instructure.espresso.OnViewWithId +import com.instructure.espresso.OnViewWithText +import com.instructure.espresso.RecyclerViewItemCountAssertion +import com.instructure.espresso.WaitForViewWithId +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.click +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText +import com.instructure.espresso.scrollTo import com.instructure.teacher.R import org.hamcrest.CoreMatchers import org.hamcrest.Matcher diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AnnouncementsListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AnnouncementsListPage.kt index 932b13e31f..f0397c3307 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AnnouncementsListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AnnouncementsListPage.kt @@ -26,15 +26,15 @@ import com.instructure.espresso.RecyclerViewItemCountAssertion import com.instructure.espresso.Searchable import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithContentDescription -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithContentDescription +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.replaceText import com.instructure.espresso.swipeDown import com.instructure.espresso.waitForCheck diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssigneeListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssigneeListPage.kt index 51faf5e03d..8a8331a588 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssigneeListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssigneeListPage.kt @@ -32,8 +32,8 @@ import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertContainsText import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onViewWithId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onViewWithId import com.instructure.teacher.R import com.instructure.teacher.holders.AssigneeItemViewHolder import org.hamcrest.Description diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentDetailsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentDetailsPage.kt index 469ec3aa5b..3c18ea609e 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentDetailsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentDetailsPage.kt @@ -37,13 +37,13 @@ import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.assertNotHasText import com.instructure.espresso.assertVisible import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.scrollTo -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.scrollTo +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.swipeDown import com.instructure.teacher.R import org.hamcrest.Matchers diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentDueDatesPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentDueDatesPage.kt index b12fabb248..4833a4ee8d 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentDueDatesPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentDueDatesPage.kt @@ -15,10 +15,23 @@ */ package com.instructure.teacher.ui.pages -import com.instructure.espresso.* -import com.instructure.espresso.page.* - +import com.instructure.espresso.OnViewWithContentDescription +import com.instructure.espresso.OnViewWithId +import com.instructure.espresso.OnViewWithText +import com.instructure.espresso.RecyclerViewItemCountAssertion +import com.instructure.espresso.WaitForViewWithId +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.assertHasText +import com.instructure.espresso.assertNotHasText +import com.instructure.espresso.click +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentListPage.kt index 0bf5665ac8..a217d28548 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentListPage.kt @@ -29,15 +29,15 @@ import com.instructure.espresso.Searchable import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.swipeDown import com.instructure.espresso.waitForCheck import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentSubmissionListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentSubmissionListPage.kt index 1f832b458c..44d6b1e34e 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentSubmissionListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/AssignmentSubmissionListPage.kt @@ -39,17 +39,17 @@ import com.instructure.espresso.actions.ForceClick import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithId +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.teacher.R import org.hamcrest.CoreMatchers.allOf import org.hamcrest.Matchers diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ChooseRecipientsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ChooseRecipientsPage.kt index c955af828d..8d2e04ab9c 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ChooseRecipientsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ChooseRecipientsPage.kt @@ -21,8 +21,8 @@ import com.instructure.dataseeding.model.CanvasUserApiModel import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.waitForViewWithText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.waitForViewWithText import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CommentLibraryPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CommentLibraryPage.kt index 1f1d2183a0..e1ec4eef22 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CommentLibraryPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CommentLibraryPage.kt @@ -22,9 +22,9 @@ import com.instructure.espresso.RecyclerViewItemCountGreaterThanAssertion import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onViewWithContentDescription -import com.instructure.espresso.page.onViewWithText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onViewWithContentDescription +import com.instructure.espresso.pages.onViewWithText import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CourseBrowserPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CourseBrowserPage.kt index 89d6564c8f..fbe682b6f6 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CourseBrowserPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CourseBrowserPage.kt @@ -31,12 +31,12 @@ import com.instructure.espresso.TextViewColorAssertion import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeDown import com.instructure.espresso.waitForCheck diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CourseSettingsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CourseSettingsPage.kt index b01492d45b..276221a54d 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CourseSettingsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/CourseSettingsPage.kt @@ -23,9 +23,9 @@ import com.instructure.canvas.espresso.matchToolbarText import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertHasText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText import com.instructure.espresso.replaceText import com.instructure.teacher.R import org.hamcrest.Matchers.`is` diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DashboardPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DashboardPage.kt index 48bb2b3d0f..11d3223605 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DashboardPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DashboardPage.kt @@ -32,15 +32,15 @@ import com.instructure.espresso.assertContainsText import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.replaceText import com.instructure.espresso.waitForCheck import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DiscussionsDetailsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DiscussionsDetailsPage.kt index 438bd51400..f67e473cbe 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DiscussionsDetailsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DiscussionsDetailsPage.kt @@ -25,12 +25,12 @@ import androidx.test.espresso.web.webdriver.DriverAtoms.webClick import androidx.test.espresso.web.webdriver.Locator import com.instructure.espresso.ModuleItemInteractions import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.waitForWebElement import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DiscussionsListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DiscussionsListPage.kt index dee91ab3f9..a09eef9224 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DiscussionsListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/DiscussionsListPage.kt @@ -26,16 +26,16 @@ import com.instructure.espresso.RecyclerViewItemCountAssertion import com.instructure.espresso.Searchable import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.swipeDown import com.instructure.espresso.waitForCheck import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditAnnouncementDetailsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditAnnouncementDetailsPage.kt index 9415744a68..2c5f370f3b 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditAnnouncementDetailsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditAnnouncementDetailsPage.kt @@ -18,9 +18,9 @@ package com.instructure.teacher.ui.pages import androidx.test.espresso.Espresso import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withId import com.instructure.espresso.replaceText import com.instructure.espresso.scrollTo import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditAssignmentDetailsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditAssignmentDetailsPage.kt index 68f3fca888..e87761e565 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditAssignmentDetailsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditAssignmentDetailsPage.kt @@ -31,17 +31,17 @@ import com.instructure.espresso.OnViewWithId import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertHasText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.scrollTo -import com.instructure.espresso.page.waitForViewWithClassName -import com.instructure.espresso.page.waitForViewWithContentDescription -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.waitScrollClick -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.scrollTo +import com.instructure.espresso.pages.waitForViewWithClassName +import com.instructure.espresso.pages.waitForViewWithContentDescription +import com.instructure.espresso.pages.waitForViewWithId +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.waitScrollClick +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.replaceText import com.instructure.espresso.scrollTo import com.instructure.teacher.R @@ -51,7 +51,8 @@ import org.hamcrest.CoreMatchers.allOf import org.hamcrest.Matchers import java.text.DecimalFormat import java.text.SimpleDateFormat -import java.util.* +import java.util.Calendar +import java.util.Locale /** * Represents the Edit Assignment Details page. diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditDashboardPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditDashboardPage.kt index 8f76e47073..e8b83d4a99 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditDashboardPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditDashboardPage.kt @@ -22,8 +22,17 @@ import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.hasSibling import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import com.instructure.canvasapi2.models.Course -import com.instructure.espresso.* -import com.instructure.espresso.page.* +import com.instructure.espresso.RecyclerViewItemCountAssertion +import com.instructure.espresso.WaitForViewWithId +import com.instructure.espresso.WaitForViewWithText +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.click +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditDiscussionsDetailsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditDiscussionsDetailsPage.kt index e89ad6cc21..de7eed37ed 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditDiscussionsDetailsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditDiscussionsDetailsPage.kt @@ -19,9 +19,9 @@ package com.instructure.teacher.ui.pages import androidx.test.espresso.Espresso import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withId import com.instructure.espresso.replaceText import com.instructure.espresso.scrollTo import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditPageDetailsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditPageDetailsPage.kt index 6f89f22fd8..4582e5d99d 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditPageDetailsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditPageDetailsPage.kt @@ -15,8 +15,8 @@ import com.instructure.espresso.ModuleItemInteractions import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.click import com.instructure.espresso.extractInnerTextById -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView import com.instructure.espresso.replaceText import com.instructure.espresso.scrollTo import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditProfileSettingsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditProfileSettingsPage.kt index 2176737592..9312c6574a 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditProfileSettingsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditProfileSettingsPage.kt @@ -19,9 +19,9 @@ package com.instructure.teacher.ui.pages import com.instructure.espresso.OnViewWithId import com.instructure.espresso.clearText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withId import com.instructure.espresso.typeText import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditQuizDetailsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditQuizDetailsPage.kt index eb377c3fbe..cb2e95e36b 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditQuizDetailsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditQuizDetailsPage.kt @@ -35,17 +35,17 @@ import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertHasText import com.instructure.espresso.assertVisible import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithContentDescription -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithClassName -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.waitScrollClick -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithContentDescription +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithClassName +import com.instructure.espresso.pages.waitForViewWithId +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.waitScrollClick +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.randomString import com.instructure.espresso.replaceText import com.instructure.espresso.scrollTo @@ -54,7 +54,8 @@ import com.instructure.teacher.view.AssignmentOverrideView import org.hamcrest.CoreMatchers.allOf import org.hamcrest.Matchers import java.text.SimpleDateFormat -import java.util.* +import java.util.Calendar +import java.util.Locale /** * The `EditQuizDetailsPage` class represents a page for editing quiz details. diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditSyllabusPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditSyllabusPage.kt index 0723ba0e80..d47bd7ccb5 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditSyllabusPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/EditSyllabusPage.kt @@ -25,9 +25,9 @@ import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.WaitForViewWithText import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withId import com.instructure.espresso.scrollTo import com.instructure.teacher.R import com.instructure.teacher.ui.utils.TypeInRCETextEditor diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/FileListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/FileListPage.kt index 2605294f93..bee5848f1d 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/FileListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/FileListPage.kt @@ -22,7 +22,11 @@ import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.swipeDown import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.assertion.ViewAssertions.doesNotExist -import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.hasChildCount +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast +import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvas.espresso.scrollRecyclerView @@ -32,12 +36,12 @@ import com.instructure.espresso.Searchable import com.instructure.espresso.assertDisplayed import com.instructure.espresso.clearText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId import com.instructure.espresso.scrollTo import com.instructure.espresso.typeText import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/HelpPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/HelpPage.kt index 8e1ac9aff4..0482601726 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/HelpPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/HelpPage.kt @@ -30,8 +30,8 @@ import com.instructure.espresso.OnViewWithText import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click import com.instructure.espresso.matchers.WaitForViewMatcher.waitForView -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.plus +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.plus import com.instructure.espresso.scrollTo import com.instructure.espresso.typeText import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/InboxMessagePage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/InboxMessagePage.kt index 25b70bc1ab..4ad41fde46 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/InboxMessagePage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/InboxMessagePage.kt @@ -33,11 +33,11 @@ import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertGone import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.teacher.R import org.hamcrest.CoreMatchers.allOf import org.hamcrest.Matchers diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LeftSideNavigationDrawerPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LeftSideNavigationDrawerPage.kt index 89bcbc6e8e..4595cad89a 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LeftSideNavigationDrawerPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LeftSideNavigationDrawerPage.kt @@ -14,10 +14,10 @@ import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertContainsText import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText import com.instructure.espresso.scrollTo import com.instructure.teacher.R import org.hamcrest.CoreMatchers diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LegalPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LegalPage.kt index af9a2c6509..7af0ea33e9 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LegalPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LegalPage.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.ui.pages import com.instructure.espresso.OnViewWithId import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LoginFindSchoolPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LoginFindSchoolPage.kt deleted file mode 100644 index f8f1d185e3..0000000000 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LoginFindSchoolPage.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.instructure.teacher.ui.pages - -import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.replaceText -import com.instructure.teacher.R - -/** - * Represents the Login Find School Page. - * - * This page extends the BasePage class and provides functionality for interacting with the login - * find school page. It contains various view elements such as toolbar, "What's your school name" - * text view, dividers, domain input edit text, find school recycler view, and toolbar next menu button. - */ -@Suppress("unused") -class LoginFindSchoolPage: BasePage() { - - private val toolbar by OnViewWithId(R.id.toolbar) - private val whatsYourSchoolNameTextView by OnViewWithId(R.id.whatsYourSchoolName) - private val topDivider by OnViewWithId(R.id.topDivider) - private val bottomDivider by OnViewWithId(R.id.bottomDivider) - private val domainInputEditText by OnViewWithId(R.id.domainInput) - private val findSchoolRecyclerView by OnViewWithId(R.id.findSchoolRecyclerView) - private val toolbarNextMenuButton by OnViewWithId(R.id.next) - - /** - * Clicks the toolbar next menu item. - */ - fun clickToolbarNextMenuItem() { - toolbarNextMenuButton.click() - } - - /** - * Enters the domain into the domain input edit text. - * - * @param domain The domain to enter. - */ - fun enterDomain(domain: String) { - domainInputEditText.replaceText(domain) - } -} - diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LoginSignInPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LoginSignInPage.kt deleted file mode 100644 index 1324380c18..0000000000 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/LoginSignInPage.kt +++ /dev/null @@ -1,165 +0,0 @@ -package com.instructure.teacher.ui.pages - -import androidx.test.espresso.web.assertion.WebViewAssertions -import androidx.test.espresso.web.sugar.Web -import androidx.test.espresso.web.sugar.Web.onWebView -import androidx.test.espresso.web.webdriver.DriverAtoms -import androidx.test.espresso.web.webdriver.DriverAtoms.clearElement -import androidx.test.espresso.web.webdriver.DriverAtoms.findElement -import androidx.test.espresso.web.webdriver.DriverAtoms.webClick -import androidx.test.espresso.web.webdriver.DriverAtoms.webKeys -import androidx.test.espresso.web.webdriver.Locator -import com.instructure.dataseeding.model.CanvasUserApiModel -import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.teacher.R -import org.hamcrest.CoreMatchers - -/** - * Represents the Login Sign-In Page. - * - * This page extends the BasePage class and provides functionality for interacting with the login - * sign-in page. It contains various view elements and helper methods for locating and interacting - * with UI elements on the page. - */ -@Suppress("unused") -class LoginSignInPage : BasePage() { - - private val EMAIL_FIELD_CSS = "input[name=\"pseudonym_session[unique_id]\"]" - private val PASSWORD_FIELD_CSS = "input[name=\"pseudonym_session[password]\"]" - private val LOGIN_BUTTON_CSS = "button[type=\"submit\"]" - private val FORGOT_PASSWORD_BUTTON_CSS = "a[class=\"forgot-password flip-to-back\"]" - private val AUTHORIZE_BUTTON_CSS = "button[type=\"submit\"]" - private val LOGIN_ERROR_MESSAGE_HOLDER_CSS = "div[class='error']" - - private val signInRoot by OnViewWithId(R.id.signInRoot, autoAssert = false) - private val toolbar by OnViewWithId(R.id.toolbar, autoAssert = false) - - //region UI Element Locator Methods - - private fun emailField(): Web.WebInteraction<*> { - return onWebView().withElement(findElement(Locator.CSS_SELECTOR, EMAIL_FIELD_CSS)) - } - - private fun passwordField(): Web.WebInteraction<*> { - return onWebView().withElement(findElement(Locator.CSS_SELECTOR, PASSWORD_FIELD_CSS)) - } - - private fun loginButton(): Web.WebInteraction<*> { - return onWebView().withElement(findElement(Locator.CSS_SELECTOR, LOGIN_BUTTON_CSS)) - } - - private fun forgotPasswordButton(): Web.WebInteraction<*> { - return onWebView().withElement(findElement(Locator.CSS_SELECTOR, FORGOT_PASSWORD_BUTTON_CSS)) - } - - private fun authorizeButton(): Web.WebInteraction<*> { - return onWebView().withElement(findElement(Locator.CSS_SELECTOR, AUTHORIZE_BUTTON_CSS)) - } - - private fun loginErrorMessageHolder(): Web.WebInteraction<*> { - return onWebView().withElement(findElement(Locator.CSS_SELECTOR, LOGIN_ERROR_MESSAGE_HOLDER_CSS)) - } - - //endregion - - //region Assertion Helpers - - /** - * Asserts the presence of page objects on the Sign-In page. - * - * @param duration The duration to wait for the assertion. - */ - override fun assertPageObjects(duration: Long) { - signInRoot.assertDisplayed() - toolbar.assertDisplayed() - - emailField() - passwordField() - loginButton() - forgotPasswordButton() - } - - //endregion - - //region UI Action Helpers - - /** - * Enters the email into the email field. - * - * @param email The email to enter. - */ - fun enterEmail(email: String) { - emailField().perform(clearElement()) - emailField().perform(webKeys(email)) - } - - /** - * Enters the password into the password field. - * - * @param password The password to enter. - */ - fun enterPassword(password: String) { - passwordField().perform(clearElement()) - passwordField().perform(webKeys(password)) - } - - /** - * Clicks the login button. - */ - fun clickLoginButton() { - loginButton().perform(webClick()) - } - - /** - * Clicks the forgot password button. - */ - fun clickForgotPasswordButton() { - forgotPasswordButton().perform(webClick()) - } - - /** - * Asserts the login error message. - * - * @param errorMessage The expected error message. - */ - fun assertLoginErrorMessage(errorMessage: String) { - loginErrorMessageHolder().check( - WebViewAssertions.webMatches( - DriverAtoms.getText(), - CoreMatchers.containsString(errorMessage) - ) - ) - } - - /** - * Logs in as the specified teacher. - * - * @param teacher The teacher to log in as. - */ - fun loginAs(teacher: CanvasUserApiModel) { - loginAs(teacher.loginId, teacher.password) - } - - /** - * Logs in with the specified login ID and password. - * - * @param loginId The login ID to enter. - * @param password The password to enter. - */ - fun loginAs(loginId: String, password: String) { - enterEmail(loginId) - enterPassword(password) - clickLoginButton() - - // Apparently not necessary when running on mobileqa.beta.instructure.com -// authorizeButton().repeatedlyUntilNot(action = webClick(), -// desiredStateMatcher = ::authorizeButton, -// maxAttempts = 20) - } - - //endregion -} - - diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ModulesPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ModulesPage.kt index 8b1cd6c598..7cfd3e7777 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ModulesPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ModulesPage.kt @@ -10,14 +10,14 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasContentDescription import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withDescendant -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withDescendant +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeDown import com.instructure.espresso.waitForCheck diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/NavDrawerPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/NavDrawerPage.kt index f4159fe6c8..89d6f2bc08 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/NavDrawerPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/NavDrawerPage.kt @@ -4,7 +4,7 @@ import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.canvasapi2.models.User import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/NotATeacherPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/NotATeacherPage.kt index d1ce0395c7..1bf3d16955 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/NotATeacherPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/NotATeacherPage.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.ui.pages import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PageListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PageListPage.kt index a42d4c9639..94c5efeba4 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PageListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PageListPage.kt @@ -26,11 +26,11 @@ import com.instructure.espresso.RecyclerViewItemCountAssertion import com.instructure.espresso.Searchable import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.waitForCheck import com.instructure.teacher.R import org.hamcrest.Matcher diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PeopleListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PeopleListPage.kt index bdb4cef085..e6b76740be 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PeopleListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PeopleListPage.kt @@ -28,15 +28,15 @@ import com.instructure.espresso.Searchable import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.teacher.R import org.hamcrest.CoreMatchers.allOf import org.hamcrest.Matcher diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PersonContextPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PersonContextPage.kt index 5e0061946d..61aeee55cf 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PersonContextPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PersonContextPage.kt @@ -24,12 +24,12 @@ import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertContainsText import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasText -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.teacher.R import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.not diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PostSettingsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PostSettingsPage.kt index 57f4030342..5b1d04dc92 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PostSettingsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PostSettingsPage.kt @@ -19,12 +19,12 @@ package com.instructure.teacher.ui.pages import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ProfileSettingsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ProfileSettingsPage.kt index 5c9e51b82b..2f68199ad7 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ProfileSettingsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ProfileSettingsPage.kt @@ -20,10 +20,10 @@ import androidx.test.espresso.assertion.ViewAssertions.matches import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertContainsText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ProgressPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ProgressPage.kt index 252f377e50..7bf4f7401d 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ProgressPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/ProgressPage.kt @@ -25,8 +25,8 @@ import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.ComposeTestRule import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource @OptIn(ExperimentalTestApi::class) class ProgressPage(private val composeTestRule: ComposeTestRule) : BasePage() { diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PushNotificationsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PushNotificationsPage.kt index 520b35e396..ac580975d3 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PushNotificationsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/PushNotificationsPage.kt @@ -19,13 +19,13 @@ package com.instructure.teacher.ui.pages import androidx.test.espresso.matcher.ViewMatchers import com.instructure.espresso.WaitForViewWithText import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeUp import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizDetailsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizDetailsPage.kt index 7f683cdb4c..b63e97be2f 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizDetailsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizDetailsPage.kt @@ -31,11 +31,11 @@ import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.assertNotHasText import com.instructure.espresso.assertVisible import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.scrollTo -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.scrollTo +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withId import com.instructure.espresso.swipeDown import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizListPage.kt index 5898120932..be051b4c20 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizListPage.kt @@ -24,13 +24,13 @@ import com.instructure.espresso.Searchable import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.swipeDown import com.instructure.espresso.waitForCheck import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizSubmissionListPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizSubmissionListPage.kt index 27363d9752..8d818d642d 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizSubmissionListPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/QuizSubmissionListPage.kt @@ -28,14 +28,14 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertGone import com.instructure.espresso.assertHasText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withText import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/RemoteConfigSettingsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/RemoteConfigSettingsPage.kt index 284274d18e..cfc01c25df 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/RemoteConfigSettingsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/RemoteConfigSettingsPage.kt @@ -26,7 +26,7 @@ import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvas.espresso.scrollRecyclerView import com.instructure.canvasapi2.utils.RemoteConfigParam import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.pandautils.R import org.hamcrest.Matcher import org.hamcrest.Matchers diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SettingsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SettingsPage.kt deleted file mode 100644 index fe53e7e9c8..0000000000 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SettingsPage.kt +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2019 - present Instructure, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.instructure.teacher.ui.pages - -import androidx.test.espresso.Espresso -import androidx.test.espresso.assertion.ViewAssertions -import androidx.test.espresso.matcher.ViewMatchers -import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.TextViewColorAssertion -import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText -import com.instructure.espresso.scrollTo -import com.instructure.teacher.R - -/** - * Represents the Settings page. - * - * This page provides functionality for interacting with the elements on the Settings page. It contains methods - * for opening various settings pages such as profile settings, push notifications, rate app dialog, legal page, about page, - * feature flags page, and remote config parameters page. It also includes methods for asserting the display of a - * five-star rating, opening the app theme settings, selecting an app theme, and asserting the text color of the app theme title - * and status. This page extends the BasePage class. - */ -class SettingsPage : BasePage(R.id.settingsPage) { - private val toolbar by OnViewWithId(R.id.toolbar) - private val profileSettingLabel by OnViewWithId(R.id.profileButton) - private val pushNotificationsLabel by OnViewWithId(R.id.notificationPreferenesButton) - private val rateAppLabel by OnViewWithId(R.id.rateButton) - private val legalLabel by OnViewWithId(R.id.legalButton) - private val aboutLabel by OnViewWithId(R.id.aboutButton) - private val featureFlagLabel by OnViewWithId(R.id.featureFlagButton) - private val remoteConfigLabel by OnViewWithId(R.id.remoteConfigButton) - private val appThemeTitle by OnViewWithId(R.id.appThemeTitle) - private val appThemeStatus by OnViewWithId(R.id.appThemeStatus) - - /** - * Opens the profile settings page. - */ - fun openProfileSettingsPage() { - profileSettingLabel.scrollTo().click() - } - - /** - * Opens the push notifications page. - */ - fun openPushNotificationsPage() { - pushNotificationsLabel.scrollTo().click() - } - - /** - * Opens the rate app dialog. - */ - fun openRateAppDialog() { - rateAppLabel.scrollTo().click() - } - - /** - * Opens the legal page. - */ - fun openLegalPage() { - legalLabel.scrollTo().click() - } - - /** - * Opens the about page. - */ - fun openAboutPage() { - aboutLabel.scrollTo().click() - } - - /** - * Opens the feature flags page. - */ - fun openFeatureFlagsPage() { - featureFlagLabel.scrollTo().click() - } - - /** - * Opens the remote config parameters page. - */ - fun openRemoteConfigParamsPage() { - remoteConfigLabel.scrollTo().click() - } - - /** - * Asserts the display of a five-star rating. - */ - fun assertFiveStarRatingDisplayed() { - for (i in 1 until 6) { - Espresso.onView(ViewMatchers.withId(R.id.star + i)) - .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) - } - } - - /** - * Opens the app theme settings. - */ - fun openAppThemeSettings() { - appThemeTitle.scrollTo().click() - } - - /** - * Selects the specified app theme. - * - * @param appTheme The app theme to select. - */ - fun selectAppTheme(appTheme: String) { - onView(withText(appTheme) + withParent(R.id.select_dialog_listview)).click() - } - - /** - * Asserts the text color of the app theme title. - * - * @param expectedTextColor The expected text color of the app theme title. - */ - fun assertAppThemeTitleTextColor(expectedTextColor: String) { - appThemeTitle.check(TextViewColorAssertion(expectedTextColor)) - } - - /** - * Asserts the text color of the app theme status. - * - * @param expectedTextColor The expected text color of the app theme status. - */ - fun assertAppThemeStatusTextColor(expectedTextColor: String) { - appThemeStatus.check(TextViewColorAssertion(expectedTextColor)) - } -} diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderCommentsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderCommentsPage.kt index 865e2b82e5..22b4e30842 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderCommentsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderCommentsPage.kt @@ -19,7 +19,6 @@ import androidx.test.espresso.Espresso import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility -import androidx.test.espresso.matcher.ViewMatchers.withParent import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvasapi2.models.Attachment import com.instructure.espresso.OnViewWithId @@ -29,17 +28,17 @@ import com.instructure.espresso.assertHasText import com.instructure.espresso.assertVisible import com.instructure.espresso.clearText import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.callOnClick -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withParent -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.callOnClick +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.espresso.scrollTo import com.instructure.espresso.typeText import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderFilesPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderFilesPage.kt index 328f1017c3..f674138f6b 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderFilesPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderFilesPage.kt @@ -17,7 +17,11 @@ package com.instructure.teacher.ui.pages import androidx.test.espresso.Espresso.onView import androidx.test.espresso.assertion.ViewAssertions -import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.Visibility +import androidx.test.espresso.matcher.ViewMatchers.hasDescendant +import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.canvasapi2.models.Attachment import com.instructure.espresso.OnViewWithId import com.instructure.espresso.RecyclerViewItemCountAssertion @@ -25,7 +29,7 @@ import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click import com.instructure.espresso.matchers.RecyclerViewMatcher -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.teacher.R import org.hamcrest.Matchers diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderGradePage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderGradePage.kt index 2547b16f03..313c0003ac 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderGradePage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderGradePage.kt @@ -28,13 +28,13 @@ import com.instructure.espresso.assertGone import com.instructure.espresso.assertHasText import com.instructure.espresso.assertVisible import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.waitForView -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.replaceText import com.instructure.teacher.R import org.hamcrest.Matchers diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderPage.kt index cca38ab1f5..5693dc763e 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderPage.kt @@ -36,17 +36,17 @@ import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasText import com.instructure.espresso.assertVisible import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.getStringFromResource -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.waitForViewWithText -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText import com.instructure.espresso.pageToItem +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.getStringFromResource +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForViewWithId +import com.instructure.espresso.pages.waitForViewWithText +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.swipeToTop import com.instructure.teacher.R import org.hamcrest.Matchers diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderQuizSubmissionPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderQuizSubmissionPage.kt index 640dad24e1..f216d99a19 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderQuizSubmissionPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SpeedGraderQuizSubmissionPage.kt @@ -21,9 +21,9 @@ import androidx.test.espresso.web.webdriver.Locator import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertVisible import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.scrollTo -import com.instructure.espresso.page.waitForViewWithText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.scrollTo +import com.instructure.espresso.pages.waitForViewWithText import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/StudentContextPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/StudentContextPage.kt index 6229683b7a..74e955685d 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/StudentContextPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/StudentContextPage.kt @@ -18,8 +18,17 @@ package com.instructure.teacher.ui.pages import com.instructure.dataseeding.model.CanvasUserApiModel -import com.instructure.espresso.* -import com.instructure.espresso.page.* +import com.instructure.espresso.WaitForViewWithId +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.assertHasText +import com.instructure.espresso.click +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.waitForView +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText +import com.instructure.espresso.scrollTo import com.instructure.teacher.R /** diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SyllabusPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SyllabusPage.kt index df93e38cf4..534a49bc68 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SyllabusPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/SyllabusPage.kt @@ -27,7 +27,7 @@ import com.instructure.canvas.espresso.checkToastText import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvas.espresso.scrollRecyclerView import com.instructure.espresso.* -import com.instructure.espresso.page.* +import com.instructure.espresso.pages.* import com.instructure.teacher.R import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.comparesEqualTo diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/TodoPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/TodoPage.kt index 2dca2c710c..35dde04dd6 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/TodoPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/TodoPage.kt @@ -19,11 +19,11 @@ package com.instructure.teacher.ui.pages import androidx.test.espresso.matcher.ViewMatchers.hasSibling import com.instructure.espresso.RecyclerViewItemCountAssertion import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.plus -import com.instructure.espresso.page.withId -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.plus +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withText import com.instructure.espresso.swipeDown import com.instructure.espresso.waitForCheck import com.instructure.teacher.R diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/UpdateFilePermissionsPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/UpdateFilePermissionsPage.kt index e3c9f2d060..f0238f1878 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/UpdateFilePermissionsPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/UpdateFilePermissionsPage.kt @@ -19,9 +19,7 @@ package com.instructure.teacher.ui.pages import android.widget.DatePicker -import android.widget.NumberPicker import android.widget.TimePicker -import androidx.databinding.adapters.TextViewBindingAdapter.setText import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.contrib.PickerActions import androidx.test.espresso.matcher.ViewMatchers.withClassName @@ -33,18 +31,14 @@ import com.instructure.espresso.assertEnabled import com.instructure.espresso.assertHasText import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click -import com.instructure.espresso.getDateInCanvasFormat -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.onViewWithId -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.waitForViewWithClassName -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.withId -import com.instructure.espresso.replaceText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.onViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.waitForViewWithClassName +import com.instructure.espresso.pages.waitForViewWithId import com.instructure.espresso.scrollTo import com.instructure.espresso.swipeUp -import com.instructure.espresso.typeText import com.instructure.teacher.R import org.hamcrest.Matchers import java.text.SimpleDateFormat @@ -129,7 +123,7 @@ class UpdateFilePermissionsPage : BasePage() { } fun assertUnlockDate(unlockDate: Date) { - val dateString = SimpleDateFormat("MMM d, YYYY").format(unlockDate) + val dateString = SimpleDateFormat("MMM d, yyyy").format(unlockDate) val timeString = SimpleDateFormat("h:mm a").format(unlockDate) waitForViewWithId(R.id.availableFromDate).scrollTo().assertDisplayed() @@ -138,7 +132,7 @@ class UpdateFilePermissionsPage : BasePage() { } fun assertLockDate(lockDate: Date) { - val dateString = SimpleDateFormat("MMM d, YYYY").format(lockDate) + val dateString = SimpleDateFormat("MMM d, yyyy").format(lockDate) val timeString = SimpleDateFormat("h:mm a").format(lockDate) waitForViewWithId(R.id.availableUntilDate).scrollTo().assertDisplayed() diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/WebViewLoginPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/WebViewLoginPage.kt index 8559af1316..f7af752415 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/WebViewLoginPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/pages/WebViewLoginPage.kt @@ -23,7 +23,7 @@ import androidx.test.espresso.web.webdriver.DriverAtoms.webClick import androidx.test.espresso.web.webdriver.DriverAtoms.webKeys import androidx.test.espresso.web.webdriver.Locator import com.instructure.dataseeding.model.CanvasUserApiModel -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage /** * Represents the WebView Login Page. diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/ModuleListRenderTest.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/ModuleListRenderTest.kt index 31bf453bbf..38da3f97f7 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/ModuleListRenderTest.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/ModuleListRenderTest.kt @@ -26,8 +26,8 @@ import com.instructure.espresso.assertCompletelyDisplayed import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertHasText import com.instructure.espresso.assertNotDisplayed -import com.instructure.espresso.page.onViewWithText -import com.instructure.espresso.page.waitForViewWithId +import com.instructure.espresso.pages.onViewWithText +import com.instructure.espresso.pages.waitForViewWithId import com.instructure.teacher.R import com.instructure.teacher.features.modules.list.ui.ModuleListFragment import com.instructure.teacher.features.modules.list.ui.ModuleListItemData diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/EditSyllabusRenderPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/EditSyllabusRenderPage.kt index 1936839aaa..266242d64b 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/EditSyllabusRenderPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/EditSyllabusRenderPage.kt @@ -26,7 +26,7 @@ import androidx.test.espresso.web.webdriver.Locator import com.instructure.espresso.OnViewWithId import com.instructure.espresso.WaitForViewWithId import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.espresso.scrollTo import com.instructure.teacher.R import org.hamcrest.Matchers.containsString diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/ModuleListRenderPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/ModuleListRenderPage.kt index 7fa38d027c..196d3eab66 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/ModuleListRenderPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/ModuleListRenderPage.kt @@ -24,10 +24,10 @@ import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import com.instructure.espresso.OnViewWithId import com.instructure.espresso.RecyclerViewItemCountAssertion import com.instructure.espresso.assertDisplayed -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.withAncestor -import com.instructure.espresso.page.withText +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withText import com.instructure.teacher.R import com.instructure.teacher.ui.utils.SwipeRefreshLayoutMatchers import com.instructure.teacher.ui.utils.ViewSizeMatcher diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/PostGradeRenderPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/PostGradeRenderPage.kt index 79394d11fd..a955b5e543 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/PostGradeRenderPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/PostGradeRenderPage.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.ui.renderTests.pages import com.instructure.espresso.OnViewWithId import com.instructure.espresso.assertDisplayed import com.instructure.espresso.assertNotDisplayed -import com.instructure.espresso.page.BasePage +import com.instructure.espresso.pages.BasePage import com.instructure.teacher.R class PostGradeRenderPage : BasePage(R.id.postGradePage) { diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/SyllabusRenderPage.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/SyllabusRenderPage.kt index 8f316fd08e..4e9283308d 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/SyllabusRenderPage.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/renderTests/pages/SyllabusRenderPage.kt @@ -17,8 +17,16 @@ package com.instructure.teacher.ui.renderTests.pages import androidx.test.espresso.action.ViewActions -import com.instructure.espresso.* -import com.instructure.espresso.page.* +import com.instructure.espresso.OnViewWithId +import com.instructure.espresso.WaitForViewWithId +import com.instructure.espresso.assertDisplayed +import com.instructure.espresso.assertNotDisplayed +import com.instructure.espresso.click +import com.instructure.espresso.pages.onView +import com.instructure.espresso.pages.withAncestor +import com.instructure.espresso.pages.withId +import com.instructure.espresso.pages.withParent +import com.instructure.espresso.pages.withText import com.instructure.teacher.R import com.instructure.teacher.ui.pages.SyllabusPage import org.hamcrest.CoreMatchers diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/PageExtensions.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/PageExtensions.kt index 18077dc17c..67fd4adaa9 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/PageExtensions.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/PageExtensions.kt @@ -17,11 +17,9 @@ package com.instructure.teacher.ui.utils import androidx.test.espresso.action.ViewActions import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.espresso.page.waitForViewWithContentDescription -import com.instructure.espresso.page.waitForViewWithId -import com.instructure.espresso.page.withId +import com.instructure.espresso.pages.BasePage +import com.instructure.espresso.pages.waitForViewWithContentDescription +import com.instructure.espresso.pages.waitForViewWithId import com.instructure.teacher.R // Navigation Extensions diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/TeacherComposeTest.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/TeacherComposeTest.kt index e132120147..a8e76a5dc9 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/TeacherComposeTest.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/TeacherComposeTest.kt @@ -25,6 +25,7 @@ import com.instructure.canvas.espresso.common.pages.compose.CalendarFilterPage import com.instructure.canvas.espresso.common.pages.compose.CalendarScreenPage import com.instructure.canvas.espresso.common.pages.compose.CalendarToDoCreateUpdatePage import com.instructure.canvas.espresso.common.pages.compose.CalendarToDoDetailsPage +import com.instructure.canvas.espresso.common.pages.compose.SettingsPage import com.instructure.teacher.activities.LoginActivity import com.instructure.teacher.ui.pages.ProgressPage @@ -42,4 +43,5 @@ abstract class TeacherComposeTest : TeacherTest() { val calendarToDoDetailsPage = CalendarToDoDetailsPage(composeTestRule) val calendarFilterPage = CalendarFilterPage(composeTestRule) val progressPage = ProgressPage(composeTestRule) + val settingsPage = SettingsPage(composeTestRule) } \ No newline at end of file diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/TeacherTest.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/TeacherTest.kt index 5e9ed54ad6..cc699177a2 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/TeacherTest.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/utils/TeacherTest.kt @@ -28,6 +28,9 @@ import com.instructure.canvas.espresso.common.pages.InboxPage import com.instructure.espresso.InstructureActivityTestRule import com.instructure.espresso.ModuleItemInteractions import com.instructure.espresso.Searchable +import com.instructure.espresso.pages.common.LoginFindSchoolPage +import com.instructure.espresso.pages.common.LoginLandingPage +import com.instructure.espresso.pages.common.LoginSignInPage import com.instructure.teacher.BuildConfig import com.instructure.teacher.R import com.instructure.teacher.activities.LoginActivity @@ -59,9 +62,6 @@ import com.instructure.teacher.ui.pages.HelpPage import com.instructure.teacher.ui.pages.InboxMessagePage import com.instructure.teacher.ui.pages.LeftSideNavigationDrawerPage import com.instructure.teacher.ui.pages.LegalPage -import com.instructure.teacher.ui.pages.LoginFindSchoolPage -import com.instructure.teacher.ui.pages.LoginLandingPage -import com.instructure.teacher.ui.pages.LoginSignInPage import com.instructure.teacher.ui.pages.ModulesPage import com.instructure.teacher.ui.pages.NavDrawerPage import com.instructure.teacher.ui.pages.NotATeacherPage @@ -75,7 +75,6 @@ import com.instructure.teacher.ui.pages.QuizDetailsPage import com.instructure.teacher.ui.pages.QuizListPage import com.instructure.teacher.ui.pages.QuizSubmissionListPage import com.instructure.teacher.ui.pages.RemoteConfigSettingsPage -import com.instructure.teacher.ui.pages.SettingsPage import com.instructure.teacher.ui.pages.SpeedGraderCommentsPage import com.instructure.teacher.ui.pages.SpeedGraderFilesPage import com.instructure.teacher.ui.pages.SpeedGraderGradePage @@ -116,7 +115,6 @@ abstract class TeacherTest : CanvasTest() { val dashboardPage = DashboardPage() val leftSideNavigationDrawerPage = LeftSideNavigationDrawerPage() val editDashboardPage = EditDashboardPage() - val settingsPage = SettingsPage() val pushNotificationsPage = PushNotificationsPage() val legalPage = LegalPage() val helpPage = HelpPage() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListAdapter.kt b/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListAdapter.kt index 4268dcf33d..93df1bea42 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListAdapter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListAdapter.kt @@ -22,7 +22,7 @@ import android.view.ViewGroup import androidx.viewbinding.ViewBinding import com.instructure.canvasapi2.models.canvadocs.CanvaDocAnnotation import com.instructure.teacher.databinding.AdapterAnnotationCommentBinding -import instructure.androidblueprint.ListRecyclerAdapter +import com.instructure.pandautils.blueprint.ListRecyclerAdapter class AnnotationCommentListAdapter( context: Context, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListPresenter.kt index 72564f15fa..a0e890e099 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListPresenter.kt @@ -27,7 +27,7 @@ import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.canvasapi2.utils.weave.weave import com.instructure.teacher.view.* -import instructure.androidblueprint.ListPresenter +import com.instructure.pandautils.blueprint.ListPresenter import kotlinx.coroutines.Job import okhttp3.ResponseBody import org.greenrobot.eventbus.EventBus diff --git a/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListPresenterFactory.kt index 14d3baf971..994f69b3e0 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListPresenterFactory.kt @@ -19,7 +19,7 @@ package com.instructure.teacher.PSPDFKit.AnnotationComments import com.instructure.canvasapi2.models.ApiValues import com.instructure.canvasapi2.models.canvadocs.CanvaDocAnnotation import com.instructure.canvasapi2.models.DocSession -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class AnnotationCommentListPresenterFactory( val annotations: ArrayList, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListView.kt b/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListView.kt index 563b8b4fc9..0a67a5e801 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/PSPDFKit/AnnotationComments/AnnotationCommentListView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.PSPDFKit.AnnotationComments import com.instructure.canvasapi2.models.canvadocs.CanvaDocAnnotation -import instructure.androidblueprint.ListManager +import com.instructure.pandautils.blueprint.ListManager interface AnnotationCommentListView : ListManager { fun showSendingStatus() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/activities/BaseAppCompatActivity.kt b/apps/teacher/src/main/java/com/instructure/teacher/activities/BaseAppCompatActivity.kt index 17ed4cf8c3..70b3caecdb 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/activities/BaseAppCompatActivity.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/activities/BaseAppCompatActivity.kt @@ -18,7 +18,6 @@ package com.instructure.teacher.activities import android.content.Intent -import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import com.instructure.canvasapi2.models.StorageQuotaExceededError import com.instructure.pandautils.utils.* @@ -26,12 +25,13 @@ import com.instructure.pandautils.utils.RequestCodes.CAMERA_PIC_REQUEST import com.instructure.pandautils.utils.RequestCodes.PICK_FILE_FROM_DEVICE import com.instructure.pandautils.utils.RequestCodes.PICK_IMAGE_GALLERY import com.instructure.teacher.R +import com.instructure.pandautils.base.BaseCanvasActivity import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") -abstract class BaseAppCompatActivity : AppCompatActivity(), +abstract class BaseAppCompatActivity : BaseCanvasActivity(), ActivityCompat.OnRequestPermissionsResultCallback by PermissionReceiver() { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/activities/FeedbackActivity.kt b/apps/teacher/src/main/java/com/instructure/teacher/activities/FeedbackActivity.kt index 48585bf0fe..826f03ad68 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/activities/FeedbackActivity.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/activities/FeedbackActivity.kt @@ -7,7 +7,7 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.webkit.WebChromeClient -import androidx.appcompat.app.AppCompatActivity +import com.instructure.pandautils.base.BaseCanvasActivity import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.pandautils.analytics.SCREEN_VIEW_FEEDBACK import com.instructure.pandautils.analytics.ScreenView @@ -19,7 +19,7 @@ import com.instructure.teacher.databinding.ActivityFeedbackBinding import com.instructure.teacher.utils.setupBackButton @ScreenView(SCREEN_VIEW_FEEDBACK) -class FeedbackActivity : AppCompatActivity() { +class FeedbackActivity : BaseCanvasActivity() { private val binding by viewBinding(ActivityFeedbackBinding::inflate) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/activities/InitActivity.kt b/apps/teacher/src/main/java/com/instructure/teacher/activities/InitActivity.kt index 04db1e8df1..cf830c3883 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/activities/InitActivity.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/activities/InitActivity.kt @@ -51,7 +51,6 @@ import com.instructure.canvasapi2.models.CourseNickname import com.instructure.canvasapi2.models.LaunchDefinition import com.instructure.canvasapi2.models.User import com.instructure.canvasapi2.utils.ApiPrefs -import com.instructure.canvasapi2.utils.LocaleUtils import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.MasqueradeHelper import com.instructure.canvasapi2.utils.Pronouns @@ -68,12 +67,16 @@ import com.instructure.loginapi.login.dialog.MasqueradingDialog import com.instructure.loginapi.login.tasks.LogoutTask import com.instructure.pandautils.activities.BasePresenterActivity import com.instructure.pandautils.binding.viewBinding +import com.instructure.pandautils.utils.LocaleUtils +import com.instructure.pandautils.dialogs.ColorPickerDialog import com.instructure.pandautils.dialogs.EditCourseNicknameDialog import com.instructure.pandautils.dialogs.RatingDialog import com.instructure.pandautils.features.calendar.CalendarFragment import com.instructure.pandautils.features.help.HelpDialogFragment import com.instructure.pandautils.features.inbox.list.InboxFragment import com.instructure.pandautils.features.inbox.list.OnUnreadCountInvalidated +import com.instructure.pandautils.features.lti.LtiLaunchFragment +import com.instructure.pandautils.features.settings.SettingsFragment import com.instructure.pandautils.features.themeselector.ThemeSelectorBottomSheet import com.instructure.pandautils.interfaces.NavigationCallbacks import com.instructure.pandautils.models.PushNotification @@ -98,7 +101,6 @@ import com.instructure.teacher.BuildConfig import com.instructure.teacher.R import com.instructure.teacher.databinding.ActivityInitBinding import com.instructure.teacher.databinding.NavigationDrawerBinding -import com.instructure.pandautils.dialogs.ColorPickerDialog import com.instructure.teacher.events.CourseUpdatedEvent import com.instructure.teacher.events.ToDoListUpdatedEvent import com.instructure.teacher.factory.InitActivityPresenterFactory @@ -106,8 +108,6 @@ import com.instructure.teacher.fragments.CourseBrowserFragment import com.instructure.teacher.fragments.DashboardFragment import com.instructure.teacher.fragments.EmptyFragment import com.instructure.teacher.fragments.FileListFragment -import com.instructure.teacher.fragments.LtiLaunchFragment -import com.instructure.teacher.fragments.SettingsFragment import com.instructure.teacher.fragments.ToDoFragment import com.instructure.teacher.presenters.InitActivityPresenter import com.instructure.teacher.router.RouteMatcher @@ -398,13 +398,13 @@ class InitActivity : BasePresenterActivity(context, presenter) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/adapters/FileListAdapter.kt b/apps/teacher/src/main/java/com/instructure/teacher/adapters/FileListAdapter.kt index 46db32ef14..e6dfdc2b3c 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/adapters/FileListAdapter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/adapters/FileListAdapter.kt @@ -25,7 +25,7 @@ import com.instructure.teacher.databinding.AdapterFileFolderBinding import com.instructure.teacher.holders.FileFolderViewHolder import com.instructure.teacher.presenters.FileListPresenter import com.instructure.teacher.viewinterface.FileListView -import instructure.androidblueprint.SyncRecyclerAdapter +import com.instructure.pandautils.blueprint.SyncRecyclerAdapter class FileListAdapter( private val mContext: Context, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/adapters/GradeableStudentSubmissionAdapter.kt b/apps/teacher/src/main/java/com/instructure/teacher/adapters/GradeableStudentSubmissionAdapter.kt index 4b769b4225..c2bbfd28e7 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/adapters/GradeableStudentSubmissionAdapter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/adapters/GradeableStudentSubmissionAdapter.kt @@ -26,7 +26,7 @@ import com.instructure.teacher.databinding.AdapterGradeableStudentSubmissionBind import com.instructure.teacher.holders.GradeableStudentSubmissionViewHolder import com.instructure.teacher.features.assignment.submission.AssignmentSubmissionListPresenter import com.instructure.teacher.viewinterface.AssignmentSubmissionListView -import instructure.androidblueprint.SyncRecyclerAdapter +import com.instructure.pandautils.blueprint.SyncRecyclerAdapter class GradeableStudentSubmissionAdapter( private val mAssignment: Assignment, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/adapters/MessageAdapter.kt b/apps/teacher/src/main/java/com/instructure/teacher/adapters/MessageAdapter.kt index 4d8aa78c89..208561c1f4 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/adapters/MessageAdapter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/adapters/MessageAdapter.kt @@ -28,7 +28,7 @@ import com.instructure.teacher.holders.MessageHolder import com.instructure.teacher.interfaces.MessageAdapterCallback import com.instructure.teacher.presenters.MessageThreadPresenter import com.instructure.teacher.viewinterface.MessageThreadView -import instructure.androidblueprint.SyncRecyclerAdapter +import com.instructure.pandautils.blueprint.SyncRecyclerAdapter open class MessageAdapter( context: Context, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/adapters/PageListAdapter.kt b/apps/teacher/src/main/java/com/instructure/teacher/adapters/PageListAdapter.kt index 34248ab1ae..af33989173 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/adapters/PageListAdapter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/adapters/PageListAdapter.kt @@ -26,7 +26,7 @@ import com.instructure.teacher.databinding.AdapterPageBinding import com.instructure.teacher.holders.PageViewHolder import com.instructure.teacher.presenters.PageListPresenter import com.instructure.teacher.viewinterface.PageListView -import instructure.androidblueprint.SyncRecyclerAdapter +import com.instructure.pandautils.blueprint.SyncRecyclerAdapter class PageListAdapter( context: Context, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/adapters/PeopleListRecyclerAdapter.kt b/apps/teacher/src/main/java/com/instructure/teacher/adapters/PeopleListRecyclerAdapter.kt index a104358685..e54621c8c6 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/adapters/PeopleListRecyclerAdapter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/adapters/PeopleListRecyclerAdapter.kt @@ -27,7 +27,7 @@ import com.instructure.teacher.holders.UserViewHolder import com.instructure.teacher.interfaces.AdapterToFragmentCallback import com.instructure.teacher.presenters.PeopleListPresenter import com.instructure.teacher.viewinterface.PeopleListView -import instructure.androidblueprint.SyncRecyclerAdapter +import com.instructure.pandautils.blueprint.SyncRecyclerAdapter class PeopleListRecyclerAdapter( context: Context, presenter: PeopleListPresenter, private val mCallback: AdapterToFragmentCallback diff --git a/apps/teacher/src/main/java/com/instructure/teacher/adapters/QuizListAdapter.kt b/apps/teacher/src/main/java/com/instructure/teacher/adapters/QuizListAdapter.kt index 9792531f6a..a8a21319cf 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/adapters/QuizListAdapter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/adapters/QuizListAdapter.kt @@ -29,7 +29,7 @@ import com.instructure.teacher.holders.QuizExpandableViewHolder import com.instructure.teacher.holders.QuizViewHolder import com.instructure.teacher.presenters.QuizListPresenter import com.instructure.teacher.viewinterface.QuizListView -import instructure.androidblueprint.SyncExpandableRecyclerAdapter +import com.instructure.pandautils.blueprint.SyncExpandableRecyclerAdapter class QuizListAdapter( context: Context, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/adapters/SpeedGraderCommentsAdapter.kt b/apps/teacher/src/main/java/com/instructure/teacher/adapters/SpeedGraderCommentsAdapter.kt index fe35ee12d9..fd4db301e6 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/adapters/SpeedGraderCommentsAdapter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/adapters/SpeedGraderCommentsAdapter.kt @@ -28,7 +28,7 @@ import com.instructure.teacher.holders.SpeedGraderCommentHolder import com.instructure.teacher.models.SubmissionCommentWrapper import com.instructure.teacher.presenters.SpeedGraderCommentsPresenter import com.instructure.teacher.viewinterface.SpeedGraderCommentsView -import instructure.androidblueprint.ListRecyclerAdapter +import com.instructure.pandautils.blueprint.ListRecyclerAdapter class SpeedGraderCommentsAdapter( context: Context, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/adapters/StudentContextFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/adapters/StudentContextFragment.kt index b0e6265cec..d25d3160ae 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/adapters/StudentContextFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/adapters/StudentContextFragment.kt @@ -66,7 +66,7 @@ import com.instructure.teacher.utils.setupBackButton import com.instructure.teacher.utils.setupBackButtonWithExpandCollapseAndBack import com.instructure.teacher.utils.updateToolbarExpandCollapseIcon import com.instructure.teacher.viewinterface.StudentContextView -import instructure.androidblueprint.PresenterFragment +import com.instructure.pandautils.blueprint.PresenterFragment import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode diff --git a/apps/teacher/src/main/java/com/instructure/teacher/adapters/ToDoAdapter.kt b/apps/teacher/src/main/java/com/instructure/teacher/adapters/ToDoAdapter.kt index 3f668b604a..166f28b9fa 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/adapters/ToDoAdapter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/adapters/ToDoAdapter.kt @@ -27,7 +27,7 @@ import com.instructure.teacher.holders.ToDoViewHolder import com.instructure.teacher.interfaces.AdapterToFragmentCallback import com.instructure.teacher.presenters.ToDoPresenter import com.instructure.teacher.viewinterface.ToDoView -import instructure.androidblueprint.SyncRecyclerAdapter +import com.instructure.pandautils.blueprint.SyncRecyclerAdapter class ToDoAdapter( context: Context, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/di/DiscussionModule.kt b/apps/teacher/src/main/java/com/instructure/teacher/di/DiscussionModule.kt index 7e8625c9cc..2523f28a94 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/di/DiscussionModule.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/di/DiscussionModule.kt @@ -1,7 +1,9 @@ package com.instructure.teacher.di import androidx.fragment.app.FragmentActivity +import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragmentBehavior import com.instructure.pandautils.features.discussion.router.DiscussionRouter +import com.instructure.teacher.features.discussion.TeacherDiscussionDetailsWebViewFragmentBehavior import com.instructure.teacher.features.discussion.routing.TeacherDiscussionRouter import dagger.Module import dagger.Provides @@ -16,4 +18,9 @@ class DiscussionModule { fun provideDiscussionRouter(activity: FragmentActivity): DiscussionRouter { return TeacherDiscussionRouter(activity) } -} \ No newline at end of file + + @Provides + fun provideDiscussionWebViewFragmentBehavior(activity: FragmentActivity): DiscussionDetailsWebViewFragmentBehavior { + return TeacherDiscussionDetailsWebViewFragmentBehavior(activity) + } +} diff --git a/apps/teacher/src/main/java/com/instructure/teacher/di/LtiLaunchModule.kt b/apps/teacher/src/main/java/com/instructure/teacher/di/LtiLaunchModule.kt new file mode 100644 index 0000000000..7adb798c0a --- /dev/null +++ b/apps/teacher/src/main/java/com/instructure/teacher/di/LtiLaunchModule.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.instructure.teacher.di + +import androidx.fragment.app.Fragment +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.pandautils.features.lti.LtiLaunchFragmentBehavior +import com.instructure.pandautils.utils.Const +import com.instructure.teacher.features.lti.TeacherLtiLaunchFragmentBehavior +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.FragmentComponent + +@Module +@InstallIn(FragmentComponent::class) +class LtiLaunchModule { + + @Provides + fun provideLtiLaunchFragmentBehavior(fragment: Fragment): LtiLaunchFragmentBehavior { + val canvasContext = fragment.arguments?.getParcelable(Const.CANVAS_CONTEXT) ?: CanvasContext.emptyUserContext() + return TeacherLtiLaunchFragmentBehavior(canvasContext) + } +} \ No newline at end of file diff --git a/apps/teacher/src/main/java/com/instructure/teacher/di/SettingsModule.kt b/apps/teacher/src/main/java/com/instructure/teacher/di/SettingsModule.kt index caf1706bbf..839edfc27b 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/di/SettingsModule.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/di/SettingsModule.kt @@ -16,24 +16,35 @@ */ package com.instructure.teacher.di +import android.content.Context +import androidx.fragment.app.FragmentActivity import com.instructure.pandautils.features.settings.SettingsBehaviour import com.instructure.pandautils.features.settings.SettingsRouter +import com.instructure.teacher.features.settings.TeacherSettingsBehaviour +import com.instructure.teacher.features.settings.TeacherSettingsRouter import dagger.Module import dagger.Provides import dagger.hilt.InstallIn +import dagger.hilt.android.components.ActivityComponent +import dagger.hilt.android.components.FragmentComponent +import dagger.hilt.android.components.ViewModelComponent +import dagger.hilt.android.qualifiers.ActivityContext import dagger.hilt.components.SingletonComponent @Module -@InstallIn(SingletonComponent::class) -class SettingsModule { - +@InstallIn(FragmentComponent::class) +class SettingsRouterModule { @Provides - fun provideSettingsRouter(): SettingsRouter { - throw NotImplementedError("Not implemented") + fun provideSettingsRouter(activity: FragmentActivity): SettingsRouter { + return TeacherSettingsRouter(activity) } +} +@Module +@InstallIn(ViewModelComponent::class) +class SettingsModule { @Provides fun provideSettingsBehavior(): SettingsBehaviour { - throw NotImplementedError("Not implemented") + return TeacherSettingsBehaviour() } } \ No newline at end of file diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/ProfileSettingsFragmentPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/di/SmartSearchModule.kt similarity index 57% rename from apps/teacher/src/main/java/com/instructure/teacher/presenters/ProfileSettingsFragmentPresenter.kt rename to apps/teacher/src/main/java/com/instructure/teacher/di/SmartSearchModule.kt index c9f9af2a1e..10976d0dae 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/ProfileSettingsFragmentPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/di/SmartSearchModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 - present Instructure, Inc. + * Copyright (C) 2024 - present Instructure, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,17 +12,22 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * */ +package com.instructure.teacher.di -package com.instructure.teacher.presenters - - -import com.instructure.teacher.viewinterface.ProfileSettingsFragmentView -import instructure.androidblueprint.FragmentPresenter - -class ProfileSettingsFragmentPresenter : FragmentPresenter() { +import com.instructure.pandautils.features.smartsearch.SmartSearchRouter +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.FragmentComponent - override fun refresh(forceNetwork: Boolean) {} +@Module +@InstallIn(FragmentComponent::class) +class SmartSearchModule { - override fun loadData(forceNetwork: Boolean) {} -} + @Provides + fun provideSmartSearchRouter(): SmartSearchRouter { + throw NotImplementedError() + } +} \ No newline at end of file diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/ConfirmDeleteFileFolderDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/ConfirmDeleteFileFolderDialog.kt index 87dae46990..1f6c935213 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/ConfirmDeleteFileFolderDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/ConfirmDeleteFileFolderDialog.kt @@ -20,7 +20,7 @@ import android.app.Dialog import android.os.Bundle import androidx.fragment.app.FragmentManager import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import com.instructure.pandautils.analytics.SCREEN_VIEW_CONFIRM_DELETE_FILE_FOLDER import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.ThemePrefs @@ -30,7 +30,7 @@ import com.instructure.pandautils.utils.BooleanArg import com.instructure.pandautils.utils.dismissExisting @ScreenView(SCREEN_VIEW_CONFIRM_DELETE_FILE_FOLDER) -class ConfirmDeleteFileFolderDialog : AppCompatDialogFragment() { +class ConfirmDeleteFileFolderDialog : BaseCanvasAppCompatDialogFragment() { private var deleteCallback: (() -> Unit)? by BlindSerializableArg() private var isFile: Boolean by BooleanArg(false) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/ConfirmRemoveAssignmentOverrideDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/ConfirmRemoveAssignmentOverrideDialog.kt index 530e2b2b5c..b3ababf256 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/ConfirmRemoveAssignmentOverrideDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/ConfirmRemoveAssignmentOverrideDialog.kt @@ -19,7 +19,7 @@ import android.app.Dialog import android.os.Bundle import androidx.fragment.app.FragmentManager import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import com.instructure.pandautils.analytics.SCREEN_VIEW_CONFIRM_REMOVE_ASSIGNMENT_OVERRIDE import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.ThemePrefs @@ -28,7 +28,7 @@ import com.instructure.pandautils.utils.BlindSerializableArg import com.instructure.pandautils.utils.dismissExisting @ScreenView(SCREEN_VIEW_CONFIRM_REMOVE_ASSIGNMENT_OVERRIDE) -class ConfirmRemoveAssignmentOverrideDialog : AppCompatDialogFragment() { +class ConfirmRemoveAssignmentOverrideDialog : BaseCanvasAppCompatDialogFragment() { private var mListener: (() -> Unit)? by BlindSerializableArg() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/CreateFolderDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/CreateFolderDialog.kt index 170cc7eb2f..da23257986 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/CreateFolderDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/CreateFolderDialog.kt @@ -23,7 +23,7 @@ import android.view.View import android.view.WindowManager import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.appcompat.widget.AppCompatEditText import androidx.fragment.app.FragmentManager import com.instructure.pandautils.analytics.SCREEN_VIEW_CREATE_FOLDER @@ -35,7 +35,7 @@ import com.instructure.teacher.R import kotlin.properties.Delegates @ScreenView(SCREEN_VIEW_CREATE_FOLDER) -class CreateFolderDialog : AppCompatDialogFragment() { +class CreateFolderDialog : BaseCanvasAppCompatDialogFragment() { init { retainInstance = true } diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/CriterionLongDescriptionDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/CriterionLongDescriptionDialog.kt index ee063f2191..9fd6f68436 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/CriterionLongDescriptionDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/CriterionLongDescriptionDialog.kt @@ -23,7 +23,7 @@ import android.os.Bundle import android.webkit.WebChromeClient import android.webkit.WebView import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.DialogFragment +import com.instructure.pandautils.base.BaseCanvasDialogFragment import androidx.fragment.app.FragmentManager import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.pandautils.analytics.SCREEN_VIEW_CRITERION_LONG_DESCRIPTION @@ -38,7 +38,7 @@ import com.instructure.teacher.router.RouteMatcher import java.util.* @ScreenView(SCREEN_VIEW_CRITERION_LONG_DESCRIPTION) -class CriterionLongDescriptionDialog : DialogFragment() { +class CriterionLongDescriptionDialog : BaseCanvasDialogFragment() { var mDescription by StringArg() var mLongDescription by StringArg() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/CustomRubricRatingDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/CustomRubricRatingDialog.kt index 01f9019e76..ef9564aa59 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/CustomRubricRatingDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/CustomRubricRatingDialog.kt @@ -25,7 +25,7 @@ import android.view.WindowManager import android.widget.FrameLayout import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.appcompat.widget.AppCompatEditText import androidx.fragment.app.FragmentManager import com.instructure.canvasapi2.utils.NumberHelper @@ -38,7 +38,7 @@ import org.greenrobot.eventbus.EventBus import java.util.Locale @ScreenView(SCREEN_VIEW_CUSTOM_RUBRIC_RATING) -class CustomRubricRatingDialog : AppCompatDialogFragment() { +class CustomRubricRatingDialog : BaseCanvasAppCompatDialogFragment() { var mCriterionId by StringArg() var mStudentId by LongArg(-1L) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/CustomizeGradeDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/CustomizeGradeDialog.kt index 19bb3748fb..5003eeda45 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/CustomizeGradeDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/CustomizeGradeDialog.kt @@ -24,7 +24,7 @@ import android.view.inputmethod.EditorInfo import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.fragment.app.FragmentManager import com.instructure.canvasapi2.models.Assignment import com.instructure.pandautils.analytics.SCREEN_VIEW_CUSTOMIZE_GRADE @@ -36,7 +36,7 @@ import java.util.* import kotlin.properties.Delegates @ScreenView(SCREEN_VIEW_CUSTOMIZE_GRADE) -class CustomizeGradeDialog : AppCompatDialogFragment() { +class CustomizeGradeDialog : BaseCanvasAppCompatDialogFragment() { init { retainInstance = true diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/DiscussionsMoveToDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/DiscussionsMoveToDialog.kt index de5a204055..f43ab8098d 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/DiscussionsMoveToDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/DiscussionsMoveToDialog.kt @@ -26,7 +26,7 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.view.ContextThemeWrapper import androidx.appcompat.widget.AppCompatRadioButton import androidx.core.widget.CompoundButtonCompat -import androidx.fragment.app.DialogFragment +import com.instructure.pandautils.base.BaseCanvasDialogFragment import androidx.fragment.app.FragmentManager import com.instructure.canvasapi2.models.DiscussionTopicHeader import com.instructure.pandautils.analytics.SCREEN_VIEW_DISCUSSION_MOVE_TO @@ -41,7 +41,7 @@ import com.instructure.teacher.utils.getColorCompat import kotlin.properties.Delegates @ScreenView(SCREEN_VIEW_DISCUSSION_MOVE_TO) -class DiscussionsMoveToDialog : DialogFragment() { +class DiscussionsMoveToDialog : BaseCanvasDialogFragment() { init { retainInstance = true diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/EditCourseNameDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/EditCourseNameDialog.kt index 87f77ffcc5..d65a1d39b3 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/EditCourseNameDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/EditCourseNameDialog.kt @@ -25,7 +25,7 @@ import android.view.WindowManager import android.view.inputmethod.EditorInfo import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.appcompat.widget.AppCompatEditText import androidx.fragment.app.FragmentManager import com.instructure.canvasapi2.models.Course @@ -37,7 +37,7 @@ import com.instructure.teacher.R import kotlin.properties.Delegates @ScreenView(SCREEN_VIEW_EDIT_COURSE_NAME) -class EditCourseNameDialog : AppCompatDialogFragment() { +class EditCourseNameDialog : BaseCanvasAppCompatDialogFragment() { init { retainInstance = true diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/EditRubricCommentDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/EditRubricCommentDialog.kt index 2e039e36c1..73d786c889 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/EditRubricCommentDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/EditRubricCommentDialog.kt @@ -22,13 +22,12 @@ import android.os.Bundle import android.view.View import android.view.WindowManager import androidx.appcompat.app.AppCompatDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.core.graphics.drawable.DrawableCompat import androidx.fragment.app.FragmentManager import com.instructure.canvasapi2.utils.Pronouns import com.instructure.pandautils.analytics.SCREEN_VIEW_EDIT_RUBRIC_COMMENT import com.instructure.pandautils.analytics.ScreenView -import com.instructure.pandautils.binding.viewBinding import com.instructure.pandautils.utils.* import com.instructure.teacher.R import com.instructure.teacher.databinding.ViewEditGradeCommentBinding @@ -37,7 +36,7 @@ import com.instructure.teacher.view.edit_rubric.RubricCommentEditedEvent import org.greenrobot.eventbus.EventBus @ScreenView(SCREEN_VIEW_EDIT_RUBRIC_COMMENT) -class EditRubricCommentDialog : AppCompatDialogFragment() { +class EditRubricCommentDialog : BaseCanvasAppCompatDialogFragment() { private lateinit var binding: ViewEditGradeCommentBinding diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/FilterSubmissionByPointsDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/FilterSubmissionByPointsDialog.kt index 36a0579ab1..ae49126a02 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/FilterSubmissionByPointsDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/FilterSubmissionByPointsDialog.kt @@ -25,7 +25,7 @@ import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.appcompat.widget.AppCompatEditText import androidx.fragment.app.FragmentManager import com.instructure.canvasapi2.utils.NumberHelper @@ -34,7 +34,7 @@ import com.instructure.teacher.R import java.util.* import kotlin.properties.Delegates -class FilterSubmissionByPointsDialog : AppCompatDialogFragment() { +class FilterSubmissionByPointsDialog : BaseCanvasAppCompatDialogFragment() { private var mFilterCallback: (Double) -> Unit by Delegates.notNull() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/NoInternetConnectionDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/NoInternetConnectionDialog.kt index 8652554aef..e0138b6df9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/NoInternetConnectionDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/NoInternetConnectionDialog.kt @@ -19,7 +19,7 @@ import android.app.Dialog import android.os.Bundle import androidx.fragment.app.FragmentManager import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import com.instructure.pandautils.analytics.SCREEN_VIEW_NO_INTERNET_CONNECTION import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.ThemePrefs @@ -27,7 +27,7 @@ import com.instructure.pandautils.utils.ThemePrefs import com.instructure.teacher.R @ScreenView(SCREEN_VIEW_NO_INTERNET_CONNECTION) -class NoInternetConnectionDialog : AppCompatDialogFragment() { +class NoInternetConnectionDialog : BaseCanvasAppCompatDialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val builder = AlertDialog.Builder(requireContext()) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/PassFailGradeDailog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/PassFailGradeDailog.kt index 861dc284b2..bce5961128 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/PassFailGradeDailog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/PassFailGradeDailog.kt @@ -23,7 +23,7 @@ import android.widget.ArrayAdapter import android.widget.Spinner import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.appcompat.widget.AppCompatCheckBox import androidx.fragment.app.FragmentManager import com.instructure.pandautils.analytics.SCREEN_VIEW_PASS_FAIL_GRADE @@ -38,7 +38,7 @@ import java.util.Locale import kotlin.properties.Delegates @ScreenView(SCREEN_VIEW_PASS_FAIL_GRADE) -class PassFailGradeDailog : AppCompatDialogFragment() { +class PassFailGradeDailog : BaseCanvasAppCompatDialogFragment() { init { retainInstance = true diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/PeopleListFilterDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/PeopleListFilterDialog.kt index b6962682e1..1f85f29792 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/PeopleListFilterDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/PeopleListFilterDialog.kt @@ -23,7 +23,7 @@ import android.view.View import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.appcompat.view.ContextThemeWrapper import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.LinearLayoutManager @@ -45,7 +45,7 @@ import com.instructure.teacher.adapters.PeopleFilterAdapter import kotlinx.coroutines.Job import kotlin.properties.Delegates -class PeopleListFilterDialog : AppCompatDialogFragment() { +class PeopleListFilterDialog : BaseCanvasAppCompatDialogFragment() { init { retainInstance = true } diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/RadioButtonDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/RadioButtonDialog.kt index 29830186f3..bad691f1f9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/RadioButtonDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/RadioButtonDialog.kt @@ -27,9 +27,8 @@ import android.view.ViewGroup import android.widget.RadioGroup import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.appcompat.widget.AppCompatRadioButton -import androidx.core.content.ContextCompat import androidx.core.widget.CompoundButtonCompat import androidx.fragment.app.FragmentManager import com.instructure.pandautils.utils.* @@ -39,7 +38,7 @@ import java.util.Locale typealias OnRadioButtonSelected = ((selectedIdx: Int) -> Unit)? -class RadioButtonDialog : AppCompatDialogFragment() { +class RadioButtonDialog : BaseCanvasAppCompatDialogFragment() { init { retainInstance = true diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/SGAddMediaCommentDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/SGAddMediaCommentDialog.kt index 435ac3b6fb..6795c71363 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/SGAddMediaCommentDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/SGAddMediaCommentDialog.kt @@ -21,7 +21,7 @@ import android.content.DialogInterface import android.os.Bundle import android.view.View import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatDialogFragment +import com.instructure.pandautils.base.BaseCanvasAppCompatDialogFragment import androidx.fragment.app.FragmentManager import com.instructure.canvasapi2.models.Assignment import com.instructure.pandautils.utils.* @@ -31,7 +31,7 @@ import com.instructure.teacher.databinding.DialogSgAddAttachmentCommentBinding import com.instructure.teacher.view.MediaCommentDialogClosedEvent import org.greenrobot.eventbus.EventBus -class SGAddMediaCommentDialog : AppCompatDialogFragment() { +class SGAddMediaCommentDialog : BaseCanvasAppCompatDialogFragment() { var assignmentId: Long by LongArg() var courseId: Long by LongArg() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/dialog/SectionPickerDialog.kt b/apps/teacher/src/main/java/com/instructure/teacher/dialog/SectionPickerDialog.kt index e0f335dbcf..334c325ece 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/dialog/SectionPickerDialog.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/dialog/SectionPickerDialog.kt @@ -20,11 +20,10 @@ package com.instructure.teacher.dialog import android.app.Dialog import android.os.Bundle import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import android.widget.CheckBox import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.DialogFragment +import com.instructure.pandautils.base.BaseCanvasDialogFragment import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -37,7 +36,7 @@ import com.instructure.teacher.R import com.instructure.teacher.databinding.DialogSectionPickerBinding import com.instructure.teacher.databinding.ViewSectionListItemBinding -class SectionPickerDialog : DialogFragment() { +class SectionPickerDialog : BaseCanvasDialogFragment() { private lateinit var binding: DialogSectionPickerBinding diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/AddMessagePresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/AddMessagePresenterFactory.kt index 08386d066d..1353ba5149 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/AddMessagePresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/AddMessagePresenterFactory.kt @@ -21,7 +21,7 @@ import com.instructure.canvasapi2.models.Message import com.instructure.canvasapi2.models.Recipient import com.instructure.teacher.presenters.AddMessagePresenter import com.instructure.teacher.viewinterface.AddMessageView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory import java.util.* class AddMessagePresenterFactory( diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/AssigneeListPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/AssigneeListPresenterFactory.kt index f474558edb..b506e12cab 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/AssigneeListPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/AssigneeListPresenterFactory.kt @@ -22,7 +22,7 @@ import com.instructure.canvasapi2.models.User import com.instructure.teacher.presenters.AssigneeListPresenter import com.instructure.teacher.utils.EditDateGroups import com.instructure.teacher.viewinterface.AssigneeListView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class AssigneeListPresenterFactory( val dateGroups: EditDateGroups, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentDetailPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentDetailPresenterFactory.kt index 704b4e6a97..3416ac0c7a 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentDetailPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentDetailPresenterFactory.kt @@ -20,7 +20,7 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.teacher.features.assignment.details.AssignmentDetailsPresenter import com.instructure.teacher.viewinterface.AssignmentDetailsView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class AssignmentDetailPresenterFactory(val assignment: Assignment) : PresenterFactory { override fun create() = AssignmentDetailsPresenter(assignment) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentListPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentListPresenterFactory.kt index 314917161c..a1c4dbc38e 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentListPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentListPresenterFactory.kt @@ -19,7 +19,7 @@ package com.instructure.teacher.factory import com.instructure.canvasapi2.models.CanvasContext import com.instructure.teacher.features.assignment.list.AssignmentListPresenter import com.instructure.teacher.viewinterface.AssignmentListView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class AssignmentListPresenterFactory(private var mCanvasContext: CanvasContext) : PresenterFactory { override fun create(): AssignmentListPresenter = AssignmentListPresenter(mCanvasContext) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentSubmissionListPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentSubmissionListPresenterFactory.kt index 3f700b71bf..fb174e728f 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentSubmissionListPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/AssignmentSubmissionListPresenterFactory.kt @@ -21,7 +21,7 @@ import com.instructure.teacher.features.assignment.submission.AssignmentSubmissi import com.instructure.teacher.features.assignment.submission.AssignmentSubmissionRepository import com.instructure.teacher.features.assignment.submission.SubmissionListFilter import com.instructure.teacher.viewinterface.AssignmentSubmissionListView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class AssignmentSubmissionListPresenterFactory( private var assignment: Assignment, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/AttendanceListPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/AttendanceListPresenterFactory.kt index 6a8ca49de0..a739ee0b04 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/AttendanceListPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/AttendanceListPresenterFactory.kt @@ -21,7 +21,7 @@ import com.instructure.canvasapi2.models.Tab import com.instructure.teacher.presenters.AttendanceListPresenter import com.instructure.teacher.viewinterface.AttendanceListView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class AttendanceListPresenterFactory(private val mCanvasContext: CanvasContext, private val mTab: Tab) : PresenterFactory { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/ChooseRecipientsPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/ChooseRecipientsPresenterFactory.kt index 9280244c68..87f169ffdd 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/ChooseRecipientsPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/ChooseRecipientsPresenterFactory.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.factory import com.instructure.teacher.presenters.ChooseRecipientsPresenter import com.instructure.teacher.viewinterface.ChooseRecipientsView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class ChooseRecipientsPresenterFactory(private val mRootContextId: String) : PresenterFactory { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseBrowserEmptyViewFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseBrowserEmptyViewFactory.kt index 9019bcfa81..0b0aefc5b4 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseBrowserEmptyViewFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseBrowserEmptyViewFactory.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.factory import com.instructure.canvasapi2.models.Course import com.instructure.teacher.presenters.CourseBrowserEmptyPresenter import com.instructure.teacher.viewinterface.CourseBrowserEmptyView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class CourseBrowserEmptyViewFactory(val course: Course) : PresenterFactory { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseBrowserPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseBrowserPresenterFactory.kt index 7ebb04ca04..1d14efbbb8 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseBrowserPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseBrowserPresenterFactory.kt @@ -19,7 +19,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Tab import com.instructure.teacher.presenters.CourseBrowserPresenter import com.instructure.teacher.viewinterface.CourseBrowserView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class CourseBrowserPresenterFactory(val course: CanvasContext, val filter: (Tab, Long) -> Boolean) : PresenterFactory { override fun create(): CourseBrowserPresenter { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseSettingsFragmentPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseSettingsFragmentPresenterFactory.kt index 297bfeceaa..e42f1ef7c2 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseSettingsFragmentPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/CourseSettingsFragmentPresenterFactory.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.factory import com.instructure.teacher.presenters.CourseSettingsFragmentPresenter import com.instructure.teacher.viewinterface.CourseSettingsFragmentView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class CourseSettingsFragmentPresenterFactory : PresenterFactory { override fun create() = CourseSettingsFragmentPresenter() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateDiscussionPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateDiscussionPresenterFactory.kt index d2751c0835..05b7ac6bef 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateDiscussionPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateDiscussionPresenterFactory.kt @@ -20,7 +20,7 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.CanvasContext import com.instructure.teacher.presenters.CreateDiscussionPresenter import com.instructure.teacher.viewinterface.CreateDiscussionView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class CreateDiscussionPresenterFactory(private var canvasContext: CanvasContext, private var assignment: Assignment?) : PresenterFactory { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateOrEditAnnouncementPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateOrEditAnnouncementPresenterFactory.kt index 1c7801f045..be2239c1f3 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateOrEditAnnouncementPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateOrEditAnnouncementPresenterFactory.kt @@ -20,7 +20,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.DiscussionTopicHeader import com.instructure.teacher.presenters.CreateOrEditAnnouncementPresenter import com.instructure.teacher.viewinterface.CreateOrEditAnnouncementView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class CreateOrEditAnnouncementPresenterFactory(private var canvasContext: CanvasContext, private var editAnnouncement: DiscussionTopicHeader?) : PresenterFactory { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateOrEditPagePresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateOrEditPagePresenterFactory.kt index 1adaaf3aeb..0c383e577c 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateOrEditPagePresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/CreateOrEditPagePresenterFactory.kt @@ -21,7 +21,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Page import com.instructure.teacher.presenters.CreateOrEditPagePresenter import com.instructure.teacher.viewinterface.CreateOrEditPageView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class CreateOrEditPagePresenterFactory(private var canvasContext: CanvasContext, private var page: Page?) : PresenterFactory { override fun create(): CreateOrEditPagePresenter = CreateOrEditPagePresenter(canvasContext, page) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/DashboardPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/DashboardPresenterFactory.kt index dbe690ab29..9f6f773622 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/DashboardPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/DashboardPresenterFactory.kt @@ -19,7 +19,7 @@ package com.instructure.teacher.factory import com.instructure.teacher.presenters.DashboardPresenter import com.instructure.teacher.viewinterface.CoursesView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class DashboardPresenterFactory : PresenterFactory { override fun create() = DashboardPresenter() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/DiscussionListPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/DiscussionListPresenterFactory.kt index df5fcc2877..13c7b38bed 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/DiscussionListPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/DiscussionListPresenterFactory.kt @@ -19,7 +19,7 @@ package com.instructure.teacher.factory import com.instructure.canvasapi2.models.CanvasContext import com.instructure.teacher.presenters.DiscussionListPresenter import com.instructure.teacher.viewinterface.DiscussionListView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class DiscussionListPresenterFactory(private var canvasContext: CanvasContext, private var isAnnouncements: Boolean) : PresenterFactory { override fun create(): DiscussionListPresenter = DiscussionListPresenter(canvasContext, isAnnouncements) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/DiscussionsUpdatePresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/DiscussionsUpdatePresenterFactory.kt index 481e839260..2a3e687c9e 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/DiscussionsUpdatePresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/DiscussionsUpdatePresenterFactory.kt @@ -21,7 +21,7 @@ import com.instructure.canvasapi2.models.DiscussionEntry import com.instructure.canvasapi2.models.DiscussionTopic import com.instructure.teacher.presenters.DiscussionsUpdatePresenter import com.instructure.teacher.viewinterface.DiscussionsUpdateView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class DiscussionsUpdatePresenterFactory( val canvasContext: CanvasContext, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/DueDatesPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/DueDatesPresenterFactory.kt index 0bfdf390f1..32369845ac 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/DueDatesPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/DueDatesPresenterFactory.kt @@ -19,7 +19,7 @@ package com.instructure.teacher.factory import com.instructure.canvasapi2.models.Assignment import com.instructure.teacher.presenters.DueDatesPresenter import com.instructure.teacher.viewinterface.DueDatesView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class DueDatesPresenterFactory(val assignment: Assignment) : PresenterFactory { override fun create() = DueDatesPresenter(assignment) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/EditFilePresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/EditFilePresenterFactory.kt index e981e4810f..3304f04b6a 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/EditFilePresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/EditFilePresenterFactory.kt @@ -20,7 +20,7 @@ import com.instructure.canvasapi2.models.FileFolder import com.instructure.canvasapi2.models.License import com.instructure.teacher.presenters.EditFileFolderPresenter import com.instructure.teacher.view.EditFileView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory import java.util.* class EditFilePresenterFactory(val fileFolder: FileFolder, val usageRightsEnabled: Boolean, val licenseList: ArrayList, val courseId: Long) : PresenterFactory { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/EditQuizDetailsPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/EditQuizDetailsPresenterFactory.kt index 6f9b9cfdb1..8686ac9710 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/EditQuizDetailsPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/EditQuizDetailsPresenterFactory.kt @@ -21,7 +21,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Quiz import com.instructure.teacher.presenters.EditQuizDetailsPresenter import com.instructure.teacher.viewinterface.EditQuizDetailsView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class EditQuizDetailsPresenterFactory(val quiz: Quiz, val assignment: Assignment, val canvasContext: CanvasContext) : PresenterFactory { override fun create(): EditQuizDetailsPresenter = EditQuizDetailsPresenter(quiz, assignment, canvasContext) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/FileListPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/FileListPresenterFactory.kt index 3fed2b81ae..d4efecf5b5 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/FileListPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/FileListPresenterFactory.kt @@ -20,7 +20,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.FileFolder import com.instructure.teacher.presenters.FileListPresenter import com.instructure.teacher.viewinterface.FileListView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class FileListPresenterFactory(private val currentFolder: FileFolder, val mCanvasContext: CanvasContext) : PresenterFactory { override fun create(): FileListPresenter = FileListPresenter(currentFolder, mCanvasContext) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/InitActivityPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/InitActivityPresenterFactory.kt index f889d526d8..9b44fe2d53 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/InitActivityPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/InitActivityPresenterFactory.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.factory import com.instructure.teacher.presenters.InitActivityPresenter import com.instructure.teacher.viewinterface.InitActivityView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class InitActivityPresenterFactory : PresenterFactory { override fun create() = InitActivityPresenter() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/InternalWebViewPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/InternalWebViewPresenterFactory.kt index a269a1d81a..a94d8c249c 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/InternalWebViewPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/InternalWebViewPresenterFactory.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.factory import com.instructure.teacher.presenters.InternalWebViewPresenter import com.instructure.teacher.viewinterface.InternalWebView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class InternalWebViewPresenterFactory : PresenterFactory { override fun create() = InternalWebViewPresenter() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/MessageThreadPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/MessageThreadPresenterFactory.kt index 288c43e22e..293f6b73f8 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/MessageThreadPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/MessageThreadPresenterFactory.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.factory import com.instructure.canvasapi2.models.Conversation import com.instructure.teacher.presenters.MessageThreadPresenter import com.instructure.teacher.viewinterface.MessageThreadView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class MessageThreadPresenterFactory( private val conversation: Conversation? = null, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/PageDetailsPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/PageDetailsPresenterFactory.kt index 79b8c5a77a..40dd90803e 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/PageDetailsPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/PageDetailsPresenterFactory.kt @@ -21,7 +21,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Page import com.instructure.teacher.presenters.PageDetailsPresenter import com.instructure.teacher.viewinterface.PageDetailsView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class PageDetailsPresenterFactory(val mCanvasContext: CanvasContext, val mPage: Page) : PresenterFactory { override fun create(): PageDetailsPresenter = PageDetailsPresenter(mCanvasContext, mPage) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/PageListPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/PageListPresenterFactory.kt index 63d60d80ac..f80376fa3c 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/PageListPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/PageListPresenterFactory.kt @@ -20,7 +20,7 @@ package com.instructure.teacher.factory import com.instructure.canvasapi2.models.CanvasContext import com.instructure.teacher.presenters.PageListPresenter import com.instructure.teacher.viewinterface.PageListView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class PageListPresenterFactory(private var canvasContext: CanvasContext) : PresenterFactory { override fun create(): PageListPresenter = PageListPresenter(canvasContext) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/PeopleListPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/PeopleListPresenterFactory.kt index 5e5f75b3e5..c824361252 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/PeopleListPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/PeopleListPresenterFactory.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.factory import com.instructure.canvasapi2.models.CanvasContext import com.instructure.teacher.presenters.PeopleListPresenter import com.instructure.teacher.viewinterface.PeopleListView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class PeopleListPresenterFactory(private val mCanvasContext: CanvasContext) : PresenterFactory { override fun create() = PeopleListPresenter(mCanvasContext) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/ProfileEditFragmentPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/ProfileEditFragmentPresenterFactory.kt index f2b1ccb9a5..38d8a8aaf5 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/ProfileEditFragmentPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/ProfileEditFragmentPresenterFactory.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.factory import com.instructure.teacher.presenters.ProfileEditFragmentPresenter import com.instructure.teacher.viewinterface.ProfileEditFragmentView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class ProfileEditFragmentPresenterFactory : PresenterFactory { override fun create() = ProfileEditFragmentPresenter() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/ProfileSettingsFragmentPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/ProfileSettingsFragmentPresenterFactory.kt deleted file mode 100644 index bacfa6d671..0000000000 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/ProfileSettingsFragmentPresenterFactory.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* -* Copyright (C) 2017 - present Instructure, Inc. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3 of the License. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -*/ -package com.instructure.teacher.factory - -import com.instructure.teacher.presenters.ProfileSettingsFragmentPresenter -import com.instructure.teacher.viewinterface.ProfileSettingsFragmentView -import instructure.androidblueprint.PresenterFactory - - -class ProfileSettingsFragmentPresenterFactory : PresenterFactory { - override fun create() = ProfileSettingsFragmentPresenter() -} diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/QuizDetailsPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/QuizDetailsPresenterFactory.kt index 48fe4353ab..410aea46e6 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/QuizDetailsPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/QuizDetailsPresenterFactory.kt @@ -20,7 +20,7 @@ import com.instructure.canvasapi2.models.Quiz import com.instructure.teacher.presenters.QuizDetailsPresenter import com.instructure.teacher.viewinterface.QuizDetailsView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class QuizDetailsPresenterFactory(val mCourse: Course, val mQuiz: Quiz) : PresenterFactory { override fun create(): QuizDetailsPresenter = QuizDetailsPresenter(mCourse, mQuiz) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/QuizListPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/QuizListPresenterFactory.kt index 3087a6c9f7..20d979bff9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/QuizListPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/QuizListPresenterFactory.kt @@ -19,7 +19,7 @@ package com.instructure.teacher.factory import com.instructure.canvasapi2.models.CanvasContext import com.instructure.teacher.presenters.QuizListPresenter import com.instructure.teacher.viewinterface.QuizListView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class QuizListPresenterFactory(private var mCanvasContext: CanvasContext) : PresenterFactory { override fun create(): QuizListPresenter = QuizListPresenter(mCanvasContext) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderCommentsPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderCommentsPresenterFactory.kt index 600c588091..14cdcd1db5 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderCommentsPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderCommentsPresenterFactory.kt @@ -22,7 +22,7 @@ import com.instructure.canvasapi2.models.SubmissionComment import com.instructure.pandautils.room.appdatabase.daos.* import com.instructure.teacher.presenters.SpeedGraderCommentsPresenter import com.instructure.teacher.viewinterface.SpeedGraderCommentsView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class SpeedGraderCommentsPresenterFactory( val rawComments: java.util.ArrayList, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderFilesPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderFilesPresenterFactory.kt index b49b731c2e..4885979989 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderFilesPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderFilesPresenterFactory.kt @@ -19,7 +19,7 @@ package com.instructure.teacher.factory import com.instructure.canvasapi2.models.Submission import com.instructure.teacher.presenters.SpeedGraderFilesPresenter import com.instructure.teacher.viewinterface.SpeedGraderFilesView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class SpeedGraderFilesPresenterFactory(val submission: Submission?) : PresenterFactory { override fun create() = SpeedGraderFilesPresenter(submission) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderGradePresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderGradePresenterFactory.kt index 0980c2cbe1..5a71e0e1b0 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderGradePresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderGradePresenterFactory.kt @@ -22,7 +22,7 @@ import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.models.Submission import com.instructure.teacher.presenters.SpeedGraderGradePresenter import com.instructure.teacher.viewinterface.SpeedGraderGradeView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class SpeedGraderGradePresenterFactory(val submission: Submission?, val assignment: Assignment, val course: Course, val assignee: Assignee) : PresenterFactory { override fun create(): SpeedGraderGradePresenter = SpeedGraderGradePresenter(submission, assignment, course, assignee) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderPresenterFactory.kt index e903d0757c..a3bd608418 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/SpeedGraderPresenterFactory.kt @@ -21,7 +21,7 @@ import com.instructure.teacher.features.assignment.submission.AssignmentSubmissi import com.instructure.teacher.features.assignment.submission.SubmissionListFilter import com.instructure.teacher.presenters.SpeedGraderPresenter import com.instructure.teacher.viewinterface.SpeedGraderView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class SpeedGraderPresenterFactory( private val courseId: Long, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/StudentContextPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/StudentContextPresenterFactory.kt index a916bb8ebb..7e93db56d9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/StudentContextPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/StudentContextPresenterFactory.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.factory import com.instructure.teacher.presenters.StudentContextPresenter import com.instructure.teacher.viewinterface.StudentContextView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class StudentContextPresenterFactory(private val studentId: Long, private val courseId: Long) : PresenterFactory { override fun create() = StudentContextPresenter(studentId, courseId) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/ToDoPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/ToDoPresenterFactory.kt index 153203abdc..476a3d486d 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/ToDoPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/ToDoPresenterFactory.kt @@ -19,7 +19,7 @@ package com.instructure.teacher.factory import com.instructure.teacher.presenters.ToDoPresenter import com.instructure.teacher.viewinterface.ToDoView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class ToDoPresenterFactory : PresenterFactory { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/factory/ViewPdfFragmentPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/factory/ViewPdfFragmentPresenterFactory.kt index 7edc11ee7c..497e34d8e3 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/factory/ViewPdfFragmentPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/factory/ViewPdfFragmentPresenterFactory.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.factory import com.instructure.teacher.presenters.ViewPdfFragmentPresenter import com.instructure.teacher.viewinterface.ViewPdfFragmentView -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class ViewPdfFragmentPresenterFactory(val pdfUrl : String) : PresenterFactory { override fun create() = ViewPdfFragmentPresenter(pdfUrl) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/details/AssignmentDetailsFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/details/AssignmentDetailsFragment.kt index eab86a161d..0cfe813400 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/details/AssignmentDetailsFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/details/AssignmentDetailsFragment.kt @@ -36,6 +36,7 @@ import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_ASSIGNMENT_DETAILS import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.features.discussion.router.DiscussionRouterFragment +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.fragments.BasePresenterFragment import com.instructure.pandautils.utils.LongArg import com.instructure.pandautils.utils.ParcelableArg @@ -65,7 +66,6 @@ import com.instructure.teacher.features.assignment.submission.AssignmentSubmissi import com.instructure.teacher.features.assignment.submission.SubmissionListFilter import com.instructure.teacher.fragments.DueDatesFragment import com.instructure.teacher.fragments.EditAssignmentDetailsFragment -import com.instructure.teacher.fragments.LtiLaunchFragment import com.instructure.teacher.router.RouteMatcher import com.instructure.teacher.utils.getColorCompat import com.instructure.teacher.utils.setupBackButtonWithExpandCollapseAndBack @@ -97,7 +97,7 @@ class AssignmentDetailsFragment : BasePresenterFragment< @Suppress("unused") @PageViewUrl - private fun makePageViewUrl() = "${ApiPrefs.fullDomain}/${course.contextId.replace("_", "s/")}/${assignment.id}" + fun makePageViewUrl() = "${ApiPrefs.fullDomain}/${course.contextId.replace("_", "s/")}/${assignment.id}" override val bindingInflater: (layoutInflater: LayoutInflater) -> FragmentAssignmentDetailsBinding = FragmentAssignmentDetailsBinding::inflate @@ -249,7 +249,7 @@ class AssignmentDetailsFragment : BasePresenterFragment< private fun configureSubmissionTypes(assignment: Assignment) = with(binding) { submissionTypesTextView.text = assignment.submissionTypesRaw.map { - submissionTypeToPrettyPrintString(getSubmissionTypeFromAPIString(it), requireContext()) }.joinToString("\n") + submissionTypeToPrettyPrintString(getSubmissionTypeFromAPIString(it), requireContext(), assignment.ltiToolType()) }.joinToString("\n") if(assignment.submissionTypesRaw.contains(Assignment.SubmissionType.EXTERNAL_TOOL.apiString)) { // External tool @@ -262,8 +262,8 @@ class AssignmentDetailsFragment : BasePresenterFragment< } val ltiUrl = assignment.url.validOrNull() ?: assignment.htmlUrl if(!ltiUrl.isNullOrBlank()) { - val args = LtiLaunchFragment.makeBundle(course, ltiUrl, assignment.name!!, true) - RouteMatcher.route(requireActivity(), Route(LtiLaunchFragment::class.java, course, args)) + val route = LtiLaunchFragment.makeRoute(course, ltiUrl, assignment.name!!, assignmentLti = true, openInternally = assignment.ltiToolType().openInternally) + RouteMatcher.route(requireActivity(), route) } } } @@ -310,7 +310,7 @@ class AssignmentDetailsFragment : BasePresenterFragment< loadHtmlJob = descriptionWebViewWrapper.webView.loadHtmlWithIframes(requireContext(), assignment.description, { descriptionWebViewWrapper.loadHtml(it, assignment.name, baseUrl = assignment.htmlUrl) }) { - LtiLaunchFragment.routeLtiLaunchFragment(requireActivity(), course, it) + RouteMatcher.route(requireActivity(), LtiLaunchFragment.makeSessionlessLtiUrlRoute(requireActivity(), course, it)) } } diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/details/AssignmentDetailsPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/details/AssignmentDetailsPresenter.kt index 19529ba06b..4486ae58c2 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/details/AssignmentDetailsPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/details/AssignmentDetailsPresenter.kt @@ -23,7 +23,7 @@ import com.instructure.canvasapi2.models.SubmissionSummary import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.weave.* import com.instructure.teacher.viewinterface.AssignmentDetailsView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job class AssignmentDetailsPresenter(var mAssignment: Assignment) : FragmentPresenter() { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/list/AssignmentListFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/list/AssignmentListFragment.kt index 25ea38d788..99e0fcc14c 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/list/AssignmentListFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/list/AssignmentListFragment.kt @@ -29,6 +29,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.GradingPeriod import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_ASSIGNMENT_LIST import com.instructure.pandautils.analytics.ScreenView @@ -70,7 +71,8 @@ class AssignmentListFragment : BaseExpandableSyncFragment< private val binding by viewBinding(FragmentAssignmentListBinding::bind) - private var canvasContext: CanvasContext by ParcelableArg(default = CanvasContext.getGenericContext(CanvasContext.Type.COURSE, -1L, "")) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(default = CanvasContext.getGenericContext(CanvasContext.Type.COURSE, -1L, "")) private var pairedWithSubmissions: Boolean = false private val linearLayoutManager by lazy { LinearLayoutManager(requireContext()) } private lateinit var mRecyclerView: RecyclerView diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/list/AssignmentListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/list/AssignmentListPresenter.kt index ae5c7adb17..6e020d5b41 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/list/AssignmentListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/list/AssignmentListPresenter.kt @@ -28,7 +28,7 @@ import com.instructure.canvasapi2.utils.filterWithQuery import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.canvasapi2.utils.weave.weave import com.instructure.teacher.viewinterface.AssignmentListView -import instructure.androidblueprint.SyncExpandablePresenter +import com.instructure.pandautils.blueprint.SyncExpandablePresenter import kotlinx.coroutines.Job import retrofit2.Response import java.util.* diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/submission/AssignmentSubmissionListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/submission/AssignmentSubmissionListPresenter.kt index 0784a4764e..d77add1668 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/submission/AssignmentSubmissionListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/assignment/submission/AssignmentSubmissionListPresenter.kt @@ -30,7 +30,7 @@ import com.instructure.canvasapi2.utils.weave.weave import com.instructure.pandautils.utils.AssignmentUtils2 import com.instructure.teacher.utils.getState import com.instructure.teacher.viewinterface.AssignmentSubmissionListView -import instructure.androidblueprint.SyncPresenter +import com.instructure.pandautils.blueprint.SyncPresenter import kotlinx.coroutines.Job import java.util.Locale import java.util.Random diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/calendar/TeacherCalendarRepository.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/calendar/TeacherCalendarRepository.kt index 934c54b85f..05066db327 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/calendar/TeacherCalendarRepository.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/calendar/TeacherCalendarRepository.kt @@ -119,9 +119,8 @@ class TeacherCalendarRepository( override suspend fun getCalendarFilterLimit(): Int { val result = featuresApi.getAccountSettingsFeatures(RestParams()) return if (result.isSuccess) { - val features = result.dataOrThrow - val increasedContextLimit = features["calendar_contexts_limit"] - if (increasedContextLimit == true) 20 else 10 + val settings = result.dataOrThrow + settings.calendarContextsLimit } else { 10 } diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/discussion/TeacherDiscussionDetailsWebViewFragmentBehavior.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/discussion/TeacherDiscussionDetailsWebViewFragmentBehavior.kt new file mode 100644 index 0000000000..f7a6878e2b --- /dev/null +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/discussion/TeacherDiscussionDetailsWebViewFragmentBehavior.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.instructure.teacher.features.discussion + +import androidx.fragment.app.FragmentActivity +import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragmentBehavior +import com.instructure.teacher.utils.isTablet + + +class TeacherDiscussionDetailsWebViewFragmentBehavior(activity: FragmentActivity) : DiscussionDetailsWebViewFragmentBehavior { + override val showBackButton = !activity.isTablet +} diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/files/details/FileDetailsFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/files/details/FileDetailsFragment.kt index f12b5bd94d..c307bfdab9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/files/details/FileDetailsFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/files/details/FileDetailsFragment.kt @@ -23,6 +23,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.viewModels import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.utils.tryOrNull @@ -41,7 +42,7 @@ import com.instructure.teacher.fragments.ViewUnsupportedFileFragment import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class FileDetailsFragment : Fragment() { +class FileDetailsFragment : BaseCanvasFragment() { private val viewModel: FileDetailsViewModel by viewModels() private val binding by viewBinding(FragmentFileDetailsBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchAdapter.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchAdapter.kt index a3b9d79ee2..72a9121e48 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchAdapter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchAdapter.kt @@ -23,7 +23,7 @@ import androidx.viewbinding.ViewBinding import com.instructure.canvasapi2.models.FileFolder import com.instructure.teacher.databinding.AdapterFileFolderBinding import com.instructure.teacher.holders.FileFolderViewHolder -import instructure.androidblueprint.SyncRecyclerAdapter +import com.instructure.pandautils.blueprint.SyncRecyclerAdapter class FileSearchAdapter( context: Context, diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchPresenter.kt index 74cbcd1091..33c5d5a0fd 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchPresenter.kt @@ -27,7 +27,7 @@ import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.pandautils.utils.isNotUser -import instructure.androidblueprint.SyncPresenter +import com.instructure.pandautils.blueprint.SyncPresenter import kotlinx.coroutines.Job class FileSearchPresenter(val canvasContext: CanvasContext) : diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchPresenterFactory.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchPresenterFactory.kt index 526a420f86..37ffee675b 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchPresenterFactory.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchPresenterFactory.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.features.files.search import com.instructure.canvasapi2.models.CanvasContext -import instructure.androidblueprint.PresenterFactory +import com.instructure.pandautils.blueprint.PresenterFactory class FileSearchPresenterFactory(val canvasContext: CanvasContext) : PresenterFactory { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchView.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchView.kt index 37106129ea..bf71b2d85c 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/files/search/FileSearchView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.features.files.search import com.instructure.canvasapi2.models.FileFolder -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface FileSearchView : SyncManager { diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/SyllabusScreen.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/lti/TeacherLtiLaunchFragmentBehavior.kt similarity index 64% rename from apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/SyllabusScreen.kt rename to apps/teacher/src/main/java/com/instructure/teacher/features/lti/TeacherLtiLaunchFragmentBehavior.kt index e617430e09..730ad58e08 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/courses/details/SyllabusScreen.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/lti/TeacherLtiLaunchFragmentBehavior.kt @@ -14,14 +14,12 @@ * along with this program. If not, see . * */ +package com.instructure.teacher.features.lti -package com.instructure.parentapp.features.courses.details +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.pandautils.features.lti.LtiLaunchFragmentBehavior +import com.instructure.pandautils.utils.color -import androidx.compose.material.Text -import androidx.compose.runtime.Composable - - -@Composable -internal fun SyllabusScreen() { - Text(text = "Syllabus") -} +class TeacherLtiLaunchFragmentBehavior(canvasContext: CanvasContext) : LtiLaunchFragmentBehavior { + override val toolbarColor: Int = canvasContext.color +} \ No newline at end of file diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/modules/list/ModuleListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/modules/list/ModuleListPresenter.kt index fbd2147a17..9d17806342 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/modules/list/ModuleListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/modules/list/ModuleListPresenter.kt @@ -111,7 +111,7 @@ object ModuleListPresenter : Presenter { pointsPossible?.let { context.resources.getQuantityString(R.plurals.moduleItemPoints, it.toInt(), it) } val iconRes: Int? = when (tryOrNull { ModuleItem.Type.valueOf(item.type.orEmpty()) }) { - ModuleItem.Type.Assignment -> R.drawable.ic_assignment + ModuleItem.Type.Assignment -> if (item.quizLti) R.drawable.ic_quiz else R.drawable.ic_assignment ModuleItem.Type.Discussion -> R.drawable.ic_discussion ModuleItem.Type.File -> R.drawable.ic_attachment ModuleItem.Type.Page -> R.drawable.ic_pages diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/modules/list/ui/ModuleListMobiusFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/modules/list/ui/ModuleListMobiusFragment.kt index 5a835619de..b9709d2fb0 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/modules/list/ui/ModuleListMobiusFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/modules/list/ui/ModuleListMobiusFragment.kt @@ -22,6 +22,7 @@ import android.view.ViewGroup import com.instructure.canvasapi2.apis.ModuleAPI import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.pandautils.analytics.SCREEN_VIEW_MODULE_LIST import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.Const @@ -40,6 +41,7 @@ import javax.inject.Inject abstract class ModuleListMobiusFragment : MobiusFragment() { + @get:PageViewUrlParam("canvasContext") val canvasContext by ParcelableArg(key = Const.COURSE) private val scrollToItemId by NLongArg(key = Const.MODULE_ITEM_ID) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/modules/progression/ModuleProgressionFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/modules/progression/ModuleProgressionFragment.kt index 827c6932e7..37c4a66c69 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/modules/progression/ModuleProgressionFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/modules/progression/ModuleProgressionFragment.kt @@ -21,7 +21,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.viewModels import androidx.viewpager.widget.ViewPager.SimpleOnPageChangeListener import com.instructure.canvasapi2.models.CanvasContext @@ -47,7 +47,7 @@ import com.instructure.teacher.router.RouteMatcher import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class ModuleProgressionFragment : Fragment() { +class ModuleProgressionFragment : BaseCanvasFragment() { private val viewModel: ModuleProgressionViewModel by viewModels() private val binding by viewBinding(FragmentModuleProgressionBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/postpolicies/ui/PostPolicyFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/postpolicies/ui/PostPolicyFragment.kt index 1cb54c0e34..344b67fb61 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/postpolicies/ui/PostPolicyFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/postpolicies/ui/PostPolicyFragment.kt @@ -22,6 +22,7 @@ import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentPagerAdapter import com.instructure.canvasapi2.models.Assignment @@ -37,7 +38,7 @@ import com.instructure.teacher.R import com.instructure.teacher.databinding.FragmentPostPolicySettingsBinding import com.instructure.teacher.utils.setupBackButtonAsBackPressedOnly -class PostPolicyFragment : Fragment() { +class PostPolicyFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentPostPolicySettingsBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/settings/TeacherSettingsBehaviour.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/settings/TeacherSettingsBehaviour.kt new file mode 100644 index 0000000000..321845d680 --- /dev/null +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/settings/TeacherSettingsBehaviour.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.teacher.features.settings + +import com.instructure.teacher.BuildConfig +import com.instructure.pandautils.features.settings.SettingsBehaviour +import com.instructure.pandautils.features.settings.SettingsItem +import com.instructure.teacher.R + +class TeacherSettingsBehaviour : SettingsBehaviour { + override val settingsItems: Map> + get() { + val preferencesList = mutableListOf( + SettingsItem.APP_THEME, + SettingsItem.PROFILE_SETTINGS, + SettingsItem.PUSH_NOTIFICATIONS, + SettingsItem.EMAIL_NOTIFICATIONS, + SettingsItem.RATE_APP + ) + if (BuildConfig.DEBUG) { + preferencesList.add(SettingsItem.FEATURE_FLAGS) + preferencesList.add(SettingsItem.REMOTE_CONFIG) + } + return mapOf( + R.string.preferences to preferencesList, + R.string.legal to listOf( + SettingsItem.ABOUT, + SettingsItem.LEGAL + ) + ) + } +} \ No newline at end of file diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/settings/TeacherSettingsRouter.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/settings/TeacherSettingsRouter.kt new file mode 100644 index 0000000000..f71e7003d1 --- /dev/null +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/settings/TeacherSettingsRouter.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2024 - present Instructure, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.instructure.teacher.features.settings + +import androidx.fragment.app.FragmentActivity +import com.instructure.interactions.router.Route +import com.instructure.pandautils.dialogs.RatingDialog +import com.instructure.pandautils.features.notification.preferences.EmailNotificationPreferencesFragment +import com.instructure.pandautils.features.notification.preferences.PushNotificationPreferencesFragment +import com.instructure.pandautils.features.settings.SettingsRouter +import com.instructure.pandautils.fragments.RemoteConfigParamsFragment +import com.instructure.pandautils.utils.AppType +import com.instructure.teacher.fragments.FeatureFlagsFragment +import com.instructure.teacher.fragments.ProfileFragment +import com.instructure.teacher.router.RouteMatcher + +class TeacherSettingsRouter(private val activity: FragmentActivity) : SettingsRouter { + + override fun navigateToProfileSettings() { + RouteMatcher.route( + activity, + Route(null, ProfileFragment::class.java) + ) + } + + override fun navigateToPushNotificationsSettings() { + RouteMatcher.route( + activity, + Route(null, PushNotificationPreferencesFragment::class.java) + ) + } + + override fun navigateToEmailNotificationsSettings() { + RouteMatcher.route( + activity, + Route(null, EmailNotificationPreferencesFragment::class.java) + ) + } + + override fun navigateToRemoteConfig() { + RouteMatcher.route( + activity, + Route(null, RemoteConfigParamsFragment::class.java) + ) + } + + override fun navigateToFeatureFlags() { + RouteMatcher.route( + activity, + Route(null, FeatureFlagsFragment::class.java) + ) + } + + override fun navigateToRateApp() { + RatingDialog.showRateDialog(activity, AppType.TEACHER) + } +} \ No newline at end of file diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/speedgrader/commentlibrary/CommentLibraryFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/speedgrader/commentlibrary/CommentLibraryFragment.kt index 6c2c7407e0..874964767a 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/speedgrader/commentlibrary/CommentLibraryFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/speedgrader/commentlibrary/CommentLibraryFragment.kt @@ -20,7 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.fragment.app.activityViewModels import com.instructure.pandautils.analytics.SCREEN_VIEW_COMMENT_LIBRARY import com.instructure.pandautils.analytics.ScreenView @@ -33,7 +33,7 @@ import dagger.hilt.android.AndroidEntryPoint @ScreenView(SCREEN_VIEW_COMMENT_LIBRARY) @AndroidEntryPoint -class CommentLibraryFragment : Fragment() { +class CommentLibraryFragment : BaseCanvasFragment() { private lateinit var binding: FragmentCommentLibraryBinding diff --git a/apps/teacher/src/main/java/com/instructure/teacher/features/syllabus/ui/SyllabusFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/features/syllabus/ui/SyllabusFragment.kt index 9311533f37..99157d601a 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/features/syllabus/ui/SyllabusFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/features/syllabus/ui/SyllabusFragment.kt @@ -21,6 +21,7 @@ import android.view.ViewGroup import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.pandautils.analytics.SCREEN_VIEW_SYLLABUS import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.Const @@ -34,6 +35,7 @@ import com.instructure.teacher.mobius.common.ui.MobiusFragment @ScreenView(SCREEN_VIEW_SYLLABUS) class SyllabusFragment : MobiusFragment() { + @get:PageViewUrlParam("canvasContext") val canvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) override fun makeEffectHandler() = SyllabusEffectHandler() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/CourseBrowserFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/CourseBrowserFragment.kt index cb6eb0913f..19ba734f19 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/CourseBrowserFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/CourseBrowserFragment.kt @@ -32,10 +32,12 @@ import com.instructure.canvasapi2.utils.AnalyticsEventConstants import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.isValid import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_COURSE_BROWSER import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.binding.viewBinding +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.fragments.BaseSyncFragment import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.Const.CANVAS_STUDENT_ID @@ -85,7 +87,8 @@ class CourseBrowserFragment : BaseSyncFragment< private val binding by viewBinding(FragmentCourseBrowserBinding::bind) - private var canvasContext: CanvasContext by ParcelableArg(Course()) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(Course()) private val courseBrowserHeader by lazy { rootView.findViewById(R.id.courseBrowserHeader) } @@ -285,11 +288,8 @@ class CourseBrowserFragment : BaseSyncFragment< Route(AttendanceListFragment::class.java, presenter.canvasContext, args) ) } else { - val args = LtiLaunchFragment.makeTabBundle(presenter.canvasContext, tab) - RouteMatcher.route( - requireActivity(), - Route(LtiLaunchFragment::class.java, presenter.canvasContext, args) - ) + val route = LtiLaunchFragment.makeRoute(presenter.canvasContext, tab) + RouteMatcher.route(requireActivity(), route) } } } diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/CourseSettingsFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/CourseSettingsFragment.kt index 7c08883311..726612fd84 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/CourseSettingsFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/CourseSettingsFragment.kt @@ -56,7 +56,7 @@ class CourseSettingsFragment : BasePresenterFragment< @Suppress("unused") @PageViewUrl - private fun makePageViewUrl() = "courses/${course.id}/settings" + fun makePageViewUrl() = "courses/${course.id}/settings" private val mHomePages: Map by lazy { // Use LinkedHashMap map to keep order consistent between API levels diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateDiscussionFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateDiscussionFragment.kt index b4e9fa2597..c96423d809 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateDiscussionFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateDiscussionFragment.kt @@ -45,6 +45,7 @@ import com.instructure.canvasapi2.models.postmodels.FileSubmitObject import com.instructure.canvasapi2.utils.NumberHelper import com.instructure.canvasapi2.utils.Pronouns import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.toApiString import com.instructure.interactions.Identity import com.instructure.interactions.router.Route @@ -113,7 +114,8 @@ class CreateDiscussionFragment : BasePresenterFragment< Identity, FileUploadDialogParent { - private var canvasContext: CanvasContext by ParcelableArg(Course(), CANVAS_CONTEXT) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(Course(), CANVAS_CONTEXT) private var discussionTopicHeader: DiscussionTopicHeader? by NullableParcelableArg(null, DISCUSSION_TOPIC_HEADER) private val sendButton: TextView? get() = view?.findViewById(R.id.menuSaveDiscussion) private val saveButton: TextView? get() = view?.findViewById(R.id.menuSave) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateOrEditAnnouncementFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateOrEditAnnouncementFragment.kt index da104051a3..5823015425 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateOrEditAnnouncementFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateOrEditAnnouncementFragment.kt @@ -30,6 +30,7 @@ import com.instructure.canvasapi2.models.DiscussionTopicHeader import com.instructure.canvasapi2.models.postmodels.FileSubmitObject import com.instructure.canvasapi2.utils.DateHelper import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.parcelCopy import com.instructure.interactions.Identity import com.instructure.pandautils.analytics.SCREEN_VIEW_CREATE_OR_EDIT_ANNOUNCEMENT @@ -87,7 +88,8 @@ class CreateOrEditAnnouncementFragment : BasePresenterFragment< FileUploadDialogParent { /* The course this announcement belongs to */ - private var canvasContext by ParcelableArg(Course()) + @get:PageViewUrlParam("canvasContext") + var canvasContext by ParcelableArg(Course()) /* The announcement to be edited. This will be null if we're creating a new announcement */ private var editAnnouncement by NullableParcelableArg() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateOrEditPageDetailsFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateOrEditPageDetailsFragment.kt index 1c13010247..237b55bfde 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateOrEditPageDetailsFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/CreateOrEditPageDetailsFragment.kt @@ -104,7 +104,7 @@ class CreateOrEditPageDetailsFragment : BasePresenterFragment< @PageViewUrl @Suppress("unused") - private fun makePageViewUrl(): String { + fun makePageViewUrl(): String { val url = StringBuilder(ApiPrefs.fullDomain) page.let { url.append(canvasContext.toAPIString()) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/DiscussionsListFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/DiscussionsListFragment.kt index e2c92eb53e..33a0ff3afb 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/DiscussionsListFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/DiscussionsListFragment.kt @@ -77,7 +77,8 @@ open class DiscussionsListFragment : BaseExpandableSyncFragment< private val binding by viewBinding(FragmentDiscussionListBinding::bind) - protected var canvasContext: CanvasContext by ParcelableArg(default = CanvasContext.getGenericContext(CanvasContext.Type.COURSE, -1L, "")) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(default = CanvasContext.getGenericContext(CanvasContext.Type.COURSE, -1L, "")) private val linearLayoutManager by lazy { LinearLayoutManager(requireContext()) } private lateinit var mRecyclerView: RecyclerView diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/DiscussionsUpdateFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/DiscussionsUpdateFragment.kt index f9b78a2b6f..c556c60e69 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/DiscussionsUpdateFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/DiscussionsUpdateFragment.kt @@ -68,9 +68,10 @@ class DiscussionsUpdateFragment : BasePresenterFragment< FragmentDiscussionsEditBinding>(), DiscussionsUpdateView { - private var canvasContext: CanvasContext by ParcelableArg(default = CanvasContext.getGenericContext(CanvasContext.Type.COURSE, -1L, "")) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(default = CanvasContext.getGenericContext(CanvasContext.Type.COURSE, -1L, "")) @get:PageViewUrlParam("topicId") - private var discussionTopicHeaderId: Long by LongArg(key = DISCUSSION_TOPIC_HEADER_ID, default = 0L) // The topic the discussion belongs too + var discussionTopicHeaderId: Long by LongArg(key = DISCUSSION_TOPIC_HEADER_ID, default = 0L) // The topic the discussion belongs too private var discussionEntry: DiscussionEntry by ParcelableArg(key = DISCUSSION_ENTRY, default = DiscussionEntry()) private var discussionTopic: DiscussionTopic by ParcelableArg(key = DISCUSSION_TOPIC, default = DiscussionTopic()) private var placeHolderList: ArrayList = ArrayList() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/EditAssignmentDetailsFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/EditAssignmentDetailsFragment.kt index 0ffade26c5..b2d93032a6 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/EditAssignmentDetailsFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/EditAssignmentDetailsFragment.kt @@ -50,6 +50,7 @@ import com.instructure.canvasapi2.utils.NumberHelper import com.instructure.canvasapi2.utils.Pronouns import com.instructure.canvasapi2.utils.pageview.PageView import com.instructure.canvasapi2.utils.pageview.PageViewUrl +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.canvasapi2.utils.weave.weave import com.instructure.interactions.router.Route @@ -86,7 +87,8 @@ class EditAssignmentDetailsFragment : BaseFragment() { private val binding by viewBinding(FragmentEditAssignmentDetailsBinding::bind) - private var course: Course by ParcelableArg(Course()) + @get:PageViewUrlParam("canvasContext") + var course: Course by ParcelableArg(Course()) private var assignment: Assignment by ParcelableArg(key = ASSIGNMENT) private var isPublished: Boolean = true private var scrollToDates: Boolean by BooleanArg(key = SHOULD_SCROLL_TO_DATES) @@ -141,7 +143,7 @@ class EditAssignmentDetailsFragment : BaseFragment() { @Suppress("unused") @PageViewUrl - private fun makePageViewUrl() = "${ApiPrefs.fullDomain}/${course.contextId.replace("_", "s/")}/${assignment.id}" + fun makePageViewUrl() = "${ApiPrefs.fullDomain}/${course.contextId.replace("_", "s/")}/${assignment.id}" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/EmptyFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/EmptyFragment.kt index d7282475a7..86854637fd 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/EmptyFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/EmptyFragment.kt @@ -19,7 +19,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.instructure.canvasapi2.models.Course import com.instructure.pandautils.binding.viewBinding import com.instructure.pandautils.utils.NullableParcelableArg @@ -30,7 +30,7 @@ import com.instructure.pandautils.utils.color import com.instructure.teacher.R import com.instructure.teacher.databinding.FragmentEmptyBinding -class EmptyFragment: Fragment() { +class EmptyFragment: BaseCanvasFragment() { private val binding by viewBinding(FragmentEmptyBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/FeatureFlagsFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/FeatureFlagsFragment.kt index 1dcae2155f..ac077215c9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/FeatureFlagsFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/FeatureFlagsFragment.kt @@ -20,7 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.recyclerview.widget.RecyclerView import com.instructure.canvasapi2.utils.FeatureFlagPref import com.instructure.pandautils.binding.viewBinding @@ -33,7 +33,7 @@ import com.instructure.teacher.databinding.AdapterFeatureFlagBinding import com.instructure.teacher.databinding.FragmentFeatureFlagsBinding import com.instructure.teacher.utils.FeatureFlags -class FeatureFlagsFragment : Fragment() { +class FeatureFlagsFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentFeatureFlagsBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/FileListFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/FileListFragment.kt index a7392f18cd..bb8b50f910 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/FileListFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/FileListFragment.kt @@ -158,7 +158,7 @@ class FileListFragment : BaseSyncFragment< @Suppress("unused") @PageViewUrl - private fun makePageViewUrl(): String { + fun makePageViewUrl(): String { var url = if (canvasContext.type == CanvasContext.Type.USER) "${ApiPrefs.fullDomain}/files" else "${ApiPrefs.fullDomain}/${canvasContext.contextId.replace("_", "s/")}/files" diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/LtiLaunchFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/LtiLaunchFragment.kt deleted file mode 100644 index d57be8d7ea..0000000000 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/LtiLaunchFragment.kt +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2017 - present Instructure, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package com.instructure.teacher.fragments - -import android.app.Activity -import android.net.Uri -import android.os.Bundle -import android.os.Handler -import android.view.View -import androidx.browser.customtabs.CustomTabColorSchemeParams -import androidx.browser.customtabs.CustomTabsIntent -import androidx.fragment.app.FragmentActivity -import com.instructure.canvasapi2.managers.SubmissionManager -import com.instructure.canvasapi2.models.CanvasContext -import com.instructure.canvasapi2.models.Course -import com.instructure.canvasapi2.models.Group -import com.instructure.canvasapi2.models.Tab -import com.instructure.canvasapi2.utils.ApiPrefs -import com.instructure.canvasapi2.utils.pageview.PageView -import com.instructure.canvasapi2.utils.pageview.PageViewUrl -import com.instructure.canvasapi2.utils.validOrNull -import com.instructure.canvasapi2.utils.weave.weave -import com.instructure.interactions.router.Route -import com.instructure.pandautils.analytics.SCREEN_VIEW_LTI_LAUNCH -import com.instructure.pandautils.analytics.ScreenView -import com.instructure.pandautils.binding.viewBinding -import com.instructure.pandautils.fragments.BaseFragment -import com.instructure.pandautils.utils.BooleanArg -import com.instructure.pandautils.utils.Const -import com.instructure.pandautils.utils.HtmlContentFormatter -import com.instructure.pandautils.utils.NullableParcelableArg -import com.instructure.pandautils.utils.NullableStringArg -import com.instructure.pandautils.utils.StringArg -import com.instructure.pandautils.utils.ThemePrefs -import com.instructure.pandautils.utils.ViewStyler -import com.instructure.pandautils.utils.asChooserExcludingInstructure -import com.instructure.pandautils.utils.color -import com.instructure.pandautils.utils.replaceWithURLQueryParameter -import com.instructure.pandautils.utils.setTextForVisibility -import com.instructure.pandautils.utils.toast -import com.instructure.teacher.R -import com.instructure.teacher.databinding.FragmentLtiLaunchBinding -import com.instructure.teacher.router.RouteMatcher -import kotlinx.coroutines.Job -import java.net.URLDecoder - -@PageView -@ScreenView(SCREEN_VIEW_LTI_LAUNCH) -class LtiLaunchFragment : BaseFragment() { - - private val binding by viewBinding(FragmentLtiLaunchBinding::bind) - - var canvasContext: CanvasContext? by NullableParcelableArg(key = Const.CANVAS_CONTEXT) - - private var title: String? by NullableStringArg(key = Const.TITLE) - private var ltiUrl: String by StringArg(key = LTI_URL) - private var ltiTab: Tab? by NullableParcelableArg(key = TAB) - private var sessionLessLaunch: Boolean by BooleanArg(key = SESSION_LESS) - - /* Tracks whether we have automatically started launching the LTI tool in a chrome custom tab. Because this fragment - re-runs certain logic in onResume, tracking the launch helps us know to pop this fragment instead of erroneously - launching again when the user returns to the app. */ - private var customTabLaunched: Boolean = false - - private var ltiUrlLaunchJob: Job? = null - - @Suppress("unused") - @PageViewUrl - private fun makePageViewUrl() = - ltiTab?.externalUrl ?: ApiPrefs.fullDomain + canvasContext?.toAPIString() + "/external_tools" - - override fun layoutResId(): Int = R.layout.fragment_lti_launch - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - customTabLaunched = savedInstanceState?.getBoolean(CUSTOM_TAB_LAUNCHED_STATE) ?: false - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putBoolean(CUSTOM_TAB_LAUNCHED_STATE, customTabLaunched) - } - - override fun onCreateView(view: View) = Unit - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val color = canvasContext?.color ?: ThemePrefs.primaryColor - ViewStyler.setStatusBarDark(requireActivity(), color) - binding.loadingView.setOverrideColor(color) - binding.toolName.setTextForVisibility(title.validOrNull() ?: ltiTab?.label?.validOrNull() ?: ltiUrl.validOrNull()) - } - - override fun onResume() { - super.onResume() - // If onResume() is called after the custom tab has launched, it means the user is returning and we should close this fragment - if (customTabLaunched) { - /* Due to how fragment management is set up, attempting to pop this fragment directly from onResume can - result in a crash. We'll work around this by posting the action to the main thread message queue. */ - Handler().post { activity?.onBackPressed() } - return - } - - try { - when { - ltiTab != null -> getSessionlessLtiUrl(ltiTab!!.ltiUrl) - ltiUrl.isNotBlank() -> { - var url = ltiUrl // Replace deep link scheme - .replaceFirst("canvas-courses://", "${ApiPrefs.protocol}://") - .replaceFirst("canvas-student://", "${ApiPrefs.protocol}://") - .replaceWithURLQueryParameter(HtmlContentFormatter.hasKalturaUrl(ltiUrl)) - - if (sessionLessLaunch) { - if (url.contains("sessionless_launch")) { - getSessionlessLtiUrl(url) - } else { - val id = url.substringAfterLast("/external_tools/").substringBefore("?") - url = when { - (id.toIntOrNull() != null) -> when (canvasContext) { - is Course -> "${ApiPrefs.fullDomain}/api/v1/courses/${(canvasContext as Course).id}/external_tools/sessionless_launch?id=$id" - is Group -> "${ApiPrefs.fullDomain}/api/v1/groups/${(canvasContext as Group).id}/external_tools/sessionless_launch?id=$id" - else -> "${ApiPrefs.fullDomain}/api/v1/accounts/self/external_tools/sessionless_launch?id=$id" - } - - else -> { - when (canvasContext) { - is Course -> "${ApiPrefs.fullDomain}/api/v1/courses/${(canvasContext as Course).id}/external_tools/sessionless_launch?url=$url" - is Group -> "${ApiPrefs.fullDomain}/api/v1/groups/${(canvasContext as Group).id}/external_tools/sessionless_launch?url=$url" - else -> "${ApiPrefs.fullDomain}/api/v1/accounts/self/external_tools/sessionless_launch?url=$url" - } - } - } - getSessionlessLtiUrl(url) - } - } else { - launchCustomTab(url) - } - } - else -> displayError() - } - } catch (e: Exception) { - // If it gets here we're in trouble and won't know what the tab is, so just display an error message - displayError() - } - } - - private fun getSessionlessLtiUrl(url: String) { - ltiUrlLaunchJob = weave { - val tool = SubmissionManager.getLtiFromAuthenticationUrlAsync(url, true).await().dataOrNull - tool?.url?.let { launchCustomTab(it) } ?: displayError() - } - } - - private fun launchCustomTab(url: String) { - val uri = Uri.parse(url) - .buildUpon() - .appendQueryParameter("display", "borderless") - .appendQueryParameter("platform", "android") - .build() - - val colorSchemeParams = CustomTabColorSchemeParams.Builder() - .setToolbarColor(canvasContext?.color ?: ThemePrefs.primaryColor) - .build() - - var intent = CustomTabsIntent.Builder() - .setDefaultColorSchemeParams(colorSchemeParams) - .setShowTitle(true) - .build() - .intent - - intent.data = uri - - // Exclude Instructure apps from chooser options - intent = intent.asChooserExcludingInstructure() - - context?.startActivity(intent) - - customTabLaunched = true - } - - private fun displayError() { - toast(R.string.errorOccurred) - (requireContext() as? Activity)?.onBackPressed() - } - - override fun onDestroyView() { - super.onDestroyView() - ltiUrlLaunchJob?.cancel() - } - - companion object { - private const val TAB = "tab" - private const val LTI_URL = "lti_url" - private const val SESSION_LESS = "session_less" - private const val CUSTOM_TAB_LAUNCHED_STATE = "custom_tab_launched_state" - - fun makeTabBundle(canvasContext: CanvasContext, ltiTab: Tab): Bundle { - val args = createBundle(canvasContext) - args.putParcelable(TAB, ltiTab) - return args - } - - fun makeBundle(canvasContext: CanvasContext?, url: String, title: String, sessionLessLaunch: Boolean): Bundle { - val args = createBundle(canvasContext) - args.putString(LTI_URL, url) - args.putBoolean(SESSION_LESS, sessionLessLaunch) - args.putString(Const.TITLE, title) - return args - } - - fun newInstance(args: Bundle) = LtiLaunchFragment().apply { arguments = args } - - fun routeLtiLaunchFragment(activity: FragmentActivity, canvasContext: CanvasContext?, url: String) { - val args = makeBundle(canvasContext, URLDecoder.decode(url, "utf-8"), activity.getString(R.string.utils_externalToolTitle), true) - RouteMatcher.route(activity, Route(LtiLaunchFragment::class.java, canvasContext, args)) - } - } -} diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/PageDetailsFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/PageDetailsFragment.kt index 3ac8a2fcb4..76e102d926 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/PageDetailsFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/PageDetailsFragment.kt @@ -34,6 +34,7 @@ import com.instructure.interactions.MasterDetailInteractions import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_PAGE_DETAILS import com.instructure.pandautils.analytics.ScreenView +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.fragments.BasePresenterFragment import com.instructure.pandautils.utils.ParcelableArg import com.instructure.pandautils.utils.PermissionUtils @@ -87,7 +88,7 @@ class PageDetailsFragment : BasePresenterFragment< @PageViewUrl @Suppress("unused") - private fun makePageViewUrl(): String { + fun makePageViewUrl(): String { val url = StringBuilder(ApiPrefs.fullDomain) page.let { url.append(canvasContext.toAPIString()) @@ -202,7 +203,7 @@ class PageDetailsFragment : BasePresenterFragment< loadHtmlJob = binding.canvasWebViewWraper.webView.loadHtmlWithIframes(requireContext(), page.body, { if (view != null) binding.canvasWebViewWraper.loadHtml(it, page.title, baseUrl = this.page.htmlUrl) }) { - LtiLaunchFragment.routeLtiLaunchFragment(requireActivity(), canvasContext, it) + RouteMatcher.route(requireActivity(), LtiLaunchFragment.makeSessionlessLtiUrlRoute(requireActivity(), canvasContext, it)) } setupToolbar() } diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/PageListFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/PageListFragment.kt index 583b6df008..0dddfc2acd 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/PageListFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/PageListFragment.kt @@ -25,6 +25,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Page import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_PAGE_LIST import com.instructure.pandautils.analytics.ScreenView @@ -66,7 +67,8 @@ class PageListFragment : BaseSyncFragment? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/QuizDetailsFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/QuizDetailsFragment.kt index 59b84fb8fd..2e82c965ac 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/QuizDetailsFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/QuizDetailsFragment.kt @@ -36,6 +36,7 @@ import com.instructure.interactions.MasterDetailInteractions import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_EDIT_QUIZ_DETAILS import com.instructure.pandautils.analytics.ScreenView +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.fragments.BasePresenterFragment import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.LongArg @@ -405,7 +406,7 @@ class QuizDetailsFragment : BasePresenterFragment< loadHtmlJob = instructionsWebViewWrapper.webView.loadHtmlWithIframes(requireContext(), quiz.description, { instructionsWebViewWrapper.loadHtml(it, quiz.title, baseUrl = this@QuizDetailsFragment.quiz.htmlUrl) }) { - LtiLaunchFragment.routeLtiLaunchFragment(requireActivity(), canvasContext, it) + RouteMatcher.route(requireActivity(), LtiLaunchFragment.makeSessionlessLtiUrlRoute(requireActivity(), canvasContext, it)) } } diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/QuizListFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/QuizListFragment.kt index 209258b92d..e105b55399 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/QuizListFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/QuizListFragment.kt @@ -24,6 +24,7 @@ import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Quiz import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.pageview.PageView +import com.instructure.canvasapi2.utils.pageview.PageViewUrlParam import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_QUIZ_LIST import com.instructure.pandautils.analytics.ScreenView @@ -66,7 +67,8 @@ class QuizListFragment : BaseExpandableSyncFragment< private val binding by viewBinding(FragmentQuizListBinding::bind) - private var canvasContext: CanvasContext by ParcelableArg(default = CanvasContext.getGenericContext(CanvasContext.Type.COURSE, -1L, "")) + @get:PageViewUrlParam("canvasContext") + var canvasContext: CanvasContext by ParcelableArg(default = CanvasContext.getGenericContext(CanvasContext.Type.COURSE, -1L, "")) private val linearLayoutManager by lazy { LinearLayoutManager(requireContext()) } private lateinit var mRecyclerView: RecyclerView diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SettingsFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SettingsFragment.kt deleted file mode 100644 index 5fb497aa7e..0000000000 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SettingsFragment.kt +++ /dev/null @@ -1,141 +0,0 @@ -/* -* Copyright (C) 2017 - present Instructure, Inc. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3 of the License. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -*/ -package com.instructure.teacher.fragments - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import com.instructure.canvasapi2.models.CanvasContext -import com.instructure.interactions.router.Route -import com.instructure.pandautils.analytics.SCREEN_VIEW_SETTINGS -import com.instructure.pandautils.analytics.ScreenView -import com.instructure.pandautils.dialogs.RatingDialog -import com.instructure.pandautils.features.about.AboutFragment -import com.instructure.pandautils.features.legal.LegalDialogFragment -import com.instructure.pandautils.features.notification.preferences.EmailNotificationPreferencesFragment -import com.instructure.pandautils.features.notification.preferences.PushNotificationPreferencesFragment -import com.instructure.pandautils.fragments.BasePresenterFragment -import com.instructure.pandautils.fragments.RemoteConfigParamsFragment -import com.instructure.pandautils.utils.AppTheme -import com.instructure.pandautils.utils.AppThemeSelector -import com.instructure.pandautils.utils.AppType -import com.instructure.pandautils.utils.Const -import com.instructure.pandautils.utils.NullableParcelableArg -import com.instructure.pandautils.utils.ThemePrefs -import com.instructure.pandautils.utils.ViewStyler -import com.instructure.pandautils.utils.makeBundle -import com.instructure.pandautils.utils.onClick -import com.instructure.pandautils.utils.setVisible -import com.instructure.teacher.BuildConfig -import com.instructure.teacher.R -import com.instructure.teacher.databinding.FragmentSettingsBinding -import com.instructure.teacher.factory.ProfileSettingsFragmentPresenterFactory -import com.instructure.teacher.presenters.ProfileSettingsFragmentPresenter -import com.instructure.teacher.router.RouteMatcher -import com.instructure.teacher.utils.setupBackButton -import com.instructure.teacher.viewinterface.ProfileSettingsFragmentView - -@ScreenView(SCREEN_VIEW_SETTINGS) -class SettingsFragment : BasePresenterFragment< - ProfileSettingsFragmentPresenter, - ProfileSettingsFragmentView, - FragmentSettingsBinding>(), - ProfileSettingsFragmentView { - - private var canvasContext: CanvasContext? by NullableParcelableArg(key = Const.CANVAS_CONTEXT) - - override val bindingInflater: (layoutInflater: LayoutInflater) -> FragmentSettingsBinding = FragmentSettingsBinding::inflate - - override fun onActivityCreated(savedInstanceState: Bundle?) = with(binding) { - super.onActivityCreated(savedInstanceState) - versionTextView.text = getString(R.string.fullVersion, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE) - profileButton.onClick { - RouteMatcher.route( - requireActivity(), - Route(null, ProfileFragment::class.java, canvasContext, canvasContext?.makeBundle() ?: Bundle()) - ) - } - rateButton.onClick { RatingDialog.showRateDialog(requireActivity(), AppType.TEACHER) } - aboutButton.onClick { AboutFragment.newInstance().show(childFragmentManager, null) } - legalButton.onClick { LegalDialogFragment().show(requireFragmentManager(), null) } - notificationPreferenesButton.onClick { - RouteMatcher.route( - requireActivity(), - Route(null, PushNotificationPreferencesFragment::class.java, canvasContext, canvasContext?.makeBundle() ?: Bundle()) - ) - } - emailNotifications.onClick { - RouteMatcher.route( - requireActivity(), - Route(null, EmailNotificationPreferencesFragment::class.java, canvasContext, canvasContext?.makeBundle() ?: Bundle()) - ) - } - if (BuildConfig.DEBUG) { - featureFlagButton.setVisible() - featureFlagButton.onClick { - RouteMatcher.route( - requireActivity(), - Route(null, FeatureFlagsFragment::class.java, canvasContext, canvasContext?.makeBundle() ?: Bundle()) - ) - } - - remoteConfigButton.setVisible() - remoteConfigButton.onClick { - RouteMatcher.route( - requireActivity(), - Route(null, RemoteConfigParamsFragment::class.java, canvasContext, canvasContext?.makeBundle() ?: Bundle()) - ) - } - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - setUpAppThemeSelector() - } - - private fun setUpAppThemeSelector() = with(binding) { - val initialAppTheme = AppTheme.fromIndex(ThemePrefs.appTheme) - appThemeStatus.setText(initialAppTheme.themeNameRes) - - appThemeContainer.onClick { - AppThemeSelector.showAppThemeSelectorDialog(requireContext(), appThemeStatus) - } - } - - override fun getPresenterFactory() = ProfileSettingsFragmentPresenterFactory() - - override fun onReadySetGo(presenter: ProfileSettingsFragmentPresenter) { - setupToolbar() - } - - fun setupToolbar() = with(binding) { - toolbar.setupBackButton(this@SettingsFragment) - toolbar.title = getString(R.string.settings) - ViewStyler.themeToolbarColored(requireActivity(), toolbar, ThemePrefs.primaryColor, ThemePrefs.primaryTextColor) - } - - override fun onRefreshStarted() {} - - override fun onRefreshFinished() {} - - override fun onPresenterPrepared(presenter: ProfileSettingsFragmentPresenter) {} - - companion object { - fun newInstance(args: Bundle) = SettingsFragment().apply { arguments = args } - } -} diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderEmptyFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderEmptyFragment.kt index 19975d3be0..7e7dd8efbd 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderEmptyFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderEmptyFragment.kt @@ -20,7 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.bumptech.glide.Glide import com.instructure.pandautils.analytics.SCREEN_VIEW_SPEED_GRADER_EMPTY import com.instructure.pandautils.analytics.ScreenView @@ -33,7 +33,7 @@ import com.instructure.teacher.R import com.instructure.teacher.databinding.FragmentSpeedgraderEmptyBinding @ScreenView(SCREEN_VIEW_SPEED_GRADER_EMPTY) -class SpeedGraderEmptyFragment : Fragment() { +class SpeedGraderEmptyFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentSpeedgraderEmptyBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderLtiSubmissionFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderLtiSubmissionFragment.kt index ad31cc278e..ba3a0df565 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderLtiSubmissionFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderLtiSubmissionFragment.kt @@ -20,28 +20,26 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment -import com.instructure.canvasapi2.models.CanvasContext -import com.instructure.interactions.router.Route +import android.webkit.WebView import com.instructure.pandautils.analytics.SCREEN_VIEW_SPEED_GRADER_LTI_SUBMISSION import com.instructure.pandautils.analytics.ScreenView +import com.instructure.pandautils.base.BaseCanvasFragment import com.instructure.pandautils.binding.viewBinding -import com.instructure.pandautils.utils.ParcelableArg import com.instructure.pandautils.utils.StringArg -import com.instructure.pandautils.utils.ViewStyler -import com.instructure.pandautils.utils.onClick +import com.instructure.pandautils.utils.enableAlgorithmicDarkening +import com.instructure.pandautils.utils.setGone +import com.instructure.pandautils.utils.setVisible +import com.instructure.pandautils.views.CanvasWebView import com.instructure.teacher.R import com.instructure.teacher.databinding.FragmentSpeedGraderLtiSubmissionBinding -import com.instructure.teacher.router.RouteMatcher import com.instructure.teacher.view.ExternalToolContent @ScreenView(SCREEN_VIEW_SPEED_GRADER_LTI_SUBMISSION) -class SpeedGraderLtiSubmissionFragment : Fragment() { +class SpeedGraderLtiSubmissionFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentSpeedGraderLtiSubmissionBinding::bind) - private var mUrl by StringArg() - private var mCanvasContext by ParcelableArg() + private var url by StringArg() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_speed_grader_lti_submission, container, false) @@ -53,19 +51,30 @@ class SpeedGraderLtiSubmissionFragment : Fragment() { } private fun setupViews() { - ViewStyler.themeButton(binding.viewLtiButton) - binding.viewLtiButton.onClick { - val args = InternalWebViewFragment.makeBundle(mUrl, getString(R.string.canvasAPI_externalTool), shouldAuthenticate = true, shouldRouteInternally = false) - RouteMatcher.route(requireActivity(), Route(InternalWebViewFragment::class.java, mCanvasContext, args)) + binding.webView.enableAlgorithmicDarkening() + binding.webView.setZoomSettings(false) + binding.webView.canvasWebViewClientCallback = object : CanvasWebView.CanvasWebViewClientCallback { + override fun openMediaFromWebView(mime: String, url: String, filename: String) = Unit + + override fun onPageStartedCallback(webView: WebView, url: String) { + if (isAdded) binding.webViewProgress.setVisible() + } + + override fun onPageFinishedCallback(webView: WebView, url: String) { + if (isAdded) binding.webViewProgress.setGone() + } + + override fun canRouteInternallyDelegate(url: String): Boolean = false + + override fun routeInternallyCallback(url: String) = Unit } + binding.webView.loadUrl(url) } companion object { fun newInstance(content: ExternalToolContent) = SpeedGraderLtiSubmissionFragment().apply { - mCanvasContext = content.canvasContext - mUrl = content.url + url = content.url } } - } diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderQuizSubmissionFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderQuizSubmissionFragment.kt index c16e016ad9..68c0938006 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderQuizSubmissionFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderQuizSubmissionFragment.kt @@ -20,7 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_SPEED_GRADER_QUIZ_SUBMISSION import com.instructure.pandautils.analytics.ScreenView @@ -36,7 +36,7 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode @ScreenView(SCREEN_VIEW_SPEED_GRADER_QUIZ_SUBMISSION) -class SpeedGraderQuizSubmissionFragment : Fragment() { +class SpeedGraderQuizSubmissionFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentSpeedGraderQuizSubmissionBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderTextSubmissionFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderTextSubmissionFragment.kt index b898c8764f..00469d4935 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderTextSubmissionFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderTextSubmissionFragment.kt @@ -22,7 +22,7 @@ import android.view.View import android.view.ViewGroup import android.webkit.WebChromeClient import android.webkit.WebView -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.pandautils.analytics.SCREEN_VIEW_SPEED_GRADER_TEXT_SUBMISSION import com.instructure.pandautils.analytics.ScreenView @@ -38,7 +38,7 @@ import com.instructure.teacher.interfaces.SpeedGraderWebNavigator import com.instructure.teacher.router.RouteMatcher @ScreenView(SCREEN_VIEW_SPEED_GRADER_TEXT_SUBMISSION) -class SpeedGraderTextSubmissionFragment : Fragment(), SpeedGraderWebNavigator { +class SpeedGraderTextSubmissionFragment : BaseCanvasFragment(), SpeedGraderWebNavigator { private val binding by viewBinding(FragmentSpeedGraderTextSubmissionBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderUrlSubmissionFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderUrlSubmissionFragment.kt index f0f1caec2e..5c03a924c2 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderUrlSubmissionFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/SpeedGraderUrlSubmissionFragment.kt @@ -19,7 +19,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.bumptech.glide.Glide import com.instructure.pandautils.analytics.SCREEN_VIEW_SPEED_GRADER_URL_SUBMISSION import com.instructure.pandautils.analytics.ScreenView @@ -33,7 +33,7 @@ import com.instructure.teacher.activities.InternalWebViewActivity import com.instructure.teacher.databinding.FragmentSpeedgraderUrlSubmissionBinding @ScreenView(SCREEN_VIEW_SPEED_GRADER_URL_SUBMISSION) -class SpeedGraderUrlSubmissionFragment : Fragment() { +class SpeedGraderUrlSubmissionFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentSpeedgraderUrlSubmissionBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewImageFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewImageFragment.kt index 4ae84977e3..7ae3dfc622 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewImageFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewImageFragment.kt @@ -22,7 +22,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.palette.graphics.Palette import com.bumptech.glide.Glide import com.bumptech.glide.load.DataSource @@ -48,7 +48,7 @@ import com.instructure.teacher.utils.updateToolbarExpandCollapseIcon import org.greenrobot.eventbus.EventBus @ScreenView(SCREEN_VIEW_VIEW_IMAGE) -class ViewImageFragment : Fragment(), ShareableFile { +class ViewImageFragment : BaseCanvasFragment(), ShareableFile { private val binding by viewBinding(FragmentViewImageBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewMediaFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewMediaFragment.kt index 51758d8a5e..9c5ca056b6 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewMediaFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewMediaFragment.kt @@ -24,7 +24,7 @@ import android.view.ViewGroup import android.widget.ImageButton import androidx.annotation.OptIn import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.media3.common.util.UnstableApi import androidx.media3.datasource.HttpDataSource import androidx.media3.exoplayer.source.UnrecognizedInputFormatException @@ -50,7 +50,7 @@ import com.instructure.teacher.view.MediaContent import org.greenrobot.eventbus.EventBus @ScreenView(SCREEN_VIEW_VIEW_MEDIA) -class ViewMediaFragment : Fragment(), ShareableFile { +class ViewMediaFragment : BaseCanvasFragment(), ShareableFile { private val binding by viewBinding(FragmentSpeedGraderMediaBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewPdfFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewPdfFragment.kt index c1a87ca423..d23b3444f6 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewPdfFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewPdfFragment.kt @@ -39,7 +39,7 @@ import com.instructure.teacher.viewinterface.ViewPdfFragmentView import com.pspdfkit.configuration.PdfConfiguration import com.pspdfkit.configuration.page.PageScrollDirection import com.pspdfkit.ui.PdfFragment -import instructure.androidblueprint.PresenterFragment +import com.instructure.pandautils.blueprint.PresenterFragment import org.greenrobot.eventbus.EventBus @ScreenView(SCREEN_VIEW_VIEW_PDF) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewUnsupportedFileFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewUnsupportedFileFragment.kt index 6567f95358..aceee9b635 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewUnsupportedFileFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/fragments/ViewUnsupportedFileFragment.kt @@ -21,7 +21,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.annotation.DrawableRes -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions import com.instructure.annotations.FileCaching.FileCache @@ -61,7 +61,7 @@ import org.greenrobot.eventbus.EventBus import java.io.File @ScreenView(SCREEN_VIEW_VIEW_UNSUPPORTED_FILE) -class ViewUnsupportedFileFragment : Fragment() { +class ViewUnsupportedFileFragment : BaseCanvasFragment() { private val binding by viewBinding(FragmentUnsupportedFileTypeBinding::bind) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/holders/AssignmentViewHolder.kt b/apps/teacher/src/main/java/com/instructure/teacher/holders/AssignmentViewHolder.kt index fa9492aab4..76b0a4c0bc 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/holders/AssignmentViewHolder.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/holders/AssignmentViewHolder.kt @@ -25,12 +25,12 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.utils.DateHelper import com.instructure.canvasapi2.utils.NumberHelper import com.instructure.pandautils.utils.ThemePrefs +import com.instructure.pandautils.utils.getAssignmentIcon import com.instructure.pandautils.utils.setGone import com.instructure.pandautils.utils.setVisible import com.instructure.teacher.R import com.instructure.teacher.databinding.AdapterAssignmentBinding -import com.instructure.teacher.utils.getAssignmentIcon -import java.util.* +import java.util.Date class AssignmentViewHolder(private val binding: AdapterAssignmentBinding) : RecyclerView.ViewHolder(binding.root) { init { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/holders/ToDoViewHolder.kt b/apps/teacher/src/main/java/com/instructure/teacher/holders/ToDoViewHolder.kt index f2be0754bf..89dba65fee 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/holders/ToDoViewHolder.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/holders/ToDoViewHolder.kt @@ -27,12 +27,12 @@ import com.instructure.canvasapi2.utils.DateHelper import com.instructure.canvasapi2.utils.NumberHelper import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.color +import com.instructure.pandautils.utils.getAssignmentIcon import com.instructure.pandautils.utils.setGone import com.instructure.pandautils.utils.setVisible import com.instructure.teacher.R import com.instructure.teacher.databinding.AdapterTodoBinding import com.instructure.teacher.interfaces.AdapterToFragmentCallback -import com.instructure.teacher.utils.getAssignmentIcon import java.util.Date class ToDoViewHolder(private val binding: AdapterTodoBinding) : RecyclerView.ViewHolder(binding.root) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/mobius/common/ui/MobiusFragment.kt b/apps/teacher/src/main/java/com/instructure/teacher/mobius/common/ui/MobiusFragment.kt index 6149b5b7ee..7389cf0749 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/mobius/common/ui/MobiusFragment.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/mobius/common/ui/MobiusFragment.kt @@ -22,7 +22,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment +import com.instructure.pandautils.base.BaseCanvasFragment import androidx.viewbinding.ViewBinding import com.instructure.pandautils.utils.getFragmentActivity import com.instructure.teacher.mobius.common.ConsumerQueueWrapper @@ -44,7 +44,7 @@ import com.spotify.mobius.android.runners.MainThreadWorkRunner import com.spotify.mobius.functions.Consumer import kotlinx.android.extensions.LayoutContainer -abstract class MobiusFragment, VIEW_STATE, BINDING: ViewBinding> : Fragment() { +abstract class MobiusFragment, VIEW_STATE, BINDING: ViewBinding> : BaseCanvasFragment() { var overrideInitModel: MODEL? = null var overrideInitViewState: VIEW_STATE? = null diff --git a/apps/teacher/src/main/java/com/instructure/teacher/navigation/TeacherWebViewRouter.kt b/apps/teacher/src/main/java/com/instructure/teacher/navigation/TeacherWebViewRouter.kt index 3540d69515..4d15cf9e9f 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/navigation/TeacherWebViewRouter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/navigation/TeacherWebViewRouter.kt @@ -21,11 +21,11 @@ import androidx.fragment.app.FragmentActivity import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.interactions.router.Route +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.navigation.WebViewRouter import com.instructure.teacher.activities.InternalWebViewActivity import com.instructure.teacher.fragments.FullscreenInternalWebViewFragment import com.instructure.teacher.fragments.InternalWebViewFragment -import com.instructure.teacher.fragments.LtiLaunchFragment import com.instructure.teacher.router.RouteMatcher class TeacherWebViewRouter(val activity: FragmentActivity) : WebViewRouter { @@ -53,7 +53,7 @@ class TeacherWebViewRouter(val activity: FragmentActivity) : WebViewRouter { } override fun openLtiScreen(canvasContext: CanvasContext?, url: String) { - LtiLaunchFragment.routeLtiLaunchFragment(activity, canvasContext, url) + RouteMatcher.route(activity, LtiLaunchFragment.makeSessionlessLtiUrlRoute(activity, canvasContext, url)) } override fun launchInternalWebViewFragment(url: String, canvasContext: CanvasContext?) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/AddMessagePresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/AddMessagePresenter.kt index dd3801dacc..fafe57b6ff 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/AddMessagePresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/AddMessagePresenter.kt @@ -26,7 +26,7 @@ import com.instructure.canvasapi2.utils.LinkHeaders import com.instructure.canvasapi2.utils.weave.inParallel import com.instructure.canvasapi2.utils.weave.weave import com.instructure.teacher.viewinterface.AddMessageView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job import retrofit2.Call import retrofit2.Response diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/AssigneeListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/AssigneeListPresenter.kt index 52f4555d41..a020db51a9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/AssigneeListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/AssigneeListPresenter.kt @@ -27,7 +27,7 @@ import com.instructure.teacher.models.AssigneeCategory import com.instructure.teacher.models.EveryoneAssignee import com.instructure.teacher.utils.EditDateGroups import com.instructure.teacher.viewinterface.AssigneeListView -import instructure.androidblueprint.SyncExpandablePresenter +import com.instructure.pandautils.blueprint.SyncExpandablePresenter import org.greenrobot.eventbus.EventBus import java.util.* diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/AttendanceListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/AttendanceListPresenter.kt index 2433572c38..c4c010eb78 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/AttendanceListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/AttendanceListPresenter.kt @@ -29,7 +29,7 @@ import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.teacher.viewinterface.AttendanceListView -import instructure.androidblueprint.SyncPresenter +import com.instructure.pandautils.blueprint.SyncPresenter import kotlinx.coroutines.Job import kotlinx.coroutines.delay import retrofit2.Call diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/ChooseRecipientsPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/ChooseRecipientsPresenter.kt index e6cc1e5ef5..c6c252d268 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/ChooseRecipientsPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/ChooseRecipientsPresenter.kt @@ -22,10 +22,10 @@ import com.instructure.canvasapi2.managers.RecipientManager import com.instructure.canvasapi2.models.Recipient import com.instructure.canvasapi2.utils.ApiType import com.instructure.canvasapi2.utils.LinkHeaders +import com.instructure.pandautils.blueprint.SyncPresenter import com.instructure.teacher.viewinterface.ChooseRecipientsView -import instructure.androidblueprint.SyncPresenter import retrofit2.Response -import java.util.* +import java.util.Stack class ChooseRecipientsPresenter(rootContextId: String) : SyncPresenter(Recipient::class.java) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseBrowserEmptyPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseBrowserEmptyPresenter.kt index 331a6b2ef4..5e6baed345 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseBrowserEmptyPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseBrowserEmptyPresenter.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.presenters import com.instructure.canvasapi2.models.Course import com.instructure.teacher.viewinterface.CourseBrowserEmptyView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter class CourseBrowserEmptyPresenter(val course: Course) : FragmentPresenter() { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseBrowserPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseBrowserPresenter.kt index 60dafefbf6..2a720be947 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseBrowserPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseBrowserPresenter.kt @@ -20,15 +20,17 @@ import com.instructure.canvasapi2.apis.AttendanceAPI import com.instructure.canvasapi2.managers.CourseManager import com.instructure.canvasapi2.managers.LaunchDefinitionsManager import com.instructure.canvasapi2.managers.TabManager -import com.instructure.canvasapi2.models.* -import com.instructure.canvasapi2.utils.RemoteConfigParam -import com.instructure.canvasapi2.utils.RemoteConfigUtils +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.models.CanvasContextPermission +import com.instructure.canvasapi2.models.Group +import com.instructure.canvasapi2.models.LaunchDefinition +import com.instructure.canvasapi2.models.Tab import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.canvasapi2.utils.weave.awaitApiResponse import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave +import com.instructure.pandautils.blueprint.SyncPresenter import com.instructure.teacher.viewinterface.CourseBrowserView -import instructure.androidblueprint.SyncPresenter import kotlinx.coroutines.Job class CourseBrowserPresenter(val canvasContext: CanvasContext, val filter: (Tab, Long) -> Boolean) : SyncPresenter(Tab::class.java) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseSettingsFragmentPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseSettingsFragmentPresenter.kt index eb04902ca4..18510a5765 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseSettingsFragmentPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CourseSettingsFragmentPresenter.kt @@ -23,7 +23,7 @@ import com.instructure.canvasapi2.utils.ApiType import com.instructure.canvasapi2.utils.LinkHeaders import com.instructure.teacher.events.CourseUpdatedEvent import com.instructure.teacher.viewinterface.CourseSettingsFragmentView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import org.greenrobot.eventbus.EventBus import retrofit2.Response diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateDiscussionPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateDiscussionPresenter.kt index 050a27ba27..98e3babf14 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateDiscussionPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateDiscussionPresenter.kt @@ -34,7 +34,7 @@ import com.instructure.teacher.events.DiscussionTopicHeaderDeletedEvent import com.instructure.teacher.events.post import com.instructure.teacher.interfaces.RceMediaUploadPresenter import com.instructure.teacher.viewinterface.CreateDiscussionView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateOrEditAnnouncementPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateOrEditAnnouncementPresenter.kt index 48bdf05162..74ecab11c9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateOrEditAnnouncementPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateOrEditAnnouncementPresenter.kt @@ -38,7 +38,7 @@ import com.instructure.teacher.events.DiscussionUpdatedEvent import com.instructure.teacher.events.post import com.instructure.teacher.interfaces.RceMediaUploadPresenter import com.instructure.teacher.viewinterface.CreateOrEditAnnouncementView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateOrEditPagePresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateOrEditPagePresenter.kt index 763e4acd09..3fad2c1670 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateOrEditPagePresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/CreateOrEditPagePresenter.kt @@ -38,7 +38,7 @@ import com.instructure.teacher.events.post import com.instructure.teacher.fragments.PageDetailsFragment import com.instructure.teacher.interfaces.RceMediaUploadPresenter import com.instructure.teacher.viewinterface.CreateOrEditPageView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import retrofit2.Response class CreateOrEditPagePresenter(private val canvasContext: CanvasContext, mPage: Page? = null) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/DashboardPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/DashboardPresenter.kt index e1fe9fb3ca..537fd0ac8a 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/DashboardPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/DashboardPresenter.kt @@ -18,11 +18,10 @@ package com.instructure.teacher.presenters import com.instructure.canvasapi2.managers.CourseManager import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.models.DashboardCard -import com.instructure.canvasapi2.utils.hasActiveEnrollment import com.instructure.canvasapi2.utils.weave.apiAsync +import com.instructure.pandautils.blueprint.SyncPresenter import com.instructure.pandautils.utils.ColorApiHelper import com.instructure.teacher.viewinterface.CoursesView -import instructure.androidblueprint.SyncPresenter import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/DiscussionListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/DiscussionListPresenter.kt index fd14c3e727..ebe86e4e0c 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/DiscussionListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/DiscussionListPresenter.kt @@ -30,7 +30,7 @@ import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.interactions.router.Route import com.instructure.pandautils.features.discussion.router.DiscussionRouterFragment import com.instructure.teacher.viewinterface.DiscussionListView -import instructure.androidblueprint.SyncExpandablePresenter +import com.instructure.pandautils.blueprint.SyncExpandablePresenter import kotlinx.coroutines.Job import retrofit2.Response import java.util.* diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/DiscussionsUpdatePresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/DiscussionsUpdatePresenter.kt index 2887c51c20..a347900054 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/DiscussionsUpdatePresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/DiscussionsUpdatePresenter.kt @@ -32,7 +32,7 @@ import com.instructure.canvasapi2.models.postmodels.FileSubmitObject import com.instructure.pandautils.utils.MediaUploadUtils import com.instructure.teacher.interfaces.RceMediaUploadPresenter import com.instructure.teacher.viewinterface.DiscussionsUpdateView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job class DiscussionsUpdatePresenter( diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/DueDatesPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/DueDatesPresenter.kt index 0cf16dd835..f5b8e998f0 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/DueDatesPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/DueDatesPresenter.kt @@ -27,11 +27,11 @@ import com.instructure.canvasapi2.models.User import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.canvasapi2.utils.weave.inParallel import com.instructure.canvasapi2.utils.weave.weave +import com.instructure.pandautils.blueprint.SyncPresenter import com.instructure.teacher.events.AssignmentUpdatedEvent import com.instructure.teacher.models.DueDateGroup import com.instructure.teacher.utils.groupedDueDates import com.instructure.teacher.viewinterface.DueDatesView -import instructure.androidblueprint.SyncPresenter import kotlinx.coroutines.Job import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/EditFileFolderPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/EditFileFolderPresenter.kt index dfe69f8040..c3d7ddac94 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/EditFileFolderPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/EditFileFolderPresenter.kt @@ -25,7 +25,7 @@ import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.teacher.R import com.instructure.teacher.view.EditFileView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job import java.util.* diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/EditQuizDetailsPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/EditQuizDetailsPresenter.kt index 589b282f60..c2ad45a913 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/EditQuizDetailsPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/EditQuizDetailsPresenter.kt @@ -26,7 +26,7 @@ import com.instructure.teacher.events.QuizUpdatedEvent import com.instructure.teacher.events.post import com.instructure.teacher.models.DueDateGroup import com.instructure.teacher.viewinterface.EditQuizDetailsView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job class EditQuizDetailsPresenter(var mQuiz: Quiz, var mAssignment: Assignment, val canvasContext: CanvasContext) : FragmentPresenter() { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/FileListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/FileListPresenter.kt index db83b17a9f..a591879e70 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/FileListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/FileListPresenter.kt @@ -18,16 +18,18 @@ package com.instructure.teacher.presenters import com.instructure.canvasapi2.managers.FeaturesManager import com.instructure.canvasapi2.managers.FileFolderManager -import com.instructure.canvasapi2.models.* +import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.models.CreateFolder +import com.instructure.canvasapi2.models.FileFolder +import com.instructure.canvasapi2.models.Group +import com.instructure.canvasapi2.models.License import com.instructure.canvasapi2.utils.Logger -import com.instructure.canvasapi2.utils.isValid import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.canvasapi2.utils.weave.awaitApis import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave +import com.instructure.pandautils.blueprint.SyncPresenter import com.instructure.teacher.viewinterface.FileListView -import instructure.androidblueprint.ListChangeCallback -import instructure.androidblueprint.SyncPresenter import kotlinx.coroutines.Job class FileListPresenter(var currentFolder: FileFolder, val mCanvasContext: CanvasContext) : SyncPresenter(FileFolder::class.java) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/InitActivityPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/InitActivityPresenter.kt index 66a5d60edc..e12af34d3d 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/InitActivityPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/InitActivityPresenter.kt @@ -31,7 +31,7 @@ import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.teacher.events.CourseColorOverlayToggledEvent import com.instructure.teacher.utils.TeacherPrefs import com.instructure.teacher.viewinterface.InitActivityView -import instructure.androidblueprint.Presenter +import com.instructure.pandautils.blueprint.Presenter import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/InternalWebViewPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/InternalWebViewPresenter.kt index baf77a7779..a13c251ef8 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/InternalWebViewPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/InternalWebViewPresenter.kt @@ -16,7 +16,7 @@ package com.instructure.teacher.presenters import com.instructure.teacher.viewinterface.InternalWebView -import instructure.androidblueprint.Presenter +import com.instructure.pandautils.blueprint.Presenter class InternalWebViewPresenter : Presenter { override fun onViewAttached(view: InternalWebView) = this diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/MessageThreadPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/MessageThreadPresenter.kt index 023da3f502..4ce876bc67 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/MessageThreadPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/MessageThreadPresenter.kt @@ -28,7 +28,7 @@ import com.instructure.canvasapi2.models.Message import com.instructure.canvasapi2.utils.weave.* import com.instructure.teacher.R import com.instructure.teacher.viewinterface.MessageThreadView -import instructure.androidblueprint.SyncPresenter +import com.instructure.pandautils.blueprint.SyncPresenter import kotlinx.coroutines.Job import java.util.* diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/PageDetailsPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/PageDetailsPresenter.kt index e03b1c9734..cd7565b1c4 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/PageDetailsPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/PageDetailsPresenter.kt @@ -25,7 +25,7 @@ import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.teacher.R import com.instructure.teacher.viewinterface.PageDetailsView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job class PageDetailsPresenter(val mCanvasContext: CanvasContext, var mPage: Page) : FragmentPresenter() { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/PageListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/PageListPresenter.kt index aec04fbb9f..8ff01cdddd 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/PageListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/PageListPresenter.kt @@ -24,7 +24,7 @@ import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.teacher.viewinterface.PageListView -import instructure.androidblueprint.SyncPresenter +import com.instructure.pandautils.blueprint.SyncPresenter import kotlinx.coroutines.Job class PageListPresenter(private val mCanvasContext: CanvasContext) : diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/PeopleListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/PeopleListPresenter.kt index ad03838028..ae9bba1017 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/PeopleListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/PeopleListPresenter.kt @@ -28,7 +28,7 @@ import com.instructure.canvasapi2.utils.ApiType import com.instructure.canvasapi2.utils.LinkHeaders import com.instructure.canvasapi2.utils.NaturalOrderComparator import com.instructure.teacher.viewinterface.PeopleListView -import instructure.androidblueprint.SyncPresenter +import com.instructure.pandautils.blueprint.SyncPresenter import retrofit2.Response import java.util.* diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/ProfileEditFragmentPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/ProfileEditFragmentPresenter.kt index 5f37538834..4300892766 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/ProfileEditFragmentPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/ProfileEditFragmentPresenter.kt @@ -24,7 +24,7 @@ import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.ApiType import com.instructure.canvasapi2.utils.LinkHeaders import com.instructure.teacher.viewinterface.ProfileEditFragmentView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job import retrofit2.Call import retrofit2.Response diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/QuizDetailsPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/QuizDetailsPresenter.kt index 0ce3e55219..bbbd29163f 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/QuizDetailsPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/QuizDetailsPresenter.kt @@ -25,7 +25,7 @@ import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.canvasapi2.utils.weave.weave import com.instructure.teacher.viewinterface.QuizDetailsView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job class QuizDetailsPresenter(val mCourse: Course, var mQuiz: Quiz) : FragmentPresenter() { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/QuizListPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/QuizListPresenter.kt index cf71eae1a3..89ebbdbd82 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/QuizListPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/QuizListPresenter.kt @@ -26,7 +26,7 @@ import com.instructure.canvasapi2.utils.weave.awaitApis import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.teacher.viewinterface.QuizListView -import instructure.androidblueprint.SyncExpandablePresenter +import com.instructure.pandautils.blueprint.SyncExpandablePresenter import kotlinx.coroutines.Job class QuizListPresenter(private val mCanvasContext: CanvasContext) : diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderCommentsPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderCommentsPresenter.kt index 71191aed4b..ecc143bbb1 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderCommentsPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderCommentsPresenter.kt @@ -41,7 +41,7 @@ import com.instructure.teacher.models.PendingCommentWrapper import com.instructure.teacher.models.SubmissionCommentWrapper import com.instructure.teacher.models.SubmissionWrapper import com.instructure.teacher.viewinterface.SpeedGraderCommentsView -import instructure.androidblueprint.ListPresenter +import com.instructure.pandautils.blueprint.ListPresenter import kotlinx.coroutines.Job import java.util.* diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderFilesPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderFilesPresenter.kt index 8e18bc2938..9ddf982ab0 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderFilesPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderFilesPresenter.kt @@ -21,7 +21,7 @@ import com.instructure.canvasapi2.models.Attachment import com.instructure.canvasapi2.models.Submission import com.instructure.teacher.utils.asMediaSubmissionPlaceholder import com.instructure.teacher.viewinterface.SpeedGraderFilesView -import instructure.androidblueprint.SyncPresenter +import com.instructure.pandautils.blueprint.SyncPresenter class SpeedGraderFilesPresenter(private var mSubmission: Submission?) : SyncPresenter(Attachment::class.java) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderGradePresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderGradePresenter.kt index 36e6186e6d..f60446c345 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderGradePresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderGradePresenter.kt @@ -25,7 +25,7 @@ import com.instructure.teacher.events.AssignmentGradedEvent import com.instructure.teacher.events.SubmissionUpdatedEvent import com.instructure.teacher.events.post import com.instructure.teacher.viewinterface.SpeedGraderGradeView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.* class SpeedGraderGradePresenter(var submission: Submission?, val assignment: Assignment, val course: Course, val assignee: Assignee) : FragmentPresenter() { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderPresenter.kt index 455ec5b774..ef0b33f685 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/SpeedGraderPresenter.kt @@ -43,7 +43,7 @@ import com.instructure.teacher.features.assignment.submission.SubmissionListFilt import com.instructure.teacher.utils.getState import com.instructure.teacher.utils.transformForQuizGrading import com.instructure.teacher.viewinterface.SpeedGraderView -import instructure.androidblueprint.Presenter +import com.instructure.pandautils.blueprint.Presenter import kotlinx.coroutines.Job import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/StudentContextPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/StudentContextPresenter.kt index a7222b2c60..594137b1a8 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/StudentContextPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/StudentContextPresenter.kt @@ -24,7 +24,7 @@ import com.instructure.canvasapi2.utils.weave.awaitQLPaginated import com.instructure.canvasapi2.utils.weave.catch import com.instructure.canvasapi2.utils.weave.tryWeave import com.instructure.teacher.viewinterface.StudentContextView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter class StudentContextPresenter( diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/ToDoPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/ToDoPresenter.kt index dbdba4f217..b6fb7082b3 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/ToDoPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/ToDoPresenter.kt @@ -25,7 +25,7 @@ import com.instructure.teacher.events.ToDoListUpdatedEvent import com.instructure.teacher.features.assignment.submission.AssignmentSubmissionListPresenter.Companion.makeGroupSubmissions import com.instructure.teacher.utils.getState import com.instructure.teacher.viewinterface.ToDoView -import instructure.androidblueprint.SyncPresenter +import com.instructure.pandautils.blueprint.SyncPresenter import org.greenrobot.eventbus.EventBus class ToDoPresenter : SyncPresenter(ToDo::class.java) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/presenters/ViewPdfFragmentPresenter.kt b/apps/teacher/src/main/java/com/instructure/teacher/presenters/ViewPdfFragmentPresenter.kt index bdebae27fa..15969a3d0a 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/presenters/ViewPdfFragmentPresenter.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/presenters/ViewPdfFragmentPresenter.kt @@ -21,7 +21,7 @@ import com.instructure.annotations.FileCaching.FileCache import com.instructure.annotations.awaitFileDownload import com.instructure.canvasapi2.utils.weave.weave import com.instructure.teacher.viewinterface.ViewPdfFragmentView -import instructure.androidblueprint.FragmentPresenter +import com.instructure.pandautils.blueprint.FragmentPresenter import kotlinx.coroutines.Job import java.io.File diff --git a/apps/teacher/src/main/java/com/instructure/teacher/router/RouteMatcher.kt b/apps/teacher/src/main/java/com/instructure/teacher/router/RouteMatcher.kt index 42938cdbb6..098fad9c4d 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/router/RouteMatcher.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/router/RouteMatcher.kt @@ -50,6 +50,8 @@ import com.instructure.pandautils.features.dashboard.edit.EditDashboardFragment import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragment import com.instructure.pandautils.features.discussion.router.DiscussionRouterFragment import com.instructure.pandautils.features.inbox.list.InboxFragment +import com.instructure.pandautils.features.lti.LtiLaunchFragment +import com.instructure.pandautils.features.settings.SettingsFragment import com.instructure.pandautils.fragments.HtmlContentFragment import com.instructure.pandautils.loaders.OpenMediaAsyncTaskLoader import com.instructure.pandautils.utils.Const @@ -95,7 +97,6 @@ import com.instructure.teacher.fragments.EditQuizDetailsFragment import com.instructure.teacher.fragments.FileListFragment import com.instructure.teacher.fragments.FullscreenInternalWebViewFragment import com.instructure.teacher.fragments.InternalWebViewFragment -import com.instructure.teacher.fragments.LtiLaunchFragment import com.instructure.teacher.fragments.MessageThreadFragment import com.instructure.teacher.fragments.PageDetailsFragment import com.instructure.teacher.fragments.PageListFragment @@ -105,7 +106,6 @@ import com.instructure.teacher.fragments.ProfileFragment import com.instructure.teacher.fragments.QuizDetailsFragment import com.instructure.teacher.fragments.QuizListFragment import com.instructure.teacher.fragments.QuizPreviewWebviewFragment -import com.instructure.teacher.fragments.SettingsFragment import com.instructure.teacher.fragments.SpeedGraderQuizWebViewFragment import com.instructure.teacher.fragments.ViewHtmlFragment import com.instructure.teacher.fragments.ViewImageFragment @@ -240,6 +240,7 @@ object RouteMatcher : BaseRouteMatcher() { DiscussionRouterFragment::class.java ) ) + routes.add(Route(courseOrGroup("/:course_id/users"), PeopleListFragment::class.java)) } private fun initClassMap() { @@ -510,9 +511,9 @@ object RouteMatcher : BaseRouteMatcher() { CreateDiscussionFragment::class.java.isAssignableFrom(cls) -> fragment = CreateDiscussionFragment.newInstance(route.arguments) CreateOrEditAnnouncementFragment::class.java.isAssignableFrom(cls) -> fragment = CreateOrEditAnnouncementFragment .newInstance(route.arguments) - SettingsFragment::class.java.isAssignableFrom(cls) -> fragment = SettingsFragment.newInstance(route.arguments) + SettingsFragment::class.java.isAssignableFrom(cls) -> fragment = SettingsFragment.newInstance(route) ProfileEditFragment::class.java.isAssignableFrom(cls) -> fragment = ProfileEditFragment.newInstance(route.arguments) - LtiLaunchFragment::class.java.isAssignableFrom(cls) -> fragment = LtiLaunchFragment.newInstance(route.arguments) + LtiLaunchFragment::class.java.isAssignableFrom(cls) -> fragment = LtiLaunchFragment.newInstance(route) PeopleListFragment::class.java.isAssignableFrom(cls) -> fragment = PeopleListFragment.newInstance(canvasContext!!) StudentContextFragment::class.java.isAssignableFrom(cls) -> fragment = StudentContextFragment.newInstance(route.arguments) AttendanceListFragment::class.java.isAssignableFrom(cls) -> fragment = AttendanceListFragment @@ -659,10 +660,10 @@ object RouteMatcher : BaseRouteMatcher() { return openMediaCallbacks!! } - fun openMedia(activity: FragmentActivity?, url: String?, fileName: String? = null) { + fun openMedia(activity: FragmentActivity?, url: String?, fileName: String? = null, fileId: String? = null) { if (activity != null) { openMediaCallbacks = null - openMediaBundle = OpenMediaAsyncTaskLoader.createBundle(url, fileName) + openMediaBundle = OpenMediaAsyncTaskLoader.createBundle(url, fileName, fileId) LoaderUtils.restartLoaderWithBundle>( LoaderManager.getInstance(activity), openMediaBundle, getLoaderCallbacks(activity), R.id.openMediaLoaderID ) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/router/RouteResolver.kt b/apps/teacher/src/main/java/com/instructure/teacher/router/RouteResolver.kt index 725dcd94a5..d14bf2b5ef 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/router/RouteResolver.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/router/RouteResolver.kt @@ -13,8 +13,10 @@ import com.instructure.pandautils.features.dashboard.edit.EditDashboardFragment import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragment import com.instructure.pandautils.features.discussion.router.DiscussionRouterFragment import com.instructure.pandautils.features.inbox.list.InboxFragment +import com.instructure.pandautils.features.lti.LtiLaunchFragment import com.instructure.pandautils.features.notification.preferences.EmailNotificationPreferencesFragment import com.instructure.pandautils.features.notification.preferences.PushNotificationPreferencesFragment +import com.instructure.pandautils.features.settings.SettingsFragment import com.instructure.pandautils.fragments.HtmlContentFragment import com.instructure.pandautils.fragments.RemoteConfigParamsFragment import com.instructure.pandautils.utils.Const @@ -52,7 +54,6 @@ import com.instructure.teacher.fragments.FeatureFlagsFragment import com.instructure.teacher.fragments.FileListFragment import com.instructure.teacher.fragments.FullscreenInternalWebViewFragment import com.instructure.teacher.fragments.InternalWebViewFragment -import com.instructure.teacher.fragments.LtiLaunchFragment import com.instructure.teacher.fragments.MessageThreadFragment import com.instructure.teacher.fragments.PageDetailsFragment import com.instructure.teacher.fragments.PageListFragment @@ -62,7 +63,6 @@ import com.instructure.teacher.fragments.ProfileFragment import com.instructure.teacher.fragments.QuizDetailsFragment import com.instructure.teacher.fragments.QuizListFragment import com.instructure.teacher.fragments.QuizPreviewWebviewFragment -import com.instructure.teacher.fragments.SettingsFragment import com.instructure.teacher.fragments.SpeedGraderQuizWebViewFragment import com.instructure.teacher.fragments.ViewHtmlFragment import com.instructure.teacher.fragments.ViewImageFragment @@ -189,7 +189,7 @@ object RouteResolver { } else if (CreateOrEditAnnouncementFragment::class.java.isAssignableFrom(cls)) { fragment = CreateOrEditAnnouncementFragment.newInstance(route.arguments) } else if (SettingsFragment::class.java.isAssignableFrom(cls)) { - fragment = SettingsFragment.newInstance(route.arguments) + fragment = SettingsFragment.newInstance(route) } else if (ProfileEditFragment::class.java.isAssignableFrom(cls)) { fragment = ProfileEditFragment.newInstance(route.arguments) } else if (FeatureFlagsFragment::class.java.isAssignableFrom(cls)) { @@ -201,7 +201,7 @@ object RouteResolver { } else if (RemoteConfigParamsFragment::class.java.isAssignableFrom(cls)) { fragment = RemoteConfigParamsFragment() } else if (LtiLaunchFragment::class.java.isAssignableFrom(cls)) { - fragment = LtiLaunchFragment.newInstance(route.arguments) + fragment = LtiLaunchFragment.newInstance(route) } else if (PeopleListFragment::class.java.isAssignableFrom(cls)) { fragment = PeopleListFragment.newInstance(canvasContext!!) } else if (StudentContextFragment::class.java.isAssignableFrom(cls)) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/tasks/TeacherLogoutTask.kt b/apps/teacher/src/main/java/com/instructure/teacher/tasks/TeacherLogoutTask.kt index 13879f1c02..7ab679be71 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/tasks/TeacherLogoutTask.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/tasks/TeacherLogoutTask.kt @@ -20,17 +20,17 @@ import android.content.Context import android.content.Intent import android.net.Uri import com.google.firebase.messaging.FirebaseMessaging -import com.heapanalytics.android.Heap import com.instructure.canvasapi2.utils.tryOrNull import com.instructure.loginapi.login.tasks.LogoutTask import com.instructure.teacher.activities.LoginActivity import com.instructure.teacher.utils.TeacherPrefs +import io.heap.core.Heap class TeacherLogoutTask(type: Type, uri: Uri? = null) : LogoutTask(type, uri) { override fun onCleanup() { TeacherPrefs.safeClearPrefs() - Heap.setTrackingEnabled(false) + Heap.stopRecording() } override fun createLoginIntent(context: Context): Intent { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/utils/AssignmentExtensions.kt b/apps/teacher/src/main/java/com/instructure/teacher/utils/AssignmentExtensions.kt index ac5fdae538..53b6c91d93 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/utils/AssignmentExtensions.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/utils/AssignmentExtensions.kt @@ -47,12 +47,6 @@ import com.instructure.teacher.models.DueDateGroup import java.util.ArrayList import java.util.Calendar -fun Assignment.getAssignmentIcon() = when { - Assignment.SubmissionType.ONLINE_QUIZ.apiString in submissionTypesRaw -> R.drawable.ic_quiz - Assignment.SubmissionType.DISCUSSION_TOPIC.apiString in submissionTypesRaw -> R.drawable.ic_discussion - else -> R.drawable.ic_assignment -} - fun List?.getAssignmentIcon() = when { this == null -> R.drawable.ic_assignment SubmissionType.ONLINE_QUIZ in this -> R.drawable.ic_quiz diff --git a/apps/teacher/src/main/java/com/instructure/teacher/utils/BaseAppManager.kt b/apps/teacher/src/main/java/com/instructure/teacher/utils/BaseAppManager.kt index f2bd23c660..b4f2155179 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/utils/BaseAppManager.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/utils/BaseAppManager.kt @@ -21,8 +21,6 @@ import android.os.Build import androidx.appcompat.app.AppCompatDelegate import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.heapanalytics.android.Heap -import com.heapanalytics.android.config.Options import com.instructure.annotations.FileCaching.FileCache import com.instructure.canvasapi2.utils.AnalyticsEventConstants import com.instructure.canvasapi2.utils.ApiPrefs @@ -31,12 +29,16 @@ import com.instructure.canvasapi2.utils.MasqueradeHelper import com.instructure.canvasapi2.utils.RemoteConfigUtils import com.instructure.canvasapi2.utils.pageview.PageViewUploadService import com.instructure.loginapi.login.tasks.LogoutTask +import com.instructure.pandautils.base.AppConfig +import com.instructure.pandautils.base.AppConfigProvider import com.instructure.pandautils.utils.AppTheme +import com.instructure.pandautils.utils.AppType import com.instructure.pandautils.utils.ColorKeeper import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.ThemePrefs import com.instructure.teacher.BuildConfig import com.instructure.teacher.R +import com.instructure.teacher.activities.InitActivity import com.instructure.teacher.services.TeacherPageViewService import com.instructure.teacher.tasks.TeacherLogoutTask import com.pspdfkit.PSPDFKit @@ -48,6 +50,7 @@ abstract class BaseAppManager : com.instructure.canvasapi2.AppManager() { override fun onCreate() { super.onCreate() + AppConfigProvider.appConfig = AppConfig(AppType.TEACHER, InitActivity::class.java) FileCache.versionCode = BuildConfig.VERSION_CODE @@ -90,10 +93,6 @@ abstract class BaseAppManager : com.instructure.canvasapi2.AppManager() { filter.addAction(Const.ACTION_MEDIA_UPLOAD_FAIL) LocalBroadcastManager.getInstance(this).registerReceiver(mediaUploadReceiver, filter) - val options = Options() - options.disableTracking() - Heap.init(this, BuildConfig.HEAP_APP_ID, options) - PageViewUploadService.schedule(this, TeacherPageViewService::class.java) } diff --git a/apps/teacher/src/main/java/com/instructure/teacher/utils/RecyclerViewUtils.kt b/apps/teacher/src/main/java/com/instructure/teacher/utils/RecyclerViewUtils.kt index a482d78b0f..33943d990f 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/utils/RecyclerViewUtils.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/utils/RecyclerViewUtils.kt @@ -24,7 +24,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.instructure.pandarecycler.interfaces.EmptyInterface import com.instructure.pandautils.utils.Utils import com.instructure.teacher.R -import instructure.androidblueprint.* +import com.instructure.pandautils.blueprint.* object RecyclerViewUtils { fun buildRecyclerView( diff --git a/apps/teacher/src/main/java/com/instructure/teacher/view/EditFileView.kt b/apps/teacher/src/main/java/com/instructure/teacher/view/EditFileView.kt index 435681cb00..57ae475592 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/view/EditFileView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/view/EditFileView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.view import com.instructure.canvasapi2.models.FileFolder -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface EditFileView : FragmentViewInterface { fun folderDeleted(deletedFileFolder: FileFolder) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/view/SubmissionContentView.kt b/apps/teacher/src/main/java/com/instructure/teacher/view/SubmissionContentView.kt index f81016eae0..5059a7a121 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/view/SubmissionContentView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/view/SubmissionContentView.kt @@ -51,7 +51,6 @@ import com.instructure.canvasapi2.models.Assignee import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.Assignment.SubmissionType import com.instructure.canvasapi2.models.Attachment -import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.models.DocSession import com.instructure.canvasapi2.models.Enrollment @@ -149,7 +148,7 @@ class SubmissionContentView( private val mAssignment: Assignment, private val mCourse: Course, var initialTabIndex: Int = 0 -) : PdfSubmissionView(context), AnnotationManager.OnAnnotationCreationModeChangeListener, AnnotationManager.OnAnnotationEditingModeChangeListener { +) : PdfSubmissionView(context, courseId = mCourse.id), AnnotationManager.OnAnnotationCreationModeChangeListener, AnnotationManager.OnAnnotationEditingModeChangeListener { private val binding: ViewSubmissionContentBinding @@ -384,7 +383,6 @@ class SubmissionContentView( // LTI submission SubmissionType.BASIC_LTI_LAUNCH -> ExternalToolContent( - mCourse, submission.previewUrl.validOrNull() ?: mAssignment.url.validOrNull() ?: mAssignment.htmlUrl ?: "" ) @@ -1043,7 +1041,7 @@ class UploadMediaCommentEvent(val file: File, val assignmentId: Long, val course sealed class GradeableContent object NoSubmissionContent : GradeableContent() object NoneContent : GradeableContent() -class ExternalToolContent(val canvasContext: CanvasContext, val url: String) : GradeableContent() +class ExternalToolContent(val url: String) : GradeableContent() object OnPaperContent : GradeableContent() object UnsupportedContent : GradeableContent() class OtherAttachmentContent(val attachment: Attachment) : GradeableContent() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/view/edit_rubric/CriterionRatingButton.kt b/apps/teacher/src/main/java/com/instructure/teacher/view/edit_rubric/CriterionRatingButton.kt index a99eb6d0f7..f190918e2a 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/view/edit_rubric/CriterionRatingButton.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/view/edit_rubric/CriterionRatingButton.kt @@ -19,7 +19,6 @@ package com.instructure.teacher.view.edit_rubric import android.annotation.SuppressLint import android.content.Context import android.graphics.Canvas -import android.graphics.Color import android.graphics.PorterDuff import android.graphics.drawable.StateListDrawable import android.util.AttributeSet @@ -29,7 +28,11 @@ import androidx.appcompat.app.AppCompatActivity import com.instructure.canvasapi2.models.RubricCriterion import com.instructure.canvasapi2.models.RubricCriterionRating import com.instructure.canvasapi2.utils.NumberHelper -import com.instructure.pandautils.utils.* +import com.instructure.pandautils.utils.DP +import com.instructure.pandautils.utils.ViewStyler +import com.instructure.pandautils.utils.getDrawableCompat +import com.instructure.pandautils.utils.onClick +import com.instructure.pandautils.utils.onLongClick import com.instructure.teacher.BuildConfig import com.instructure.teacher.R import com.instructure.teacher.dialog.CustomRubricRatingDialog diff --git a/apps/teacher/src/main/java/com/instructure/teacher/view/edit_rubric/RubricCriterionItemView.kt b/apps/teacher/src/main/java/com/instructure/teacher/view/edit_rubric/RubricCriterionItemView.kt index 106392c1e1..ef555b12f9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/view/edit_rubric/RubricCriterionItemView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/view/edit_rubric/RubricCriterionItemView.kt @@ -25,7 +25,12 @@ import android.widget.ScrollView import androidx.appcompat.app.AppCompatActivity import com.instructure.canvasapi2.models.RubricCriterion import com.instructure.canvasapi2.models.RubricCriterionAssessment -import com.instructure.pandautils.utils.* +import com.instructure.pandautils.utils.ThemePrefs +import com.instructure.pandautils.utils.firstAncestorOrNull +import com.instructure.pandautils.utils.onClick +import com.instructure.pandautils.utils.setGone +import com.instructure.pandautils.utils.setVisible +import com.instructure.pandautils.utils.topOffsetIn import com.instructure.teacher.databinding.ViewRubricCriterionItemBinding import com.instructure.teacher.dialog.CriterionLongDescriptionDialog import com.instructure.teacher.dialog.EditRubricCommentDialog diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AddMessageView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AddMessageView.kt index e0173798d6..aa4f03c107 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AddMessageView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AddMessageView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.models.Group -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface import java.util.* interface AddMessageView : FragmentViewInterface { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AllCoursesView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AllCoursesView.kt index bd587fb733..8b7d365adb 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AllCoursesView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AllCoursesView.kt @@ -18,6 +18,6 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Course -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface AllCoursesView : SyncManager diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssigneeListView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssigneeListView.kt index b023d3f913..ecfb001903 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssigneeListView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssigneeListView.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.CanvasComparable import com.instructure.teacher.models.AssigneeCategory -import instructure.androidblueprint.SyncExpandableManager +import com.instructure.pandautils.blueprint.SyncExpandableManager import java.util.ArrayList interface AssigneeListView : SyncExpandableManager> { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentDetailsView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentDetailsView.kt index c2e7991b47..2698a0650d 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentDetailsView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentDetailsView.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Assignment -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface AssignmentDetailsView : FragmentViewInterface { fun populateAssignmentDetails(assignment: Assignment) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentListView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentListView.kt index 98e81d4828..a24a4435e0 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentListView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentListView.kt @@ -19,7 +19,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.AssignmentGroup import com.instructure.canvasapi2.models.GradingPeriod -import instructure.androidblueprint.SyncExpandableManager +import com.instructure.pandautils.blueprint.SyncExpandableManager interface AssignmentListView : SyncExpandableManager { fun getDefaultGradingPeriodTitle(): String diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentSubmissionListView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentSubmissionListView.kt index 8293502b30..e29f9bc806 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentSubmissionListView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AssignmentSubmissionListView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.GradeableStudentSubmission -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface AssignmentSubmissionListView : SyncManager { } diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AttendanceListView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AttendanceListView.kt index 3d0b15f618..5daaf4150c 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AttendanceListView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/AttendanceListView.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Attendance import com.instructure.canvasapi2.models.Section import com.instructure.canvasapi2.models.Tab -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface AttendanceListView : SyncManager { fun launchLTI(tab: Tab) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CanvasContextView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CanvasContextView.kt index f636bf9ceb..3b0f9fdd70 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CanvasContextView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CanvasContextView.kt @@ -17,6 +17,6 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.CanvasContext -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface CanvasContextView : SyncManager diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ChooseRecipientsView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ChooseRecipientsView.kt index f64cbc5c7c..b7b7c58f5f 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ChooseRecipientsView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ChooseRecipientsView.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Recipient -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface ChooseRecipientsView : SyncManager diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseBrowserEmptyView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseBrowserEmptyView.kt index ad292e7cf0..54b86d54df 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseBrowserEmptyView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseBrowserEmptyView.kt @@ -15,6 +15,6 @@ */ package com.instructure.teacher.viewinterface -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface CourseBrowserEmptyView : FragmentViewInterface diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseBrowserView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseBrowserView.kt index 0dbaa65e47..e9cef7e36e 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseBrowserView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseBrowserView.kt @@ -16,7 +16,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Tab -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface CourseBrowserView : SyncManager { fun isStudentInstalled(): Boolean diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseSettingsFragmentView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseSettingsFragmentView.kt index d0fca11a98..94abd6dc38 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseSettingsFragmentView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CourseSettingsFragmentView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Course -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface CourseSettingsFragmentView : FragmentViewInterface { fun showEditCourseNameDialog() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CoursesView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CoursesView.kt index 3bae67faf9..5b5bf5c58a 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CoursesView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CoursesView.kt @@ -16,6 +16,6 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Course -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface CoursesView : SyncManager diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateDiscussionView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateDiscussionView.kt index e1a4705df0..18e655da52 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateDiscussionView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateDiscussionView.kt @@ -21,7 +21,7 @@ import com.instructure.canvasapi2.models.Group import com.instructure.canvasapi2.models.Section import com.instructure.canvasapi2.models.User import com.instructure.teacher.interfaces.RceMediaUploadView -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface CreateDiscussionView : FragmentViewInterface, RceMediaUploadView { fun startSavingDiscussion() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateOrEditAnnouncementView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateOrEditAnnouncementView.kt index f2dcd571f4..58aa718438 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateOrEditAnnouncementView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateOrEditAnnouncementView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.viewinterface import com.instructure.teacher.interfaces.RceMediaUploadView -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface CreateOrEditAnnouncementView : FragmentViewInterface, RceMediaUploadView { fun onSaveStarted() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateOrEditPageView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateOrEditPageView.kt index f37450b5fd..703286da59 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateOrEditPageView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/CreateOrEditPageView.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.viewinterface import com.instructure.teacher.interfaces.RceMediaUploadView -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface CreateOrEditPageView : FragmentViewInterface, RceMediaUploadView { fun onSaveStarted() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DiscussionListView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DiscussionListView.kt index 20c0b6198e..32657f51c1 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DiscussionListView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DiscussionListView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.DiscussionTopicHeader -import instructure.androidblueprint.SyncExpandableManager +import com.instructure.pandautils.blueprint.SyncExpandableManager interface DiscussionListView : SyncExpandableManager { fun askToDeleteDiscussionTopicHeader(discussionTopicHeader: DiscussionTopicHeader) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DiscussionsUpdateView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DiscussionsUpdateView.kt index fb91fff475..377e64c97f 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DiscussionsUpdateView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DiscussionsUpdateView.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.DiscussionEntry import com.instructure.teacher.interfaces.RceMediaUploadView -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface DiscussionsUpdateView : FragmentViewInterface, RceMediaUploadView { fun messageSuccess(entry: DiscussionEntry) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DueDatesView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DueDatesView.kt index 16225aa7cf..851c5898b9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DueDatesView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/DueDatesView.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Assignment import com.instructure.teacher.models.DueDateGroup -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface DueDatesView : SyncManager { fun hideMenu() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/EditQuizDetailsView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/EditQuizDetailsView.kt index 65ca9b9a12..cbce7a3170 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/EditQuizDetailsView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/EditQuizDetailsView.kt @@ -16,7 +16,7 @@ */ package com.instructure.teacher.viewinterface -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface EditQuizDetailsView : FragmentViewInterface { fun setupOverrides() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/FileListView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/FileListView.kt index e2342334ee..8fee55b6b9 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/FileListView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/FileListView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.FileFolder -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface FileListView : SyncManager { fun folderCreationError() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/InboxView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/InboxView.kt index ac3ab549d2..aaf5c1bb0f 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/InboxView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/InboxView.kt @@ -16,7 +16,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Conversation -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface InboxView : SyncManager { fun unreadCountUpdated(unreadCount: Int) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/MessageThreadView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/MessageThreadView.kt index b6ec67f878..e8916101d0 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/MessageThreadView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/MessageThreadView.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Message -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface MessageThreadView : SyncManager { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PageDetailsView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PageDetailsView.kt index 2df9c2c04c..f30e87d5c7 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PageDetailsView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PageDetailsView.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Page -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface PageDetailsView : FragmentViewInterface { fun populatePageDetails(page: Page) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PageListView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PageListView.kt index d3a04800f0..791e85b46e 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PageListView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PageListView.kt @@ -18,6 +18,6 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Page -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface PageListView : SyncManager \ No newline at end of file diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PeopleListView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PeopleListView.kt index c34c805941..3d1f1f7c97 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PeopleListView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/PeopleListView.kt @@ -16,6 +16,6 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.User -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface PeopleListView : SyncManager diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ProfileEditFragmentView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ProfileEditFragmentView.kt index 9254ef9ee8..7b315840c6 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ProfileEditFragmentView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ProfileEditFragmentView.kt @@ -16,7 +16,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.User -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface ProfileEditFragmentView : FragmentViewInterface { fun readyToLoadUI(user: User?) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ProfileSettingsFragmentView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ProfileSettingsFragmentView.kt deleted file mode 100644 index 81848bb3ac..0000000000 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ProfileSettingsFragmentView.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2017 - present Instructure, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.instructure.teacher.viewinterface - -import instructure.androidblueprint.FragmentViewInterface - -interface ProfileSettingsFragmentView : FragmentViewInterface \ No newline at end of file diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/QuizDetailsView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/QuizDetailsView.kt index 3e2ea8a6b2..8522d22082 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/QuizDetailsView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/QuizDetailsView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Quiz -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface QuizDetailsView : FragmentViewInterface { fun populateQuizDetails(quiz: Quiz) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/QuizListView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/QuizListView.kt index 64c7781d41..49f5241b17 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/QuizListView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/QuizListView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Quiz -import instructure.androidblueprint.SyncExpandableManager +import com.instructure.pandautils.blueprint.SyncExpandableManager interface QuizListView : SyncExpandableManager { fun displayLoadingError() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderCommentsView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderCommentsView.kt index 43bd0f6751..b1740e9e91 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderCommentsView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderCommentsView.kt @@ -18,7 +18,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.postmodels.FileUploadWorkerData import com.instructure.teacher.models.SubmissionCommentWrapper -import instructure.androidblueprint.ListManager +import com.instructure.pandautils.blueprint.ListManager import java.util.* interface SpeedGraderCommentsView : ListManager { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderFilesView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderFilesView.kt index 98b78fc736..4172411bcd 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderFilesView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderFilesView.kt @@ -17,6 +17,6 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.models.Attachment -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface SpeedGraderFilesView : SyncManager \ No newline at end of file diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderGradeView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderGradeView.kt index bf58dd291f..a0a57f4e38 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderGradeView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/SpeedGraderGradeView.kt @@ -16,7 +16,7 @@ */ package com.instructure.teacher.viewinterface -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface SpeedGraderGradeView : FragmentViewInterface { fun updateGradeText() diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/StudentContextView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/StudentContextView.kt index b35e49384a..5303d4d402 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/StudentContextView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/StudentContextView.kt @@ -16,7 +16,7 @@ package com.instructure.teacher.viewinterface import com.instructure.canvasapi2.StudentContextCardQuery.* -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface StudentContextView : FragmentViewInterface { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ToDoView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ToDoView.kt index cd2bd7cdf5..4d0735b4fa 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ToDoView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ToDoView.kt @@ -21,7 +21,7 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.models.GradeableStudentSubmission import com.instructure.canvasapi2.models.ToDo -import instructure.androidblueprint.SyncManager +import com.instructure.pandautils.blueprint.SyncManager interface ToDoView : SyncManager { fun onRouteSuccessfully(course: Course, assignment: Assignment, submissions: List) diff --git a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ViewPdfFragmentView.kt b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ViewPdfFragmentView.kt index 3a0e7e4a81..0950113f5b 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ViewPdfFragmentView.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/viewinterface/ViewPdfFragmentView.kt @@ -17,7 +17,7 @@ package com.instructure.teacher.viewinterface import android.net.Uri -import instructure.androidblueprint.FragmentViewInterface +import com.instructure.pandautils.blueprint.FragmentViewInterface interface ViewPdfFragmentView : FragmentViewInterface { fun onLoadingStarted() diff --git a/apps/teacher/src/main/res/layout/activity_route_validator.xml b/apps/teacher/src/main/res/layout/activity_route_validator.xml index d5922f088f..446c382ba5 100644 --- a/apps/teacher/src/main/res/layout/activity_route_validator.xml +++ b/apps/teacher/src/main/res/layout/activity_route_validator.xml @@ -29,7 +29,7 @@ android:layout_height="match_parent" android:visibility="invisible"/> - - - - - - - - - - - - - diff --git a/apps/teacher/src/main/res/layout/fragment_page_details.xml b/apps/teacher/src/main/res/layout/fragment_page_details.xml index 60e2eb6680..f08875494d 100644 --- a/apps/teacher/src/main/res/layout/fragment_page_details.xml +++ b/apps/teacher/src/main/res/layout/fragment_page_details.xml @@ -40,7 +40,7 @@ android:layout_marginTop="8dp" android:layout_marginBottom="8dp" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/teacher/src/main/res/layout/fragment_speed_grader_lti_submission.xml b/apps/teacher/src/main/res/layout/fragment_speed_grader_lti_submission.xml index 1ce4e09cf8..e5e5a7669c 100644 --- a/apps/teacher/src/main/res/layout/fragment_speed_grader_lti_submission.xml +++ b/apps/teacher/src/main/res/layout/fragment_speed_grader_lti_submission.xml @@ -14,64 +14,21 @@ ~ You should have received a copy of the GNU General Public License ~ along with this program. If not, see . --> - + android:fillViewport="true"> - - - - - - - + android:layout_height="match_parent" /> - - -