diff --git a/apps/flutter_parent/assets/fonts/lato_regular.ttf b/apps/flutter_parent/assets/fonts/lato_regular.ttf new file mode 100644 index 0000000000..adbfc467d2 Binary files /dev/null and b/apps/flutter_parent/assets/fonts/lato_regular.ttf differ diff --git a/apps/flutter_parent/lib/l10n/res/intl_es_ES.arb b/apps/flutter_parent/lib/l10n/res/intl_es_ES.arb index b10bfe2f17..a3d9bdff63 100644 --- a/apps/flutter_parent/lib/l10n/res/intl_es_ES.arb +++ b/apps/flutter_parent/lib/l10n/res/intl_es_ES.arb @@ -21,35 +21,35 @@ "placeholders_order": [], "placeholders": {} }, - "No Students": "No hay alumnos", + "No Students": "No hay estudiantes", "@No Students": { "description": "Text for when an observer has no students they are observing", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Tap to show student selector": "Pulse para ver el selector de alumnos", + "Tap to show student selector": "Pulsa para ver el selector de estudiantes", "@Tap to show student selector": { "description": "Semantics label for the area that will show the student selector when tapped", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Tap to pair with a new student": "Pulse para emparejar con un nuevo alumno", + "Tap to pair with a new student": "Pulsa para emparejar con un nuevo estudiante", "@Tap to pair with a new student": { "description": "Semantics label for the add student button in the student selector", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Tap to select this student": "Pulse para seleccionar este alumno", + "Tap to select this student": "Pulsa para seleccionar este estudiante", "@Tap to select this student": { "description": "Semantics label on individual students in the student switcher", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Manage Students": "Administrar alumnos", + "Manage Students": "Administrar estudiantes", "@Manage Students": { "description": "Label text for the Manage Students nav drawer button as well as the title for the Manage Students screen", "type": "text", @@ -88,7 +88,7 @@ "version": {} } }, - "Are you sure you want to log out?": "¿Está seguro de que desea salir?", + "Are you sure you want to log out?": "¿Estás seguro de que quieres salir?", "@Are you sure you want to log out?": { "description": "Confirmation message displayed when the user tries to log out", "type": "text", @@ -196,14 +196,14 @@ "placeholders_order": [], "placeholders": {} }, - "There was an error loading your student's calendar": "Ha habido un error al cargar el calendario de su alumno", + "There was an error loading your student's calendar": "Ha habido un error al cargar el calendario de tu estudiante", "@There was an error loading your student's calendar": { "description": "Message displayed when calendar events could not be loaded for the current student", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Tap to favorite the courses you want to see on the Calendar. Select up to 10.": "Pulse para marcar las asignaturas que desea ver en el calendario como favoritos. Seleccione hasta 10.", + "Tap to favorite the courses you want to see on the Calendar. Select up to 10.": "Pulsa para marcar las asignaturas que quieres ver en el calendario como favoritos. Selecciona hasta 10.", "@Tap to favorite the courses you want to see on the Calendar. Select up to 10.": { "description": "Description text on calendar filter screen.", "type": "text", @@ -217,7 +217,7 @@ "placeholders_order": [], "placeholders": {} }, - "You must select at least one calendar to display": "Debe seleccionar al menos un calendario para mostrar", + "You must select at least one calendar to display": "Debes seleccionar al menos un calendario para mostrar", "@You must select at least one calendar to display": { "description": "Error text when trying to de-select all calendars", "type": "text", @@ -259,7 +259,7 @@ "placeholders_order": [], "placeholders": {} }, - "domainSearchInputHint": "Introduzca el nombre de la escuela o el distrito...", + "domainSearchInputHint": "Introduce el nombre de la escuela o el distrito...", "@domainSearchInputHint": { "description": "Input hint for the text box on the domain search screen", "type": "text", @@ -298,7 +298,7 @@ "placeholders_order": [], "placeholders": {} }, - "domainSearchHelpBody": "Intente buscar el nombre de la escuela o el distrito al que intenta acceder, como “Smith Private School” o “Smith County Schools”. También puede introducir directamente a un dominio de Canvas, como “smith.instructure.com”.\n\nPara obtener más información sobre cómo encontrar la cuenta de Canvas de su institución, puede visitar {canvasGuides}, ponerse en contacto con {canvasSupport} o con su escuela para recibir asistencia.", + "domainSearchHelpBody": "Intenta buscar el nombre de la escuela o el distrito al que intentas acceder, como “Smith Private School” o “Smith County Schools”. También puedes introducir directamente un dominio de Canvas, como “smith.instructure.com”.\n\nPara obtener más información sobre cómo encontrar la cuenta de Canvas de tu institución, puedes visitar {canvasGuides}, ponerte en contacto con {canvasSupport} o con tu escuela para recibir asistencia.", "@domainSearchHelpBody": { "description": "The body text shown in the help dialog on the domain search screen", "type": "text", @@ -318,14 +318,14 @@ "placeholders_order": [], "placeholders": {} }, - "We’re not sure what happened, but it wasn’t good. Contact us if this keeps happening.": "No sabemos qué ha ocurrido, pero no es nada bueno. Póngase en contacto con nosotros si el problema continúa.", + "We’re not sure what happened, but it wasn’t good. Contact us if this keeps happening.": "No sabemos qué ha ocurrido, pero no es nada bueno. Ponte en contacto con nosotros si el problema continúa.", "@We’re not sure what happened, but it wasn’t good. Contact us if this keeps happening.": { "description": "Message shown when a crash has occurred", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Contact Support": "Póngase en contacto con el soporte técnico", + "Contact Support": "Ponte en contacto con el soporte técnico", "@Contact Support": { "description": "Label for the button that allows users to contact support after a crash has occurred", "type": "text", @@ -381,7 +381,7 @@ "placeholders_order": [], "placeholders": {} }, - "There was an error loading your inbox messages.": "Ha habido un error al cargar sus mensajes de la bandeja de entrada.", + "There was an error loading your inbox messages.": "Ha habido un error al cargar tus mensajes de la bandeja de entrada.", "@There was an error loading your inbox messages.": { "type": "text", "placeholders_order": [], @@ -394,14 +394,14 @@ "placeholders_order": [], "placeholders": {} }, - "Unable to fetch courses. Please check your connection and try again.": "No se han podido obtener las asignaturas. Compruebe su conexión y vuelva a intentarlo.", + "Unable to fetch courses. Please check your connection and try again.": "No se han podido obtener las asignaturas. Comprueba tu conexión y vuelve a intentarlo.", "@Unable to fetch courses. Please check your connection and try again.": { "description": "Message shown when an error occured while loading courses", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Choose a course to message": "Elija una asignatura para enviar un mensaje", + "Choose a course to message": "Elige una asignatura para enviar un mensaje", "@Choose a course to message": { "description": "Header in the course list shown when the user is choosing which course to associate with a new message", "type": "text", @@ -415,7 +415,7 @@ "placeholders_order": [], "placeholders": {} }, - "You’re all caught up!": "¡Ya está al día!", + "You’re all caught up!": "¡Ya estás al día!", "@You’re all caught up!": { "description": "Subtitle of the message shown when there are no inbox messages", "type": "text", @@ -429,7 +429,7 @@ "placeholders_order": [], "placeholders": {} }, - "Unable to send message. Check your connection and try again.": "No se puede enviar el mensaje. Compruebe su conexión y vuelva a intentarlo.", + "Unable to send message. Check your connection and try again.": "No se puede enviar el mensaje. Comprueba tu conexión y vuelve a intentarlo.", "@Unable to send message. Check your connection and try again.": { "description": "Message show when there was an error creating or sending a new message", "type": "text", @@ -443,7 +443,7 @@ "placeholders_order": [], "placeholders": {} }, - "Are you sure you wish to close this page? Your unsent message will be lost.": "¿Está seguro de que desea cerrar esta página? Su mensaje no enviado se perderá.", + "Are you sure you wish to close this page? Your unsent message will be lost.": "¿Estás seguro de que quieres cerrar esta página? Tu mensaje no enviado se perderá.", "@Are you sure you wish to close this page? Your unsent message will be lost.": { "description": "Body text of the dialog shown when the user tries leave with unsaved changes", "type": "text", @@ -478,7 +478,7 @@ "placeholders_order": [], "placeholders": {} }, - "No recipients selected": "No ha seleccionado ningún destinatario", + "No recipients selected": "No has seleccionado ningún destinatario", "@No recipients selected": { "description": "Hint displayed when the user has not selected any message recipients", "type": "text", @@ -519,7 +519,7 @@ } } }, - "Failed. Tap for options.": "Ha habido un error. Toque para ver las opciones.", + "Failed. Tap for options.": "Ha habido un error. Toca para ver las opciones.", "@Failed. Tap for options.": { "description": "Short message shown on a message attachment when uploading has failed", "type": "text", @@ -686,14 +686,14 @@ "placeholders_order": [], "placeholders": {} }, - "Your student’s courses might not be published yet.": "Es posible que las asignaturas de sus alumnos aún no estén publicadas.", + "Your student’s courses might not be published yet.": "Es posible que las asignaturas de tus estudiantes aún no estén publicadas.", "@Your student’s courses might not be published yet.": { "description": "Message for having no courses", "type": "text", "placeholders_order": [], "placeholders": {} }, - "There was an error loading your student’s courses.": "Ha habido un error al cargar las asignaturas de su alumno.", + "There was an error loading your student’s courses.": "Ha habido un error al cargar las asignaturas de tu estudiante.", "@There was an error loading your student’s courses.": { "description": "Message displayed when the list of student courses could not be loaded", "type": "text", @@ -777,7 +777,7 @@ "placeholders_order": [], "placeholders": {} }, - "Late": "Con atraso", + "Late": "Con retraso", "@Late": { "description": "Label for assignments that have been marked late or submitted late", "type": "text", @@ -1007,7 +1007,7 @@ "placeholders_order": [], "placeholders": {} }, - "You will be notified about this assignment on…": "Se le notificará acerca de esta actividad el...", + "You will be notified about this assignment on…": "Se te notificará acerca de esta actividad el...", "@You will be notified about this assignment on…": { "description": "Description for when a reminder is set", "type": "text", @@ -1077,7 +1077,7 @@ "placeholders_order": [], "placeholders": {} }, - "In order to provide you with a better experience, we have updated how reminders work. You can add new reminders by viewing an assignment or calendar event and tapping the switch under the \"Remind Me\" section.\n\nBe aware that any reminders created with older versions of this app will not be compatible with the new changes and you will need to create them again.": "Para brindarle una mejor experiencia, hemos actualizado el funcionamiento de los recordatorios. Para añadir nuevos recordatorios, vea una actividad o evento del calendario y pulse el botón en la sección \"Recordarme\" (\"Remind Me\").\n\nTenga presente que cualquier recordatorio creado con versiones anteriores de esta aplicación no será compatible con los nuevos cambios, y deberá volver a crearlo.", + "In order to provide you with a better experience, we have updated how reminders work. You can add new reminders by viewing an assignment or calendar event and tapping the switch under the \"Remind Me\" section.\n\nBe aware that any reminders created with older versions of this app will not be compatible with the new changes and you will need to create them again.": "Para brindarte una mejor experiencia, hemos actualizado el funcionamiento de los recordatorios. Para añadir nuevos recordatorios, consulta una actividad o evento del calendario y pulsa el botón en la sección \"Recordarme\" (\"Remind Me\").\n\nTen presente que cualquier recordatorio creado con versiones anteriores de esta aplicación no será compatible con los nuevos cambios, y deberás volver a crearlo.", "@In order to provide you with a better experience, we have updated how reminders work. You can add new reminders by viewing an assignment or calendar event and tapping the switch under the \"Remind Me\" section.\n\nBe aware that any reminders created with older versions of this app will not be compatible with the new changes and you will need to create them again.": { "type": "text", "placeholders_order": [], @@ -1090,21 +1090,21 @@ "placeholders_order": [], "placeholders": {} }, - "We couldn't find any students associated with this account": "No hemos podido encontrar ningún alumno relacionado con esta cuenta", + "We couldn't find any students associated with this account": "No hemos podido encontrar ningún estudiante relacionado con esta cuenta", "@We couldn't find any students associated with this account": { "description": "Subtitle for the screen that shows when the user is not observing any students", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Are you a student or teacher?": "¿Es alumno o profesor?", + "Are you a student or teacher?": "¿Es estudiante o profesor?", "@Are you a student or teacher?": { "description": "Label for button that will show users the option to view other Canvas apps in the Play Store", "type": "text", "placeholders_order": [], "placeholders": {} }, - "One of our other apps might be a better fit. Tap one to visit the Play Store.": "Una de nuestras otras aplicaciones podría ser más adecuada. Toque una para visitar la Play Store.", + "One of our other apps might be a better fit. Tap one to visit the Play Store.": "Una de nuestras otras aplicaciones podría ser más adecuada. Toca una para visitar la Play Store.", "@One of our other apps might be a better fit. Tap one to visit the Play Store.": { "description": "Description of options to view other Canvas apps in the Play Store", "type": "text", @@ -1118,7 +1118,7 @@ "placeholders_order": [], "placeholders": {} }, - "STUDENT": "ALUMNO", + "STUDENT": "ESTUDIANTE", "@STUDENT": { "description": "The \"student\" portion of the \"Canvas Student\" app name, in all caps. \"Canvas\" is excluded in this context as it will be displayed to the user as a wordmark image", "type": "text", @@ -1433,7 +1433,7 @@ "placeholders_order": [], "placeholders": {} }, - "There was an error loading your student's alerts.": "Ha habido un error al cargar las alertas de sus alumnos.", + "There was an error loading your student's alerts.": "Ha habido un error al cargar las alertas de tus estudiantes.", "@There was an error loading your student's alerts.": { "type": "text", "placeholders_order": [], @@ -1471,7 +1471,7 @@ } } }, - "Select Student Color": "Seleccionar color del alumno", + "Select Student Color": "Seleccionar color del estudiante", "@Select Student Color": { "description": "Title for screen that allows users to assign a color to a specific student", "type": "text", @@ -1520,7 +1520,7 @@ "placeholders_order": [], "placeholders": {} }, - "An error occurred while saving your selection. Please try again.": "Ha habido un error al guardar su selección. Inténtelo de nuevo.", + "An error occurred while saving your selection. Please try again.": "Ha habido un error al guardar tu selección. Inténtalo de nuevo.", "@An error occurred while saving your selection. Please try again.": { "type": "text", "placeholders_order": [], @@ -1544,7 +1544,7 @@ "placeholders_order": [], "placeholders": {} }, - "Student": "Alumno", + "Student": "Estudiante", "@Student": { "description": "Label for the Student enrollment type", "type": "text", @@ -1593,25 +1593,25 @@ "placeholders_order": [], "placeholders": {} }, - "Add student with…": "Añadir alumno con...", + "Add student with…": "Añadir estudiante con...", "@Add student with…": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "Add Student": "Añadir alumno", + "Add Student": "Añadir estudiante", "@Add Student": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "You are not observing any students.": "No está observando a ningún alumno.", + "You are not observing any students.": "No estás observando a ningún estudiante.", "@You are not observing any students.": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "There was an error loading your students.": "Ha habido un error al cargar sus alumnos.", + "There was an error loading your students.": "Ha habido un error al cargar tus estudiantes.", "@There was an error loading your students.": { "type": "text", "placeholders_order": [], @@ -1623,25 +1623,25 @@ "placeholders_order": [], "placeholders": {} }, - "Students can obtain a pairing code through the Canvas website": "Los alumnos pueden obtener un código de emparejamiento a través del sitio web de Canvas", + "Students can obtain a pairing code through the Canvas website": "Los estudiantes pueden obtener un código de emparejamiento a través del sitio web de Canvas", "@Students can obtain a pairing code through the Canvas website": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "Enter the student pairing code provided to you. If the pairing code doesn't work, it may have expired": "Introduzca el código de emparejamiento de alumno que se le ha proporcionado. Si el código de emparejamiento no funciona, es posible que haya caducado", + "Enter the student pairing code provided to you. If the pairing code doesn't work, it may have expired": "Introduce el código de emparejamiento de estudiante que se te ha proporcionado. Si el código de emparejamiento no funciona, es posible que haya caducado", "@Enter the student pairing code provided to you. If the pairing code doesn't work, it may have expired": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "Your code is incorrect or expired.": "Su código es incorrecto o ha caducado.", + "Your code is incorrect or expired.": "Tu código es incorrecto o ha caducado.", "@Your code is incorrect or expired.": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "Something went wrong trying to create your account, please reach out to your school for assistance.": "Algo ha salido mal al intentar crear su cuenta; póngase en contacto con su escuela para obtener asistencia.", + "Something went wrong trying to create your account, please reach out to your school for assistance.": "Algo ha salido mal al intentar crear tu cuenta; ponte en contacto con tu escuela para obtener asistencia.", "@Something went wrong trying to create your account, please reach out to your school for assistance.": { "type": "text", "placeholders_order": [], @@ -1653,13 +1653,13 @@ "placeholders_order": [], "placeholders": {} }, - "Students can create a QR code using the Canvas Student app on their mobile device": "Los alumnos pueden crear un código QR mediante la aplicación Canvas Student en sus dispositivos móviles", + "Students can create a QR code using the Canvas Student app on their mobile device": "Los estudiantes pueden crear un código QR mediante la aplicación Canvas Student en sus dispositivos móviles", "@Students can create a QR code using the Canvas Student app on their mobile device": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "Add new student": "Añadir nuevo alumno", + "Add new student": "Añadir nuevo estudiante", "@Add new student": { "description": "Semantics label for the FAB on the Manage Students Screen", "type": "text", @@ -1733,21 +1733,21 @@ "placeholders_order": [], "placeholders": {} }, - "Please enter full name": "Introduzca el nombre completo", + "Please enter full name": "Introduce el nombre completo", "@Please enter full name": { "description": "Error message for form field", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Please enter an email address": "Introduzca una dirección de correo electrónico", + "Please enter an email address": "Introduce una dirección de correo electrónico", "@Please enter an email address": { "description": "Error message for form field", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Please enter a valid email address": "Introduzca una dirección de correo electrónico válida", + "Please enter a valid email address": "Introduce una dirección de correo electrónico válida", "@Please enter a valid email address": { "description": "Error message for form field", "type": "text", @@ -1768,7 +1768,7 @@ "placeholders_order": [], "placeholders": {} }, - "qrCreateAccountTos": "Al tocar en “Crear usuario”, acepta los {termsOfService} y la {privacyPolicy}", + "qrCreateAccountTos": "Al tocar en “Crear usuario”, aceptas los {termsOfService} y la {privacyPolicy}", "@qrCreateAccountTos": { "description": "The text show on the account creation screen", "type": "text", @@ -1801,7 +1801,7 @@ "placeholders_order": [], "placeholders": {} }, - "Already have an account? ": "¿Ya tiene una cuenta? ", + "Already have an account? ": "¿Ya tienes una cuenta? ", "@Already have an account? ": { "description": "Part of multiline text span, includes AccountSignIn1-2, in that order", "type": "text", @@ -1891,21 +1891,21 @@ "placeholders_order": [], "placeholders": {} }, - "You will be notified about this event on…": "Se le notificará acerca de este evento el...", + "You will be notified about this event on…": "Se te notificará acerca de este evento el...", "@You will be notified about this event on…": { "description": "Description for when an event reminder is set", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Share Your Love for the App": "Comparta su amor por la aplicación", + "Share Your Love for the App": "Comparte tu amor por la aplicación", "@Share Your Love for the App": { "description": "Label for option to open the app store", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Tell us about your favorite parts of the app": "Díganos cuáles son las partes de la aplicación que le gustan más", + "Tell us about your favorite parts of the app": "Dinos cuáles son las partes de la aplicación que más te gustan", "@Tell us about your favorite parts of the app": { "description": "Description for option to open the app store", "type": "text", @@ -1933,7 +1933,7 @@ "placeholders_order": [], "placeholders": {} }, - "The following information will help us better understand your idea:": "La siguiente información nos ayudará a comprender mejor su idea:", + "The following information will help us better understand your idea:": "La siguiente información nos ayudará a comprender mejor tu idea:", "@The following information will help us better understand your idea:": { "description": "The header for the users information that is attached to a feature request", "type": "text", @@ -2051,7 +2051,7 @@ "placeholders_order": [], "placeholders": {} }, - "How is this affecting you?": "¿Cómo le afecta esto?", + "How is this affecting you?": "¿Cómo te afecta esto?", "@How is this affecting you?": { "description": "Label used for the dropdown to select how severe the issue is", "type": "text", @@ -2083,7 +2083,7 @@ "placeholders_order": [], "placeholders": {} }, - "I can't get things done until I hear back from you.": "No puedo hacer nada hasta que me contesten.", + "I can't get things done until I hear back from you.": "No puedo hacer nada hasta que me contestéis.", "@I can't get things done until I hear back from you.": { "type": "text", "placeholders_order": [], @@ -2155,7 +2155,7 @@ "userName": {} } }, - "\"Act as\" is essentially logging in as this user without a password. You will be able to take any action as if you were this user, and from other users' points of views, it will be as if this user performed them. However, audit logs record that you were the one who performed the actions on behalf of this user.": "\"Actuar como\" es básicamente iniciar sesión como si fuera este usuario pero sin una contraseña. Podrá realizar cualquier acción como si fuera este usuario y, desde el punto de vista de los demás usuarios, será como si este usuario las hubiera realizado. Sin embargo, los registros de auditoría indican que usted es quien ha realizado las acciones en representación de este usuario.", + "\"Act as\" is essentially logging in as this user without a password. You will be able to take any action as if you were this user, and from other users' points of views, it will be as if this user performed them. However, audit logs record that you were the one who performed the actions on behalf of this user.": "\"Actuar como\" es básicamente iniciar sesión como si fuera este usuario pero sin una contraseña. Podrás realizar cualquier acción como si fueras este usuario y, desde el punto de vista de los demás usuarios, será como si este usuario las hubiera realizado. Sin embargo, los registros de auditoría indican que tu eres quien ha realizado las acciones en representación de este usuario.", "@\"Act as\" is essentially logging in as this user without a password. You will be able to take any action as if you were this user, and from other users' points of views, it will be as if this user performed them. However, audit logs record that you were the one who performed the actions on behalf of this user.": { "type": "text", "placeholders_order": [], @@ -2168,7 +2168,7 @@ "placeholders_order": [], "placeholders": {} }, - "You must enter a valid domain": "Debe introducir un dominio válido", + "You must enter a valid domain": "Debes introducir un dominio válido", "@You must enter a valid domain": { "description": "Message displayed for domain input error", "type": "text", @@ -2182,20 +2182,20 @@ "placeholders_order": [], "placeholders": {} }, - "You must enter a user id": "Debe introducir una identificación de usuario", + "You must enter a user id": "Debes introducir una identificación de usuario", "@You must enter a user id": { "description": "Message displayed for user Id input error", "type": "text", "placeholders_order": [], "placeholders": {} }, - "There was an error trying to act as this user. Please check the Domain and User ID and try again.": "Ha habido un error al intentar actuar en nombre de este usuario. Revise el dominio y la identificación de usuario y vuelva a intentarlo.", + "There was an error trying to act as this user. Please check the Domain and User ID and try again.": "Ha habido un error al intentar actuar en nombre de este usuario. Revisa el dominio y la identificación de usuario y vuelve a intentarlo.", "@There was an error trying to act as this user. Please check the Domain and User ID and try again.": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "endMasqueradeMessage": "Dejará de actuar como {userName} y volverá a su cuenta original.", + "endMasqueradeMessage": "Dejarás de actuar como {userName} y volverás a tu cuenta original.", "@endMasqueradeMessage": { "description": "Confirmation message displayed when the user wants to stop acting (masquerading) as another user", "type": "text", @@ -2206,7 +2206,7 @@ "userName": {} } }, - "endMasqueradeLogoutMessage": "Dejará de actuar como {userName} y cerrará la sesión.", + "endMasqueradeLogoutMessage": "Dejarás de actuar como {userName} y cerrarás la sesión.", "@endMasqueradeLogoutMessage": { "description": "Confirmation message displayed when the user wants to stop acting (masquerading) as another user and will be logged out.", "type": "text", @@ -2217,7 +2217,7 @@ "userName": {} } }, - "How are we doing?": "¿Cómo está?", + "How are we doing?": "¿Cómo estás?", "@How are we doing?": { "description": "Title for dialog asking user to rate the app out of 5 stars.", "type": "text", @@ -2269,7 +2269,7 @@ } } }, - "Student Pairing": "Emparejamiento del alumno", + "Student Pairing": "Emparejamiento del estudiante", "@Student Pairing": { "description": "Title for the screen where users can pair to students using a QR code", "type": "text", @@ -2283,7 +2283,7 @@ "placeholders_order": [], "placeholders": {} }, - "You'll need to open your student's Canvas Student app to continue. Go into Main Menu > Settings > Pair with Observer and scan the QR code you see there.": "Para continuar, debe abrir la aplicación Canvas Student de su alumno. Vaya a Menú Principal > Configuraciones > Emparejar con Observador y escanee el código QR que aparece allí.", + "You'll need to open your student's Canvas Student app to continue. Go into Main Menu > Settings > Pair with Observer and scan the QR code you see there.": "Para continuar, debes abrir la aplicación Canvas Student de tu estudiante. Ve a Menú Principal > Configuraciones > Emparejar con Observador y escanea el código QR que aparece allí.", "@You'll need to open your student's Canvas Student app to continue. Go into Main Menu > Settings > Pair with Observer and scan the QR code you see there.": { "description": "Message explaining how QR code pairing works", "type": "text", @@ -2304,13 +2304,13 @@ "placeholders_order": [], "placeholders": {} }, - "The QR code you scanned may have expired. Refresh the code on the student's device and try again.": "Es posible que el código QR que ha escaneado haya caducado. Actualice el código en el dispositivo del alumno y vuelva a intentarlo.", + "The QR code you scanned may have expired. Refresh the code on the student's device and try again.": "Es posible que el código QR que has escaneado haya caducado. Actualiza el código en el dispositivo del estudiante y vuelve a intentarlo.", "@The QR code you scanned may have expired. Refresh the code on the student's device and try again.": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "A network error occurred when adding this student. Check your connection and try again.": "Ha habido un error de la red al añadir a este alumno. Compruebe su conexión y vuelva a intentarlo.", + "A network error occurred when adding this student. Check your connection and try again.": "Ha habido un error de la red al añadir a este estudiante. Comprueba tu conexión y vuelve a intentarlo.", "@A network error occurred when adding this student. Check your connection and try again.": { "type": "text", "placeholders_order": [], @@ -2330,7 +2330,7 @@ "placeholders_order": [], "placeholders": {} }, - "The student you are trying to add belongs to a different school. Log in or create an account with that school to scan this code.": "El alumno que está intentando añadir pertenece a una escuela diferente. Inicie sesión o cree una cuenta con esa escuela para escanear el código.", + "The student you are trying to add belongs to a different school. Log in or create an account with that school to scan this code.": "El estudiante que está intentando añadir pertenece a una escuela diferente. Inicia sesión o crea una cuenta con esa escuela para escanear el código.", "@The student you are trying to add belongs to a different school. Log in or create an account with that school to scan this code.": { "type": "text", "placeholders_order": [], @@ -2343,14 +2343,14 @@ "placeholders_order": [], "placeholders": {} }, - "This will unpair and remove all enrollments for this student from your account.": "Deshará el emparejamiento y eliminará todas las inscripciones de este alumno en su cuenta.", + "This will unpair and remove all enrollments for this student from your account.": "Esto deshará el emparejamiento y eliminará todas las inscripciones de este estudiante en tu cuenta.", "@This will unpair and remove all enrollments for this student from your account.": { "description": "Confirmation message shown when the user tries to delete a student from their account", "type": "text", "placeholders_order": [], "placeholders": {} }, - "There was a problem removing this student from your account. Please check your connection and try again.": "Ha habido un problema al eliminar a este alumno de su cuenta. Compruebe su conexión y vuelva a intentarlo.", + "There was a problem removing this student from your account. Please check your connection and try again.": "Ha habido un problema al eliminar a este estudiante de tu cuenta. Comprueba tu conexión y vuelve a intentarlo.", "@There was a problem removing this student from your account. Please check your connection and try again.": { "type": "text", "placeholders_order": [], @@ -2454,7 +2454,7 @@ "placeholders_order": [], "placeholders": {} }, - "Interactions on this page are limited by your institution.": "Las interacciones en esta página están limitadas por su institución.", + "Interactions on this page are limited by your institution.": "Las interacciones en esta página están limitadas por tu institución.", "@Interactions on this page are limited by your institution.": { "description": "Message describing how the webview has limited access due to an instution setting", "type": "text", @@ -2549,7 +2549,7 @@ "placeholders_order": [], "placeholders": {} }, - "We are currently building this feature for your viewing pleasure.": "Actualmente estamos desarrollando esta funcionalidad para que pueda disfrutarla.", + "We are currently building this feature for your viewing pleasure.": "Actualmente estamos desarrollando esta funcionalidad para que puedas disfrutarla.", "@We are currently building this feature for your viewing pleasure.": { "type": "text", "placeholders_order": [], @@ -2583,7 +2583,7 @@ "placeholders_order": [], "placeholders": {} }, - "We are unable to display this link, it may belong to an institution you currently aren't logged in to.": "No podemos mostrar este enlace; es posible que pertenezca a una institución en la que no tiene sesión abierta actualmente.", + "We are unable to display this link, it may belong to an institution you currently aren't logged in to.": "No podemos mostrar este enlace; es posible que pertenezca a una institución en la que no tienes sesión abierta actualmente.", "@We are unable to display this link, it may belong to an institution you currently aren't logged in to.": { "description": "Description for error page shown when clicking a link", "type": "text", @@ -2604,7 +2604,7 @@ "placeholders_order": [], "placeholders": {} }, - "You'll find the QR code on the web in your account profile. Click 'QR for Mobile Login' in the list.": "Encontrará el código QR en el sitio web, en su perfil de la cuenta. Haga clic en “QR para Inicio de sesión móvil” en la lista.", + "You'll find the QR code on the web in your account profile. Click 'QR for Mobile Login' in the list.": "Encontrarás el código QR en el sitio web, en tu perfil de la cuenta. Haz clic en “QR para Inicio de sesión móvil” en la lista.", "@You'll find the QR code on the web in your account profile. Click 'QR for Mobile Login' in the list.": { "description": "Text for qr login tutorial screen", "type": "text", @@ -2618,14 +2618,14 @@ "placeholders_order": [], "placeholders": {} }, - "Please scan a QR code generated by Canvas": "Escanee un código QR generado por Canvas", + "Please scan a QR code generated by Canvas": "Escanea un código QR generado por Canvas", "@Please scan a QR code generated by Canvas": { "description": "Text for qr login error with incorrect qr code", "type": "text", "placeholders_order": [], "placeholders": {} }, - "There was an error logging in. Please generate another QR Code and try again.": "Ha habido un error al iniciar sesión. Genere otro código QR y vuelva a intentarlo.", + "There was an error logging in. Please generate another QR Code and try again.": "Ha habido un error al iniciar sesión. Genera otro código QR y vuelve a intentarlo.", "@There was an error logging in. Please generate another QR Code and try again.": { "description": "Text for qr login error", "type": "text", diff --git a/apps/flutter_parent/lib/l10n/res/intl_ja.arb b/apps/flutter_parent/lib/l10n/res/intl_ja.arb index 9b8c9d4151..03ea099623 100644 --- a/apps/flutter_parent/lib/l10n/res/intl_ja.arb +++ b/apps/flutter_parent/lib/l10n/res/intl_ja.arb @@ -7,7 +7,7 @@ "placeholders_order": [], "placeholders": {} }, - "calendarLabel": "予定表", + "calendarLabel": "カレンダー", "@calendarLabel": { "description": "The label for the Calendar tab", "type": "text", @@ -21,35 +21,35 @@ "placeholders_order": [], "placeholders": {} }, - "No Students": "受講生はいません", + "No Students": "受講者はいません", "@No Students": { "description": "Text for when an observer has no students they are observing", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Tap to show student selector": "タップして受講生セレクタを表示します", + "Tap to show student selector": "タップして受講者セレクタを表示します", "@Tap to show student selector": { "description": "Semantics label for the area that will show the student selector when tapped", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Tap to pair with a new student": "タップして新しい受講生とペアにします", + "Tap to pair with a new student": "タップして新しい受講者とペアにします", "@Tap to pair with a new student": { "description": "Semantics label for the add student button in the student selector", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Tap to select this student": "タップしてこの受講生を選択します", + "Tap to select this student": "タップしてこの受講者を選択します", "@Tap to select this student": { "description": "Semantics label on individual students in the student switcher", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Manage Students": "受講生を管理する", + "Manage Students": "受講者を管理する", "@Manage Students": { "description": "Label text for the Manage Students nav drawer button as well as the title for the Manage Students screen", "type": "text", @@ -95,7 +95,7 @@ "placeholders_order": [], "placeholders": {} }, - "Calendars": "予定表", + "Calendars": "カレンダー", "@Calendars": { "description": "Label for button that lets users select which calendars to display", "type": "text", @@ -196,14 +196,14 @@ "placeholders_order": [], "placeholders": {} }, - "There was an error loading your student's calendar": "受講生の予定表のロード中にエラーが発生しました", + "There was an error loading your student's calendar": "受講者のカレンダーのロード中にエラーが発生しました", "@There was an error loading your student's calendar": { "description": "Message displayed when calendar events could not be loaded for the current student", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Tap to favorite the courses you want to see on the Calendar. Select up to 10.": "タップして予定表に表示したいコースをお気に入りにします。10まで選んでください。", + "Tap to favorite the courses you want to see on the Calendar. Select up to 10.": "タップしてカレンダーに表示したいコースをお気に入りにします。10まで選んでください。", "@Tap to favorite the courses you want to see on the Calendar. Select up to 10.": { "description": "Description text on calendar filter screen.", "type": "text", @@ -686,21 +686,21 @@ "placeholders_order": [], "placeholders": {} }, - "Your student’s courses might not be published yet.": "受講生のコースはまだ公開されていない可能性があります", + "Your student’s courses might not be published yet.": "受講者のコースはまだ公開されていない可能性があります", "@Your student’s courses might not be published yet.": { "description": "Message for having no courses", "type": "text", "placeholders_order": [], "placeholders": {} }, - "There was an error loading your student’s courses.": "受講生のコースを読み込み中にエラーが発生しました。", + "There was an error loading your student’s courses.": "受講者のコースを読み込み中にエラーが発生しました。", "@There was an error loading your student’s courses.": { "description": "Message displayed when the list of student courses could not be loaded", "type": "text", "placeholders_order": [], "placeholders": {} }, - "No Grade": "成績はありません", + "No Grade": "評定はありません", "@No Grade": { "description": "Message shown when there is currently no grade available for a course", "type": "text", @@ -714,7 +714,7 @@ "placeholders_order": [], "placeholders": {} }, - "Grades": "成績", + "Grades": "評定", "@Grades": { "description": "Label for the \"Grades\" tab in course details", "type": "text", @@ -749,7 +749,7 @@ "placeholders_order": [], "placeholders": {} }, - "Total Grade": "合計成績", + "Total Grade": "合計評定", "@Total Grade": { "description": "Label for the total grade in the course", "type": "text", @@ -833,7 +833,7 @@ "placeholders_order": [], "placeholders": {} }, - "This course does not have any assignments or calendar events yet.": "このコースには、まだ課題または予定表イベントがありません。", + "This course does not have any assignments or calendar events yet.": "このコースには、まだ課題またはカレンダーイベントがありません。", "@This course does not have any assignments or calendar events yet.": { "description": "Message displayed when there are no items in the course summary", "type": "text", @@ -866,7 +866,7 @@ "pointsPossible": {} } }, - "gradesSubjectMessage": "Re:{studentName}、成績", + "gradesSubjectMessage": "Re:{studentName}、評定", "@gradesSubjectMessage": { "description": "The subject line for a message to a teacher regarding a student's grades", "type": "text", @@ -968,7 +968,7 @@ "placeholders_order": [], "placeholders": {} }, - "Grade": "成績", + "Grade": "評定", "@Grade": { "description": "Label for the section that displays an assignment's grade", "type": "text", @@ -1063,7 +1063,7 @@ "placeholders_order": [], "placeholders": {} }, - "Notifications for reminders about assignments and calendar events": "課題と予定表イベントに関するリマインダの通知", + "Notifications for reminders about assignments and calendar events": "課題とカレンダーイベントに関するリマインダの通知", "@Notifications for reminders about assignments and calendar events": { "description": "Description of the system notification channel for assignment and event reminders", "type": "text", @@ -1090,14 +1090,14 @@ "placeholders_order": [], "placeholders": {} }, - "We couldn't find any students associated with this account": "このアカウントに関連付けられている受講生を見つけることができませんでした", + "We couldn't find any students associated with this account": "このアカウントに関連付けられている受講者を見つけることができませんでした", "@We couldn't find any students associated with this account": { "description": "Subtitle for the screen that shows when the user is not observing any students", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Are you a student or teacher?": "受講生と講師のどちらですか?", + "Are you a student or teacher?": "受講者と教員のどちらですか?", "@Are you a student or teacher?": { "description": "Label for button that will show users the option to view other Canvas apps in the Play Store", "type": "text", @@ -1118,28 +1118,28 @@ "placeholders_order": [], "placeholders": {} }, - "STUDENT": "受講生", + "STUDENT": "受講者", "@STUDENT": { "description": "The \"student\" portion of the \"Canvas Student\" app name, in all caps. \"Canvas\" is excluded in this context as it will be displayed to the user as a wordmark image", "type": "text", "placeholders_order": [], "placeholders": {} }, - "TEACHER": "講師", + "TEACHER": "教員", "@TEACHER": { "description": "The \"teacher\" portion of the \"Canvas Teacher\" app name, in all caps. \"Canvas\" is excluded in this context as it will be displayed to the user as a wordmark image", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Canvas Student": "Canvas 受講生", + "Canvas Student": "Canvas 受講者", "@Canvas Student": { "description": "The name of the Canvas Student app. Only \"Student\" should be translated as \"Canvas\" is a brand name in this context and should not be translated.", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Canvas Teacher": "Canvas 講師", + "Canvas Teacher": "Canvas 教員", "@Canvas Teacher": { "description": "The name of the Canvas Teacher app. Only \"Teacher\" should be translated as \"Canvas\" is a brand name in this context and should not be translated.", "type": "text", @@ -1185,7 +1185,7 @@ "placeholders_order": [], "placeholders": {} }, - "assignmentGradeAboveThreshold": "{threshold} 点を超える課題成績", + "assignmentGradeAboveThreshold": "{threshold} 点を超える課題評定", "@assignmentGradeAboveThreshold": { "description": "Title for alerts when an assignment grade is above the threshold value", "type": "text", @@ -1196,7 +1196,7 @@ "threshold": {} } }, - "assignmentGradeBelowThreshold": "{threshold} 点未満の課題成績", + "assignmentGradeBelowThreshold": "{threshold} 点未満の課題評定", "@assignmentGradeBelowThreshold": { "description": "Title for alerts when an assignment grade is below the threshold value", "type": "text", @@ -1207,7 +1207,7 @@ "threshold": {} } }, - "courseGradeAboveThreshold": "{threshold} 点を超えるコース成績", + "courseGradeAboveThreshold": "{threshold} 点を超えるコース評定", "@courseGradeAboveThreshold": { "description": "Title for alerts when a course grade is above the threshold value", "type": "text", @@ -1218,7 +1218,7 @@ "threshold": {} } }, - "courseGradeBelowThreshold": "{threshold} 点未満のコース成績", + "courseGradeBelowThreshold": "{threshold} 点未満のコース評定", "@courseGradeBelowThreshold": { "description": "Title for alerts when a course grade is below the threshold value", "type": "text", @@ -1350,7 +1350,7 @@ "pointsLost": {} } }, - "finalGrade": "最終成績:{grade}", + "finalGrade": "最終評定:{grade}", "@finalGrade": { "description": "Text that displays the final grade of an assignment", "type": "text", @@ -1374,14 +1374,14 @@ "placeholders_order": [], "placeholders": {} }, - "Course grade below": "を超えるコース成績", + "Course grade below": "を超えるコース評定", "@Course grade below": { "description": "Label describing the threshold for when the course grade is below a certain percentage", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Course grade above": "未満のコース成績", + "Course grade above": "未満のコース評定", "@Course grade above": { "description": "Label describing the threshold for when the course grade is above a certain percentage", "type": "text", @@ -1394,14 +1394,14 @@ "placeholders_order": [], "placeholders": {} }, - "Assignment grade below": "を超える課題成績", + "Assignment grade below": "を超える課題評定", "@Assignment grade below": { "description": "Label describing the threshold for when an assignment is graded below a certain percentage", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Assignment grade above": "未満の課題成績", + "Assignment grade above": "未満の課題評定", "@Assignment grade above": { "description": "Label describing the threshold for when an assignment is graded above a certain percentage", "type": "text", @@ -1427,13 +1427,13 @@ "placeholders_order": [], "placeholders": {} }, - "Grade percentage": "成績パーセンテージ", + "Grade percentage": "評定パーセンテージ", "@Grade percentage": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "There was an error loading your student's alerts.": "受講生のアラートのロード中にエラーが発生しました", + "There was an error loading your student's alerts.": "受講者のアラートのロード中にエラーが発生しました", "@There was an error loading your student's alerts.": { "type": "text", "placeholders_order": [], @@ -1471,7 +1471,7 @@ } } }, - "Select Student Color": "受講生の色を選択する", + "Select Student Color": "受講者の色を選択する", "@Select Student Color": { "description": "Title for screen that allows users to assign a color to a specific student", "type": "text", @@ -1537,7 +1537,7 @@ "studentName": {} } }, - "Teacher": "教師", + "Teacher": "教員", "@Teacher": { "description": "Label for the Teacher enrollment type", "type": "text", @@ -1593,25 +1593,25 @@ "placeholders_order": [], "placeholders": {} }, - "Add student with…": "次を使って受講生を追加します…", + "Add student with…": "次を使って受講者を追加します…", "@Add student with…": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "Add Student": "受講生を追加", + "Add Student": "受講者を追加", "@Add Student": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "You are not observing any students.": "どの受講生もオブザーブしていません。", + "You are not observing any students.": "どの受講者もオブザーブしていません。", "@You are not observing any students.": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "There was an error loading your students.": "受講生のロード中にエラーが発生しました。", + "There was an error loading your students.": "受講者のロード中にエラーが発生しました。", "@There was an error loading your students.": { "type": "text", "placeholders_order": [], @@ -1623,13 +1623,13 @@ "placeholders_order": [], "placeholders": {} }, - "Students can obtain a pairing code through the Canvas website": "受講生はCanvas Webサイトからペアリングコードを取得できます", + "Students can obtain a pairing code through the Canvas website": "受講者はCanvas Webサイトからペアリングコードを取得できます", "@Students can obtain a pairing code through the Canvas website": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "Enter the student pairing code provided to you. If the pairing code doesn't work, it may have expired": "提供されている受講生ペアリングコードを入力してください。ペアリングコードが機能しない場合は、有効期限が切れているかもしれません", + "Enter the student pairing code provided to you. If the pairing code doesn't work, it may have expired": "提供されている受講者ペアリングコードを入力してください。ペアリングコードが機能しない場合は、有効期限が切れているかもしれません", "@Enter the student pairing code provided to you. If the pairing code doesn't work, it may have expired": { "type": "text", "placeholders_order": [], @@ -1653,13 +1653,13 @@ "placeholders_order": [], "placeholders": {} }, - "Students can create a QR code using the Canvas Student app on their mobile device": "受講生はモバイルデバイスのCanvas Studentアプリを使用してQRコードを作成できます", + "Students can create a QR code using the Canvas Student app on their mobile device": "受講者はモバイルデバイスのCanvas Studentアプリを使用してQRコードを作成できます", "@Students can create a QR code using the Canvas Student app on their mobile device": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "Add new student": "新しい受講生を追加する", + "Add new student": "新しい受講者を追加する", "@Add new student": { "description": "Semantics label for the FAB on the Manage Students Screen", "type": "text", @@ -2269,21 +2269,21 @@ } } }, - "Student Pairing": "受講生のペアリング", + "Student Pairing": "受講者のペアリング", "@Student Pairing": { "description": "Title for the screen where users can pair to students using a QR code", "type": "text", "placeholders_order": [], "placeholders": {} }, - "Open Canvas Student": "Open Canvas受講生", + "Open Canvas Student": "Open Canvas受講者", "@Open Canvas Student": { "description": "Title for QR pairing tutorial screen instructing users to open the Canvas Student app", "type": "text", "placeholders_order": [], "placeholders": {} }, - "You'll need to open your student's Canvas Student app to continue. Go into Main Menu > Settings > Pair with Observer and scan the QR code you see there.": "続行するには、受講生のCanvas Studentアプリを開く必要があります。メインメニュー > [設定] > [オブザーバーとのペアリング]に移動し、そこに表示されるQRコードをスキャンしてください。", + "You'll need to open your student's Canvas Student app to continue. Go into Main Menu > Settings > Pair with Observer and scan the QR code you see there.": "続行するには、受講者のCanvas Studentアプリを開く必要があります。メインメニュー > [設定] > [オブザーバーとのペアリング]に移動し、そこに表示されるQRコードをスキャンしてください。", "@You'll need to open your student's Canvas Student app to continue. Go into Main Menu > Settings > Pair with Observer and scan the QR code you see there.": { "description": "Message explaining how QR code pairing works", "type": "text", @@ -2304,13 +2304,13 @@ "placeholders_order": [], "placeholders": {} }, - "The QR code you scanned may have expired. Refresh the code on the student's device and try again.": "スキャンしたQRコードの有効期限が切れている可能性があります。受講生のデバイスでコードを更新して、もう一度やり直してください。", + "The QR code you scanned may have expired. Refresh the code on the student's device and try again.": "スキャンしたQRコードの有効期限が切れている可能性があります。受講者のデバイスでコードを更新して、もう一度やり直してください。", "@The QR code you scanned may have expired. Refresh the code on the student's device and try again.": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "A network error occurred when adding this student. Check your connection and try again.": "この受講生を追加中にネットワークエラーが発生しました。接続をチェックして、もう一度やり直してください。", + "A network error occurred when adding this student. Check your connection and try again.": "この受講者を追加中にネットワークエラーが発生しました。接続をチェックして、もう一度やり直してください。", "@A network error occurred when adding this student. Check your connection and try again.": { "type": "text", "placeholders_order": [], @@ -2330,7 +2330,7 @@ "placeholders_order": [], "placeholders": {} }, - "The student you are trying to add belongs to a different school. Log in or create an account with that school to scan this code.": "追加しようとしている受講生は、別の学校に所属しています。このコードをスキャンするには、その学校にログインするかアカウントを作成してください。", + "The student you are trying to add belongs to a different school. Log in or create an account with that school to scan this code.": "追加しようとしている受講者は、別の学校に所属しています。このコードをスキャンするには、その学校にログインするかアカウントを作成してください。", "@The student you are trying to add belongs to a different school. Log in or create an account with that school to scan this code.": { "type": "text", "placeholders_order": [], @@ -2343,14 +2343,14 @@ "placeholders_order": [], "placeholders": {} }, - "This will unpair and remove all enrollments for this student from your account.": "これにより、この受講生の登録がすべて解除され、アカウントから削除されます。", + "This will unpair and remove all enrollments for this student from your account.": "これにより、この受講者の登録がすべて解除され、アカウントから削除されます。", "@This will unpair and remove all enrollments for this student from your account.": { "description": "Confirmation message shown when the user tries to delete a student from their account", "type": "text", "placeholders_order": [], "placeholders": {} }, - "There was a problem removing this student from your account. Please check your connection and try again.": "この受講生をアカウントから削除する際に問題が発生しました。接続を確認して、もう一度お試しください。", + "There was a problem removing this student from your account. Please check your connection and try again.": "この受講者をアカウントから削除する際に問題が発生しました。接続を確認して、もう一度お試しください。", "@There was a problem removing this student from your account. Please check your connection and try again.": { "type": "text", "placeholders_order": [], diff --git a/apps/flutter_parent/lib/utils/common_widgets/empty_panda_widget.dart b/apps/flutter_parent/lib/utils/common_widgets/empty_panda_widget.dart index 6a5f0a78d0..7e3c626a57 100644 --- a/apps/flutter_parent/lib/utils/common_widgets/empty_panda_widget.dart +++ b/apps/flutter_parent/lib/utils/common_widgets/empty_panda_widget.dart @@ -48,7 +48,7 @@ class EmptyPandaWidget extends StatelessWidget { Text( title, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.headline6.copyWith(fontSize: 20, fontWeight: FontWeight.bold), + style: Theme.of(context).textTheme.headline6.copyWith(fontSize: 20, fontWeight: FontWeight.normal), ), if (title != null && subtitle != null) SizedBox(height: 8), if (subtitle != null) diff --git a/apps/flutter_parent/lib/utils/design/parent_theme.dart b/apps/flutter_parent/lib/utils/design/parent_theme.dart index adaf65ce52..e550afafa6 100644 --- a/apps/flutter_parent/lib/utils/design/parent_theme.dart +++ b/apps/flutter_parent/lib/utils/design/parent_theme.dart @@ -263,6 +263,7 @@ class _ParentThemeState extends State { accentIconTheme: IconThemeData(color: isDarkMode ? Colors.black : Colors.white), dividerColor: isHC ? onSurfaceColor : isDarkMode ? ParentColors.oxford : ParentColors.tiara, buttonTheme: ButtonThemeData(height: 48, minWidth: 120, textTheme: ButtonTextTheme.primary), + fontFamily: 'Lato' ); } diff --git a/apps/flutter_parent/lib/utils/web_view_utils.dart b/apps/flutter_parent/lib/utils/web_view_utils.dart index fca6ab5e22..1a8bfe49a6 100644 --- a/apps/flutter_parent/lib/utils/web_view_utils.dart +++ b/apps/flutter_parent/lib/utils/web_view_utils.dart @@ -33,6 +33,7 @@ extension WebViewUtils on WebViewController { String fileText = await rootBundle.loadString('assets/html/html_wrapper.html'); html = _applyWorkAroundForDoubleSlashesAsUrlSource(html); html = _addProtocolToLinks(html); + html = _checkForMathTags(html); html = fileText.replaceAll('{CANVAS_CONTENT}', html); html = html.replaceAll('{PADDING}', horizontalPadding.toString()); this.loadData(baseUrl, html, 'text/html', 'utf-8'); @@ -47,6 +48,16 @@ extension WebViewUtils on WebViewController { } } +String _checkForMathTags(String html) { + if ((RegExp('\$\$.+\$\$|\\\(.+\\\)').hasMatch(html) || html.contains(' + $html"""; + } else { + return html; + } +} + String _applyWorkAroundForDoubleSlashesAsUrlSource(String html) { if (html.isEmpty) return ''; // Fix for embedded videos that have // instead of http:// diff --git a/apps/flutter_parent/pubspec.yaml b/apps/flutter_parent/pubspec.yaml index d964415413..be8cd80c1a 100644 --- a/apps/flutter_parent/pubspec.yaml +++ b/apps/flutter_parent/pubspec.yaml @@ -141,6 +141,9 @@ flutter: - family: CanvasIconsSolid fonts: - asset: assets/fonts/CanvasIconsSolid.ttf + - family: Lato + fonts: + - asset: assets/fonts/lato_regular.ttf # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a diff --git a/apps/student/build.gradle b/apps/student/build.gradle index bffe3ae6df..bf0f74afac 100644 --- a/apps/student/build.gradle +++ b/apps/student/build.gradle @@ -54,8 +54,8 @@ android { applicationId "com.instructure.candroid" minSdkVersion Versions.MIN_SDK targetSdkVersion Versions.TARGET_SDK - versionCode = 236 - versionName = '6.16.2' + versionCode = 238 + versionName = '6.17.1' vectorDrawables.useSupportLibrary = true multiDexEnabled = true diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/AnnouncementsE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/AnnouncementsE2ETest.kt new file mode 100644 index 0000000000..6b03be97c9 --- /dev/null +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/AnnouncementsE2ETest.kt @@ -0,0 +1,115 @@ +/* + * 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.e2e + +import android.util.Log +import androidx.test.espresso.Espresso +import com.instructure.canvas.espresso.E2E +import com.instructure.canvas.espresso.refresh +import com.instructure.canvasapi2.models.DiscussionEntry +import com.instructure.panda_annotations.FeatureCategory +import com.instructure.panda_annotations.Priority +import com.instructure.panda_annotations.TestCategory +import com.instructure.panda_annotations.TestMetaData +import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.seedData +import com.instructure.student.ui.utils.tokenLogin +import dagger.hilt.android.testing.HiltAndroidTest +import org.junit.Test +import java.lang.Thread.sleep + +@HiltAndroidTest +class AnnouncementsE2ETest : StudentTest() { + override fun displaysPageObjects() = Unit + + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + + @E2E + @Test + @TestMetaData(Priority.MANDATORY, FeatureCategory.ANNOUNCEMENTS, TestCategory.E2E) + fun testAnnouncementsE2E() { + + Log.d(PREPARATION_TAG,"Seeding data.") + val data = seedData(students = 1, teachers = 1, courses = 1, announcements = 2, locked = true) + val student = data.studentsList[0] + val course = data.coursesList[0] + val announcement = data.announcementsList[0] + val secondAnnouncement = data.announcementsList[1] + + Log.d(STEP_TAG,"Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") + tokenLogin(student) + dashboardPage.waitForRender() + + Log.d(STEP_TAG,"Navigate to ${course.name} course's announcements page.") + dashboardPage.assertDisplaysCourse(course) + dashboardPage.selectCourse(course) + courseBrowserPage.selectAnnouncements() + + Log.d(STEP_TAG,"Assert that ${announcement.title} announcement is displayed.") + discussionListPage.assertTopicDisplayed(announcement.title) + + Log.d(STEP_TAG,"Select ${announcement.title} announcement and assert if we are landing on the Discussion Details Page.") + discussionListPage.selectTopic(announcement.title) + discussionDetailsPage.assertTitleText(announcement.title) + + val replyMessage = "Reply text" + Log.d(STEP_TAG,"Send a reply to the selected announcement with message: $replyMessage.") + discussionDetailsPage.sendReply(replyMessage) + discussionDetailsPage.assertPageObjects() + + Log.d(STEP_TAG,"Assert that the previously sent reply has been displayed.") + val announcementReply = DiscussionEntry(message = replyMessage) + discussionDetailsPage.assertIfThereIsAReply() + discussionDetailsPage.assertReplyDisplayed(announcementReply) + + Log.d(STEP_TAG,"Click on Search button and type ${announcement.title} to the search input field.") + Espresso.pressBack() + discussionListPage.clickOnSearchButton() + discussionListPage.typeToSearchBar(announcement.title) + + Log.d(STEP_TAG,"Assert that only the matching announcement is displayed on the Discussion List Page.") + discussionListPage.pullToUpdate() + discussionListPage.assertTopicDisplayed(announcement.title) + discussionListPage.assertTopicNotDisplayed(secondAnnouncement.title) + + Log.d(STEP_TAG,"Clear search input field value and assert if all the announcements are displayed again on the Discussion List Page.") + discussionListPage.clickOnClearSearchButton() + discussionListPage.waitForDiscussionTopicToDisplay(secondAnnouncement.title) + discussionListPage.assertTopicDisplayed(announcement.title) + + Log.d(STEP_TAG,"Type a search value to the search input field which does not much with any of the existing announcements.") + discussionListPage.typeToSearchBar("Non existing announcement title") + sleep(3000) //We need this wait here to let make sure the search process has finished. + + Log.d(STEP_TAG,"Assert that the empty view is displayed and none of the announcements are appearing on the page.") + discussionListPage.assertEmpty() + discussionListPage.assertTopicNotDisplayed(announcement.title) + discussionListPage.assertTopicNotDisplayed(secondAnnouncement.title) + + Log.d(STEP_TAG,"Clear search input field value and assert if all the announcements are displayed again on the Discussion List Page.") + discussionListPage.clickOnClearSearchButton() + discussionListPage.waitForDiscussionTopicToDisplay(secondAnnouncement.title) + discussionListPage.assertTopicDisplayed(announcement.title) + + Log.d(STEP_TAG,"Refresh the page and assert that after refresh, still all the announcements are displayed.") + refresh() + discussionListPage.assertTopicDisplayed(announcement.title) + discussionListPage.assertTopicDisplayed(secondAnnouncement.title) + } +} \ 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 f19e8695cb..77561fa26e 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 @@ -17,6 +17,7 @@ package com.instructure.student.ui.e2e import android.os.SystemClock.sleep +import android.util.Log import androidx.test.espresso.Espresso import androidx.test.rule.GrantPermissionRule import com.instructure.canvas.espresso.E2E @@ -45,7 +46,7 @@ class AssignmentsE2ETest: StudentTest() { override fun displaysPageObjects() = Unit override fun enableAndConfigureAccessibilityChecks() { - //We dont want to see accessibility errors on E2E tests + //We don't want to see accessibility errors on E2E tests } @Rule @@ -57,13 +58,16 @@ class AssignmentsE2ETest: StudentTest() { @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.ASSIGNMENTS, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.E2E) fun testPointsGradeTextAssignmentE2E() { + + 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] + Log.d(PREPARATION_TAG,"Seeding 'Text Entry' assignment for ${course.name} course.") val pointsTextAssignment = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY), @@ -73,22 +77,21 @@ class AssignmentsE2ETest: StudentTest() { dueAt = 1.days.fromNow.iso8601 )) - // Sign in with lone student + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) - - // Go into our course dashboardPage.waitForRender() + + Log.d(STEP_TAG,"Select course: ${course.name}.") dashboardPage.selectCourse(course) - // Select the assignments tab + Log.d(STEP_TAG,"Navigate to course Assignments Page.") courseBrowserPage.selectAssignments() - // Verify that our assignments are present, along with any grade/date info + Log.d(STEP_TAG,"Verify that our assignments are present, along with any grade/date info. Click on assignment ${pointsTextAssignment.name}.") assignmentListPage.assertHasAssignment(pointsTextAssignment) - - // Let's submit a text assignment assignmentListPage.clickAssignment(pointsTextAssignment) + Log.d(PREPARATION_TAG,"Submit assignment: ${pointsTextAssignment.name} for student: ${student.name}.") SubmissionsApi.submitCourseAssignment( submissionType = SubmissionType.ONLINE_TEXT_ENTRY, courseId = course.id, @@ -97,9 +100,11 @@ class AssignmentsE2ETest: StudentTest() { fileIds = emptyList().toMutableList() ) + Log.d(STEP_TAG,"Refresh the page, and assert that the assignment ${pointsTextAssignment.name} has been submitted successfully.") assignmentDetailsPage.refresh() - assignmentDetailsPage.verifyAssignmentSubmitted() + assignmentDetailsPage.assertAssignmentSubmitted() + Log.d(PREPARATION_TAG,"Grade submission: ${pointsTextAssignment.name} with 13 points.") val textGrade = SubmissionsApi.gradeSubmission( teacherToken = teacher.token, courseId = course.id, @@ -109,11 +114,12 @@ class AssignmentsE2ETest: StudentTest() { excused = false ) + Log.d(STEP_TAG,"Refresh the page. Assert that the assignment ${pointsTextAssignment.name} has been graded with 13 points.") assignmentDetailsPage.refresh() assignmentDetailsPage.verifyAssignmentGraded("13") - // Back to assignment list page - Espresso.pressBack() + Log.d(STEP_TAG,"Navigate back to Assignments Page and assert that the assignment ${pointsTextAssignment.name} can be seen there with the corresponding grade.") + Espresso.pressBack() assignmentListPage.refresh() assignmentListPage.assertHasAssignment(pointsTextAssignment, textGrade.grade) @@ -121,14 +127,16 @@ class AssignmentsE2ETest: StudentTest() { @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.ASSIGNMENTS, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.E2E) fun testLetterGradeTextAssignmentE2E() { + + 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] - // Pre-seed a submission and a grade for the letter grade text assignment + Log.d(PREPARATION_TAG,"Seeding 'Text Entry' assignment for ${course.name} course.") val letterGradeTextAssignment = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY), @@ -136,6 +144,8 @@ class AssignmentsE2ETest: StudentTest() { teacherToken = teacher.token, pointsPossible = 20.0 )) + + Log.d(PREPARATION_TAG,"Submit assignment: ${letterGradeTextAssignment.name} for student: ${student.name}.") SubmissionsApi.seedAssignmentSubmission(SubmissionsApi.SubmissionSeedRequest( assignmentId = letterGradeTextAssignment.id, courseId = course.id, @@ -146,6 +156,7 @@ class AssignmentsE2ETest: StudentTest() { )) )) + Log.d(PREPARATION_TAG,"Grade submission: ${letterGradeTextAssignment.name} with 13 points.") val submissionGrade = SubmissionsApi.gradeSubmission( teacherToken = teacher.token, courseId = course.id, @@ -154,30 +165,32 @@ class AssignmentsE2ETest: StudentTest() { postedGrade = "16", excused = false ) - // Sign in with lone student - tokenLogin(student) - // Go into our course + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") + tokenLogin(student) dashboardPage.waitForRender() - dashboardPage.selectCourse(course) - // Select the assignments tab + Log.d(STEP_TAG,"Select ${course.name} course and navigate to it's Assignments Page.") + dashboardPage.selectCourse(course) courseBrowserPage.selectAssignments() - // Verify that our assignments are present, along with any grade/date info + Log.d(STEP_TAG,"Assert that ${letterGradeTextAssignment.name} assignment is displayed with the corresponding grade: ${submissionGrade.grade}.") assignmentListPage.assertHasAssignment(letterGradeTextAssignment, submissionGrade.grade) } @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.ASSIGNMENTS, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.E2E) fun testPercentageFileAssignmentWithCommentE2E() { + + 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] + Log.d(PREPARATION_TAG,"Seeding assignment for ${course.name} course.") val percentageFileAssignment = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, submissionTypes = listOf(SubmissionType.ONLINE_UPLOAD), @@ -187,20 +200,23 @@ class AssignmentsE2ETest: StudentTest() { allowedExtensions = listOf("txt", "pdf", "jpg") )) + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) - - // Go into our course dashboardPage.waitForRender() - dashboardPage.selectCourse(course) - // Select the assignments tab + Log.d(STEP_TAG,"Select ${course.name} course and navigate to it's Assignments Page.") + dashboardPage.selectCourse(course) courseBrowserPage.selectAssignments() - // Verify that our assignments are present, along with any grade/date info + Log.d(STEP_TAG,"Assert that ${percentageFileAssignment.name} assignment is displayed.") assignmentListPage.assertHasAssignment(percentageFileAssignment) - // Upload a text file for submission + Log.d(STEP_TAG,"Select assignment: ${percentageFileAssignment.name}.") + + Log.d(STEP_TAG,"Click on ${percentageFileAssignment.name} assignment.") assignmentListPage.clickAssignment(percentageFileAssignment) + + Log.d(PREPARATION_TAG, "Seed a text file.") val uploadInfo = uploadTextFile( courseId = course.id, assignmentId = percentageFileAssignment.id, @@ -208,7 +224,7 @@ class AssignmentsE2ETest: StudentTest() { fileUploadType = FileUploadType.ASSIGNMENT_SUBMISSION ) - // Submit the assignment + Log.d(PREPARATION_TAG,"Submit ${percentageFileAssignment.name} assignment for ${student.name} student.") SubmissionsApi.submitCourseAssignment( submissionType = SubmissionType.ONLINE_UPLOAD, courseId = course.id, @@ -217,11 +233,11 @@ class AssignmentsE2ETest: StudentTest() { studentToken = student.token ) - // Verify that assignment has been submitted + Log.d(STEP_TAG,"Refresh the page. Assert that the ${percentageFileAssignment.name} assignment has been submitted.") assignmentDetailsPage.refresh() - assignmentDetailsPage.verifyAssignmentSubmitted() + assignmentDetailsPage.assertAssignmentSubmitted() - // Grade the assignment + Log.d(PREPARATION_TAG,"Grade ${percentageFileAssignment.name} assignment with 22 percentage.") SubmissionsApi.gradeSubmission( teacherToken = teacher.token, courseId = course.id, @@ -231,36 +247,41 @@ class AssignmentsE2ETest: StudentTest() { excused = false ) - // Verify that the assignment has been graded + Log.d(STEP_TAG,"Refresh the page. Assert that the ${percentageFileAssignment.name} assignment has been graded with 22 percentage.") assignmentDetailsPage.refresh() assignmentDetailsPage.verifyAssignmentGraded("22") - // Let's make sure that comments are working + + Log.d(STEP_TAG,"Navigate to submission details Comments Tab.") assignmentDetailsPage.goToSubmissionDetails() submissionDetailsPage.openComments() + + Log.d(STEP_TAG,"Assert that ${uploadInfo.fileName} file has been displayed as a comment.") submissionDetailsPage.assertCommentDisplayed( uploadInfo.fileName, student) - // Add a comment, make sure it shows up in the stream - submissionDetailsPage.addAndSendComment("My comment!!") + val newComment = "My comment!!" + Log.d(STEP_TAG,"Add a new comment ($newComment) and send it.") + submissionDetailsPage.addAndSendComment(newComment) sleep(2000) // Give the comment time to propagate - submissionDetailsPage.assertCommentDisplayed( - "My comment!!", - student - ) + + Log.d(STEP_TAG,"Assert that $newComment is displayed.") + submissionDetailsPage.assertCommentDisplayed(newComment, student) } @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.ASSIGNMENTS, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.E2E) fun testMultipleAssignmentsE2E() { + + 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] - // Pre-seed submissions and grade for letter grade assignment and points text assignment + Log.d(PREPARATION_TAG,"Seeding assignment for ${course.name} course.") val letterGradeTextAssignment = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY), @@ -269,6 +290,7 @@ class AssignmentsE2ETest: StudentTest() { pointsPossible = 20.0 )) + Log.d(PREPARATION_TAG,"Submit ${letterGradeTextAssignment.name} assignment for ${student.name} student.") SubmissionsApi.seedAssignmentSubmission(SubmissionsApi.SubmissionSeedRequest( assignmentId = letterGradeTextAssignment.id, courseId = course.id, @@ -279,6 +301,7 @@ class AssignmentsE2ETest: StudentTest() { )) )) + Log.d(PREPARATION_TAG,"Grade ${letterGradeTextAssignment.name} assignment with 16.") SubmissionsApi.gradeSubmission( teacherToken = teacher.token, courseId = course.id, @@ -288,6 +311,7 @@ class AssignmentsE2ETest: StudentTest() { excused = false ) + Log.d(PREPARATION_TAG,"Seeding assignment for ${course.name} course.") val pointsTextAssignment = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY), @@ -297,6 +321,7 @@ class AssignmentsE2ETest: StudentTest() { dueAt = 1.days.fromNow.iso8601 )) + Log.d(PREPARATION_TAG,"Submit ${pointsTextAssignment.name} assignment for ${student.name} student.") SubmissionsApi.seedAssignmentSubmission(SubmissionsApi.SubmissionSeedRequest( assignmentId = pointsTextAssignment.id, courseId = course.id, @@ -307,6 +332,7 @@ class AssignmentsE2ETest: StudentTest() { )) )) + Log.d(PREPARATION_TAG,"Grade ${pointsTextAssignment.name} assignment with 13 points.") SubmissionsApi.gradeSubmission( teacherToken = teacher.token, courseId = course.id, @@ -316,32 +342,33 @@ class AssignmentsE2ETest: StudentTest() { excused = false ) - // Sign in with lone student + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) - - // Go into our course dashboardPage.waitForRender() - dashboardPage.selectCourse(course) - // Select the assignments tab + Log.d(STEP_TAG,"Select ${course.name} course and navigate to it's Assignments Page.") + dashboardPage.selectCourse(course) courseBrowserPage.selectAssignments() - // Verify that our assignments are present, along with any grade/date info + Log.d(STEP_TAG,"Assert that ${pointsTextAssignment.name} assignment is displayed with the corresponding grade: 13.") assignmentListPage.assertHasAssignment(pointsTextAssignment,"13") + + Log.d(STEP_TAG,"Assert that ${letterGradeTextAssignment.name} assignment is displayed with the corresponding grade: 16.") assignmentListPage.assertHasAssignment(letterGradeTextAssignment, "16") } @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.COMMENTS, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.COMMENTS, TestCategory.E2E) fun testMediaCommentsE2E() { - // Seed basic student/teacher/course data + + 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] - // Seed an assignment and a submission + Log.d(PREPARATION_TAG,"Seeding assignment for ${course.name} course.") val assignment = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY), @@ -351,7 +378,8 @@ class AssignmentsE2ETest: StudentTest() { dueAt = 1.days.fromNow.iso8601 )) - val submission = SubmissionsApi.seedAssignmentSubmission(SubmissionsApi.SubmissionSeedRequest( + Log.d(PREPARATION_TAG,"Submit ${assignment.name} assignment for ${student.name} student.") + SubmissionsApi.seedAssignmentSubmission(SubmissionsApi.SubmissionSeedRequest( assignmentId = assignment.id, courseId = course.id, studentToken = student.token, @@ -361,20 +389,18 @@ class AssignmentsE2ETest: StudentTest() { )) )) - // Sign in with lone student + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) - - // Go into our course dashboardPage.waitForRender() - dashboardPage.selectCourse(course) - // Select the assignments tab + Log.d(STEP_TAG,"Select ${course.name} course and navigate to it's Assignments Page.") + dashboardPage.selectCourse(course) courseBrowserPage.selectAssignments() - // Select our assignment + Log.d(STEP_TAG,"Click on ${assignment.name} assignment.") assignmentListPage.clickAssignment(assignment) - // Open the submission details and the comments tab + Log.d(STEP_TAG,"Navigate to submission details Comments Tab.") assignmentDetailsPage.goToSubmissionDetails() submissionDetailsPage.openComments() @@ -386,9 +412,11 @@ class AssignmentsE2ETest: StudentTest() { //sleep(3000) // wait for video comment submission to propagate //submissionDetailsPage.assertVideoCommentDisplayed() - // send audio comment + Log.d(STEP_TAG,"Send an audio comment.") submissionDetailsPage.addAndSendAudioComment() - sleep(3000) // wait for audio comment submission to propagate + sleep(3000) // Wait for audio comment submission to propagate + + Log.d(STEP_TAG,"Assert that the audio comment has been displayed.") submissionDetailsPage.assertAudioCommentDisplayed() } } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/BookmarksE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/BookmarksE2ETest.kt new file mode 100644 index 0000000000..e05d57161a --- /dev/null +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/BookmarksE2ETest.kt @@ -0,0 +1,123 @@ +/* + * 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.e2e + +import android.util.Log +import androidx.test.espresso.Espresso +import com.instructure.canvas.espresso.E2E +import com.instructure.canvas.espresso.refresh +import com.instructure.dataseeding.api.AssignmentsApi +import com.instructure.dataseeding.model.GradingType +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.panda_annotations.FeatureCategory +import com.instructure.panda_annotations.Priority +import com.instructure.panda_annotations.TestCategory +import com.instructure.panda_annotations.TestMetaData +import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.seedData +import com.instructure.student.ui.utils.tokenLogin +import dagger.hilt.android.testing.HiltAndroidTest +import org.junit.Test + +@HiltAndroidTest +class BookmarksE2ETest : StudentTest() { + override fun displaysPageObjects() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + + @E2E + @Test + @TestMetaData(Priority.MANDATORY, FeatureCategory.BOOKMARKS, TestCategory.E2E) + fun testBookmarksE2E() { + + Log.d(PREPARATION_TAG,"Seeding data.") + val data = seedData(students = 1, teachers = 1, courses = 2) + val student = data.studentsList[0] + val teacher = data.teachersList[0] + val course = data.coursesList[0] + + Log.d(PREPARATION_TAG,"Preparing an assignment which will be saved as a bookmark.") + val assignment = AssignmentsApi.createAssignment( + AssignmentsApi.CreateAssignmentRequest( + courseId = course.id, + submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY), + gradingType = GradingType.POINTS, + teacherToken = teacher.token, + pointsPossible = 15.0, + dueAt = 1.days.fromNow.iso8601 + )) + + Log.d(STEP_TAG,"Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") + tokenLogin(student) + dashboardPage.waitForRender() + + Log.d(STEP_TAG, "Navigate to assignments page and click on the prepared assignment.") + dashboardPage.selectCourse(course) + courseBrowserPage.selectAssignments() + assignmentListPage.clickAssignment(assignment) + + val bookmarkName = "Assignment Details BM" + Log.d(STEP_TAG,"Add a new bookmark with name: $bookmarkName") + assignmentDetailsPage.addBookmark(bookmarkName) + + Log.d(STEP_TAG,"Navigate back to Bookmarks page and assert if the newly created bookmark has displayed.") + Espresso.pressBack() + Espresso.pressBack() + Espresso.pressBack() + dashboardPage.gotoBookmarks() + bookmarkPage.assertBookmarkDisplayed(bookmarkName) + + Log.d(STEP_TAG,"Click on $bookmarkName bookmark and assert if it's navigating to the assignment details page.") + bookmarkPage.clickBookmark(bookmarkName) + assignmentDetailsPage.verifyAssignmentTitle(assignment.name) + + Log.d(STEP_TAG,"Navigate back to bookmark page.") + Espresso.pressBack() + dashboardPage.gotoBookmarks() + bookmarkPage.assertBookmarkDisplayed(bookmarkName) + + val newName = "Assignment Details BM Modified" + Log.d(STEP_TAG,"Change bookmark's name from $bookmarkName to $newName.") + bookmarkPage.changeBookmarkName(bookmarkName, newName) + + Log.d(STEP_TAG,"Refresh bookmark page and assert if the bookmark's name has been changed.") + refresh() + bookmarkPage.assertBookmarkDisplayed(newName) + + Log.d(STEP_TAG,"Click on the previously renamed bookmark and assert if it's still navigating to the corresponding assignment's details page.") + bookmarkPage.clickBookmark(newName) + assignmentDetailsPage.verifyAssignmentTitle(assignment.name) + + Log.d(STEP_TAG,"Navigate back to the bookmark page.") + Espresso.pressBack() + dashboardPage.gotoBookmarks() + + Log.d(STEP_TAG, "Delete bookmark: $newName.") + bookmarkPage.deleteBookmark(newName) + + Log.d(STEP_TAG,"Assert that empty view is displayed, so the bookmark has been deleted.") + bookmarkPage.assertEmptyView() + } + +} \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/CollaborationsE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/CollaborationsE2ETest.kt index ddf44b5d4f..323fee40d5 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/CollaborationsE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/CollaborationsE2ETest.kt @@ -1,5 +1,6 @@ package com.instructure.student.ui.e2e +import android.util.Log import com.instructure.canvas.espresso.E2E import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority @@ -23,25 +24,30 @@ class CollaborationsE2ETest: StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.COLLABORATIONS, TestCategory.E2E, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.COLLABORATIONS, TestCategory.E2E) fun testCollaborationsE2E() { - // Seed basic student/teacher/course data + + Log.d(PREPARATION_TAG,"Seeding data.") val data = seedData(students = 1, teachers = 1, courses = 1) val student = data.studentsList[0] val course = data.coursesList[0] - // Sign the student in + Log.d(STEP_TAG,"Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) dashboardPage.waitForRender() - // Navigate to course collaborations + Log.d(STEP_TAG,"Navigate to ${course.name} course's Collaborations Page.") dashboardPage.selectCourse(course) courseBrowserPage.selectCollaborations() - // Verify that various elements of the web page are present + Log.d(STEP_TAG,"Verify that various elements of the web page are present.") CollaborationsPage.assertCurrentCollaborationsHeaderPresent() // For some reason, these aren't showing up when run in FTL, though they do diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ConferencesE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ConferencesE2ETest.kt index 9fe0d38fe6..a100993eaf 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ConferencesE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ConferencesE2ETest.kt @@ -1,5 +1,6 @@ package com.instructure.student.ui.e2e +import android.util.Log import com.instructure.canvas.espresso.E2E import com.instructure.canvas.espresso.Stub import com.instructure.panda_annotations.FeatureCategory @@ -19,6 +20,10 @@ class ConferencesE2ETest: StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + // Fairly basic test that we can create and view a conference with the app. // I didn't attempt to actually start the conference because that goes through // an external web browser and would be really gross (if not impossible) to @@ -30,31 +35,28 @@ class ConferencesE2ETest: StudentTest() { @Stub @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.CONFERENCES, TestCategory.E2E, true) + @TestMetaData(Priority.MANDATORY, FeatureCategory.CONFERENCES, TestCategory.E2E, true) fun testConferencesE2E() { - // Seed basic student/teacher/course data + 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] - // Sign the student in + Log.d(STEP_TAG,"Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) dashboardPage.waitForRender() - // Navigate to course conferences + Log.d(STEP_TAG,"Navigate to ${course.name} course's Conferences Page.") dashboardPage.selectCourse(course) courseBrowserPage.selectConferences() - // Some values to use/track val title = "Awesome Conference!" var description = "Awesome! Spectacular! Mind-blowing!" - - // Create a conference + Log.d(STEP_TAG,"Create a new conference with $title title and $description description.") ConferencesPage.createConference(title, description) - // Verify that your created conference is now displayed. + Log.d(STEP_TAG,"Assert that the previously created conference is displayed with $title title and $description description.") ConferencesPage.assertConferenceTitlePresent(title) ConferencesPage.assertConferenceDescriptionPresent(description) } diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/DashboardE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/DashboardE2ETest.kt index c936147809..40acdb7f5f 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/DashboardE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/DashboardE2ETest.kt @@ -16,6 +16,7 @@ */ package com.instructure.student.ui.e2e +import android.util.Log import com.instructure.canvas.espresso.E2E import com.instructure.dataseeding.api.ConversationsApi import com.instructure.dataseeding.api.GroupsApi @@ -36,49 +37,47 @@ class DashboardE2ETest : StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.DASHBOARD, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DASHBOARD, TestCategory.E2E) fun testDashboardE2E() { - // Seed data + Log.d(PREPARATION_TAG,"Seeding data.") val data = seedData(students = 1, teachers = 1, courses = 2) val student = data.studentsList[0] val teacher = data.teachersList[0] - - // This will not consistently result in a badge on the email icon on the bottom of the screen. - // So the check below is disabled. :-( - // Seed a conversation, to give us an email in our inbox + Log.d(PREPARATION_TAG, "Seed an Inbox conversation via API.") ConversationsApi.createConversation( token = teacher.token, recipients = listOf(student.id.toString()) ) - // Seed some group info + Log.d(PREPARATION_TAG,"Seed some group info.") val groupCategory = GroupsApi.createCourseGroupCategory(data.coursesList[0].id, teacher.token) val group = GroupsApi.createGroup(groupCategory.id, teacher.token) - val groupMembership = GroupsApi.createGroupMembership(group.id, student.id, teacher.token) - // Sanity check - assertEquals("course id for group", data.coursesList[0].id, group.courseId) + Log.d(PREPARATION_TAG,"Create group membership for ${student.name} student.") + GroupsApi.createGroupMembership(group.id, student.id, teacher.token) - // Sign in with lone student + Log.d(STEP_TAG,"Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) - - // Verify that the page rendered and our courses are there dashboardPage.waitForRender() - dashboardPage.assertPageObjects() - dashboardPage.assertDisplaysCourses() + for(course in data.coursesList) { + Log.d(STEP_TAG,"Assert that ${course.name} course is displayed.") dashboardPage.assertDisplaysCourse(course) } - // Verify that our group is displayed + Log.d(STEP_TAG,"Assert that ${group.name} groups is displayed.") dashboardPage.assertDisplaysGroup(group, data.coursesList[0]) - // Verify that our email conversation is represented - //dashboardPage.assertUnreadEmails(count = 1) // Not reliable :-( + Log.d(STEP_TAG,"Assert that there is an unread e-mail so we have the number '1' on the Inbox bottom-menu icon as a badge.") + dashboardPage.assertUnreadEmails(1) } } \ No newline at end of file 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 89ada0b788..cd2238f1e5 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 @@ -17,9 +17,11 @@ package com.instructure.student.ui.e2e import android.os.SystemClock.sleep +import android.util.Log import androidx.test.espresso.Espresso import com.instructure.canvas.espresso.E2E import com.instructure.dataseeding.api.DiscussionTopicsApi +import com.instructure.espresso.ViewUtils import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority import com.instructure.panda_annotations.TestCategory @@ -36,105 +38,134 @@ class DiscussionsE2ETest: StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - // Includes test logic for Announcements + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.E2E, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.E2E) fun testDiscussionsE2E() { - // Seed basic data + 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] - // Seed some discussion topics and an announcement + Log.d(PREPARATION_TAG,"Seed a discussion topic.") val topic1 = DiscussionTopicsApi.createDiscussion( courseId = course.id, token = teacher.token ) + Log.d(PREPARATION_TAG,"Seed another discussion topic.") val topic2 = DiscussionTopicsApi.createDiscussion( courseId = course.id, token = teacher.token ) + Log.d(STEP_TAG,"Seed an announcement for ${course.name} course.") val announcement = DiscussionTopicsApi.createAnnouncement( courseId = course.id, token = teacher.token ) + Log.d(STEP_TAG,"Seed another announcement for ${course.name} course.") val announcement2 = DiscussionTopicsApi.createAnnouncement( courseId = course.id, token = teacher.token ) - // Sign in our student + Log.d(STEP_TAG,"Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) dashboardPage.waitForRender() - // Select the class on the dashboard + Log.d(STEP_TAG,"Select course: ${course.name}.") dashboardPage.selectCourse(course) - // Verify that the "Discussions" and "Announcements" tabs are both displayed in course browser + Log.d(STEP_TAG,"Verify that the Discussions and Assignments Tabs are both displayed on the CourseBrowser Page.") courseBrowserPage.assertTabDisplayed("Announcements") courseBrowserPage.assertTabDisplayed("Discussions") - // Drill into seeded announcement, verifying what we can - // Note that DiscussionListPage, DiscussionDetailsPage are reused for announcements + Log.d(STEP_TAG,"Navigate to Announcements Page. Assert that both ${announcement.title} and ${announcement2.title} announcements are displayed.") courseBrowserPage.selectAnnouncements() discussionListPage.assertTopicDisplayed(announcement.title) discussionListPage.assertTopicDisplayed(announcement2.title) + + Log.d(STEP_TAG,"Select ${announcement.title} announcement and assert if the details page is displayed.") discussionListPage.selectTopic(announcement.title) discussionDetailsPage.assertTitleText(announcement.title) + + Log.d(STEP_TAG,"Navigate back.") Espresso.pressBack() - //Search for an announcement and check if the search works. - //Also, checking that not matching announcement is disappearing after typing a string into the search field. + Log.d(STEP_TAG,"Click on the 'Search' button and search for ${announcement2.title}. announcement.") discussionListPage.clickOnSearchButton() discussionListPage.typeToSearchBar(announcement2.title) + Log.d(STEP_TAG,"Refresh the page. Assert that the searching method is working well, so ${announcement.title} won't be displayed and ${announcement2.title} is displayed.") discussionListPage.pullToUpdate() discussionListPage.assertTopicDisplayed(announcement2.title) discussionListPage.assertTopicNotDisplayed(announcement.title) + Log.d(STEP_TAG,"Clear the search input field and assert that both announcements, ${announcement.title} and ${announcement2.title} has been diplayed.") discussionListPage.clickOnClearSearchButton() discussionListPage.waitForDiscussionTopicToDisplay(announcement.title) discussionListPage.assertTopicDisplayed(announcement2.title) - Espresso.pressBack() // Click away from Search input - Espresso.pressBack() // Back to announcement list - Espresso.pressBack() // Back to course browser page + Log.d(STEP_TAG,"Navigate back to CourseBrowser Page.") + ViewUtils.pressBackButton(3) - // Drill into the seeded discussions, verifying what we can + Log.d(STEP_TAG,"Navigate to Discussions Page.") courseBrowserPage.selectDiscussions() + + Log.d(STEP_TAG,"Select ${topic1.title} discussion and assert if the details page is displayed and there is no reply for the discussion yet.") discussionListPage.assertTopicDisplayed(topic1.title) discussionListPage.selectTopic(topic1.title) discussionDetailsPage.assertTitleText(topic1.title) discussionDetailsPage.assertNoRepliesDisplayed() + + Log.d(STEP_TAG,"Navigate back to Discussions Page.") Espresso.pressBack() // Back to discussion list + + Log.d(STEP_TAG,"Select ${topic1.title} discussion and assert if the details page is displayed and there is no reply for the discussion yet.") discussionListPage.assertTopicDisplayed(topic2.title) discussionListPage.selectTopic(topic2.title) discussionDetailsPage.assertTitleText(topic2.title) discussionDetailsPage.assertNoRepliesDisplayed() - Espresso.pressBack() // Back to discussion list - // Now let's try creating a discussion topic & replying to a discussion via the UI + Log.d(STEP_TAG,"Navigate back to Discussions Page.") + Espresso.pressBack() + val newTopicName = "Do we really need discussions?" val newTopicDescription = "Let's discuss" + Log.d(STEP_TAG,"Create a new discussion topic with '$newTopicName' topic name and '$newTopicDescription' topic description.") discussionListPage.createDiscussionTopic(newTopicName, newTopicDescription) sleep(2000) // Allow some time for creation to propagate + + Log.d(STEP_TAG,"Assert that $newTopicName topic has been created successfully with 0 reply count.") discussionListPage.assertTopicDisplayed(newTopicName) discussionListPage.assertReplyCount(newTopicName, 0) + + Log.d(STEP_TAG,"Select $newTopicName topic and assert that there is no reply on the details page as well.") discussionListPage.selectTopic(newTopicName) discussionDetailsPage.assertNoRepliesDisplayed() - discussionDetailsPage.sendReply("My reply") + + val replyMessage = "My reply" + Log.d(STEP_TAG,"Send a reply with text: '$replyMessage'.") + discussionDetailsPage.sendReply(replyMessage) sleep(2000) // Allow some time for reply to propagate + + Log.d(STEP_TAG,"Assert the the previously sent reply ($replyMessage) is displayed on the details page.") discussionDetailsPage.assertRepliesDisplayed() - Espresso.pressBack() // Back to discussion list + + Log.d(STEP_TAG,"Navigate back to Discussions Page.") + Espresso.pressBack() + + Log.d(STEP_TAG,"Refresh the page. Assert that the previously sent reply has been counted.") discussionListPage.pullToUpdate() discussionListPage.assertReplyCount(newTopicName, 1) - } } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/EventsE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/EventsE2ETest.kt deleted file mode 100644 index 50ad0e4ade..0000000000 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/EventsE2ETest.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.instructure.student.ui.e2e - -import android.os.SystemClock.sleep -import com.instructure.canvas.espresso.E2E -import com.instructure.dataseeding.api.AssignmentsApi -import com.instructure.dataseeding.api.GroupsApi -import com.instructure.dataseeding.api.QuizzesApi -import com.instructure.dataseeding.util.days -import com.instructure.dataseeding.util.fromNow -import com.instructure.dataseeding.util.iso8601 -import com.instructure.panda_annotations.FeatureCategory -import com.instructure.panda_annotations.Priority -import com.instructure.panda_annotations.TestCategory -import com.instructure.panda_annotations.TestMetaData -import com.instructure.student.ui.utils.StudentTest -import com.instructure.student.ui.utils.seedAssignments -import com.instructure.student.ui.utils.seedData -import com.instructure.student.ui.utils.tokenLogin -import dagger.hilt.android.testing.HiltAndroidTest -import org.junit.Test - -@HiltAndroidTest -class EventsE2ETest: StudentTest() { - override fun displaysPageObjects() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - // TODO: Get this working with embedded Flutter - /*@E2E - @Test - @TestMetaData(Priority.P0, FeatureCategory.EVENTS, TestCategory.E2E) - fun testEventsE2E() { - // Seed 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] - - // Seed an assignment due today, for calendar tab - val seededAssignments = seedAssignments( - courseId = course.id, - teacherToken = teacher.token, - dueAt = 0.days.fromNow.iso8601, - assignments = 1 - ) - - // Seed a grouped assignment due today, for calendar tab - var groupCategory = GroupsApi.createCourseGroupCategory(course.id, teacher.token) - var group = GroupsApi.createGroup(groupCategory.id, teacher.token) - GroupsApi.createGroupMembership(group.id, student.id, teacher.token) - - val groupedAssignmentRequest = AssignmentsApi.CreateAssignmentRequest( - courseId = course.id, - teacherToken = teacher.token, - dueAt = 0.days.fromNow.iso8601, - groupCategoryId = groupCategory.id, - submissionTypes = emptyList() - ) - val groupedAssignment = AssignmentsApi.createAssignment(groupedAssignmentRequest) - - - // Seed a quiz due today, for calendar tab - val quiz = QuizzesApi.createQuiz( - QuizzesApi.CreateQuizRequest( - courseId = course.id, - withDescription = true, - published = true, - token = teacher.token, - dueAt = 0.days.fromNow.iso8601) - - ) - - // Sign in with lone student - tokenLogin(student) - - // Navigate to calendar - dashboardPage.waitForRender() - dashboardPage.clickCalendarTab() - //calendarPage.waitForRender() - - // Select the calendars for your courses/groups - calendarPage.selectDesiredCalendarsAndDismiss(course.name, group.name) - - // Hide the calendar itself. This helps on low-res devices. - calendarPage.toggleCalendarVisibility() - - // Make sure that your assignment shows up on the calendar - calendarPage.assertAssignmentDisplayed(seededAssignments.assignmentList[0]) - - // Assert that the grouped assignment is there - calendarPage.assertAssignmentDisplayed(groupedAssignment) - - // Make sure that your quiz shows up on the calendar - calendarPage.assertQuizDisplayed(quiz) - }*/ - - // TODO: Can we test other types of events? - // https://mobileqa.test.instructure.com/api/v1/calendar_events/?all_events=false&type=assignment -- covered - // https://mobileqa.test.instructure.com/api/v1/calendar_events/?all_events=false&type=event... -- ?? - -} diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/FilesE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/FilesE2ETest.kt index dea26eccf1..6431b77053 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/FilesE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/FilesE2ETest.kt @@ -18,9 +18,7 @@ package com.instructure.student.ui.e2e import android.os.Environment import android.util.Log -import androidx.test.espresso.Espresso.pressBack import com.instructure.canvas.espresso.E2E -import com.instructure.canvas.espresso.Stub import com.instructure.canvasapi2.managers.DiscussionManager import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.DiscussionEntry @@ -38,6 +36,7 @@ import com.instructure.panda_annotations.Priority import com.instructure.panda_annotations.TestCategory import com.instructure.panda_annotations.TestMetaData import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.ViewUtils import com.instructure.student.ui.utils.seedData import com.instructure.student.ui.utils.tokenLogin import com.instructure.student.ui.utils.uploadTextFile @@ -46,26 +45,28 @@ import org.junit.Test import java.io.File import java.io.FileWriter -// Tests that files (assignment uploads, assignment comment attachments, discussion attachments) -// are properly displayed @HiltAndroidTest class FilesE2ETest: StudentTest() { override fun displaysPageObjects() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.FILES, TestCategory.E2E, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.FILES, TestCategory.E2E) fun testFilesE2E() { - // Seed basic data + 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] - // Seed a text assignment/file/submission + Log.d(PREPARATION_TAG,"Seeding assignment for ${course.name} course.") val assignment = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, withDescription = false, @@ -74,6 +75,7 @@ class FilesE2ETest: StudentTest() { teacherToken = teacher.token )) + Log.d(PREPARATION_TAG, "Seed a text file.") val submissionUploadInfo = uploadTextFile( assignmentId = assignment.id, courseId = course.id, @@ -81,7 +83,8 @@ class FilesE2ETest: StudentTest() { fileUploadType = FileUploadType.ASSIGNMENT_SUBMISSION ) - val submission = SubmissionsApi.submitCourseAssignment( + Log.d(PREPARATION_TAG,"Submit ${assignment.name} assignment for ${student.name} student.") + SubmissionsApi.submitCourseAssignment( submissionType = SubmissionType.ONLINE_UPLOAD, courseId = course.id, assignmentId = assignment.id, @@ -89,7 +92,7 @@ class FilesE2ETest: StudentTest() { studentToken = student.token ) - // Seed a comment attachment upload + Log.d(STEP_TAG,"Seed a comment attachment upload.") val commentUploadInfo = uploadTextFile( assignmentId = assignment.id, courseId = course.id, @@ -104,32 +107,30 @@ class FilesE2ETest: StudentTest() { fileIds = mutableListOf(commentUploadInfo.id) ) - // Seed a discussion topic; will add a reply with attachment below + Log.d(STEP_TAG,"Seed a discussion for ${course.name} course.") val discussionTopic = DiscussionTopicsApi.createDiscussion( courseId = course.id, token = student.token ) - // At this point, sign in our student. Login is necessary for the "real" API call - // below to work correctly. + Log.d(STEP_TAG,"Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) dashboardPage.waitForRender() - // Create a discussion attachment file + Log.d(STEP_TAG,"Create a discussion attachment file.") val discussionAttachmentFile = File( Randomizer.randomTextFileName(Environment.getExternalStorageDirectory().absolutePath)) .apply { createNewFile() } - // Add contents to file + Log.d(STEP_TAG,"Add some random content to the ${discussionAttachmentFile.name} file.") FileWriter(discussionAttachmentFile, true).apply { write(Randomizer.randomTextFileContents()) flush() close() } - // Use a "normal" api (rather than seeding) to create a reply to our - // discussion that contains an attachment. - val result = tryWeave { + Log.d(PREPARATION_TAG,"Use real API (rather than seeding) to create a reply to our discussion that contains an attachment.") + tryWeave { awaitApiResponse { DiscussionManager.postToDiscussionTopic( canvasContext = CanvasContext.emptyCourseContext(id = course.id), @@ -140,58 +141,85 @@ class FilesE2ETest: StudentTest() { callback = it) } } catch { - Log.v("FilesE2E", "Discussion post error: $it") + Log.v(PREPARATION_TAG, "Discussion post error: $it") } - // - // OK, let's get to testing - // - - // Let's make sure that our submitted file and our discussion attachment are displayed - // in the main files list. - // - // The fileListPage is a little different in that it keeps getting used over and over again, - // recursively, as we traverse the file tree. + Log.d(STEP_TAG,"Navigate to 'Files' menu in user left-side menubar.") dashboardPage.gotoGlobalFiles() + + Log.d(STEP_TAG,"Assert that there is a directory called 'Submissions' is displayed.") fileListPage.assertItemDisplayed("Submissions") + + Log.d(STEP_TAG,"Select 'Submissions' directory. Assert that ${discussionAttachmentFile.name} file is displayed on the File List Page.") fileListPage.selectItem("Submissions") + + Log.d(STEP_TAG,"Assert that ${course.name} course is displayed.") fileListPage.assertItemDisplayed(course.name) + + Log.d(STEP_TAG,"Select ${course.name} course.") fileListPage.selectItem(course.name) + + Log.d(STEP_TAG,"Assert that ${discussionAttachmentFile.name} file is displayed on the File List Page.") fileListPage.assertItemDisplayed(submissionUploadInfo.fileName) - pressBack() // Back to Submissions - pressBack() // Back to main file list + + Log.d(STEP_TAG,"Navigate back to File List Page.") + ViewUtils.pressBackButton(2) + + Log.d(STEP_TAG,"Assert that there is a directory called 'unfiled' is displayed.") fileListPage.assertItemDisplayed("unfiled") // Our discussion attachment goes under "unfiled" + + Log.d(STEP_TAG,"Select 'unfiled' directory. Assert that ${discussionAttachmentFile.name} file is displayed on the File List Page.") fileListPage.selectItem("unfiled") fileListPage.assertItemDisplayed(discussionAttachmentFile.name) - pressBack() // Back to main file list - pressBack() // Back to dashboard - // Let's check that our submission file and assignment comment attachment are shown in the assignment details + Log.d(STEP_TAG,"Navigate back to Dashboard Page.") + ViewUtils.pressBackButton(2) + + Log.d(STEP_TAG,"Select ${course.name} course.") dashboardPage.selectCourse(course) + + Log.d(STEP_TAG,"Navigate to Assignments Page.") courseBrowserPage.selectAssignments() + + Log.d(STEP_TAG,"Click on ${assignment.name} assignment.") assignmentListPage.clickAssignment(assignment) + + Log.d(STEP_TAG,"Navigate to Submission Details Page and open Files Tab.") assignmentDetailsPage.goToSubmissionDetails() submissionDetailsPage.openFiles() + + Log.d(STEP_TAG,"Assert that ${submissionUploadInfo.fileName} file has been displayed.") submissionDetailsPage.assertFileDisplayed(submissionUploadInfo.fileName) + + Log.d(STEP_TAG,"Open Comments Tab. Assert that ${commentUploadInfo.fileName} file is displayed as a comment by ${student.name} student.") submissionDetailsPage.openComments() - submissionDetailsPage.assertCommentAttachmentDisplayed(commentUploadInfo.fileName,student) - pressBack() // Back to assignment details - pressBack() // Back to assignment list - pressBack() // Back to course browser page + submissionDetailsPage.assertCommentAttachmentDisplayed(commentUploadInfo.fileName, student) - // I'd like to go into discussions and verify that our reply-with-attachment shows up, - // but that info is in a webview and thus would not be easy to verify. + Log.d(STEP_TAG,"Navigate back to Dashboard Page.") + ViewUtils.pressBackButton(5) - // Test renaming and deleting the discussion attachment - pressBack() // Back to Dashboard + Log.d(STEP_TAG,"Navigate to 'Files' menu in user left-side menubar.") dashboardPage.gotoGlobalFiles() + + Log.d(STEP_TAG,"Assert that there is a directory called 'unfiled' is displayed.") fileListPage.assertItemDisplayed("unfiled") // Our discussion attachment goes under "unfiled" + + Log.d(STEP_TAG,"Select 'unfiled' directory. Assert that ${discussionAttachmentFile.name} file is displayed on the File List Page.") fileListPage.selectItem("unfiled") fileListPage.assertItemDisplayed(discussionAttachmentFile.name) - val newFileName = "blah.txt" + + val newFileName = "newTextFileName.txt" + Log.d(STEP_TAG,"Rename ${discussionAttachmentFile.name} file to: $newFileName.") fileListPage.renameFile(discussionAttachmentFile.name, newFileName) + + Log.d(STEP_TAG,"Assert that the file is displayed with it's new file name: $newFileName.") fileListPage.assertItemDisplayed(newFileName) + + Log.d(STEP_TAG,"Delete $newFileName file.") fileListPage.deleteFile(newFileName) + fileListPage.assertPageObjects() + + Log.d(STEP_TAG,"Assert that empty view is displayed after deletion.") fileListPage.assertViewEmpty() } } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/GradesE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/GradesE2ETest.kt index 3982a1531d..81856f5373 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/GradesE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/GradesE2ETest.kt @@ -1,14 +1,12 @@ package com.instructure.student.ui.e2e -import androidx.test.espresso.Espresso +import android.util.Log import androidx.test.espresso.matcher.ViewMatchers.withText import com.instructure.canvas.espresso.E2E -import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.dataseeding.api.AssignmentsApi import com.instructure.dataseeding.api.QuizzesApi import com.instructure.dataseeding.api.SubmissionsApi -import com.instructure.dataseeding.model.CreateQuizQuestion import com.instructure.dataseeding.model.GradingType import com.instructure.dataseeding.model.QuizAnswer import com.instructure.dataseeding.model.QuizQuestion @@ -33,17 +31,22 @@ class GradesE2ETest: StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.GRADES, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GRADES, TestCategory.E2E) fun testGradesE2E() { - // Seed basic student/teacher/course data + + 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] - // Create an assignment + Log.d(PREPARATION_TAG,"Seeding assignment for ${course.name} course.") val assignment = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, withDescription = true, @@ -54,7 +57,7 @@ class GradesE2ETest: StudentTest() { pointsPossible = 15.0 )) - // Create a quiz with some questions + Log.d(PREPARATION_TAG,"Create a quiz with some questions.") val quizQuestions = listOf( QuizQuestion( pointsPossible = 5, @@ -79,47 +82,56 @@ class GradesE2ETest: StudentTest() { ) ) + Log.d(STEP_TAG,"Publish the previously made quiz.") val quiz = QuizzesApi.createAndPublishQuiz(course.id, teacher.token, quizQuestions) - // Sign the student in + Log.d(STEP_TAG,"Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) dashboardPage.waitForRender() - // Navigate to our course + Log.d(STEP_TAG,"Select ${course.name} course.") dashboardPage.selectCourse(course) - // Let's take a look at the grades page + Log.d(STEP_TAG,"Navigate to Grades Page.") courseBrowserPage.selectGrades() - // At this point, with nothing turned in, our total grade should be "N/A" + Log.d(STEP_TAG,"Assert that there is no grade for any submission yet.") courseGradesPage.assertTotalGrade(withText(R.string.noGradeText)) - // We'll be using these a lot val assignmentMatcher = withText(assignment.name) val quizMatcher = withText(quiz.title) - - // Make sure our assignments/quizzes are displayed + Log.d(STEP_TAG,"Refresh the page. Assert that the ${assignment.name} assignment and ${quiz.title} quiz are displayed and there is no grade for them.") courseGradesPage.refresh() courseGradesPage.assertItemDisplayed(assignmentMatcher) courseGradesPage.assertGradeNotDisplayed(assignmentMatcher) courseGradesPage.assertItemDisplayed(quizMatcher) courseGradesPage.assertGradeNotDisplayed(quizMatcher) - // Let's try a what-if + Log.d(STEP_TAG,"Check in the 'What-If Score' checkbox.") courseGradesPage.toggleWhatIf() + + Log.d(STEP_TAG,"Enter '12' as a what-if grade for ${assignment.name} assignment.") courseGradesPage.enterWhatIfGrade(assignmentMatcher, "12") + + Log.d(STEP_TAG,"Assert that 'Total Grade' contains the score '80'.") courseGradesPage.assertTotalGrade(containsTextCaseInsensitive("80")) + + Log.d(STEP_TAG,"Check out the 'What-If Score' checkbox.") courseGradesPage.toggleWhatIf() + + Log.d(STEP_TAG,"Assert that after disabling the 'What-If Score' checkbox there will be no 'real' grade.") courseGradesPage.assertTotalGrade(withText(R.string.noGradeText)) - // Let's submit our assignment, and grade it - val submission = SubmissionsApi.submitCourseAssignment( + Log.d(PREPARATION_TAG,"Seed a submission for ${assignment.name} assignment.") + SubmissionsApi.submitCourseAssignment( submissionType = SubmissionType.ONLINE_TEXT_ENTRY, courseId = course.id, assignmentId = assignment.id, fileIds = mutableListOf(), studentToken = student.token ) + + Log.d(PREPARATION_TAG,"Grade the previously seeded submission for ${assignment.name} assignment.") SubmissionsApi.gradeSubmission( teacherToken = teacher.token, courseId = course.id, @@ -127,16 +139,18 @@ class GradesE2ETest: StudentTest() { studentId = student.id, postedGrade="9", excused = false) - courseGradesPage.refresh() - // 9 out of 15 + Log.d(STEP_TAG,"Refresh the page. Assert that the assignment's score is '60'.") + courseGradesPage.refresh() courseGradesPage.assertGradeDisplayed( assignmentMatcher, containsTextCaseInsensitive("60")) - // Let's toggle "Base on graded assignments" and verify that we see the correct score + Log.d(STEP_TAG,"Toggle 'Base on graded assignments' button. Assert that we can see the correct score (36).") courseGradesPage.toggleBaseOnGradedAssignments() courseGradesPage.refreshUntilAssertTotalGrade(containsTextCaseInsensitive("36")) // 9 out of 25 + + Log.d(STEP_TAG,"Disable 'Base on graded assignments' button. Assert that we can see the correct score (60).") courseGradesPage.toggleBaseOnGradedAssignments() courseGradesPage.refreshUntilAssertTotalGrade(containsTextCaseInsensitive("60")) // 9 out of 15 diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/InboxE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/InboxE2ETest.kt index 02fe645387..657015df25 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/InboxE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/InboxE2ETest.kt @@ -17,6 +17,7 @@ package com.instructure.student.ui.e2e import android.os.SystemClock.sleep +import android.util.Log import com.instructure.canvas.espresso.E2E import com.instructure.dataseeding.api.ConversationsApi import com.instructure.dataseeding.api.GroupsApi @@ -36,12 +37,16 @@ class InboxE2ETest: StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.E2E) fun testInboxE2E() { - // Seed basic data + Log.d(PREPARATION_TAG, "Seeding data.") val data = seedData(students = 2, teachers = 1, courses = 1) val teacher = data.teachersList[0] val course = data.coursesList[0] @@ -51,61 +56,72 @@ class InboxE2ETest: StudentTest() { // Create a group and put both students in it val groupCategory = GroupsApi.createCourseGroupCategory(course.id, teacher.token) val group = GroupsApi.createGroup(groupCategory.id, teacher.token) + Log.d(PREPARATION_TAG, "Create group membership for ${student1.name} and ${student2.name} students to the group: ${group.name}.") GroupsApi.createGroupMembership(group.id, student1.id, teacher.token) GroupsApi.createGroupMembership(group.id, student2.id, teacher.token) - // Seed an email from the teacher to the students + Log.d(PREPARATION_TAG,"Seed an email from the teacher to ${student1.name} and ${student2.name} students.") val seededConversation = ConversationsApi.createConversation( token = teacher.token, recipients = listOf(student1.id.toString(), student2.id.toString()) ).get(0) - // Sign in with student1 + Log.d(STEP_TAG,"Login with user: ${student1.name}, login id: ${student1.loginId} , password: ${student1.password}") tokenLogin(student1) - - // Make sure that the seeded conversation shows up dashboardPage.waitForRender() - dashboardPage.clickInboxTab() - inboxPage.assertPageObjects() + Log.d(STEP_TAG,"Open Inbox Page. Assert that the previously seeded conversation is displayed.") + dashboardPage.clickInboxTab() + inboxPage.assertPageObjects() //TODO: Refactor to assert to the empty view just like in teacher would be better. AFTER THAT, seed the conversation. inboxPage.assertConversationDisplayed(seededConversation) - // Compose and send an email to the other student + Log.d(STEP_TAG,"Click on 'New Message' button.") inboxPage.pressNewMessageButton() + val newMessageSubject = "Hey There" + val newMessage = "Just checking in" + Log.d(STEP_TAG,"Create a new message with subject: $newMessageSubject, and message: $newMessage") newMessagePage.populateMessage( course, student2, - "Hey There", - "Just checking in" + newMessageSubject, + newMessage ) - newMessagePage.hitSend() - // Compose and send an email to a group + Log.d(STEP_TAG,"Click on 'Send' button.") + newMessagePage.clickSend() + + Log.d(STEP_TAG,"Click on 'New Message' button.") inboxPage.pressNewMessageButton() + val newGroupMessageSubject = "Group Message" + val newGroupMessage = "Testing Group ${group.name}" + Log.d(STEP_TAG,"Create a new message with subject: $newGroupMessageSubject, and message: $newGroupMessage") newMessagePage.populateGroupMessage( group, student2, - "Group Message", - "Testing Group ${group.name}" + newGroupMessageSubject, + newGroupMessage ) - newMessagePage.hitSend() + + Log.d(STEP_TAG,"Click on 'Send' button.") + newMessagePage.clickSend() sleep(3000) // Allow time for messages to propagate - // Now sign out and sign back in as student2 + Log.d(STEP_TAG,"Navigate back to Dashboard Page.") inboxPage.goToDashboard() - dashboardPage.waitForRender() - dashboardPage.signOut() - tokenLogin(student2) + Log.d(STEP_TAG,"Log out with ${student1.name} student.") + dashboardPage.logOut() - // Navigate to the inbox and verify that the expected messages are there + Log.d(STEP_TAG,"Login with user: ${student2.name}, login id: ${student2.loginId} , password: ${student2.password}") + tokenLogin(student2) dashboardPage.waitForRender() - dashboardPage.clickInboxTab() + Log.d(STEP_TAG,"Open Inbox Page. Assert that both, the previously seeded 'normal' conversation and the group conversation are displayed.") + dashboardPage.clickInboxTab() inboxPage.assertConversationDisplayed(seededConversation) inboxPage.assertConversationDisplayed("Hey There") inboxPage.assertConversationDisplayed("Group Message") diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/LoginE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/LoginE2ETest.kt index 43e784fb7f..62d522e87a 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/LoginE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/LoginE2ETest.kt @@ -16,6 +16,7 @@ */ package com.instructure.student.ui.e2e +import android.util.Log import androidx.test.espresso.Espresso import com.instructure.canvas.espresso.E2E import com.instructure.dataseeding.api.CoursesApi @@ -39,120 +40,162 @@ class LoginE2ETest : StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.LOGIN, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.LOGIN, TestCategory.E2E) fun testLoginE2E() { - // Seed data + Log.d(PREPARATION_TAG, "Seeding data.") val data = seedData(students = 2, teachers = 1, courses = 1) val student1 = data.studentsList[0] val student2 = data.studentsList[1] - // Sign in with student 1 + Log.d(STEP_TAG,"Click 'Find My School' button.") loginLandingPage.clickFindMySchoolButton() + + Log.d(STEP_TAG,"Enter domain: ${student1.domain}.") loginFindSchoolPage.enterDomain(student1.domain) + + Log.d(STEP_TAG,"Click on 'Next' button on the Toolbar.") loginFindSchoolPage.clickToolbarNextMenuItem() + + Log.d(STEP_TAG,"Login with user: ${student1.name}, login id: ${student1.loginId} , password: ${student1.password}") loginSignInPage.loginAs(student1) - // Verify that the dashboard page looks good + Log.d(STEP_TAG,"Assert that the Dashboard Page is the landing page and it is loaded successfully.") verifyDashboardPage(student1) - // Sign out - dashboardPage.signOut() + Log.d(STEP_TAG,"Log out with ${student1.name} student.") + dashboardPage.logOut() - // Sign in with student 2 + Log.d(STEP_TAG,"Click 'Find My School' button.") loginLandingPage.clickFindMySchoolButton() + + Log.d(STEP_TAG,"Enter domain: ${student2.domain}.") loginFindSchoolPage.enterDomain(student2.domain) + + Log.d(STEP_TAG,"Click on 'Next' button on the Toolbar.") loginFindSchoolPage.clickToolbarNextMenuItem() + + Log.d(STEP_TAG,"Login with user: ${student2.name}, login id: ${student2.loginId} , password: ${student2.password}") loginSignInPage.loginAs(student2) - // Verify that the dashboard page looks good + Log.d(STEP_TAG,"Assert that the Dashboard Page is the landing page and it is loaded successfully.") verifyDashboardPage(student2) - // Change user back to student 1 with "change user" + manual login + Log.d(STEP_TAG,"Click on 'Change User' button on the left-side menu.") dashboardPage.pressChangeUser() + + Log.d(STEP_TAG,"Assert that the previously logins has been displayed.") loginLandingPage.assertDisplaysPreviousLogins() + + Log.d(STEP_TAG,"Login MANUALLY. Click 'Find My School' button.") loginLandingPage.clickFindMySchoolButton() + + Log.d(STEP_TAG,"Enter domain: ${student1.domain}.") loginFindSchoolPage.enterDomain(student1.domain) + + Log.d(STEP_TAG,"Click on 'Next' button on the Toolbar.") loginFindSchoolPage.clickToolbarNextMenuItem() + + Log.d(STEP_TAG,"Login with user: ${student1.name}, login id: ${student1.loginId} , password: ${student1.password}") loginSignInPage.loginAs(student1) - // Verify that the dashboard page looks good + Log.d(STEP_TAG,"Assert that the Dashboard Page is the landing page and it is loaded successfully.") verifyDashboardPage(student1) - // Now change back to student 2 with "change user" + select previous user + Log.d(STEP_TAG,"Click on 'Change User' button on the left-side menu.") dashboardPage.pressChangeUser() + + Log.d(STEP_TAG,"Assert that the previously logins has been displayed.") loginLandingPage.assertDisplaysPreviousLogins() + + Log.d(STEP_TAG,"Login with the previous user, ${student2.name}, with one click, by clicking on the user's name on the bottom.") loginLandingPage.loginWithPreviousUser(student2) - // Verify that the dashboard page looks good + Log.d(STEP_TAG,"Assert that the Dashboard Page is the landing page and it is loaded successfully.") verifyDashboardPage(student2) } @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.LOGIN, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.LOGIN, TestCategory.E2E) fun testUserRolesLoginE2E() { - // Seed student, teacher, TA and parent data + Log.d(PREPARATION_TAG, "Seeding data.") val data = seedData(students = 1, teachers = 1, tas = 1, courses = 1) val parentData = SeedApi.seedParentData( SeedApi.SeedParentDataRequest( courses=1, students=1, parents=1 ) ) + val student = data.studentsList[0] + val teacher = data.teachersList[0] + val ta = data.taList[0] + val course = data.coursesList[0] - // Test for student - validateUserAndRole(data.studentsList[0], data.coursesList[0], "Student") - - // Test for teacher - validateUserAndRole(data.teachersList[0], data.coursesList[0], "Teacher") + Log.d(STEP_TAG,"Validate ${student.name} user's role as a Student.") + validateUserAndRole(student, course, "Student") - // Test for TA - validateUserAndRole(data.taList[0], data.coursesList[0], "TA") + Log.d(STEP_TAG,"Validate ${teacher.name} user's role as a Teacher.") + validateUserAndRole(teacher, course, "Teacher") - // Test for parent, which is different/abbreviated because parents don't show - // up in the "People" page so we can't verify their role. + Log.d(STEP_TAG,"Validate ${ta.name} user's role as a TA.") + validateUserAndRole(ta, course, "TA") - // Sign in as a parent + // Test with Parent user. parents don't show up in the "People" page so we can't verify their role. val parent = parentData.parentsList[0] + Log.d(STEP_TAG,"Click 'Find My School' button.") loginLandingPage.clickFindMySchoolButton() + + Log.d(STEP_TAG,"Enter domain: ${parent.domain}.") loginFindSchoolPage.enterDomain(parent.domain) + + Log.d(STEP_TAG,"Enter domain: ${parent.domain}.") loginFindSchoolPage.clickToolbarNextMenuItem() + + Log.d(STEP_TAG,"Login with user: ${parent.name}, login id: ${parent.loginId} , password: ${parent.password}") loginSignInPage.loginAs(parent) - // Verify that we are signed in as the parent + Log.d(STEP_TAG,"Assert that the Dashboard Page is the landing page and it is loaded successfully.") verifyDashboardPage(parent) - // Sign the parent out - dashboardPage.signOut() + Log.d(STEP_TAG,"Log out with ${parent.name} student.") + dashboardPage.logOut() } // Verify that students can sign into vanity domain @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.LOGIN, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.LOGIN, TestCategory.E2E) fun testVanityDomainLoginE2E() { // Create a Retrofit client for our vanity domain val domain = "canvas.beta.jitops.computer" // Our test vanity domain val retrofitClient = CanvasNetworkAdapter.createAdminRetrofitClient(domain) - // Create services off of that Retrofit client + Log.d(PREPARATION_TAG,"Create services off of that Retrofit client.") val userService = retrofitClient.create(UserApi.UserService::class.java) val coursesService = retrofitClient.create(CoursesApi.CoursesService::class.java) val enrollmentsService = retrofitClient.create(EnrollmentsApi.EnrollmentsService::class.java) - // Create student, teacher, course and enrollments in our vanity domain + Log.d(PREPARATION_TAG,"Create student, teacher, and a course via API.") val student = UserApi.createCanvasUser(userService = userService, userDomain = domain) val teacher = UserApi.createCanvasUser(userService = userService, userDomain = domain) val course = CoursesApi.createCourse(coursesService = coursesService) + + Log.d(PREPARATION_TAG,"Enroll ${student.name} student to ${course.name} course.") EnrollmentsApi.enrollUser( courseId = course.id, userId = student.id, enrollmentType = STUDENT_ENROLLMENT, enrollmentService = enrollmentsService ) + + Log.d(PREPARATION_TAG,"Enroll ${teacher.name} teacher to ${course.name} course.") EnrollmentsApi.enrollUser( courseId = course.id, userId = teacher.id, @@ -160,8 +203,8 @@ class LoginE2ETest : StudentTest() { enrollmentService = enrollmentsService ) - // Attempt to sign into our vanity domain, and validate ourself as a student - validateUserAndRole(user = student, course = course, role = "Student" ) + Log.d(STEP_TAG,"Attempt to sign into our vanity domain, and validate ${student.name} user's role as a Student.") + validateUserAndRole(student, course,"Student" ) } // Repeated logic from the testUserRolesLoginE2E test. @@ -183,7 +226,7 @@ class LoginE2ETest : StudentTest() { Espresso.pressBack() // to dashboard page // Sign the user out - dashboardPage.signOut() + dashboardPage.logOut() } 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 44571d2e1a..03c4305a3a 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 @@ -16,6 +16,7 @@ */ package com.instructure.student.ui.e2e +import android.util.Log import androidx.test.espresso.Espresso import com.instructure.canvas.espresso.E2E import com.instructure.dataseeding.api.AssignmentsApi @@ -44,18 +45,22 @@ class ModulesE2ETest: StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.MODULES, TestCategory.E2E, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.E2E, false) fun testModulesE2E() { - // Seed basic data + 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] - // Create some assignments, quizzes, pages, etc... + Log.d(PREPARATION_TAG,"Seeding assignment for ${course.name} course.") val assignment1 = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, withDescription = true, @@ -64,6 +69,7 @@ class ModulesE2ETest: StudentTest() { dueAt = 1.days.fromNow.iso8601 )) + Log.d(PREPARATION_TAG,"Seeding another assignment for ${course.name} course.") val assignment2 = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, withDescription = true, @@ -72,6 +78,7 @@ class ModulesE2ETest: StudentTest() { dueAt = 2.days.fromNow.iso8601 )) + Log.d(PREPARATION_TAG,"Create a PUBLISHED quiz for ${course.name} course.") val quiz1 = QuizzesApi.createQuiz(QuizzesApi.CreateQuizRequest( courseId = course.id, withDescription = true, @@ -80,6 +87,7 @@ class ModulesE2ETest: StudentTest() { published = true )) + Log.d(PREPARATION_TAG,"Create a page for ${course.name} course.") val page1 = PagesApi.createCoursePage( courseId = course.id, published = true, @@ -87,23 +95,26 @@ class ModulesE2ETest: StudentTest() { token = teacher.token ) + Log.d(PREPARATION_TAG,"Create a discussion topic for ${course.name} course.") val discussionTopic1 = DiscussionTopicsApi.createDiscussion( courseId = course.id, token = teacher.token ) - // Create a couple of modules. They start out as unpublished. + //Modules start out as unpublished. + Log.d(PREPARATION_TAG,"Create a module for ${course.name} course.") val module1 = ModulesApi.createModule( courseId = course.id, teacherToken = teacher.token, unlockAt = null) + Log.d(PREPARATION_TAG,"Create another module for ${course.name} course.") val module2 = ModulesApi.createModule( courseId = course.id, teacherToken = teacher.token, unlockAt = null) - // Associate items with module 1 + Log.d(PREPARATION_TAG,"Associate ${assignment1.name} assignment with ${module1.name} module.") ModulesApi.createModuleItem( courseId = course.id, moduleId = module1.id, @@ -113,6 +124,7 @@ class ModulesE2ETest: StudentTest() { contentId = assignment1.id.toString() ) + Log.d(PREPARATION_TAG,"Associate ${quiz1.title} quiz with ${module1.name} module.") ModulesApi.createModuleItem( courseId = course.id, moduleId = module1.id, @@ -122,7 +134,7 @@ class ModulesE2ETest: StudentTest() { contentId = quiz1.id.toString() ) - // Associated items with module 2 + Log.d(PREPARATION_TAG,"Associate ${assignment2.name} assignment with ${module2.name} module.") ModulesApi.createModuleItem( courseId = course.id, moduleId = module2.id, @@ -132,6 +144,7 @@ class ModulesE2ETest: StudentTest() { contentId = assignment2.id.toString() ) + Log.d(PREPARATION_TAG,"Associate ${page1.title} page with ${module2.name} module.") ModulesApi.createModuleItem( courseId = course.id, moduleId = module2.id, @@ -142,6 +155,7 @@ class ModulesE2ETest: StudentTest() { pageUrl = page1.url // Only necessary for Page item ) + Log.d(PREPARATION_TAG,"Associate ${discussionTopic1.title} discussion topic with ${module2.name} module.") ModulesApi.createModuleItem( courseId = course.id, moduleId = module2.id, @@ -151,26 +165,36 @@ class ModulesE2ETest: StudentTest() { contentId = discussionTopic1.id.toString() ) - // Sign in and navigate to our course + Log.d(STEP_TAG, "Login with user: ${teacher.name}, login id: ${teacher.loginId} , password: ${teacher.password}") tokenLogin(student) dashboardPage.waitForRender() + + Log.d(STEP_TAG,"Assert that ${course.name} course is displayed.") dashboardPage.assertDisplaysCourse(course) + + Log.d(STEP_TAG,"Select ${course.name} course.") dashboardPage.selectCourse(course) - // Assert that no modules are present, since none are published + Log.d(STEP_TAG,"Assert that there are no modules displayed yet because there are not published. Assert that the 'Modules' Tab is not displayed as well.") courseBrowserPage.assertTitleCorrect(course) courseBrowserPage.assertTabNotDisplayed("Modules") + + Log.d(STEP_TAG,"Click on 'Home' label and assert that the empty view is displayed on the Modules Page.") courseBrowserPage.selectHome() modulesPage.assertEmptyView() - Espresso.pressBack() // Back to course browser view - // Let's publish our modules + Log.d(STEP_TAG,"Navigate back to Course Browser Page.") + Espresso.pressBack() + + Log.d(PREPARATION_TAG,"Publish ${module1.name} module.") ModulesApi.updateModule( courseId = course.id, id = module1.id, published = true, teacherToken = teacher.token ) + + Log.d(PREPARATION_TAG,"Publish ${module2.name} module.") ModulesApi.updateModule( courseId = course.id, id = module2.id, @@ -178,19 +202,20 @@ class ModulesE2ETest: StudentTest() { teacherToken = teacher.token ) - // Refresh our screen to get updated tabs + Log.d(STEP_TAG,"Refresh the page. Assert that the 'Modules' Tab is displayed.") courseBrowserPage.refresh() - - // Now see that the Modules tab is displayed courseBrowserPage.assertTabDisplayed("Modules") - // Go to modules + Log.d(STEP_TAG,"Navigate to Modules Page.") courseBrowserPage.selectModules() - // Verify that both modules are displayed, along with their items + Log.d(STEP_TAG,"Assert that ${module1.name} module is displayed with the following items: ${assignment1.name} assignment, ${quiz1.title} quiz.") modulesPage.assertModuleDisplayed(module1) modulesPage.assertModuleItemDisplayed(module1, assignment1.name) modulesPage.assertModuleItemDisplayed(module1, quiz1.title) + + Log.d(STEP_TAG,"Assert that ${module2.name} module is displayed with the following items: ${assignment2.name} assignment," + + " ${page1.title} page, ${discussionTopic1.title} discussion topic.") modulesPage.assertModuleDisplayed(module2) modulesPage.assertModuleItemDisplayed(module2, assignment2.name) modulesPage.assertModuleItemDisplayed(module2, page1.title) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/NotificationsE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/NotificationsE2ETest.kt new file mode 100644 index 0000000000..ab8d53bfd4 --- /dev/null +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/NotificationsE2ETest.kt @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2020 - 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.e2e + +import android.util.Log +import com.instructure.canvas.espresso.E2E +import com.instructure.canvas.espresso.refresh +import com.instructure.dataseeding.api.AssignmentsApi +import com.instructure.dataseeding.api.QuizzesApi +import com.instructure.dataseeding.api.SubmissionsApi +import com.instructure.dataseeding.model.GradingType +import com.instructure.dataseeding.model.QuizAnswer +import com.instructure.dataseeding.model.QuizQuestion +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.panda_annotations.FeatureCategory +import com.instructure.panda_annotations.Priority +import com.instructure.panda_annotations.TestCategory +import com.instructure.panda_annotations.TestMetaData +import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.seedData +import com.instructure.student.ui.utils.tokenLogin +import dagger.hilt.android.testing.HiltAndroidTest +import org.junit.Test +import java.lang.Thread.sleep + +@HiltAndroidTest +class NotificationsE2ETest : StudentTest() { + override fun displaysPageObjects() = Unit + + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + + @E2E + @Test + @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.E2E) + fun testNotificationsE2E() { + + Log.d(PREPARATION_TAG,"Seeding data.") + val data = seedData(students = 2, teachers = 1, courses = 1, announcements = 1, discussions = 1) + val student = data.studentsList[0] + val teacher = data.teachersList[0] + val course = data.coursesList[0] + + Log.d(PREPARATION_TAG,"Seed an assignment for ${course.name} course.") + val testAssignment = AssignmentsApi.createAssignment( + AssignmentsApi.CreateAssignmentRequest( + courseId = course.id, + submissionTypes = listOf(SubmissionType.ONLINE_TEXT_ENTRY), + gradingType = GradingType.POINTS, + teacherToken = teacher.token, + pointsPossible = 15.0, + dueAt = 1.days.fromNow.iso8601 + ) + ) + + Log.d(PREPARATION_TAG,"Seed a quiz for ${course.name} course with some questions.") + val quizQuestions = listOf( + QuizQuestion( + questionText = "What's your favorite color?", + questionType = "multiple_choice_question", + pointsPossible = 5, + answers = listOf( + QuizAnswer(id = 1, weight = 0, text = "Red"), + QuizAnswer(id = 1, weight = 1, text = "Blue"), + QuizAnswer(id = 1, weight = 0, text = "Yellow") + ) + ), + QuizQuestion( + questionText = "Who let the dogs out?", + questionType = "multiple_choice_question", + pointsPossible = 5, + answers = listOf( + QuizAnswer(id = 1, weight = 1, text = "Who Who Who-Who"), + QuizAnswer(id = 1, weight = 0, text = "Who Who-Who-Who"), + QuizAnswer(id = 1, weight = 0, text = "Who-Who Who-Who") + ) + ) + ) + + Log.d(PREPARATION_TAG,"Create and publish a quiz with the previously seeded questions.") + QuizzesApi.createAndPublishQuiz(course.id, teacher.token, quizQuestions) + + Log.d(STEP_TAG,"Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") + tokenLogin(student) + dashboardPage.waitForRender() + + Log.d(STEP_TAG,"Navigate to 'Notifications' page via bottom-menu.") + dashboardPage.clickNotificationsTab() + + Log.d(STEP_TAG,"Assert that there are some notifications on the Notifications Page. There should be 4 notification at this point, but sometimes the API does not work properly.") + notificationPage.assertNotificationCountIsGreaterThan(0) //At least one notification is displayed. + try { + notificationPage.assertNotificationCountIsGreaterThan(3) //"Soft assert", because API does not working consistently. Sometimes it simply does not create notifications about some events, even if we would wait enough to let it do that. + Log.d(STEP_TAG,"All four notifications are displayed.") + } + catch(e: AssertionError) { + println("API may not work properly, so not all the notifications can be seen on the screen.") + } + + Log.d(PREPARATION_TAG,"Submit ${testAssignment.name} assignment with student: ${student.name}.") + SubmissionsApi.submitCourseAssignment( + submissionType = SubmissionType.ONLINE_TEXT_ENTRY, + courseId = course.id, + assignmentId = testAssignment.id, + studentToken = student.token, + fileIds = emptyList().toMutableList() + ) + + Log.d(PREPARATION_TAG,"Grade the submission of ${student.name} student for assignment: ${testAssignment.name}.") + SubmissionsApi.gradeSubmission( + teacherToken = teacher.token, + courseId = course.id, + assignmentId = testAssignment.id, + studentId = student.id, + postedGrade = "13", + excused = false + ) + + Log.d(STEP_TAG,"Refresh the Notifications Page. Assert that there is a notification about the submission grading appearing.") + sleep(5000) //Let the submission api do it's job + refresh() + notificationPage.assertHasGrade(testAssignment.name,"13") + } + +} \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PagesE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PagesE2ETest.kt index ce20c4ceb0..0ab9529ddc 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PagesE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PagesE2ETest.kt @@ -16,6 +16,7 @@ */ package com.instructure.student.ui.e2e +import android.util.Log import androidx.test.espresso.Espresso import androidx.test.espresso.web.webdriver.Locator import com.instructure.canvas.espresso.E2E @@ -37,18 +38,22 @@ class PagesE2ETest: StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.PAGES, TestCategory.E2E, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.PAGES, TestCategory.E2E, false) fun testPagesE2E() { - // Seed basic data + 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] - // Seed some pages + Log.d(PREPARATION_TAG,"Seed an UNPUBLISHED page for ${course.name} course.") val pageUnpublished = PagesApi.createCoursePage( courseId = course.id, published = false, @@ -56,6 +61,7 @@ class PagesE2ETest: StudentTest() { token = teacher.token ) + Log.d(PREPARATION_TAG,"Seed a PUBLISHED page for ${course.name} course.") val pagePublished = PagesApi.createCoursePage( courseId = course.id, published = true, @@ -64,6 +70,7 @@ class PagesE2ETest: StudentTest() { body = "

Regular Page Text

" ) + Log.d(PREPARATION_TAG,"Seed a PUBLISHED, FRONT page for ${course.name} course.") val pagePublishedFront = PagesApi.createCoursePage( courseId = course.id, published = true, @@ -72,25 +79,33 @@ class PagesE2ETest: StudentTest() { body = "

Front Page Text

" ) - // Sign in our student + Log.d(STEP_TAG,"Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) dashboardPage.waitForRender() - // Navigate to the Pages page of our course + Log.d(STEP_TAG,"Select ${course.name} course and navigate to Modules Page.") dashboardPage.selectCourse(course) courseBrowserPage.selectPages() - // Verify that our published pages show up, and unpublished ones do not + Log.d(STEP_TAG,"Assert that ${pagePublishedFront.title} published front page is displayed.") pageListPage.assertFrontPageDisplayed(pagePublishedFront) + + Log.d(STEP_TAG,"Assert that ${pagePublished.title} published page is displayed.") pageListPage.assertRegularPageDisplayed(pagePublished) + + Log.d(STEP_TAG,"Assert that ${pageUnpublished.title} unpublished page is NOT displayed.") pageListPage.assertPageNotDisplayed(pageUnpublished) - // Click into each page and verify the content of each + Log.d(STEP_TAG,"Open ${pagePublishedFront.title} page. Assert that it is really a front (published) page via web view assertions.") pageListPage.selectFrontPage(pagePublishedFront) canvasWebViewPage.runTextChecks( WebViewTextCheck(Locator.ID, "header1", "Front Page Text") ) + + Log.d(STEP_TAG,"Navigate back to Pages page.") Espresso.pressBack() + + Log.d(STEP_TAG,"Open ${pagePublished.title} page. Assert that it is really a regular published page via web view assertions.") pageListPage.selectRegularPage(pagePublished) canvasWebViewPage.runTextChecks( WebViewTextCheck(Locator.ID, "header1", "Regular Page Text") diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PeopleE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PeopleE2ETest.kt index 92bc754f1f..7d1eb54def 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PeopleE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/PeopleE2ETest.kt @@ -16,69 +16,93 @@ */ package com.instructure.student.ui.e2e +import android.util.Log import androidx.test.espresso.Espresso import com.instructure.canvas.espresso.E2E -import com.instructure.canvas.espresso.Stub import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority import com.instructure.panda_annotations.TestCategory import com.instructure.panda_annotations.TestMetaData import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.ViewUtils import com.instructure.student.ui.utils.seedData import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Test +private const val STEP_TAG = "PeopleE2ETest #STEP# " +private const val PREPARATION_TAG = "PeopleE2ETest #PREPARATION# " + @HiltAndroidTest -class PeopleE2ETest: StudentTest() { +class PeopleE2ETest : StudentTest() { override fun displaysPageObjects() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - @Stub + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.PEOPLE, TestCategory.E2E, true) + @TestMetaData(Priority.MANDATORY, FeatureCategory.PEOPLE, TestCategory.E2E) fun testPeopleE2E() { - // Seed basic data + + Log.d(PREPARATION_TAG, "Seeding data.") val data = seedData(students = 2, teachers = 1, courses = 1) val teacher = data.teachersList[0] val course = data.coursesList[0] val student1 = data.studentsList[0] val student2 = data.studentsList[1] - // Sign in with student1 + Log.d(STEP_TAG, "Login with user: ${student1.name}, login id: ${student1.loginId} , password: ${student1.password}") tokenLogin(student1) - - // Navigate to the "People" page of our course dashboardPage.waitForRender() + + Log.d(STEP_TAG,"Navigate to ${course.name} course's People Page.") dashboardPage.selectCourse(course) courseBrowserPage.selectPeople() - // Assert that all people are listed + Log.d(STEP_TAG,"Assert that the teacher user and both of the student users has been displayed.") + peopleListPage.assertPersonListed(teacher) + peopleListPage.assertPersonListed(student1) + peopleListPage.assertPersonListed(student2) + peopleListPage.assertPeopleCount(5) //2 for Teachers and Students sections, 1 for teacher user and 2 for student users. + + Log.d(STEP_TAG,"Collapse student list and assert that the students are not displayed, but the teacher user is displayed.") + peopleListPage.clickOnStudentsExpandCollapseButton() peopleListPage.assertPersonListed(teacher) + peopleListPage.assertPeopleCount(3) //2 for Teachers and Students sections, and 3rd for the teacher user. + peopleListPage.clickOnStudentsExpandCollapseButton() peopleListPage.assertPersonListed(student1) peopleListPage.assertPersonListed(student2) + peopleListPage.assertPeopleCount(5) //2 for Teachers and Students sections, 1 for teacher user and 2 for student users. - // Let's send a message to student2 + Log.d(STEP_TAG,"Select ${student2.name} student and assert if we are landing on the Person Details Page.") peopleListPage.selectPerson(student2) personDetailsPage.assertPageObjects() + + Log.d(STEP_TAG,"Compose a new message for ${student2.name} student.") personDetailsPage.clickCompose() newMessagePage.populateMessage(course,student2,"Yo!", "Hello from a fellow student", recipientPopulated = true) - newMessagePage.hitSend() - Espresso.pressBack() // Exit personDetailsPage - Espresso.pressBack() // Exit peopleListPage - Espresso.pressBack() // Exit courseBrowserPage + Log.d(STEP_TAG,"Send the message and assert if we are landing on the Person Details Page.") + newMessagePage.clickSend() + personDetailsPage.assertPageObjects() + + Log.d(STEP_TAG,"Navigate back to the Dashboard (Course List) Page.") + ViewUtils.pressBackButton(3) + + Log.d(STEP_TAG,"Sign out with ${student1.name} student.") + dashboardPage.logOut() - // Sign out and back in as student2 - dashboardPage.signOut() + Log.d(STEP_TAG, "Login with user: ${student2.name}, login id: ${student2.loginId} , password: ${student2.password}") tokenLogin(student2) dashboardPage.waitForRender() - // Go to the inbox and make sure that student1's message is showing + Log.d(STEP_TAG,"Click on the 'Inbox' bottom menu and assert that ${student1.name}'s message is displayed.") dashboardPage.clickInboxTab() inboxPage.assertConversationDisplayed("Yo!") - } + } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/QuizzesE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/QuizzesE2ETest.kt index 38e314f322..d7b9a5260b 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/QuizzesE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/QuizzesE2ETest.kt @@ -42,6 +42,7 @@ import com.instructure.panda_annotations.TestMetaData import com.instructure.student.R import com.instructure.student.ui.pages.WebViewTextCheck import com.instructure.student.ui.utils.StudentTest +import com.instructure.student.ui.utils.ViewUtils import com.instructure.student.ui.utils.seedData import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest @@ -54,6 +55,10 @@ class QuizzesE2ETest: StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + // Fairly basic test of webview-based quizzes. Seeds/takes a quiz with two multiple-choice // questions. // @@ -62,16 +67,16 @@ class QuizzesE2ETest: StudentTest() { @E2E @Stub @Test - @TestMetaData(Priority.P0, FeatureCategory.PAGES, TestCategory.E2E, true) + @TestMetaData(Priority.MANDATORY, FeatureCategory.PAGES, TestCategory.E2E, true) fun testQuizzesE2E() { - // Seed basic data + 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] - // Seed an unpublished quiz + Log.d(PREPARATION_TAG,"Seed a quiz for ${course.name} course.") val quizUnpublished = QuizzesApi.createQuiz(QuizzesApi.CreateQuizRequest( courseId = course.id, withDescription = true, @@ -79,7 +84,7 @@ class QuizzesE2ETest: StudentTest() { token = teacher.token )) - // Seed a published quiz with some questions + Log.d(PREPARATION_TAG,"Seed another quiz for ${course.name} with some questions.") val quizQuestions = listOf( QuizQuestion( questionText = "What's your favorite color?", @@ -110,25 +115,30 @@ class QuizzesE2ETest: StudentTest() { // answers = listOf() // ) ) + + Log.d(PREPARATION_TAG,"Publish the previously seeded quiz.") val quizPublished = createAndPublishQuiz(course.id, teacher.token, quizQuestions) - // Sign in our user and navigate to our course + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) dashboardPage.waitForRender() + + Log.d(STEP_TAG,"Select ${course.name} course.") dashboardPage.selectCourse(course) - // Verify that quiz info shows up in Quizzes tab + Log.d(STEP_TAG,"Navigate to Quizzes Page. Assert that ${quizPublished.title} published quiz is displayed and ${quizUnpublished.title} unpublished quiz has not displayed.") courseBrowserPage.selectQuizzes() quizListPage.assertQuizDisplayed(quizPublished) quizListPage.assertQuizNotDisplayed(quizUnpublished) - // Verify that the quiz title is displayed, launch quiz + Log.d(STEP_TAG,"Select ${quizPublished.title} quiz. Assert that the ${quizPublished.title} quiz title is displayed.") quizListPage.selectQuiz(quizPublished) canvasWebViewPage.runTextChecks( WebViewTextCheck(locatorType = Locator.ID, locatorValue = "quiz_title", textValue = quizPublished.title) ) + // Launch the quiz // Pressing the "Take the Quiz" button does not work on an FTL Api 25 device. // Not even the logic below, which tries 10 times to press the button! // Every time the button is pressed on an FTL device, we get this console message: @@ -184,14 +194,17 @@ class QuizzesE2ETest: StudentTest() { } // Enter answers to questions. Right now, only multiple-choice questions are supported. + Log.d(STEP_TAG,"Enter answers to the questions:") for(question in quizQuestions) { + Log.d(STEP_TAG,"Assert that the following question is displayed: ${question.questionText}.") quizTakingPage.verifyQuestionDisplayed(question.id!!, question.questionText!!) if(question.questionType == "multiple_choice_question") { + Log.d(STEP_TAG,"Choosing an answer for the following question: ${question.questionText}.") quizTakingPage.selectAnyAnswer(question.id!!) // Just choose any answer } } - // Submit the quiz + Log.d(STEP_TAG,"Submit the ${quizPublished.title} quiz.") quizTakingPage.submitQuiz() // Interesting situation here. If you wait long enough, the web page will update itself, @@ -201,10 +214,13 @@ class QuizzesE2ETest: StudentTest() { // // Chosen strategy: pressBack() until you get to the quiz list page, // then reload the quiz details to get the latest info. + Log.d(STEP_TAG,"Navigate back to Quizzes Page.") while(!isElementDisplayed(R.id.quizListPage)) pressBack() + + Log.d(STEP_TAG,"Select ${quizPublished.title} quiz.") quizListPage.selectQuiz(quizPublished) - // Assert that the quiz now has a history. + Log.d(STEP_TAG,"Assert (on web) that the ${quizPublished.title} quiz now has a history.") onWebView(withId(R.id.canvasWebView)) .withElement(findElement(Locator.ID, "quiz-submission-version-table")) .withContextualElement(findElement(Locator.CLASS_NAME, "desc")) @@ -215,14 +231,14 @@ class QuizzesE2ETest: StudentTest() { .perform(webScrollIntoView()) .check(webMatches(getText(),containsString("LATEST"))) + Log.d(STEP_TAG,"Navigate back to Course Browser Page.") + ViewUtils.pressBackButton(2) - pressBack() // Back to get to quiz list page - pressBack() // Back to course browser page - - // Go to grades page + Log.d(STEP_TAG,"Navigate to Grades Page.") courseBrowserPage.selectGrades() // For some reason, this quiz is resulting in a 10/10 grade, although with the weights assigned and // answers given it should be 5/10. Let's just make sure that a "10" shows up. + Log.d(STEP_TAG,"Assert that the corresponding grade (10) is displayed for ${quizPublished.title} quiz.") courseGradesPage.assertGradeDisplayed(withText(quizPublished.title), containsTextCaseInsensitive("10")) } 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 4b80ff1a06..f74e1faa41 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 @@ -16,18 +16,22 @@ */ package com.instructure.student.ui.e2e +import android.util.Log import androidx.test.espresso.Espresso import com.instructure.canvas.espresso.E2E import com.instructure.canvasapi2.utils.RemoteConfigParam import com.instructure.canvasapi2.utils.RemoteConfigUtils +import com.instructure.espresso.ViewUtils import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority import com.instructure.panda_annotations.TestCategory import com.instructure.panda_annotations.TestMetaData +import com.instructure.student.R import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.seedData import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest +import org.junit.Assert import org.junit.Test @HiltAndroidTest @@ -36,78 +40,174 @@ class SettingsE2ETest : StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - // Basically just verifies that the proper items show up in the settings page, - // legal page and help page. As these are all somewhat dependent on API calls, - // they seemed like legitimate targets for an E2E test. + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.SETTINGS, TestCategory.E2E) - fun testSettingsE2E() { + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.E2E) + fun testProfileSettingsE2E() { + + Log.d(PREPARATION_TAG, "Seeding data.") val data = seedData(students = 1, teachers = 1, courses = 1) - val student = data.studentsList[0] - tokenLogin(student) + val teacher = data.teachersList[0] + Log.d(STEP_TAG, "Login with user: ${teacher.name}, login id: ${teacher.loginId} , password: ${teacher.password}") + tokenLogin(teacher) dashboardPage.waitForRender() + + Log.d(STEP_TAG, "Navigate to User Settings Page.") dashboardPage.launchSettingsPage() + settingsPage.assertPageObjects() + + Log.d(STEP_TAG, "Open Profile Settings Page.") + settingsPage.launchProfileSettings() + profileSettingsPage.assertPageObjects() + val newUserName = "John Doe" + Log.d(STEP_TAG, "Edit username to: $newUserName. Click on 'Save' button.") + profileSettingsPage.changeUserNameTo(newUserName) + + Log.d(STEP_TAG, "Navigate back to Dashboard Page. Assert that the username has been changed to $newUserName.") + ViewUtils.pressBackButton(2) + dashboardPage.assertUserLoggedIn(newUserName) + + val originalSavedPandaAvatarCount = getSavedPandaAvatarCount() + + Log.d(STEP_TAG, "Navigate to Settings Page again and open Panda Avatar Creator.") + dashboardPage.launchSettingsPage() settingsPage.assertPageObjects() - settingsPage.launchLegalPage() + settingsPage.launchProfileSettings() + profileSettingsPage.assertPageObjects() + profileSettingsPage.launchPandaAvatarCreator() + + Log.d(STEP_TAG, "Set panda avatar head.") + pandaAvatarPage.selectChangeHead() + pandaAvatarPage.choosePart(R.string.content_description_panda_head_4) + pandaAvatarPage.clickBackButton() + + Log.d(STEP_TAG, "Set panda avatar body.") + pandaAvatarPage.selectChangeBody() + pandaAvatarPage.choosePart(R.string.content_description_panda_body_4) + pandaAvatarPage.clickBackButton() + + Log.d(STEP_TAG, "Set panda avatar legs.") + pandaAvatarPage.selectChangeLegs() + pandaAvatarPage.choosePart(R.string.content_description_panda_feet_5) + pandaAvatarPage.clickBackButton() + + Log.d(STEP_TAG, "Click on 'Save as avatar' button.") + pandaAvatarPage.save() + + val newSavedPandaAvatarCount = getSavedPandaAvatarCount() + Log.d(STEP_TAG, "Assert that saved panda avatar count has increased by one. Old value: $originalSavedPandaAvatarCount, new value: $newSavedPandaAvatarCount.") + Assert.assertTrue(newSavedPandaAvatarCount == originalSavedPandaAvatarCount + 1) + + } + + @E2E + @Test + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.E2E) + fun testLegalPageE2E() { + + Log.d(PREPARATION_TAG, "Seeding data.") + val data = seedData(students = 1, teachers = 1, courses = 1) + val student = data.studentsList[0] + + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") + tokenLogin(student) + dashboardPage.waitForRender() + Log.d(STEP_TAG, "Navigate to Settings Page on the left-side menu.") + dashboardPage.launchSettingsPage() + settingsPage.assertPageObjects() + + Log.d(STEP_TAG, "Click on 'Legal' link to open Legal Page. Assert that Legal Page has opened.") + settingsPage.launchLegalPage() legalPage.assertPageObjects() - Espresso.pressBack() // Exit legal page } - // The remote config settings page (only available on debug builds) used to do some - // really bizarre things when reacting to the soft keyboard appearing and disappearing. - // This test verifies that no remote config values change in response to the - // soft keyboard appearing. - // - // Marked as P2 because this is not testing user-facing functionality. @E2E @Test - @TestMetaData(Priority.P2, FeatureCategory.SETTINGS, TestCategory.E2E) - fun testRemoteConfigSettingsE2E() { + @TestMetaData(Priority.IMPORTANT, FeatureCategory.SETTINGS, TestCategory.E2E) + fun testAboutE2E() { + + Log.d(PREPARATION_TAG, "Seeding data.") val data = seedData(students = 1, teachers = 1, courses = 1) val student = data.studentsList[0] + + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) + dashboardPage.waitForRender() + + Log.d(STEP_TAG, "Navigate to Settings Page on the left-side menu.") + dashboardPage.launchSettingsPage() + settingsPage.assertPageObjects() + + Log.d(STEP_TAG, "Click on 'About' link to open About Page. Assert that About Page has opened.") + settingsPage.launchAboutPage() + aboutPage.assertPageObjects() + + Log.d(STEP_TAG,"Check that domain is equal to: ${student.domain} (student's domain).") + aboutPage.domainIs(student.domain) + + Log.d(STEP_TAG,"Check that Login ID is equal to: ${student.loginId} (student's Login ID).") + aboutPage.loginIdIs(student.loginId) + Log.d(STEP_TAG,"Check that e-mail is equal to: ${student.loginId} (student's Login ID).") + aboutPage.emailIs(student.loginId) + + } + + //The remote config settings page only available on debug builds. + @E2E + @Test + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SETTINGS, TestCategory.E2E) + fun testRemoteConfigSettingsE2E() { + + Log.d(PREPARATION_TAG, "Seeding data.") + val data = seedData(students = 1, teachers = 1, courses = 1) + val student = data.studentsList[0] + + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") + tokenLogin(student) dashboardPage.waitForRender() + + Log.d(STEP_TAG, "Navigate to Settings Page on the left-side menu.") dashboardPage.launchSettingsPage() - // Capture the initial remote config values + Log.d(PREPARATION_TAG,"Store the initial values on Remote Config Settings Page.") val initialValues = mutableMapOf() RemoteConfigParam.values().forEach {param -> initialValues.put(param.rc_name, RemoteConfigUtils.getString(param))} - // Launch the remote config page + Log.d(STEP_TAG, "Navigate to Remote Config Settings Page.") settingsPage.launchRemoteConfigParams() - // Click on each EditText, which brings up the soft keyboard, then dismiss it. RemoteConfigParam.values().forEach { param -> - // Bring up the soft keyboard + Log.d(STEP_TAG, "Edit ${param.name} parameter.") + + Log.d(STEP_TAG, "Bring up the soft keyboard.") remoteConfigSettingsPage.clickRemoteConfigParamValue(param) - // and dismiss it - Espresso.closeSoftKeyboard() + Log.d(STEP_TAG, "Dismiss the soft keyboard.") + Espresso.closeSoftKeyboard() //we need to do this to make this test work. TODO: investigate - // If we don't clear the focus on the EditText, it can cause - // funky behavior when we click on the next EditText (like the - // "paste | select all" menu popping up). - remoteConfigSettingsPage.clearRemoteConfigParamValueFocus(param) + Log.d(STEP_TAG, "Clear remote config parameter valu: ${param.name}.") + remoteConfigSettingsPage.clearRemoteConfigParamValueFocus(param) //we need to clear it because otherwise it would be flaky. } - // Exit the remote config page + Log.d(STEP_TAG, "Navigate back to Settings Page.") Espresso.pressBack() - // Go back in again + Log.d(STEP_TAG, "Navigate to Remote Config Settings Page.") settingsPage.launchRemoteConfigParams() - // Verify that all fields have maintained their initial value + Log.d(STEP_TAG, "Assert that all fields have maintained their initial value.") RemoteConfigParam.values().forEach { param -> remoteConfigSettingsPage.verifyRemoteConfigParamValue(param, initialValues.get(param.rc_name)!!) } - // Exit the remote config page - Espresso.pressBack() } } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ShardE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ShardE2ETest.kt deleted file mode 100644 index 8f90364da7..0000000000 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/ShardE2ETest.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.instructure.student.ui.e2e - -import com.instructure.canvas.espresso.E2E -import com.instructure.panda_annotations.FeatureCategory -import com.instructure.panda_annotations.Priority -import com.instructure.panda_annotations.TestCategory -import com.instructure.panda_annotations.TestMetaData -import com.instructure.student.ui.utils.StudentTest -import dagger.hilt.android.testing.HiltAndroidTest -import org.junit.Test - -@HiltAndroidTest -class ShardE2ETest: StudentTest() { - override fun displaysPageObjects() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - @E2E - @Test - @TestMetaData(Priority.P0, FeatureCategory.NONE, TestCategory.E2E, true) - fun testShardE2E() { - // TODO: Test against institutions across multiple shards, for courses/assignments/etc... that have cross shard ids - // (i.e., 12345~1234 instead of 1234500000000001234) - } -} \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/SyllabusE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/SyllabusE2ETest.kt index 0d270ee43c..5be307ab37 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/SyllabusE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/SyllabusE2ETest.kt @@ -16,9 +16,8 @@ */ package com.instructure.student.ui.e2e -import androidx.test.espresso.Espresso.pressBack +import android.util.Log import com.instructure.canvas.espresso.E2E -import com.instructure.canvas.espresso.Stub import com.instructure.dataseeding.api.AssignmentsApi import com.instructure.dataseeding.api.QuizzesApi import com.instructure.dataseeding.model.SubmissionType @@ -41,28 +40,33 @@ class SyllabusE2ETest: StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.SYLLABUS, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SYLLABUS, TestCategory.E2E) fun testSyllabusE2E() { - // Seed basic data + 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] - // Sign in and navigate to the course. The course syllabus should be empty + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) dashboardPage.waitForRender() + + Log.d(STEP_TAG,"Select ${course.name} course.") dashboardPage.selectCourse(course) + + Log.d(STEP_TAG,"Navigate to Syllabus Page. Assert that Empty View is displayed, because there is no syllabus yet.") courseBrowserPage.selectSyllabus() syllabusPage.assertEmptyView() - - // Create/publish our syllabus items - - // Seed an assignment + Log.d(PREPARATION_TAG,"Seed an assignment for ${course.name} course.") val assignment = AssignmentsApi.createAssignment(AssignmentsApi.CreateAssignmentRequest( courseId = course.id, teacherToken = teacher.token, @@ -71,7 +75,7 @@ class SyllabusE2ETest: StudentTest() { withDescription = true )) - // Seed a quiz + Log.d(PREPARATION_TAG,"Seed a quiz for ${course.name} course.") val quiz = QuizzesApi.createQuiz(QuizzesApi.CreateQuizRequest( courseId = course.id, withDescription = true, @@ -82,7 +86,7 @@ class SyllabusE2ETest: StudentTest() { // TODO: Seed a generic calendar event - // Now refresh our syllabus page and verify that our assignment and quiz are showing + Log.d(STEP_TAG,"Refresh the page. Assert that all of the items, so ${assignment.name} assignment and ${quiz.title} quiz are displayed.") syllabusPage.refresh() syllabusPage.assertItemDisplayed(assignment.name) syllabusPage.assertItemDisplayed(quiz.title) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/TodoE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/TodoE2ETest.kt index 5f734e9055..34cef2228f 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/TodoE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/TodoE2ETest.kt @@ -1,5 +1,6 @@ package com.instructure.student.ui.e2e +import android.util.Log import com.instructure.canvas.espresso.E2E import com.instructure.dataseeding.api.QuizzesApi import com.instructure.dataseeding.util.days @@ -23,9 +24,13 @@ class TodoE2ETest: StudentTest() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } + override fun enableAndConfigureAccessibilityChecks() { + //We don't want to see accessibility errors on E2E tests + } + @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.TODOS, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.TODOS, TestCategory.E2E) fun testTodoE2E() { // Don't attempt this test on a Friday, Saturday or Sunday. @@ -36,20 +41,22 @@ class TodoE2ETest: StudentTest() { return } - // Seed data + 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] - // Seed an assignment due tomorrow, for todo tab + Log.d(PREPARATION_TAG,"Seed an assignment for ${course.name} course.") val seededAssignments = seedAssignments( courseId = course.id, teacherToken = teacher.token, dueAt = 1.days.fromNow.iso8601 ) - // Seed a quiz due tomorrow, for todo tab + val testAssignment = seededAssignments[0] + + Log.d(PREPARATION_TAG,"Seed a quiz for ${course.name} course with tomorrow due date.") val quiz = QuizzesApi.createQuiz( QuizzesApi.CreateQuizRequest( courseId = course.id, @@ -57,21 +64,19 @@ class TodoE2ETest: StudentTest() { published = true, token = teacher.token, dueAt = 1.days.fromNow.iso8601) - ) - // Sign in with lone student + Log.d(STEP_TAG, "Login with user: ${student.name}, login id: ${student.loginId} , password: ${student.password}") tokenLogin(student) - - // Navigate to ToDo tab dashboardPage.waitForRender() + + Log.d(STEP_TAG,"Navigate to 'To Do' page via bottom-menu.") dashboardPage.clickTodoTab() - //todoPage.waitForRender() - // Verify that your assignment shows up - todoPage.assertAssignmentDisplayed(seededAssignments[0]) + Log.d(STEP_TAG,"Assert that ${testAssignment.name} assignment is displayed.") + todoPage.assertAssignmentDisplayed(testAssignment) - // Verify that your quiz shows up + Log.d(STEP_TAG,"Assert that ${quiz.title} quiz is displayed.") todoPage.assertQuizDisplayed(quiz) } } \ No newline at end of file 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 3d6cd26131..c03240b5ad 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 @@ -18,7 +18,6 @@ package com.instructure.student.ui.e2e.k5 import androidx.test.espresso.Espresso import com.instructure.canvas.espresso.E2E -import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvasapi2.utils.toApiString import com.instructure.dataseeding.api.AssignmentsApi import com.instructure.dataseeding.api.GradingPeriodsApi @@ -51,7 +50,7 @@ class GradesElementaryE2ETest : StudentTest() { @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.E2E) fun gradesE2ETest() { // Seed data for K5 sub-account 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 6fee3a98a8..a7bf54c824 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 @@ -35,7 +35,6 @@ import com.instructure.student.ui.utils.seedDataForK5 import com.instructure.student.ui.utils.tokenLoginElementary import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Test -import java.text.SimpleDateFormat import java.util.* @HiltAndroidTest @@ -51,7 +50,7 @@ class HomeroomE2ETest : StudentTest() { @E2E @FlakyE2E("Need to investigate why is it breaking when asserting todo text. Timezone shouldn't be a problem anymore since we run these tests at 8 PM.") @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.E2E) fun homeroomE2ETest() { // Seed data for K5 sub-account diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ImportantDatesE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ImportantDatesE2ETest.kt index 46ead3c53b..36301abaf7 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ImportantDatesE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ImportantDatesE2ETest.kt @@ -18,11 +18,8 @@ package com.instructure.student.ui.e2e.k5 import androidx.test.espresso.Espresso import com.instructure.canvas.espresso.E2E -import com.instructure.canvas.espresso.refresh -import com.instructure.canvasapi2.utils.toApiString import com.instructure.canvasapi2.utils.toDate import com.instructure.dataseeding.api.AssignmentsApi -import com.instructure.dataseeding.model.CanvasUserApiModel import com.instructure.dataseeding.model.GradingType import com.instructure.dataseeding.model.SubmissionType import com.instructure.dataseeding.util.days @@ -51,7 +48,7 @@ class ImportantDatesE2ETest : StudentTest() { @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.E2E) fun importantDatesE2ETest() { // Seed data for K5 sub-account diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ResourcesE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ResourcesE2ETest.kt index e2e69d2b2c..ebe7a5f604 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ResourcesE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/k5/ResourcesE2ETest.kt @@ -42,7 +42,7 @@ class ResourcesE2ETest : StudentTest() { @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.E2E) fun resourcesE2ETest() { // Seed data for K5 sub-account 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 f369904035..586620f868 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 @@ -48,7 +48,7 @@ class ScheduleE2ETest : StudentTest() { @E2E @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.E2E) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.E2E) fun scheduleE2ETest() { // Seed data for K5 sub-account diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AnnouncementInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AnnouncementInteractionTest.kt index 84d60cd877..56ffbf4801 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AnnouncementInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AnnouncementInteractionTest.kt @@ -45,7 +45,7 @@ class AnnouncementInteractionTest : StudentTest() { // Student enrolled in intended section can see and reply to the announcement // (This kind of seems like more of a test of the mocked endpoint, but we'll go with it.) @Test - @TestMetaData(Priority.P0, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) fun testAnnouncement_replyToSectionSpecificAnnouncement() { val data = getToCourse(createSections = true) @@ -83,7 +83,7 @@ class AnnouncementInteractionTest : StudentTest() { // User can preview an announcement attachment @Test - @TestMetaData(Priority.P0, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) fun testAnnouncement_previewAttachment() { val data = getToCourse() @@ -125,7 +125,7 @@ class AnnouncementInteractionTest : StudentTest() { // View/reply to an announcement @Test - @TestMetaData(Priority.P0, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) fun testAnnouncement_reply() { val data = getToCourse() @@ -149,7 +149,7 @@ class AnnouncementInteractionTest : StudentTest() { // Tests that we can create an announcement (as teacher). @Test - @TestMetaData(Priority.P0, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) fun testAnnouncementCreate_base() { val data = getToAnnouncementList() @@ -161,7 +161,7 @@ class AnnouncementInteractionTest : StudentTest() { // Tests code around closing / aborting announcement creation @Test - @TestMetaData(Priority.P1, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) fun testAnnouncementCreate_abort() { val data = getToAnnouncementList() val course = data.courses.values.first() @@ -179,7 +179,7 @@ class AnnouncementInteractionTest : StudentTest() { // Tests code around creating an announcement with no description @Test - @TestMetaData(Priority.P2, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.COMMON, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) fun testAnnouncementCreate_missingDescription() { getToAnnouncementList() @@ -190,14 +190,14 @@ class AnnouncementInteractionTest : StudentTest() { // Tests code around creating an announcement with no title @Test - @TestMetaData(Priority.P2, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.COMMON, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) fun testAnnouncementCreate_missingTitle() { getToAnnouncementList() discussionListPage.createAnnouncement("", "description") } @Test - @TestMetaData(Priority.P1, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ANNOUNCEMENTS, TestCategory.INTERACTION, false) fun testSearchAnnouncement() { val data = getToAnnouncementList() val course = data.courses.values.first() 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 3ee24c2e4a..34d76bd5a6 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 @@ -18,9 +18,9 @@ package com.instructure.student.ui.interaction import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.mockCanvas.* import com.instructure.canvasapi2.models.Assignment -import com.instructure.canvasapi2.models.Submission import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority +import com.instructure.panda_annotations.SecondaryFeatureCategory import com.instructure.panda_annotations.TestCategory import com.instructure.panda_annotations.TestMetaData import com.instructure.student.ui.utils.StudentTest @@ -29,14 +29,13 @@ import com.instructure.student.ui.utils.tokenLogin import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Assert.assertNotNull import org.junit.Test -import java.util.* @HiltAndroidTest class AssignmentDetailsInteractionTest : StudentTest() { override fun displaysPageObjects() = Unit // Not used for interaction tests @Test - @TestMetaData(Priority.P0, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION, false, FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.SUBMISSIONS_ONLINE_URL) fun testSubmission_submitAssignment() { // TODO - Test submitting for each submission type // For now, I'm going to just test one submission type @@ -63,7 +62,7 @@ class AssignmentDetailsInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION, false, FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false) fun testNavigating_viewSubmissionDetails() { // Test clicking on the Submission and Rubric button to load the Submission Details Page goToAssignmentFromList() @@ -72,7 +71,7 @@ class AssignmentDetailsInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION, false) fun testNavigating_viewAssignmentDetails() { // Test clicking on the Assignment item in the Assignment List to load the Assignment Details Page goToAssignmentFromList() @@ -81,7 +80,7 @@ class AssignmentDetailsInteractionTest : StudentTest() { @Stub @Test - @TestMetaData(Priority.P0, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION, true, FeatureCategory.QUIZZES) + @TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION, true, SecondaryFeatureCategory.ASSIGNMENT_QUIZZES) fun testQuizzesNext_launchQuizzesNextAssignment() { // Launch into Quizzes.Next assignment /* First attempt based on hardcoded verifier response @@ -111,13 +110,6 @@ class AssignmentDetailsInteractionTest : StudentTest() { */ } - @Stub - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION, true, FeatureCategory.BOOKMARKS) - fun testAssignments_createBookmark() { - // Student can bookmark the assignment - } - private fun goToAssignmentFromList() { // Test clicking on the Submission and Rubric button to load the Submission Details Page val data = MockCanvas.init( diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AssignmentListInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AssignmentListInteractionTest.kt index 26a7b82099..c92de79225 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AssignmentListInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/AssignmentListInteractionTest.kt @@ -31,28 +31,28 @@ import org.junit.Test class AssignmentListInteractionTest : StudentTest() { @Test - @TestMetaData(Priority.P1, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) override fun displaysPageObjects() { getToAssignmentsPage(0) assignmentListPage.assertPageObjects() } @Test - @TestMetaData(Priority.P1, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) fun displaysNoAssignmentsView() { getToAssignmentsPage(0) assignmentListPage.assertDisplaysNoAssignmentsView() } @Test - @TestMetaData(Priority.P1, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) fun displaysAssignment() { val assignment = getToAssignmentsPage()[0] assignmentListPage.assertHasAssignment(assignment) } @Test - @TestMetaData(Priority.P1, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) fun sortAssignmentsByTimeByDefault() { val assignment = getToAssignmentsPage()[0] assignmentListPage.assertHasAssignment(assignment) @@ -61,7 +61,7 @@ class AssignmentListInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION) fun sortAssignmentsByTypeWhenTypeIsSelectedInTheDialog() { val assignment = getToAssignmentsPage()[0] 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 5ac9d0a61e..6eccfb2fdb 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 @@ -38,7 +38,7 @@ class BookmarkInteractionTest : StudentTest() { // Test that we can create a bookmark via the UI and see it in the bookmark list @Test - @TestMetaData(Priority.P1, FeatureCategory.BOOKMARKS, TestCategory.INTERACTION, false, FeatureCategory.ASSIGNMENTS) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.BOOKMARKS, TestCategory.INTERACTION, false) fun testBookmark_create() { val data = init() val course = data.courses.values.first() @@ -49,7 +49,7 @@ class BookmarkInteractionTest : StudentTest() { courseBrowserPage.selectAssignments() assignmentListPage.clickAssignment(assignment) val bookmarkName = "Bookmark name 1" - assignmentDetailsPage.bookmark(bookmarkName) + assignmentDetailsPage.addBookmark(bookmarkName) Espresso.pressBack() // to assignment list Espresso.pressBack() // to course Espresso.pressBack() // to main dashboard @@ -60,7 +60,7 @@ class BookmarkInteractionTest : StudentTest() { // Tests that we can click a bookmark and end up in the bookmarked location @Test - @TestMetaData(Priority.P1, FeatureCategory.BOOKMARKS, TestCategory.INTERACTION, false, FeatureCategory.ASSIGNMENTS) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.BOOKMARKS, TestCategory.INTERACTION, false) fun testBookmark_click() { val data = init() val student = data.students.first() @@ -83,7 +83,7 @@ class BookmarkInteractionTest : StudentTest() { // Tests that we can change the name of a bookmark and still click through to the intended location @Test - @TestMetaData(Priority.P1, FeatureCategory.BOOKMARKS, TestCategory.INTERACTION, false, FeatureCategory.ASSIGNMENTS) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.BOOKMARKS, TestCategory.INTERACTION, false) fun testBookmark_changeName() { val data = init() val student = data.students.first() diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CalendarInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CalendarInteractionTest.kt deleted file mode 100644 index ae6153df60..0000000000 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CalendarInteractionTest.kt +++ /dev/null @@ -1,117 +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.interaction - -import com.instructure.canvas.espresso.Stub -import com.instructure.panda_annotations.FeatureCategory -import com.instructure.panda_annotations.Priority -import com.instructure.panda_annotations.TestCategory -import com.instructure.panda_annotations.TestMetaData -import com.instructure.student.ui.utils.StudentTest -import dagger.hilt.android.testing.HiltAndroidTest -import org.junit.Test - -@HiltAndroidTest -class CalendarInteractionTest : StudentTest() { - override fun displaysPageObjects() = Unit // Not used for interaction tests - - @Stub - @Test - @TestMetaData(Priority.P1, FeatureCategory.EVENTS, TestCategory.INTERACTION, true) - fun testMonthView_tappingADayDisplaysAllItemsForThatDay() { - // Tapping a day in the calendar view should display all items for that day in the list view - } - - @Stub - @Test - @TestMetaData(Priority.P1, FeatureCategory.EVENTS, TestCategory.INTERACTION, true) - fun testMonthView_itemListIsScrollable() { - // List of calendar items should be scrollable - } - - @Stub - @Test - @TestMetaData(Priority.P1, FeatureCategory.EVENTS, TestCategory.INTERACTION, true) - fun testMonthView_todayButtonGoesToCurrentDate() { - // The 'today' button in the toolbar should select the current date in the calendar - } - - @Stub - @Test - @TestMetaData(Priority.P1, FeatureCategory.EVENTS, TestCategory.INTERACTION, true) - fun testMonthView_tappingDayWithWeekRangeShowsAllItemsForThatWeek() { - // The Week range/selected date is displayed and shows all events for that week range - } - - @Stub - @Test - @TestMetaData(Priority.P1, FeatureCategory.EVENTS, TestCategory.INTERACTION, true) - fun testMonthView_monthRangeShowsAllItemsForThatMonth() { - // The Month range/selected date is displayed and shows all events for that month range - } - - @Stub - @Test - @TestMetaData(Priority.P1, FeatureCategory.EVENTS, TestCategory.INTERACTION, true) - fun testMonthView_addEventUpdatesList() { - // *key note, these are personal events only - // The user should be able to add an event, success is measured by the new event showing up in the list - } - - @Stub - @Test - @TestMetaData(Priority.P1, FeatureCategory.EVENTS, TestCategory.INTERACTION, true) - fun testMonthView_deleteEventUpdatesList() { - // *key note, these are personal events only - // The user should be able to delete an event, success is measured by the deleted event being removed from the list - } - - @Stub - @Test - @TestMetaData(Priority.P1, FeatureCategory.EVENTS, TestCategory.INTERACTION, true) - fun testMonthView_pullToRefresh() { - // The user should be able to ptr to refresh the screen - } - - @Stub - @Test - @TestMetaData(Priority.P0, FeatureCategory.EVENTS, TestCategory.INTERACTION, true, FeatureCategory.ASSIGNMENTS) - fun testMonthView_tappingAssignmentItemDisplaysDetails() { - // Tapping Assignment item navigates user to assignment details - } - - @Stub - @Test - @TestMetaData(Priority.P0, FeatureCategory.EVENTS, TestCategory.INTERACTION, true, FeatureCategory.DISCUSSIONS) - fun testMonthView_tappingDiscussionItemDisplaysDetails() { - // Tapping Discussion item navigates user to discussion details - } - - @Stub - @Test - @TestMetaData(Priority.P0, FeatureCategory.EVENTS, TestCategory.INTERACTION, true, FeatureCategory.QUIZZES) - fun testMonthView_tappingQuizItemDisplaysDetails() { - // Tapping Quiz item navigates user to quiz details - } - - @Stub - @Test - @TestMetaData(Priority.P0, FeatureCategory.EVENTS, TestCategory.INTERACTION, true, FeatureCategory.NOTIFICATIONS) - fun testMonthView_tappingNotificationItemDisplaysDetails() { - // Tapping Notification item navigates user to details - } - -} diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CommentsInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CommentsInteractionTest.kt deleted file mode 100644 index 65fd96f8db..0000000000 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CommentsInteractionTest.kt +++ /dev/null @@ -1,38 +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.interaction - -import com.instructure.canvas.espresso.Stub -import com.instructure.panda_annotations.FeatureCategory -import com.instructure.panda_annotations.Priority -import com.instructure.panda_annotations.TestCategory -import com.instructure.panda_annotations.TestMetaData -import com.instructure.student.ui.utils.StudentTest -import dagger.hilt.android.testing.HiltAndroidTest -import org.junit.Test - -@HiltAndroidTest -class CommentsInteractionTest: StudentTest() { - override fun displaysPageObjects() = Unit // Not used for interaction tests - - @Stub - @Test - @TestMetaData(Priority.P0, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION, true, FeatureCategory.COMMENTS) - fun testComments_addComment() { - // Test adding a comment to an assignment comment stream - } - -} \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CourseInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CourseInteractionTest.kt index 8c5502ece1..6f33a765b5 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CourseInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/CourseInteractionTest.kt @@ -46,7 +46,7 @@ class CourseInteractionTest : StudentTest() { // Link from a course page to another public course should open in the app @Test - @TestMetaData(Priority.P1, FeatureCategory.COURSE, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.COURSE, TestCategory.INTERACTION, false) fun testCourse_linkFromCoursePageToPublicCoursePage() { val data = getToCourse(courseCount = 2, favoriteCourseCount = 2) @@ -81,7 +81,7 @@ class CourseInteractionTest : StudentTest() { // user should be able to open/preview course file @Test - @TestMetaData(Priority.P0, FeatureCategory.COURSE, TestCategory.INTERACTION, false, FeatureCategory.FILES) + @TestMetaData(Priority.MANDATORY, FeatureCategory.FILES, TestCategory.INTERACTION, false) fun testCourse_openFile() { // MBL-13499: Don't run this test on API 28 and above until we add HTTPS support diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/DashboardInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/DashboardInteractionTest.kt index beac072c3f..e4f986e61b 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/DashboardInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/DashboardInteractionTest.kt @@ -17,10 +17,8 @@ package com.instructure.student.ui.interaction import androidx.test.espresso.Espresso -import androidx.test.espresso.NoMatchingViewException import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.addAccountNotification -import com.instructure.canvas.espresso.mockCanvas.addEnrollment import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvasapi2.apis.EnrollmentAPI import com.instructure.panda_annotations.FeatureCategory @@ -38,7 +36,7 @@ class DashboardInteractionTest : StudentTest() { override fun displaysPageObjects() = Unit // Not used for interaction tests @Test - @TestMetaData(Priority.P0, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testNavigateToDashboard() { // User should be able to tap and navigate to dashboard page val data = getToDashboard(courseCount = 1, favoriteCourseCount = 1) @@ -52,7 +50,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testDashboardCourses_emptyState() { // Empty state should be displayed with a 'Add Courses' button, when nothing is favorited (and courses are completed/concluded) // With the new DashboardCard api being used, if nothing is a favorite it will default to active enrollments @@ -61,7 +59,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testDashboardCourses_addFavorite() { // Starring should add course to favorite list @@ -82,7 +80,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testDashboardCourses_removeFavorite() { // Un-starring should remove course from favorite list @@ -105,7 +103,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testDashboardCourses_addAllToFavorites() { val data = getToDashboard(courseCount = 3, favoriteCourseCount = 0) val toFavorite = data.courses.values @@ -123,7 +121,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testDashboardCourses_removeAllFromFavorites() { val data = getToDashboard(courseCount = 3, favoriteCourseCount = 2) val toRemove = data.courses.values.filter { it.isFavorite } @@ -141,7 +139,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testDashboardAnnouncement_refresh() { // Pull to refresh loads new announcements val data = getToDashboard(courseCount = 1, favoriteCourseCount = 1) // No announcements initially @@ -152,7 +150,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testDashboardAnnouncement_dismiss() { // Tapping dismiss should remove the announcement. Refresh should not display it again. val data = getToDashboard(courseCount = 1, favoriteCourseCount = 1, announcementCount = 1) @@ -166,7 +164,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testDashboardInvite_accept() { val data = getToDashboard(courseCount = 2, invitedCourseCount = 1) val invitedCourse = data.courses.values.first { it.enrollments?.any { it.enrollmentState == EnrollmentAPI.STATE_INVITED } ?: false } @@ -182,7 +180,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testDashboardInvite_decline() { val data = getToDashboard(courseCount = 2, invitedCourseCount = 1) val invitedCourse = data.courses.values.first { it.enrollments?.any { it.enrollmentState == EnrollmentAPI.STATE_INVITED } ?: false } @@ -198,7 +196,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION) fun testDashboardAnnouncement_view() { // Tapping global announcement displays the content val data = getToDashboard(courseCount = 1, favoriteCourseCount = 1, announcementCount = 1) @@ -212,7 +210,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.DASHBOARD, TestCategory.INTERACTION, false, FeatureCategory.COURSE) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DASHBOARD, TestCategory.INTERACTION, false) fun testDashboardCourses_tappingCourseCardDisplaysCourseBrowser() { // Tapping on a course card opens course browser page val data = getToDashboard(courseCount = 1, favoriteCourseCount = 1) @@ -229,7 +227,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION, false, FeatureCategory.COURSE) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION, false) fun testDashboardCourses_gradeIsDisplayedWhenShowGradesIsSelected() { // [Student] Grade is displayed when 'Show Grades' (located in navigation drawer) is selected getToDashboard(courseCount = 1, favoriteCourseCount = 1) @@ -238,7 +236,7 @@ class DashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.DASHBOARD, TestCategory.INTERACTION, false, FeatureCategory.COURSE) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DASHBOARD, TestCategory.INTERACTION, false) fun testDashboardCourses_gradeIsNotDisplayedWhenShowGradesIsDeSelected() { // [Student] Grade is NOT displayed when 'Show Grades' (located in navigation drawer) is de-selected getToDashboard(courseCount = 1, favoriteCourseCount = 1) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/DiscussionsInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/DiscussionsInteractionTest.kt index 81cc22044a..4b28e5fc11 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/DiscussionsInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/DiscussionsInteractionTest.kt @@ -48,7 +48,7 @@ class DiscussionsInteractionTest : StudentTest() { // Verify that a discussion header shows up properly after discussion creation @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionCreate_base() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) @@ -67,7 +67,7 @@ class DiscussionsInteractionTest : StudentTest() { // It's actually impossible to attach anything to a discussion topic with our app, // so the attachment is done behind the scenes, after the fact. @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionCreate_withAttachment() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) val course = data.courses.values.first() @@ -111,7 +111,7 @@ class DiscussionsInteractionTest : StudentTest() { // Test that you can't create a discussion when discussion creation is disabled @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionCreate_disabledWhenNotPermitted() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = false) @@ -122,7 +122,7 @@ class DiscussionsInteractionTest : StudentTest() { // Tests that links to other Canvas content routes properly @Test - @TestMetaData(Priority.P1, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussion_linksRouteInApp() { val data = getToCourse(studentCount = 2, courseCount = 2, enableDiscussionTopicCreation = true) val course1 = data.courses.values.first() @@ -150,7 +150,7 @@ class DiscussionsInteractionTest : StudentTest() { // Replies automatically get marked as read as the user scrolls through the list @Test - @TestMetaData(Priority.P1, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussion_postsGetMarkedAsRead() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) val course = data.courses.values.first() @@ -189,7 +189,7 @@ class DiscussionsInteractionTest : StudentTest() { // Attachment is html, so that we can keep the viewing of it "in-house" // NOTE: Very similar to testDiscussionCreate_withAttachment @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussion_previewAttachment() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) @@ -231,7 +231,7 @@ class DiscussionsInteractionTest : StudentTest() { // Tests that users can like entries and the correct like count is displayed, if the liking is enabled @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionLikePost_base() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) @@ -272,7 +272,7 @@ class DiscussionsInteractionTest : StudentTest() { // Tests that like count is shown if only graders can like @Test - @TestMetaData(Priority.P1, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionLikes_whenOnlyGradersCanRate() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) val course = data.courses.values.first() @@ -309,7 +309,7 @@ class DiscussionsInteractionTest : StudentTest() { // Tests that discussion entry liking is not available when disabled @Test - @TestMetaData(Priority.P1, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionLikePost_disabledWhenNotPermitted() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) data.discussionRatingsEnabled = false @@ -338,7 +338,7 @@ class DiscussionsInteractionTest : StudentTest() { // Test basic discussion view @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionView_base() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) val course1 = data.courses.values.first() @@ -358,7 +358,7 @@ class DiscussionsInteractionTest : StudentTest() { // Test that you can reply to a discussion (if enabled) @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionView_replies() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) val course1 = data.courses.values.first() @@ -385,7 +385,7 @@ class DiscussionsInteractionTest : StudentTest() { // Test that replies are not possible when they are not enabled @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionView_repliesHiddenWhenNotPermitted() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) val course1 = data.courses.values.first() @@ -406,7 +406,7 @@ class DiscussionsInteractionTest : StudentTest() { // Test that a reply is displayed properly @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionReply_base() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) val course1 = data.courses.values.first() @@ -434,7 +434,7 @@ class DiscussionsInteractionTest : StudentTest() { // It is a whole other gear to manually specify an attachment the same way that a user would, // so we add the attachments programmatically. @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionReply_withAttachment() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) val course1 = data.courses.values.first() @@ -485,7 +485,7 @@ class DiscussionsInteractionTest : StudentTest() { // Tests that we can make a threaded reply to a reply @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionReply_threaded() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) val course1 = data.courses.values.first() @@ -522,7 +522,7 @@ class DiscussionsInteractionTest : StudentTest() { // It is a whole other gear to manually specify an attachment the same way that a user would, // so we add the attachments programmatically. @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussionReply_threadedWithAttachment() { val data = getToCourse(studentCount = 1, courseCount = 1, enableDiscussionTopicCreation = true) val course1 = data.courses.values.first() @@ -572,6 +572,7 @@ class DiscussionsInteractionTest : StudentTest() { replyReplyEntry.attachments = mutableListOf(attachment) discussionDetailsPage.refresh() // To pick up updated discussion reply + Thread.sleep(3000) //Need this because somehow sometimes refresh does "double-refresh" and assert is failing below. discussionDetailsPage.assertReplyDisplayed(replyReplyEntry) discussionDetailsPage.assertReplyAttachment(replyReplyEntry) discussionDetailsPage.previewAndCheckReplyAttachment(replyReplyEntry, @@ -582,7 +583,7 @@ class DiscussionsInteractionTest : StudentTest() { // Tests a discussion with a linked assignment. @Test - @TestMetaData(Priority.P0, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.DISCUSSIONS, TestCategory.INTERACTION, false) fun testDiscussion_linkedAssignment() { val data = MockCanvas.init(teacherCount = 1, studentCount = 1, courseCount = 1, favoriteCourseCount = 1) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ElementaryDashboardInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ElementaryDashboardInteractionTest.kt index b7af73d8bb..8ea359fcf4 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ElementaryDashboardInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ElementaryDashboardInteractionTest.kt @@ -18,8 +18,6 @@ package com.instructure.student.ui.interaction import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.init -import com.instructure.canvasapi2.utils.RemoteConfigParam -import com.instructure.canvasapi2.utils.RemoteConfigPrefs import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority import com.instructure.panda_annotations.TestCategory @@ -36,7 +34,7 @@ class ElementaryDashboardInteractionTest : StudentTest() { override fun displaysPageObjects() = Unit @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testNavigateToElementaryDashboard() { // User should be able to tap and navigate to dashboard page goToElementaryDashboard(courseCount = 1, favoriteCourseCount = 1) @@ -48,7 +46,7 @@ class ElementaryDashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testTabsNavigation() { goToElementaryDashboard(courseCount = 1, favoriteCourseCount = 1) elementaryDashboardPage.assertElementaryTabVisibleAndSelected(ElementaryDashboardPage.ElementaryTabType.HOMEROOM) @@ -72,7 +70,7 @@ class ElementaryDashboardInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOnlyElementarySpecificNavigationItemsShownInTheNavigationDrawer() { goToElementaryDashboard(courseCount = 1, favoriteCourseCount = 1) elementaryDashboardPage.openDrawer() diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/GradesInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/GradesInteractionTest.kt index 4b206c3e50..c3ab301674 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/GradesInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/GradesInteractionTest.kt @@ -39,7 +39,7 @@ class GradesInteractionTest : StudentTest() { override fun displaysPageObjects() = Unit @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testShowGrades() { val data = createMockData(courseCount = 3) goToGradesTab(data) @@ -52,7 +52,7 @@ class GradesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testRefresh() { val data = createMockData(courseCount = 1) goToGradesTab(data) @@ -72,7 +72,7 @@ class GradesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenCourseGrades() { val data = createMockData(courseCount = 3) goToGradesTab(data) @@ -90,7 +90,7 @@ class GradesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testChangeGradingPeriod() { val data = createMockData(courseCount = 3, withGradingPeriods = true) goToGradesTab(data) @@ -104,7 +104,7 @@ class GradesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.COMMON, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testEmptyView() { val data = createMockData(homeroomCourseCount = 1) goToGradesTab(data) @@ -114,7 +114,7 @@ class GradesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.COMMON, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testShowPercentageOnlyIfNoAlphabeticalGrade() { val data = createMockData(courseCount = 1) goToGradesTab(data) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/GroupLinksInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/GroupLinksInteractionTest.kt index 7288017c9d..c4a9340031 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/GroupLinksInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/GroupLinksInteractionTest.kt @@ -18,15 +18,12 @@ package com.instructure.student.ui.interaction import android.os.Build import androidx.test.espresso.web.webdriver.Locator -import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.addDiscussionTopicToCourse -import com.instructure.canvas.espresso.mockCanvas.addFileToCourse import com.instructure.canvas.espresso.mockCanvas.addFileToFolder import com.instructure.canvas.espresso.mockCanvas.addFolderToCourse import com.instructure.canvas.espresso.mockCanvas.addGroupToCourse import com.instructure.canvas.espresso.mockCanvas.addPageToCourse -import com.instructure.canvas.espresso.mockCanvas.addQuizToCourse import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.models.DiscussionTopicHeader @@ -35,6 +32,7 @@ import com.instructure.canvasapi2.models.Page import com.instructure.canvasapi2.models.Tab import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority +import com.instructure.panda_annotations.SecondaryFeatureCategory import com.instructure.panda_annotations.TestCategory import com.instructure.panda_annotations.TestMetaData import com.instructure.student.ui.pages.WebViewTextCheck @@ -59,7 +57,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to group opens group browser - eg: "/groups/:id" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false) fun testGroupLink_base() { setUpGroupAndSignIn() dashboardPage.selectGroup(group) @@ -68,7 +66,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to groups opens dashboard - eg: "/groups" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.DASHBOARD) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_DASHBOARD) fun testGroupLink_dashboard() { setUpGroupAndSignIn() dashboardPage.assertDisplaysGroup(group, course) @@ -76,7 +74,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to file preview opens file - eg: "/groups/:id/files/folder/:id?preview=:id" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.FILES) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_FILES) fun testGroupLink_filePreview() { // MBL-13499: This will cause an http request to our mock web server, and http requests from webviews are illegal @@ -97,7 +95,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to group announcement opens announcement - eg: "/groups/:id/discussion_topics/:id" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.ANNOUNCEMENTS) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_ANNOUNCEMENTS) fun testGroupLink_announcement() { setUpGroupAndSignIn() dashboardPage.selectGroup(group) @@ -109,7 +107,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to group announcements list opens announcements - eg: "/groups/:id/announcements" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.ANNOUNCEMENTS) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_ANNOUNCEMENTS) fun testGroupLink_announcementList() { setUpGroupAndSignIn() dashboardPage.selectGroup(group) @@ -119,7 +117,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to group discussion opens discussion - eg: "/groups/:id/discussion_topics/:id" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.DISCUSSIONS) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_DISCUSSIONS) fun testGroupLink_discussion() { setUpGroupAndSignIn() dashboardPage.selectGroup(group) @@ -130,7 +128,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to group discussion list opens list - eg: "/groups/:id/discussion_topics" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.DISCUSSIONS) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_DISCUSSIONS) fun testGroupLink_discussionList() { setUpGroupAndSignIn() dashboardPage.selectGroup(group) @@ -140,7 +138,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to group files list opens group files list - eg: "/groups/:id/files" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.FILES) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_FILES) fun testGroupLink_files() { setUpGroupAndSignIn() dashboardPage.selectGroup(group) @@ -150,7 +148,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to group files folder opens folder - eg: "/groups/:id/files/folder/:id/" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.FILES) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_FILES) fun testGroupLink_fileFolder() { setUpGroupAndSignIn() dashboardPage.selectGroup(group) @@ -162,7 +160,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to group page list opens pages - eg: "/groups/:id/pages" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.PAGES) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_PAGES) fun testGroupLink_pagesList() { setUpGroupAndSignIn() dashboardPage.selectGroup(group) @@ -172,7 +170,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to group page opens page - eg: "/groups/:id/pages/:id" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.PAGES) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_PAGES) fun testGroupLink_Page() { setUpGroupAndSignIn() dashboardPage.selectGroup(group) @@ -185,7 +183,7 @@ class GroupLinksInteractionTest : StudentTest() { // Link to group people list opens list - eg: "/groups/:id/users" @Test - @TestMetaData(Priority.P0, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, FeatureCategory.PEOPLE) + @TestMetaData(Priority.MANDATORY, FeatureCategory.GROUPS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.GROUPS_PEOPLE) fun testGroupLink_people() { setUpGroupAndSignIn() dashboardPage.selectGroup(group) 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 7247ea7dbe..9b8350907f 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 @@ -16,12 +16,9 @@ */ package com.instructure.student.ui.interaction -import com.instructure.canvas.espresso.StubLandscape import com.instructure.canvas.espresso.mockCanvas.* import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.Enrollment -import com.instructure.canvasapi2.utils.RemoteConfigParam -import com.instructure.canvasapi2.utils.RemoteConfigPrefs import com.instructure.espresso.page.getStringFromResource import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority @@ -40,7 +37,7 @@ class HomeroomInteractionTest : StudentTest() { override fun displaysPageObjects() = Unit @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testAnnouncementsAndCoursesShowUpOnHomeroom() { val data = createMockDataWithHomeroomCourse(courseCount = 3) val homeroomCourse = data.courses.values.first { it.homeroomCourse } @@ -65,7 +62,7 @@ class HomeroomInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOnlyCoursesShowUpOnHomeroomIfNoHomeroomAnnouncement() { val data = createMockDataWithHomeroomCourse(courseCount = 3) @@ -86,7 +83,7 @@ class HomeroomInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOnlyAnnouncementShowsUpOnHomeroomIfNoCourses() { val data = createMockDataWithHomeroomCourse() val homeroomCourse = data.courses.values.first { it.homeroomCourse } @@ -105,7 +102,7 @@ class HomeroomInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenCourse() { val data = createMockDataWithHomeroomCourse(courseCount = 3) val homeroomCourse = data.courses.values.first { it.homeroomCourse } @@ -126,7 +123,7 @@ class HomeroomInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testRefreshAfterEnrolledToCourses() { val data = createMockDataWithHomeroomCourse() @@ -159,7 +156,7 @@ class HomeroomInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenHomeroomCourseAnnouncements() { val data = createMockDataWithHomeroomCourse(courseCount = 3, homeroomCourseCount = 2) val homeroomCourse = data.courses.values.first { it.homeroomCourse } @@ -183,7 +180,7 @@ class HomeroomInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenCourseAnnouncements() { val data = createMockDataWithHomeroomCourse(courseCount = 1) @@ -202,7 +199,7 @@ class HomeroomInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testShowCourseCardWithAnnouncement() { val data = createMockDataWithHomeroomCourse(courseCount = 3) val homeroomCourse = data.courses.values.first { it.homeroomCourse } @@ -223,7 +220,7 @@ class HomeroomInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testDueTodayAndMissingAssignments() { val data = createMockDataWithHomeroomCourse(courseCount = 1) val homeroomCourse = data.courses.values.first { it.homeroomCourse } @@ -248,7 +245,7 @@ class HomeroomInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenAssignments() { val data = createMockDataWithHomeroomCourse(courseCount = 1) val homeroomCourse = data.courses.values.first { it.homeroomCourse } @@ -271,7 +268,7 @@ class HomeroomInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.COMMON, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testEmptyState() { val data = createMockDataWithHomeroomCourse() diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ImportantDatesInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ImportantDatesInteractionTest.kt index 8a61dc9068..9c9d186423 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ImportantDatesInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ImportantDatesInteractionTest.kt @@ -19,7 +19,6 @@ package com.instructure.student.ui.interaction import com.instructure.canvas.espresso.StubTablet import com.instructure.canvas.espresso.mockCanvas.* import com.instructure.canvasapi2.models.Assignment -import com.instructure.canvasapi2.utils.toDate import com.instructure.dataseeding.util.days import com.instructure.dataseeding.util.fromNow import com.instructure.dataseeding.util.iso8601 @@ -41,7 +40,7 @@ class ImportantDatesInteractionTest : StudentTest() { @Test @StubTablet(description = "The UI is different on tablet, so we only check the phone version") - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testShowCalendarEvents() { val data = createMockData(courseCount = 1) val course = data.courses.values.toList()[0] @@ -56,7 +55,7 @@ class ImportantDatesInteractionTest : StudentTest() { @Test @StubTablet(description = "The UI is different on tablet, so we only check the phone version") - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testShowAssignment() { val data = createMockData(courseCount = 1) val course = data.courses.values.toList()[0] @@ -72,7 +71,7 @@ class ImportantDatesInteractionTest : StudentTest() { @Test @StubTablet(description = "The UI is different on tablet, so we only check the phone version") - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testEmptyView() { val data = createMockData(courseCount = 1) @@ -83,7 +82,7 @@ class ImportantDatesInteractionTest : StudentTest() { @Test @StubTablet(description = "The UI is different on tablet, so we only check the phone version") - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testPullToRefresh() { val data = createMockData(courseCount = 1) val course = data.courses.values.toList()[0] @@ -104,7 +103,7 @@ class ImportantDatesInteractionTest : StudentTest() { @Test @StubTablet(description = "The UI is different on tablet, so we only check the phone version") - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenCalendarEvent() { val data = createMockData(courseCount = 1) val course = data.courses.values.toList()[0] @@ -124,7 +123,7 @@ class ImportantDatesInteractionTest : StudentTest() { @Test @StubTablet(description = "The UI is different on tablet, so we only check the phone version") - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenAssignment() { val data = createMockData(courseCount = 1) val course = data.courses.values.toList()[0] @@ -144,7 +143,7 @@ class ImportantDatesInteractionTest : StudentTest() { @Test @StubTablet(description = "The UI is different on tablet, so we only check the phone version") - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testShowMultipleCalendarEventsOnSameDay() { val data = createMockData(courseCount = 1) val course = data.courses.values.toList()[0] @@ -168,7 +167,7 @@ class ImportantDatesInteractionTest : StudentTest() { @Test @StubTablet(description = "The UI is different on tablet, so we only check the phone version") - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testMultipleCalendarEventsOnDifferentDays() { val data = createMockData(courseCount = 1) val course = data.courses.values.toList()[0] diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/InboxInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/InboxInteractionTest.kt index 83c53f822b..b4c7a157f4 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/InboxInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/InboxInteractionTest.kt @@ -34,7 +34,7 @@ class InboxInteractionTest : StudentTest() { override fun displaysPageObjects() = Unit // Not used for interaction tests @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_createAndSendMessageToIndividual() { // Should be able to create and send a message to an individual recipient val data = goToInbox() @@ -46,13 +46,13 @@ class InboxInteractionTest : StudentTest() { newMessagePage.setRecipient(data.teachers.first(), userType = "Teachers") newMessagePage.setSubject(subject) newMessagePage.setMessage("Hodor, Hodor? Hodor!") - newMessagePage.hitSend() + newMessagePage.clickSend() inboxPage.selectInboxScope(InboxApi.Scope.SENT) inboxPage.assertConversationDisplayed(subject) } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_createAndSendMessageToMultiple() { // Should be able to create and send a message to multiple recipients val data = goToInbox(teacherCount = 3) @@ -64,13 +64,13 @@ class InboxInteractionTest : StudentTest() { newMessagePage.setRecipients(data.teachers, userType = "Teachers") newMessagePage.setSubject(subject) newMessagePage.setMessage("Hodor, Hodor? Hodor!") - newMessagePage.hitSend() + newMessagePage.clickSend() inboxPage.selectInboxScope(InboxApi.Scope.SENT) inboxPage.assertConversationDisplayed(subject) } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_createAndSendMessageToAllUsers() { // Should be able to create and send a message to all users in a course // Note: There isn't a "single" way to send a message to all users, so I'm just going to select all the @@ -84,13 +84,13 @@ class InboxInteractionTest : StudentTest() { newMessagePage.selectAllRecipients(listOf("Teachers", "Students")) newMessagePage.setSubject(subject) newMessagePage.setMessage("Hodor, Hodor? Hodor!") - newMessagePage.hitSend() + newMessagePage.clickSend() inboxPage.selectInboxScope(InboxApi.Scope.SENT) inboxPage.assertConversationDisplayed(subject) } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_createAndSendMessageToIndividualWithAttachment() { // Should be able to create and send a message, with an attachment, to an individual recipient val data = goToInbox() @@ -103,7 +103,7 @@ class InboxInteractionTest : StudentTest() { newMessagePage.setRecipient(teacher1, userType = "Teachers") newMessagePage.setSubject(subject) newMessagePage.setMessage(message) - newMessagePage.hitSend() + newMessagePage.clickSend() // Now let's append the attachment after-the-fact, since it is very hard // to manually attach anything via Espresso, since it would require manipulating // system UIs. @@ -120,7 +120,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_createAndSendMessageToMultipleWithAttachment() { // Should be able to create and send a message, with an attachment, to multiple recipients val data = goToInbox() @@ -132,7 +132,7 @@ class InboxInteractionTest : StudentTest() { newMessagePage.setRecipients(data.teachers, userType = "Teachers") newMessagePage.setSubject(subject) newMessagePage.setMessage("Hodor, Hodor? Hodor!") - newMessagePage.hitSend() + newMessagePage.clickSend() // Now let's append the attachment after-the-fact, since it is very hard // to manually attach anything via Espresso, since it would require manipulating // system UIs. @@ -149,7 +149,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_createAndSendMessageToAllUsersWithAttachment() { // Should be able to create and send a message, with an attachment, to all users in a course val data = goToInbox() @@ -161,7 +161,7 @@ class InboxInteractionTest : StudentTest() { newMessagePage.selectAllRecipients(listOf("Teachers", "Students")) newMessagePage.setSubject(subject) newMessagePage.setMessage("Hodor, Hodor? Hodor!") - newMessagePage.hitSend() + newMessagePage.clickSend() // Now let's append the attachment after-the-fact, since it is very hard // to manually attach anything via Espresso, since it would require manipulating // system UIs. @@ -178,7 +178,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_replyToMessage() { // Should be able to reply to a message val data = goToInbox() @@ -191,7 +191,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_replyToMessageWithAttachment() { // Should be able to reply (with attachment) to a message val data = goToInbox() @@ -212,7 +212,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_filterMessagesByTypeAll() { // Should be able to filter messages by All val data = goToInbox() @@ -223,7 +223,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_filterMessagesByTypeUnread() { // Should be able to filter messages by Unread val data = goToInbox() @@ -237,7 +237,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_filterMessagesByTypeStarred() { // Should be able to filter messages by Starred val data = goToInbox() @@ -251,7 +251,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_filterMessagesByTypeSend() { // Should be able to filter messages by Send val data = goToInbox() @@ -265,7 +265,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_filterMessagesByTypeArchived() { // Should be able to filter messages by Archived val data = goToInbox() @@ -279,7 +279,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_filterMessagesByContext() { // Should be able to filter messages by course or group val data = goToInbox(courseCount = 2) @@ -291,7 +291,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_canComposeAndSendToRoleGroupsIfPermissionEnabled() { // Can compose and send messages to one or more role groups if "Send messages to the entire class is enabled" val data = goToInbox(teacherCount = 3) @@ -303,13 +303,13 @@ class InboxInteractionTest : StudentTest() { newMessagePage.setRecipientGroup(userType = "Teachers") newMessagePage.setSubject(subject) newMessagePage.setMessage("Hodor, Hodor? Hodor!") - newMessagePage.hitSend() + newMessagePage.clickSend() inboxPage.selectInboxScope(InboxApi.Scope.SENT) inboxPage.assertConversationDisplayed(subject) } @Test - @TestMetaData(Priority.P1, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_canNotComposeAndSendToRoleGroupsIfPermissionDisabled() { // Can NOT compose and send messages to one or more role groups if "Send messages to the entire class is disabled" val data = goToInbox(sendMessagesAll = false) @@ -320,7 +320,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_canComposeAndSendToIndividualCourseMembersIfPermissionEnabled() { // Can compose and send messages to individual course members if "Send messages to individual course members" is enabled // This test is identical to testInbox_createAndSendMessageToIndividual, not sure if its worth having both @@ -333,13 +333,13 @@ class InboxInteractionTest : StudentTest() { newMessagePage.setRecipient(teacher1, userType = "Teachers") newMessagePage.setSubject(subject) newMessagePage.setMessage("Hodor, Hodor? Hodor!") - newMessagePage.hitSend() + newMessagePage.clickSend() inboxPage.selectInboxScope(InboxApi.Scope.SENT) inboxPage.assertConversationDisplayed(subject) } @Test - @TestMetaData(Priority.P1, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_canNotComposeAndSendToIndividualCourseMembersIfPermissionDisabled() { // Can NOT compose and send messages to individual course members if "Send messages to individual course members" is disabled // This test is controlled by the api, so while we are utilizing a mocked CanvasContextPermission value, the only @@ -352,7 +352,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_replyAll() { val data = goToInbox(studentCount = 3, teacherCount = 1) val conversationSubject = "Reply All Message Subject" @@ -375,7 +375,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_toggleStarred() { val data = goToInbox(studentCount = 3, teacherCount = 1) val conversationSubject = "Toggle Starred Message Subject" @@ -398,7 +398,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_markUnread() { val data = goToInbox(studentCount = 3, teacherCount = 1) val conversationSubject = "Mark Unread Message Subject" @@ -422,7 +422,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_archive() { val data = goToInbox(studentCount = 3, teacherCount = 1) val conversationSubject = "Archive Message Subject" @@ -443,7 +443,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_deleteConversation() { val data = goToInbox(studentCount = 3, teacherCount = 1) val conversationSubject = "Delete Conversation Message Subject" @@ -463,7 +463,7 @@ class InboxInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.INBOX, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.INBOX, TestCategory.INTERACTION) fun testInbox_deleteMessage() { val data = goToInbox(studentCount = 3, teacherCount = 1) val conversationSubject = "Delete Message Message Subject" diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/LoginInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/LoginInteractionTest.kt index 2f6d9670c8..f70b605a3a 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/LoginInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/LoginInteractionTest.kt @@ -30,13 +30,13 @@ class LoginInteractionTest : StudentTest() { @Stub @Test - @TestMetaData(Priority.P0, FeatureCategory.LOGIN, TestCategory.INTERACTION, true) + @TestMetaData(Priority.MANDATORY, FeatureCategory.LOGIN, TestCategory.INTERACTION, true) fun testLogin_canFindSchool() { // Should be able to search for and select a school in the "What's your school's name?" page } @Test - @TestMetaData(Priority.P0, FeatureCategory.LOGIN, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.LOGIN, TestCategory.INTERACTION, false) fun testLogin_qrTutorialPageLoads() { // Should be able to view and assert page objects on the QR tutorial page loginLandingPage.clickQRCodeButton() 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 0785329030..b1a6092ddb 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 @@ -15,7 +15,6 @@ */ package com.instructure.student.ui.interaction -import android.os.SystemClock.sleep import android.text.Html import androidx.test.espresso.Espresso import androidx.test.espresso.web.webdriver.Locator @@ -44,9 +43,9 @@ import com.instructure.dataseeding.util.fromNow import com.instructure.dataseeding.util.iso8601 import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority +import com.instructure.panda_annotations.SecondaryFeatureCategory import com.instructure.panda_annotations.TestCategory import com.instructure.panda_annotations.TestMetaData -import com.instructure.pandautils.utils.ColorKeeper import com.instructure.student.R import com.instructure.student.ui.pages.WebViewTextCheck import com.instructure.student.ui.utils.StudentTest @@ -71,7 +70,7 @@ class ModuleInteractionTest : StudentTest() { // Tapping an Assignment module item should navigate to that item's detail page @Test - @TestMetaData(Priority.P0, FeatureCategory.MODULES, TestCategory.INTERACTION, false, FeatureCategory.ASSIGNMENTS) + @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.INTERACTION, false, SecondaryFeatureCategory.MODULES_ASSIGNMENTS) fun testModules_launchesIntoAssignment() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) @@ -88,7 +87,7 @@ class ModuleInteractionTest : StudentTest() { // Tapping a Discussion module item should navigate to that item's detail page @Test - @TestMetaData(Priority.P0, FeatureCategory.MODULES, TestCategory.INTERACTION, false, FeatureCategory.DISCUSSIONS) + @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.INTERACTION, false, SecondaryFeatureCategory.MODULES_DISCUSSIONS) fun testModules_launchesIntoDiscussion() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) @@ -105,14 +104,14 @@ class ModuleInteractionTest : StudentTest() { // I'm punting on LTI testing for now. But MBL-13517 captures this work. @Stub @Test - @TestMetaData(Priority.P0, FeatureCategory.MODULES, TestCategory.INTERACTION, true) + @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.INTERACTION, true) fun testModules_launchesIntoExternalTool() { // Tapping an ExternalTool module item should navigate to that item's detail page } // Tapping an ExternalURL module item should navigate to that item's detail page @Test - @TestMetaData(Priority.P0, FeatureCategory.MODULES, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.INTERACTION, false) fun testModules_launchesIntoExternalURL() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) @@ -127,7 +126,7 @@ class ModuleInteractionTest : StudentTest() { // Tapping a File module item should navigate to that item's detail page @Test - @TestMetaData(Priority.P0, FeatureCategory.MODULES, TestCategory.INTERACTION, false, FeatureCategory.FILES) + @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.INTERACTION, false, SecondaryFeatureCategory.MODULES_FILES) fun testModules_launchesIntoFile() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) @@ -141,7 +140,7 @@ class ModuleInteractionTest : StudentTest() { // Tapping a Page module item should navigate to that item's detail page @Test - @TestMetaData(Priority.P0, FeatureCategory.MODULES, TestCategory.INTERACTION, false, FeatureCategory.PAGES) + @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.INTERACTION, false, SecondaryFeatureCategory.MODULES_PAGES) fun testModules_launchesIntoPage() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) @@ -167,7 +166,7 @@ class ModuleInteractionTest : StudentTest() { // Tapping a Quiz module item should navigate to that item's detail page @Test - @TestMetaData(Priority.P0, FeatureCategory.MODULES, TestCategory.INTERACTION, false, FeatureCategory.QUIZZES) + @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.INTERACTION, false, SecondaryFeatureCategory.EVENTS_QUIZZES) fun testModules_launchesIntoQuiz() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) @@ -189,7 +188,7 @@ class ModuleInteractionTest : StudentTest() { // Tapping a module should collapse and hide all of that module's items in the module list // Tapping a collapsed module should expand it @Test - @TestMetaData(Priority.P1, FeatureCategory.MODULES, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.MODULES, TestCategory.INTERACTION, false) fun testModules_modulesExpandAndCollapse() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) @@ -214,7 +213,7 @@ class ModuleInteractionTest : StudentTest() { // After entering the detail page for a module item, pressing the back button or back arrow should navigate back // to the module list. This should also work if the detail page is accessed via deep link @Test - @TestMetaData(Priority.P0, FeatureCategory.MODULES, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.INTERACTION, false) fun testModules_navigateBackToModuleListFromModuleItem() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) @@ -234,7 +233,7 @@ class ModuleInteractionTest : StudentTest() { // When viewing the detail page for an item in a module with multiple items, the detail page should have // 'next' and 'previous' navigation buttons. Clicking these should navigate to the next/previous module items. @Test - @TestMetaData(Priority.P0, FeatureCategory.MODULES, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.MODULES, TestCategory.INTERACTION, false) fun testModules_navigateToNextAndPreviousModuleItems() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) @@ -288,7 +287,7 @@ class ModuleInteractionTest : StudentTest() { // Module can't be accessed unless all prerequisites have been fulfilled @Test - @TestMetaData(Priority.P1, FeatureCategory.MODULES, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.MODULES, TestCategory.INTERACTION, false) fun testModules_moduleLockedWithUnfulfilledPrerequisite() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) @@ -329,7 +328,7 @@ class ModuleInteractionTest : StudentTest() { // Module can't be accessed until the availability date has passed @Test - @TestMetaData(Priority.P1, FeatureCategory.MODULES, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.MODULES, TestCategory.INTERACTION, false) fun testModules_moduleLockedUntilAvailabilityDate() { // Basic mock setup val data = getToCourseModules(studentCount = 1, courseCount = 1) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/NavigationDrawerInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/NavigationDrawerInteractionTest.kt index f1e3d4e8f3..020c69234d 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/NavigationDrawerInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/NavigationDrawerInteractionTest.kt @@ -22,8 +22,6 @@ import android.os.Build import android.util.Log import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.IntentMatchers -import androidx.test.espresso.web.webdriver.Locator -import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvasapi2.models.Course @@ -36,7 +34,6 @@ import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority import com.instructure.panda_annotations.TestCategory import com.instructure.panda_annotations.TestMetaData -import com.instructure.student.ui.pages.WebViewTextCheck import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.tokenLogin import com.instructure.student.R @@ -66,7 +63,7 @@ class NavigationDrawerInteractionTest : StudentTest() { // Should be able to change the user from the navigation drawer @Test - @TestMetaData(Priority.P1, FeatureCategory.LOGIN, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.LOGIN, TestCategory.INTERACTION, false) fun testNavDrawer_changeUser() { // This test fails on API-28 in FTL due to a "TOO_MANY_REGISTRATIONS" issue on logout. @@ -110,7 +107,7 @@ class NavigationDrawerInteractionTest : StudentTest() { // Should be able to log out from the navigation drawer @Test - @TestMetaData(Priority.P1, FeatureCategory.LOGIN, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.LOGIN, TestCategory.INTERACTION, false) fun testNavDrawer_logOut() { // This test fails on API-28 in FTL due to a "TOO_MANY_REGISTRATIONS" issue on logout. @@ -121,7 +118,7 @@ class NavigationDrawerInteractionTest : StudentTest() { signInStudent() - dashboardPage.signOut() + dashboardPage.logOut() loginLandingPage.assertPageObjects() } @@ -150,7 +147,7 @@ class NavigationDrawerInteractionTest : StudentTest() { // Should open a dialog and send a question for the selected course // (Checks to see that we can fill out the question and the SEND button exists.) @Test - @TestMetaData(Priority.P0, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) fun testHelp_askQuestion() { signInStudent() @@ -161,7 +158,7 @@ class NavigationDrawerInteractionTest : StudentTest() { // Should open the Canvas guides in a WebView @Test - @TestMetaData(Priority.P0, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) fun testHelp_searchCanvasGuides() { signInStudent() @@ -173,7 +170,7 @@ class NavigationDrawerInteractionTest : StudentTest() { // Should send an error report // (Checks to see that we can fill out an error report and that the SEND button is displayed.) @Test - @TestMetaData(Priority.P0, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) fun testHelp_reportAProblem() { signInStudent() @@ -190,7 +187,7 @@ class NavigationDrawerInteractionTest : StudentTest() { // // So this is a watered-down test that just checks whether an email app chooser gets displayed. @Test - @TestMetaData(Priority.P0, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) fun testHelp_submitFeatureIdea() { signInStudent() @@ -241,7 +238,7 @@ class NavigationDrawerInteractionTest : StudentTest() { // Should send an intent to open the listing for Student App in the Play Store @Test - @TestMetaData(Priority.P0, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) fun testHelp_shareYourLove() { signInStudent() 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 a7a2a6c0c7..7a86641dbc 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,7 +16,6 @@ */ package com.instructure.student.ui.interaction -import android.os.Build import androidx.test.espresso.web.sugar.Web import androidx.test.espresso.web.webdriver.DriverAtoms import androidx.test.espresso.web.webdriver.Locator @@ -28,6 +27,7 @@ import com.instructure.canvasapi2.models.Attachment import com.instructure.canvasapi2.models.Tab import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority +import com.instructure.panda_annotations.SecondaryFeatureCategory import com.instructure.panda_annotations.TestCategory import com.instructure.panda_annotations.TestMetaData import com.instructure.pandautils.loaders.OpenMediaAsyncTaskLoader @@ -51,14 +51,14 @@ class PdfInteractionTest : StudentTest() { private lateinit var attachment: Attachment @Test - @TestMetaData(Priority.P0, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false, FeatureCategory.ANNOTATIONS) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.SUBMISSIONS_ANNOTATIONS) fun testAnnotations_viewPdfSubmission() { goToAssignmentPdfSubmission() submissionDetailsPage.assertFileDisplayed(pdfFileName) } @Test - @TestMetaData(Priority.P1, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false, FeatureCategory.ANNOTATIONS) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.SUBMISSIONS_ANNOTATIONS) fun testAnnotations_viewAndSelectAnnotationsInSubmission() { goToAssignmentPdfSubmission() submissionDetailsPage.clickSubmissionContentAtPosition(.5f, .5f) @@ -66,7 +66,7 @@ class PdfInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false, FeatureCategory.ANNOTATIONS) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.SUBMISSIONS_ANNOTATIONS) fun testAnnotations_selectAndCommentOnAnnotationWithNoExistingComments() { val sentCommentContents = "what up dog" // Configure the comment to be sent in mock Canvas @@ -79,7 +79,7 @@ class PdfInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false, FeatureCategory.ANNOTATIONS) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.SUBMISSIONS_ANNOTATIONS) fun testAnnotations_selectAndCommentOnAnnotationWithExistingComments() { val sentCommentContents = "what up dog" // Configure the comment to be sent in mock Canvas and the existing comment @@ -93,7 +93,7 @@ class PdfInteractionTest : StudentTest() { @Test - @TestMetaData(Priority.P1, FeatureCategory.FILES, TestCategory.INTERACTION, false, FeatureCategory.ANNOTATIONS) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.FILES, TestCategory.INTERACTION, false, SecondaryFeatureCategory.SUBMISSIONS_ANNOTATIONS) fun testAnnotations_openPdfFilesInPSPDFKit() { // Annotation toolbar icon needs to be present val data = getToCourse() @@ -114,7 +114,7 @@ class PdfInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION, false, FeatureCategory.ANNOTATIONS) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION, false, SecondaryFeatureCategory.SUBMISSIONS_ANNOTATIONS) fun testAnnotations_openPdfsInPSPDFKitFromLinksInAssignment() { // Annotation toolbar icon needs to be present, this link is specific to assignment details, as that was the advertised use case val data = MockCanvas.init( diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PeopleInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PeopleInteractionTest.kt index 4d9b01cd38..0119b9fbbc 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PeopleInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PeopleInteractionTest.kt @@ -15,7 +15,6 @@ */ package com.instructure.student.ui.interaction -import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvasapi2.models.User @@ -34,7 +33,7 @@ class PeopleInteractionTest : StudentTest() { override fun displaysPageObjects() = Unit // Not used for interaction tests @Test - @TestMetaData(Priority.P1, FeatureCategory.PEOPLE, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.PEOPLE, TestCategory.INTERACTION, false) fun testClick_openContextCard() { // Should be able to view all enrolled users and tap on one to open their context card goToPeopleList() 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 932e7ebbd7..df94833479 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 @@ -66,34 +66,34 @@ class PickerSubmissionUploadInteractionTest : StudentTest() { @Stub @Test - @TestMetaData(Priority.P2, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) fun testFab_camera() { } @Stub @Test - @TestMetaData(Priority.P2, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) fun testFab_galleryPicker() { } @Stub @Test - @TestMetaData(Priority.P2, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) fun testFab_filePicker() { } @Stub @Test - @TestMetaData(Priority.P2, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) fun testDeleteFile() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false) fun testSubmit() { val data = goToSubmissionPicker() 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 f0bd7b8659..06953de666 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 @@ -31,7 +31,7 @@ class ProfileSettingsInteractionTest : StudentTest() { ) @Test - @TestMetaData(Priority.P1, FeatureCategory.SETTINGS, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.SETTINGS, TestCategory.INTERACTION) fun testProfileSettings_changeUsername() { val data = MockCanvas.init(studentCount = 1, teacherCount = 1, courseCount = 1, favoriteCourseCount = 1) val student = data.students[0] @@ -53,7 +53,7 @@ class ProfileSettingsInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.SETTINGS, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.SETTINGS, TestCategory.INTERACTION) fun testProfileSettings_disabledIfNoPermissions() { val data = MockCanvas.init(studentCount = 1, teacherCount = 1, courseCount = 1, favoriteCourseCount = 1) val student = data.students[0] @@ -69,7 +69,7 @@ class ProfileSettingsInteractionTest : StudentTest() { // Creates a panda avatar, saves it, and verifies that a new panda avatar was saved. @Test - @TestMetaData(Priority.P1, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) fun testProfileSettings_createPandaAvatar() { val data = MockCanvas.init(studentCount = 1, teacherCount = 1, courseCount = 1, favoriteCourseCount = 1) val student = data.students[0] diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PushNotificationInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PushNotificationInteractionTest.kt index 78e9e751b1..008a76b641 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PushNotificationInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/PushNotificationInteractionTest.kt @@ -39,13 +39,13 @@ class PushNotificationInteractionTest : StudentTest() { override fun displaysPageObjects() = Unit // Not used for interaction tests @Test - @TestMetaData(Priority.P0, FeatureCategory.NONE, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.NONE, TestCategory.INTERACTION, false) fun testClick_itWorks() { // Test that push notifications work when you click on them val data = goToNotifications() val assignment = data.assignments.values.first() - notificationPage.verifyNotificationDisplayed(assignment.name!!) + notificationPage.assertNotificationDisplayed(assignment.name!!) notificationPage.clickNotification(assignment.name!!) assignmentDetailsPage.verifyAssignmentDetails(assignment) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ResourcesInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ResourcesInteractionTest.kt index 652e88ed00..d4e42a2fcd 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ResourcesInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/ResourcesInteractionTest.kt @@ -34,7 +34,7 @@ class ResourcesInteractionTest : StudentTest() { override fun displaysPageObjects() = Unit @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testImportantLinksAndActionItemsShowUpInResourcesScreen() { val data = createMockDataWithHomeroomCourse(courseCount = 2) @@ -63,7 +63,7 @@ class ResourcesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOnlyActionItemsShowIfSyllabusIsEmpty() { val data = createMockDataWithHomeroomCourse(courseCount = 2) @@ -91,7 +91,7 @@ class ResourcesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOnlyLtiToolsShowIfNoHomeroomCourse() { val data = createMockDataWithHomeroomCourse(courseCount = 2, homeroomCourseCount = 0) @@ -113,7 +113,7 @@ class ResourcesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testRefresh() { val data = createMockDataWithHomeroomCourse(courseCount = 2, homeroomCourseCount = 0) @@ -148,7 +148,7 @@ class ResourcesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenLtiToolShowsCourseSelector() { val data = createMockDataWithHomeroomCourse(courseCount = 2) @@ -171,7 +171,7 @@ class ResourcesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenComposeMessageScreen() { val data = createMockDataWithHomeroomCourse(courseCount = 2) @@ -197,7 +197,7 @@ class ResourcesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.COMMON, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testImportantLinksForTwoCourses() { val data = createMockDataWithHomeroomCourse(courseCount = 2) @@ -221,7 +221,7 @@ class ResourcesInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.COMMON, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testEmptyState() { val data = createMockDataWithHomeroomCourse(courseCount = 2, homeroomCourseCount = 0) 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 64e46ffb1f..a90b745753 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 @@ -22,8 +22,6 @@ import com.instructure.canvas.espresso.mockCanvas.addAssignment 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.RemoteConfigParam -import com.instructure.canvasapi2.utils.RemoteConfigPrefs import com.instructure.canvasapi2.utils.toApiString import com.instructure.espresso.page.getStringFromResource import com.instructure.panda_annotations.FeatureCategory @@ -58,7 +56,7 @@ class ScheduleInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testShowCorrectHeaderItems() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) @@ -83,7 +81,7 @@ class ScheduleInteractionTest : StudentTest() { @Test @StubLandscape(description = "This is intentionally stubbed on landscape mode because the item view is too narrow, but that's not a bug, it's intentional.") - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testShowScheduledAssignments() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) @@ -102,7 +100,7 @@ class ScheduleInteractionTest : StudentTest() { @Test @StubLandscape(description = "This is intentionally stubbed on landscape mode because the item view is too narrow, but that's not a bug, it's intentional.") - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testShowMissingAssignments() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) @@ -118,7 +116,7 @@ class ScheduleInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P0, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.MANDATORY, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testShowToDoEvents() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) @@ -134,7 +132,7 @@ class ScheduleInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testRefresh() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) @@ -163,7 +161,7 @@ class ScheduleInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testGoBack2Weeks() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) @@ -186,7 +184,7 @@ class ScheduleInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testGoForward2Weeks() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) @@ -209,7 +207,7 @@ class ScheduleInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenAssignment() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) @@ -229,7 +227,7 @@ class ScheduleInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testOpenCourse() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) @@ -248,7 +246,7 @@ class ScheduleInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.COMMON, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testMarkAsDone() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) @@ -265,7 +263,7 @@ class ScheduleInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) + @TestMetaData(Priority.COMMON, FeatureCategory.K5_DASHBOARD, TestCategory.INTERACTION) fun testTodayButton() { setDate(2021, Calendar.AUGUST, 11) val data = createMockData(courseCount = 1) 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 db0e01d8ec..da3ac3fb7b 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 @@ -20,7 +20,6 @@ import android.app.Instrumentation import android.content.Intent import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.IntentMatchers -import com.instructure.canvas.espresso.Stub import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.init import com.instructure.canvasapi2.models.Course @@ -54,7 +53,7 @@ class SettingsInteractionTest : StudentTest() { // Should launch an intent to go to our canvas-android github page @Test - @TestMetaData(Priority.P0, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) fun testLegal_showCanvasOnGithub() { setUpAndSignIn() @@ -75,7 +74,7 @@ class SettingsInteractionTest : StudentTest() { // Should display terms of use in a WebView @Test - @TestMetaData(Priority.P0, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) fun testLegal_showTermsOfUse() { setUpAndSignIn() @@ -87,7 +86,7 @@ class SettingsInteractionTest : StudentTest() { // Should display the privacy policy in a WebView @Test - @TestMetaData(Priority.P0, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) fun testLegal_showPrivacyPolicy() { setUpAndSignIn() @@ -102,7 +101,7 @@ class SettingsInteractionTest : StudentTest() { // Should open a page and have a pairing code that can be refreshed // (Checks to see that we can refresh and get a new code) @Test - @TestMetaData(Priority.P0, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SETTINGS, TestCategory.INTERACTION, false) fun testPairObserver_refreshCode() { setUpAndSignIn() 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 157388af16..7cf275eda2 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,10 +17,8 @@ package com.instructure.student.ui.interaction import android.os.SystemClock.sleep -import androidx.test.espresso.Espresso import androidx.test.espresso.web.webdriver.Locator import com.instructure.canvas.espresso.Stub -import com.instructure.canvas.espresso.mockCanvas.AssignmentGroupType import com.instructure.canvas.espresso.mockCanvas.MockCanvas import com.instructure.canvas.espresso.mockCanvas.addAssignment import com.instructure.canvas.espresso.mockCanvas.addFileToCourse @@ -31,13 +29,9 @@ import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.Attachment import com.instructure.canvasapi2.models.Author import com.instructure.canvasapi2.models.Course -import com.instructure.canvasapi2.models.RemoteFile import com.instructure.canvasapi2.models.RubricCriterion import com.instructure.canvasapi2.models.RubricCriterionRating import com.instructure.canvasapi2.models.SubmissionComment -import com.instructure.dataseeding.api.AssignmentsApi -import com.instructure.dataseeding.api.FileUploadsApi -import com.instructure.dataseeding.model.SubmissionType import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority import com.instructure.panda_annotations.TestCategory @@ -58,7 +52,7 @@ class SubmissionDetailsInteractionTest : StudentTest() { // Clicking the "Description" button on a rubric criterion item should show a new page with the full description // Also checks to see that the rubric criterion is displayed correctly, and responds to clicks correctly @Test - @TestMetaData(Priority.P0, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false) fun testRubrics_showCriterionDescription() { val data = getToCourse() @@ -103,7 +97,7 @@ class SubmissionDetailsInteractionTest : StudentTest() { // Should be able to add a comment on a submission @Test - @TestMetaData(Priority.P0, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false) fun testComments_addCommentToSubmission() { val data = getToCourse() @@ -118,7 +112,7 @@ class SubmissionDetailsInteractionTest : StudentTest() { assignmentDetailsPage.clickSubmit() urlSubmissionUploadPage.submitText("https://google.com") sleep(1000) // Allow some time for the submission to propagate - assignmentDetailsPage.verifyAssignmentSubmitted() + assignmentDetailsPage.assertAssignmentSubmitted() assignmentDetailsPage.goToSubmissionDetails() submissionDetailsPage.openComments() submissionDetailsPage.addAndSendComment("Hey!") @@ -127,7 +121,7 @@ class SubmissionDetailsInteractionTest : StudentTest() { // Student can preview an assignment comment attachment @Test - @TestMetaData(Priority.P0, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, false) fun testComments_previewAttachment() { val data = getToCourse() @@ -192,14 +186,14 @@ class SubmissionDetailsInteractionTest : StudentTest() { @Stub @Test - @TestMetaData(Priority.P2, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) fun testComments_videoCommentPlayback() { // After recording a video comment, user should be able to view a replay } @Stub @Test - @TestMetaData(Priority.P2, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, true) fun testComments_audioCommentPlayback() { // After recording an audio comment, user should be able to hear an audio playback } diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SyllabusInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SyllabusInteractionTest.kt index ae2f297c9f..63a4f61c12 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SyllabusInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/SyllabusInteractionTest.kt @@ -43,7 +43,7 @@ class SyllabusInteractionTest : StudentTest() { // Tests that we can display a calendar event from the syllabus/summary, // and does some verification of the calendar event. @Test - @TestMetaData(Priority.P0, FeatureCategory.SYLLABUS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.SYLLABUS, TestCategory.INTERACTION, false) fun testSyllabus_calendarEvent() { val data = goToSyllabus(eventCount = 1, assignmentCount = 0) 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 41be02348d..ffe511b42d 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 @@ -45,7 +45,7 @@ class TodoInteractionTest : StudentTest() { // Todo items should be clickable @Test - @TestMetaData(Priority.P0, FeatureCategory.TODOS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.MANDATORY, FeatureCategory.TODOS, TestCategory.INTERACTION, false) fun testClick_todoItemClickable() { val data = goToTodos() @@ -63,7 +63,7 @@ class TodoInteractionTest : StudentTest() { } @Test - @TestMetaData(Priority.P1, FeatureCategory.TODOS, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.TODOS, TestCategory.INTERACTION, false) fun testFilters() { val data = goToTodos(courseCount = 2, favoriteCourseCount = 1) val favoriteCourse = data.courses.values.first {course -> course.isFavorite} diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/UserFilesInteractionTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/UserFilesInteractionTest.kt index 3285c03861..17cbc628d6 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/UserFilesInteractionTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/interaction/UserFilesInteractionTest.kt @@ -86,7 +86,7 @@ class UserFilesInteractionTest : StudentTest() { // Should be able to upload a file from the user's device // Mocks the result from the expected intent, then uploads it. @Test - @TestMetaData(Priority.P1, FeatureCategory.FILES, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.FILES, TestCategory.INTERACTION, false) fun testUpload_deviceFile() { goToFilePicker() @@ -116,7 +116,7 @@ class UserFilesInteractionTest : StudentTest() { // Should be able to upload a file from the camera // Mocks the result from the expected intent, then uploads it. @Test - @TestMetaData(Priority.P1, FeatureCategory.FILES, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.FILES, TestCategory.INTERACTION, false) fun testUpload_fileFromCamera() { goToFilePicker() @@ -157,7 +157,7 @@ class UserFilesInteractionTest : StudentTest() { // Should be able to upload a file from the user's photo gallery // Mocks the result from the expected intent, then uploads it. @Test - @TestMetaData(Priority.P1, FeatureCategory.FILES, TestCategory.INTERACTION, false) + @TestMetaData(Priority.IMPORTANT, FeatureCategory.FILES, TestCategory.INTERACTION, false) fun testUpload_gallery() { goToFilePicker() @@ -187,28 +187,28 @@ class UserFilesInteractionTest : StudentTest() { @Stub @Test - @TestMetaData(Priority.P2, FeatureCategory.FILES, TestCategory.INTERACTION, true) + @TestMetaData(Priority.COMMON, FeatureCategory.FILES, TestCategory.INTERACTION, true) fun testView_previewAudio() { // Should be able to preview an audio file } @Stub @Test - @TestMetaData(Priority.P2, FeatureCategory.FILES, TestCategory.INTERACTION, true) + @TestMetaData(Priority.COMMON, FeatureCategory.FILES, TestCategory.INTERACTION, true) fun testView_previewVideo() { // Should be able to preview a video file } @Stub @Test - @TestMetaData(Priority.P2, FeatureCategory.FILES, TestCategory.INTERACTION, true) + @TestMetaData(Priority.COMMON, FeatureCategory.FILES, TestCategory.INTERACTION, true) fun testView_createDirectory() { // Should be able to create a directory and upload a file to that directory } @Stub @Test - @TestMetaData(Priority.P2, FeatureCategory.FILES, TestCategory.INTERACTION, true) + @TestMetaData(Priority.COMMON, FeatureCategory.FILES, TestCategory.INTERACTION, true) fun testView_previewImage() { // Should be able to preview an image file } 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 new file mode 100644 index 0000000000..af6d2f458b --- /dev/null +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AboutPage.kt @@ -0,0 +1,50 @@ +/* + * 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.Espresso.onView +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withParent +import com.instructure.canvas.espresso.containsTextCaseInsensitive +import com.instructure.espresso.OnViewWithId +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.plus +import com.instructure.espresso.page.withText +import com.instructure.student.R +import org.hamcrest.Matchers.allOf + +class AboutPage : BasePage(R.id.aboutPage) { + + private val domainLabel by OnViewWithText(R.string.domain) + private val loginIdLabel by OnViewWithText(R.string.loginId) + private val emailLabel by OnViewWithText(R.string.email) + + fun domainIs(domain: String) { + onView(withText(domain)).assertDisplayed() + } + + fun loginIdIs(loginId: String) { + onView(withId(R.id.loginId) + withText(loginId)).assertDisplayed() + } + + fun emailIs(email: String) { + onView(withId(R.id.email) + withText(email)).assertDisplayed() + } +} \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AssignmentDetailsPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AssignmentDetailsPage.kt index 7db66aa049..d25afa194e 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AssignmentDetailsPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/AssignmentDetailsPage.kt @@ -60,7 +60,7 @@ open class AssignmentDetailsPage : BasePage(R.id.assignmentDetailsPage) { onView(withId(R.id.assignmentName)).assertHasText(assignmentName) } - fun verifyAssignmentSubmitted() { + fun assertAssignmentSubmitted() { onView(withText(R.string.submissionStatusSuccessTitle)).scrollTo().assertDisplayed() onView(allOf(withId(R.id.submissionStatus), withText(R.string.submitted))).scrollTo().assertDisplayed() } @@ -109,7 +109,7 @@ open class AssignmentDetailsPage : BasePage(R.id.assignmentDetailsPage) { waitForMatcherWithSleeps(withId(R.id.descriptionWebView), waitMs = 30000, sleepMs = 1000).scrollTo() } - fun bookmark(bookmarkName: String) { + fun addBookmark(bookmarkName: String) { Espresso.onView( allOf( ViewMatchers.withContentDescription(stringContainsTextCaseInsensitive("More options")), 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 d8fd12ecd8..54c6b73b47 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 @@ -29,6 +29,8 @@ 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.plus +import com.instructure.espresso.page.withAncestor import com.instructure.espresso.typeText import com.instructure.student.R import org.hamcrest.Matchers.allOf @@ -41,6 +43,10 @@ class BookmarkPage : BasePage() { onView(matcher).assertDisplayed() } + fun assertEmptyView() { + onView(withText(R.string.no_bookmarks)).assertDisplayed() + } + fun clickBookmark(bookmarkName: String) { val matcher = allOf(withId(R.id.title), withText(bookmarkName)) scrollRecyclerView(R.id.listView, matcher) @@ -50,13 +56,7 @@ class BookmarkPage : BasePage() { fun changeBookmarkName(originalName: String, newName: String) { // Open the overflow menu for the bookmark - val matcher = allOf( - withId(R.id.overflow), - hasSibling(withText(originalName)) - ) - scrollRecyclerView(R.id.listView, matcher) - onView(matcher).click() - + clickOnMoreMenu(originalName) // Click on "Edit" onView(allOf(withId(R.id.title), withText("Edit"), isDisplayed())).click() @@ -67,4 +67,19 @@ class BookmarkPage : BasePage() { // Save onView(allOf(isAssignableFrom(AppCompatButton::class.java), containsTextCaseInsensitive("DONE"))).click() } + + fun clickOnMoreMenu(bookmarkName: String) { + val matcher = allOf( + withId(R.id.overflow), + hasSibling(withText(bookmarkName)) + ) + scrollRecyclerView(R.id.listView, matcher) + onView(matcher).click() + } + + fun deleteBookmark(bookmarkName: String) { + clickOnMoreMenu(bookmarkName) + onView(allOf(withId(R.id.title), withText("Delete"), isDisplayed())).click() + onView(withText(R.string.ok) + withAncestor(R.id.buttonPanel)).click() + } } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CalendarPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CalendarPage.kt deleted file mode 100644 index 2ceb82f492..0000000000 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CalendarPage.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.instructure.student.ui.pages - -import androidx.test.espresso.action.ViewActions.click -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.withId -import androidx.test.espresso.matcher.ViewMatchers.withText -import com.instructure.canvas.espresso.scrollRecyclerView -import com.instructure.canvas.espresso.withCustomConstraints -import com.instructure.dataseeding.model.AssignmentApiModel -import com.instructure.dataseeding.model.QuizApiModel -import com.instructure.espresso.OnViewWithId -import com.instructure.espresso.click -import com.instructure.espresso.page.BasePage -import com.instructure.espresso.page.onView -import com.instructure.student.R -import org.hamcrest.Matchers -import org.hamcrest.Matchers.allOf - -class CalendarPage: BasePage(R.id.calendarPage) { - - // TODO: Get this working with embedded Flutter - /*private val toolbar by OnViewWithId(R.id.toolbar) - private val listview by OnViewWithId(R.id.listview, autoAssert = false) - - fun selectDesiredCalendarsAndDismiss(vararg courseNames: String) { - for(courseName in courseNames) { - onView(allOf(withText(courseName), isDisplayed(), withId(R.id.courseName))).click() - } - onView(withText(R.string.done)).click() - } - - // Tolerant of assignment being scrolled off the page - fun assertAssignmentDisplayed(assignment: AssignmentApiModel) { - assertTextDisplayedInRecyclerView(assignment.name) - } - - // Tolerant of quiz being scrolled off the page - fun assertQuizDisplayed(quiz: QuizApiModel) { - assertTextDisplayedInRecyclerView(quiz.title) - } - - // On low-res devices, the month text can get scrunched, and may not completely display. - // So we'll only ask that 50% of it be displayed. - fun toggleCalendarVisibility() { - onView(withId(R.id.monthText)).perform(withCustomConstraints(click(), isDisplayingAtLeast(50))) - } - - private fun assertTextDisplayedInRecyclerView(s: String) { - // Common matcher - val matcher = ViewMatchers.withText(Matchers.containsString(s)) - - // Scroll RecyclerView item into view, if necessary - scrollRecyclerView(R.id.calendarRecyclerView, matcher) - - // Now make sure that it is displayed - // Shouldn't be necessary given that the line above passed. Also, this line can - // fail (after the line above passes!) for no apparent reason. - // Espresso.onView(matcher).assertDisplayed() - }*/ - -// fun waitForRender() { -// toolbar.assertDisplayed() -// } - -} 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 e08b6b1a66..669ce60d3c 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 @@ -94,7 +94,7 @@ class CourseBrowserPage : BasePage(R.id.courseBrowserPage) { } fun selectConferences() { - val matcher = withText("Conferences") + val matcher = withText("BigBlueButton") selectSection(matcher) } 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 75b94b4833..551826ff7b 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 @@ -130,7 +130,7 @@ class DashboardPage : BasePage(R.id.dashboardPage) { onViewWithId(R.id.addCoursesButton).assertDisplayed() } - fun signOut() { + fun logOut() { onView(hamburgerButtonMatcher).click() onViewWithId(R.id.navigationDrawerItem_logout).scrollTo().click() onViewWithText(android.R.string.yes).click() 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 6c63b0d547..09bfe982d5 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 @@ -24,6 +24,7 @@ import androidx.test.espresso.action.ViewActions.swipeUp import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.web.assertion.WebViewAssertions import androidx.test.espresso.web.assertion.WebViewAssertions.webMatches import androidx.test.espresso.web.sugar.Web.onWebView import androidx.test.espresso.web.webdriver.DriverAtoms.findElement @@ -142,6 +143,17 @@ class DiscussionDetailsPage : BasePage(R.id.discussionDetailsPage) { .check(webMatches(getText(),containsString(reply.message))) } + fun assertReplyDisplayed(reply: DiscussionEntry) { + onWebView(withId(R.id.discussionRepliesWebView)) + .withElement(findElement(Locator.TAG_NAME, "html")) + .check(webMatches(getText(), containsString(reply.message))) + } + + fun assertIfThereIsAReply() { + onView(withId(R.id.discussionTopicRepliesTitle)).assertDisplayed() + onView(withId(R.id.discussionRepliesWebView)).assertDisplayed() + } + fun assertFavoritingEnabled(reply: DiscussionEntry) { try { onWebView(withId(R.id.discussionRepliesWebView)) 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 9037179366..ec7b425f03 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 @@ -109,7 +109,7 @@ class ModulesPage : BasePage(R.id.modulesPage) { // Assert that a module item is displayed and, optionally, click it private fun assertAndClickModuleItem(moduleName: String, itemTitle: String, clickItem: Boolean = false) { try { - onView(withText(itemTitle)).scrollTo() + scrollRecyclerView(R.id.listView, withText(itemTitle)) if(clickItem) { onView(withText(itemTitle)).click() } 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 7d146add29..5bd887a0cb 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 @@ -67,7 +67,7 @@ class NewMessagePage : BasePage() { fun setRecipient(user: CanvasUserApiModel, isGroupRecipient: Boolean = false) { addContactsButton.click() if(!isGroupRecipient) onView(withText("Students")).click() - onView(withText(user.shortName)).click() + onView(withId(R.id.title) + withText(user.shortName)).click() onView(withText(R.string.done)).click() } @@ -135,7 +135,7 @@ class NewMessagePage : BasePage() { .typeText(messageText) } - fun hitSend() { + fun clickSend() { Espresso.closeSoftKeyboard() sendButton.click() } 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 5d0e11cd06..45fc71cfe3 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 @@ -17,19 +17,37 @@ package com.instructure.student.ui.pages import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.espresso.NoMatchingViewException +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.RecyclerViewItemCountGreaterThanAssertion import com.instructure.espresso.assertDisplayed import com.instructure.espresso.click 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.waitForCheck import com.instructure.student.R +import org.hamcrest.CoreMatchers.allOf +import org.hamcrest.Matchers class NotificationPage : BasePage() { - fun verifyNotificationDisplayed(title: String) { + fun assertNotificationDisplayed(title: String) { val matcher = withText(title) scrollRecyclerView(R.id.listView, matcher) onView(matcher).assertDisplayed() + + } + + fun assertHasGrade(title: String, grade: String) { + val matcher = allOf(withText(title) + hasSibling(withId(R.id.description) + withText("Grade: $grade"))) + scrollRecyclerView(R.id.listView, matcher) + onView(matcher).assertDisplayed() } fun clickNotification(title: String) { @@ -37,4 +55,28 @@ class NotificationPage : BasePage() { scrollRecyclerView(R.id.listView, matcher) onView(matcher).click() } + + fun assertNotificationWithPoll(title: String, times: Int, pollIntervalSeconds: Long) { + var iteration = 0 + while (iteration < times) { + Thread.sleep(pollIntervalSeconds*1000) + try { + val words = title.split(" ") + onView(containsTextCaseInsensitive(words[0] + " " + words[1] + " " + words[2])).assertDisplayed() + } catch(e: NoMatchingViewException) { + iteration++ + refresh() + } + + } + } + + fun assertNotificationCountIsGreaterThan(count: Int) { + val itemMatcher = Matchers.allOf( + withAncestor(R.id.swipeRefreshLayout), + hasSibling(withId(R.id.notificationsFragment)), + withId(R.id.listView) + ) + onView(itemMatcher).waitForCheck(RecyclerViewItemCountGreaterThanAssertion(count)) + } } \ No newline at end of file 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 c93879f8cd..8cb2e65700 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 @@ -19,8 +19,10 @@ package com.instructure.student.ui.pages import android.view.View import androidx.recyclerview.widget.RecyclerView import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.hasChildCount import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.hasSibling import androidx.test.espresso.matcher.ViewMatchers.isDisplayed @@ -30,9 +32,14 @@ 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.assertGone +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.withAncestor +import com.instructure.espresso.page.withId +import com.instructure.espresso.page.withParent import com.instructure.student.R import org.hamcrest.Matcher import org.hamcrest.Matchers.allOf @@ -63,6 +70,10 @@ class PeopleListPage: BasePage(R.id.peopleListPage) { onView(matcher).assertDisplayed() } + fun assertPeopleCount(count: Int) { + onView(withId(R.id.listView) + withAncestor(R.id.peopleListPage)).check(ViewAssertions.matches(hasChildCount(count))) + } + fun assertPersonListed(person: User) { val matcher = allOf(withText(person.name), withId(R.id.title)) @@ -89,4 +100,13 @@ class PeopleListPage: BasePage(R.id.peopleListPage) { .perform(RecyclerViewActions.scrollTo(hasDescendant(matcher))) } + fun clickOnStudentsExpandCollapseButton() { + val matcher = allOf( + withId(R.id.expand_collapse), + ViewMatchers.isDescendantOfA( + allOf(withId(R.id.rootView), + hasDescendant(withText(R.string.students))))) + onView(matcher).click() + } + } \ No newline at end of file diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/AssignmentDetailsRenderTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/AssignmentDetailsRenderTest.kt index f4d46295fe..4b468fe200 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/AssignmentDetailsRenderTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/AssignmentDetailsRenderTest.kt @@ -26,6 +26,7 @@ import com.instructure.canvasapi2.utils.toApiString import com.instructure.espresso.assertGone import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority +import com.instructure.panda_annotations.SecondaryFeatureCategory import com.instructure.panda_annotations.TestCategory import com.instructure.panda_annotations.TestMetaData import com.instructure.pandautils.utils.ThemePrefs @@ -62,7 +63,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysToolbarTitles() { val model = baseModel.copy() loadPageWithModel(model) @@ -71,7 +72,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysTitleDataNotSubmitted() { val assignment = Assignment( name = "Test Assignment", @@ -85,7 +86,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysTitleDataSubmitted() { val submission = Submission(workflowState = "submitted", submittedAt = Date()) val assignment = Assignment( @@ -101,7 +102,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysDueDate() { val expectedDueDate = "January 31, 2050 at 11:59 PM" val calendar = Calendar.getInstance().apply { set(2050, 0, 31, 23, 59, 0) } @@ -115,7 +116,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysNoDueDate() { val model = baseModel.copy(assignmentResult = DataResult.Success(Assignment(name = "Test Assignment"))) loadPageWithModel(model) @@ -123,7 +124,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysNoneSubmissionType() { val assignment = Assignment( name = "Test Assignment", @@ -135,7 +136,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysNotGradedSubmissionType() { val assignment = Assignment( name = "Test Assignment", @@ -146,210 +147,13 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { assignmentDetailsRenderPage.assertDisplaysSubmissionTypes("Not Graded") } - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.QUIZZES) - fun displaysQuizDetails() { - val quizId = 123L - val timeLimit = 10 - val allowedAttempts = 1 - val questionCount = 1 - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("online_quiz"), - quizId = quizId - ) - val quiz = Quiz( - id = quizId, - timeLimit = timeLimit, - allowedAttempts = allowedAttempts, - questionCount = questionCount - ) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) - loadPageWithModel(model) - assignmentDetailsRenderPage.assertQuizDescription(timeLimit.toString(), allowedAttempts.toString(), questionCount.toString()) - } - - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.QUIZZES) - fun displaysQuizDetailsNoTimeLimit() { - val quizId = 123L - val timeLimit = 0 - val allowedAttempts = 1 - val questionCount = 1 - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("online_quiz"), - quizId = quizId - ) - val quiz = Quiz( - id = quizId, - timeLimit = timeLimit, - allowedAttempts = allowedAttempts, - questionCount = questionCount - ) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) - loadPageWithModel(model) - assignmentDetailsRenderPage.assertQuizDescription(R.string.quizNoTimeLimit, allowedAttempts.toString(), questionCount.toString()) - } - - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.QUIZZES) - fun displaysQuizDetailsUnlimitedAttempts() { - val quizId = 123L - val timeLimit = 10 - val allowedAttempts = -1 - val questionCount = 1 - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("online_quiz"), - quizId = quizId - ) - val quiz = Quiz( - id = quizId, - timeLimit = timeLimit, - allowedAttempts = allowedAttempts, - questionCount = questionCount - ) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) - loadPageWithModel(model) - assignmentDetailsRenderPage.assertQuizDescription(timeLimit.toString(), R.string.unlimited, questionCount.toString()) - } - - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.QUIZZES) - fun displaysNoSubmissionTypesForQuiz() { - val quizId = 123L - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("online_quiz"), - quizId = quizId - ) - val quiz = Quiz(id = quizId) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) - loadPageWithModel(model) - assignmentDetailsRenderPage.submissionTypes.assertGone() - } - - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.DISCUSSIONS) - fun displaysNoSubmissionTypesForDiscussion() { - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("discussion_topic"), - discussionTopicHeader = DiscussionTopicHeader(id = 123L, author = DiscussionParticipant(displayName = "hodor"), postedDate = Date()) - ) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) - loadPageWithModel(model) - assignmentDetailsRenderPage.submissionTypes.assertGone() - } - - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.DISCUSSIONS) - fun displaysDiscussionTopicHeader() { - val authorAvatarUrl = "pretty-hodor.com" - val authorName = "hodor" - val authoredDate = "Jul 23 at 9:59 AM" - val attachmentIconVisibility = false - val discussionMessage = "yo yo yo" - val calendar = GregorianCalendar.getInstance() - calendar.set(2019, 6, 23, 9, 59) - val discussionTopicHeader = DiscussionTopicHeader(id = 123L, message = discussionMessage, author = DiscussionParticipant(displayName = authorName, avatarImageUrl = authorAvatarUrl), postedDate = calendar.time) - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("discussion_topic"), - discussionTopicHeader = discussionTopicHeader - ) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) - loadPageWithModel(model) - assignmentDetailsRenderPage.assertDiscussionHeader(authorName, authoredDate, attachmentIconVisibility) - } - - @Test - @TestMetaData( - Priority.P2, - FeatureCategory.ASSIGNMENTS, - TestCategory.RENDER, - secondaryFeature = FeatureCategory.DISCUSSIONS - ) - fun displaysDiscussionTopicHeaderWithAuthorPronouns() { - val authorAvatarUrl = "pretty-hodor.com" - val authorName = "hodor" - val authorPronouns = "Pro/Noun" - val authoredDate = "Jul 23 at 9:59 AM" - val attachmentIconVisibility = false - val discussionMessage = "yo yo yo" - val calendar = GregorianCalendar.getInstance() - calendar.set(2019, 6, 23, 9, 59) - val discussionTopicHeader = DiscussionTopicHeader( - id = 123L, - message = discussionMessage, - author = DiscussionParticipant( - displayName = authorName, - pronouns = authorPronouns, - avatarImageUrl = authorAvatarUrl - ), - postedDate = calendar.time - ) - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("discussion_topic"), - discussionTopicHeader = discussionTopicHeader - ) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) - loadPageWithModel(model) - assignmentDetailsRenderPage.assertDiscussionHeader("hodor (Pro/Noun)", authoredDate, attachmentIconVisibility) - } - - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.DISCUSSIONS) - fun displaysDiscussionTopicHeaderWithAttachments() { - val authorAvatarUrl = "pretty-hodor.com" - val authorName = "hodor" - val authoredDate = "Jul 23 at 9:59 AM" - val attachmentIconVisibility = true - val attachmentId = 12345L - val remoteFiles = mutableListOf(RemoteFile(id = attachmentId)) - val discussionMessage = "yo yo yo" - val calendar = GregorianCalendar.getInstance() - calendar.set(2019, 6, 23, 9, 59) - val discussionTopicHeader = DiscussionTopicHeader(id = 123L, attachments = remoteFiles, message = discussionMessage, author = DiscussionParticipant(displayName = authorName, avatarImageUrl = authorAvatarUrl), postedDate = calendar.time) - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("discussion_topic"), - discussionTopicHeader = discussionTopicHeader - ) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) - loadPageWithModel(model) - assignmentDetailsRenderPage.assertDiscussionHeader(authorName, authoredDate, attachmentIconVisibility) - } - - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.DISCUSSIONS) - fun displaysDiscussionDescription() { - val authorAvatarUrl = "pretty-hodor.com" - val authorName = "hodor" - val attachmentId = 12345L - val remoteFiles = mutableListOf(RemoteFile(id = attachmentId)) - val discussionMessage = "yo yo yo" - val calendar = GregorianCalendar.getInstance() - calendar.set(2019, 6, 23, 9, 59) - val discussionTopicHeader = DiscussionTopicHeader(id = 123L, attachments = remoteFiles, message = discussionMessage, author = DiscussionParticipant(displayName = authorName, avatarImageUrl = authorAvatarUrl), postedDate = calendar.time) - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("discussion_topic"), - discussionTopicHeader = discussionTopicHeader - ) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) - loadPageWithModel(model) - assignmentDetailsRenderPage.assertDisplaysDiscussionDescription(discussionMessage) - } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun neverDisplaysSubmitButtonForObserver() { val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("online_upload") + name = "Test Assignment", + submissionTypesRaw = listOf("online_upload") ) val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), isObserver = true) loadPageWithModel(model) @@ -357,35 +161,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.QUIZZES) - fun displaysViewQuizButton() { - val quizId = 123L - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("online_quiz"), - quizId = quizId - ) - val quiz = Quiz(id = quizId) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) - loadPageWithModel(model) - assignmentDetailsRenderPage.assertSubmitButton(R.string.viewQuiz) - } - - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.DISCUSSIONS) - fun displaysViewDiscussionButton() { - val assignment = Assignment( - name = "Test Assignment", - submissionTypesRaw = listOf("discussion_topic"), - discussionTopicHeader = DiscussionTopicHeader(id = 123L, author = DiscussionParticipant(displayName = "hodor"), postedDate = Date()) - ) - val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) - loadPageWithModel(model) - assignmentDetailsRenderPage.assertSubmitButton(R.string.viewDiscussion) - } - - @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysOnPaperSubmissionType() { val assignment = Assignment( name = "Test Assignment", @@ -397,7 +173,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysExternalToolSubmissionType() { val assignment = Assignment( name = "Test Assignment", @@ -409,7 +185,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysOtherSubmissionTypes() { val assignment = Assignment( name = "Test Assignment", @@ -430,7 +206,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysFileTypes() { val assignment = Assignment( name = "Test Assignment", @@ -443,7 +219,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysDescription() { val descriptionText = "This is a description!" val assignment = Assignment(description = "

$descriptionText

") @@ -453,7 +229,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysNoDescription() { val model = baseModel.copy(assignmentResult = DataResult.Success(Assignment())) loadPageWithModel(model) @@ -461,7 +237,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysGradeCell() { val assignment = Assignment( name = "Test Assignment", @@ -480,7 +256,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysSubmitted() { val assignment = Assignment( name = "Test Assignment", @@ -496,7 +272,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysUploading() { val assignment = Assignment(name = "Test Assignment") val model = baseModel.copy( @@ -509,7 +285,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysFailed() { val assignment = Assignment(name = "Test Assignment") val model = baseModel.copy( @@ -521,7 +297,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun displaysBookmarkMenuItem() { val course = baseModel.course.copy(id = 123) val assignment = Assignment( @@ -539,7 +315,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun setsPointsContentDescription() { val assignment = Assignment( name = "Test Assignment", @@ -552,7 +328,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, false, FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER, false) fun hideSubmissionStatusSubmissionTypeNone() { val allTypes = listOf(Assignment.SubmissionType.NONE) val assignment = Assignment( @@ -568,15 +344,15 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, false, FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER, false) fun hideSubmissionStatusSubmissionTypeOnPaper() { val allTypes = listOf(Assignment.SubmissionType.ON_PAPER) val assignment = Assignment( - id = 123, - name = "Assignment Name", - description = "This is a description", - pointsPossible = 35.0, - submissionTypesRaw = allTypes.map { it.apiString } + id = 123, + name = "Assignment Name", + description = "This is a description", + pointsPossible = 35.0, + submissionTypesRaw = allTypes.map { it.apiString } ) val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) loadPageWithModel(model) @@ -584,16 +360,16 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, false, FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER, false) fun showsSubmissionStatusSubmissionTypeOnPaperWithGrade() { val allTypes = listOf(Assignment.SubmissionType.ON_PAPER) val assignment = Assignment( - id = 123, - name = "Assignment Name", - description = "This is a description", - pointsPossible = 35.0, - submission = Submission(id = 1, grade = "A", score = 35.0, late = false, attempt = 1, missing = false, postedAt = Date()), - submissionTypesRaw = allTypes.map { it.apiString } + id = 123, + name = "Assignment Name", + description = "This is a description", + pointsPossible = 35.0, + submission = Submission(id = 1, grade = "A", score = 35.0, late = false, attempt = 1, missing = false, postedAt = Date()), + submissionTypesRaw = allTypes.map { it.apiString } ) val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) loadPageWithModel(model) @@ -601,24 +377,24 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, false, FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER, false) fun showSubmissionStatusSubmissionTypeOnline() { val allTypes = listOf( - Assignment.SubmissionType.ONLINE_UPLOAD, - Assignment.SubmissionType.ONLINE_TEXT_ENTRY, - Assignment.SubmissionType.ONLINE_URL, - Assignment.SubmissionType.BASIC_LTI_LAUNCH, - Assignment.SubmissionType.EXTERNAL_TOOL, - Assignment.SubmissionType.ATTENDANCE, - Assignment.SubmissionType.MEDIA_RECORDING - ) - val assignment = Assignment( - id = 123, - name = "Assignment Name", - description = "This is a description", - pointsPossible = 35.0, - submission = Submission(id = 1, grade = "A", score = 35.0, late = false, attempt = 1, missing = false, postedAt = Date()), - submissionTypesRaw = allTypes.map { it.apiString } + Assignment.SubmissionType.ONLINE_UPLOAD, + Assignment.SubmissionType.ONLINE_TEXT_ENTRY, + Assignment.SubmissionType.ONLINE_URL, + Assignment.SubmissionType.BASIC_LTI_LAUNCH, + Assignment.SubmissionType.EXTERNAL_TOOL, + Assignment.SubmissionType.ATTENDANCE, + Assignment.SubmissionType.MEDIA_RECORDING + ) + val assignment = Assignment( + id = 123, + name = "Assignment Name", + description = "This is a description", + pointsPossible = 35.0, + submission = Submission(id = 1, grade = "A", score = 35.0, late = false, attempt = 1, missing = false, postedAt = Date()), + submissionTypesRaw = allTypes.map { it.apiString } ) val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) loadPageWithModel(model) @@ -626,24 +402,24 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, false, FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER, false) fun showSubmissionStatusSubmissionTypeOnlineWithGrade() { val allTypes = listOf( - Assignment.SubmissionType.ONLINE_UPLOAD, - Assignment.SubmissionType.ONLINE_TEXT_ENTRY, - Assignment.SubmissionType.ONLINE_URL, - Assignment.SubmissionType.BASIC_LTI_LAUNCH, - Assignment.SubmissionType.EXTERNAL_TOOL, - Assignment.SubmissionType.ATTENDANCE, - Assignment.SubmissionType.MEDIA_RECORDING + Assignment.SubmissionType.ONLINE_UPLOAD, + Assignment.SubmissionType.ONLINE_TEXT_ENTRY, + Assignment.SubmissionType.ONLINE_URL, + Assignment.SubmissionType.BASIC_LTI_LAUNCH, + Assignment.SubmissionType.EXTERNAL_TOOL, + Assignment.SubmissionType.ATTENDANCE, + Assignment.SubmissionType.MEDIA_RECORDING ) val assignment = Assignment( - id = 123, - name = "Assignment Name", - description = "This is a description", - pointsPossible = 35.0, + id = 123, + name = "Assignment Name", + description = "This is a description", + pointsPossible = 35.0, - submissionTypesRaw = allTypes.map { it.apiString } + submissionTypesRaw = allTypes.map { it.apiString } ) val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) loadPageWithModel(model) @@ -651,21 +427,21 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, false, FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER, false) fun showSubmissionStatusSubmissionTypeQuiz() { val allTypes = listOf( - Assignment.SubmissionType.ONLINE_QUIZ + Assignment.SubmissionType.ONLINE_QUIZ ) val quiz = Quiz( - id = 123L + id = 123L ) val assignment = Assignment( - id = 123, - name = "Assignment Name", - description = "This is a description", - pointsPossible = 35.0, - submissionTypesRaw = allTypes.map { it.apiString }, - quizId = quiz.id + id = 123, + name = "Assignment Name", + description = "This is a description", + pointsPossible = 35.0, + submissionTypesRaw = allTypes.map { it.apiString }, + quizId = quiz.id ) val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) loadPageWithModel(model) @@ -673,27 +449,27 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, false, FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER, false) fun showSubmissionStatusSubmissionTypeDiscussion() { val allTypes = listOf( - Assignment.SubmissionType.DISCUSSION_TOPIC + Assignment.SubmissionType.DISCUSSION_TOPIC ) val discussion = DiscussionTopicHeader( - id = 123L, - message = "discussion message", - author = DiscussionParticipant( - displayName = "Hodor", - avatarImageUrl = "pretty-hodor.com" - ), - postedDate = Date() - ) - val assignment = Assignment( - id = 123, - name = "Assignment Name", - description = "This is a description", - pointsPossible = 35.0, - submissionTypesRaw = allTypes.map { it.apiString }, - discussionTopicHeader = discussion + id = 123L, + message = "discussion message", + author = DiscussionParticipant( + displayName = "Hodor", + avatarImageUrl = "pretty-hodor.com" + ), + postedDate = Date() + ) + val assignment = Assignment( + id = 123, + name = "Assignment Name", + description = "This is a description", + pointsPossible = 35.0, + submissionTypesRaw = allTypes.map { it.apiString }, + discussionTopicHeader = discussion ) val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) loadPageWithModel(model) @@ -701,7 +477,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun showsAllowedAttempts() { val allowed = 35L val used = 20L @@ -718,7 +494,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun showsAllowedAttemptsWithDisabledButton() { val allowed = 35L val used = 35L @@ -735,7 +511,7 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER) fun hidesAllowedAttemptsWhenNotSet() { val assignment = Assignment( name = "Test Assignment", @@ -746,6 +522,227 @@ class AssignmentDetailsRenderTest : StudentRenderTest() { assignmentDetailsRenderPage.assertAssignmentAttemptsGone() } + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_QUIZZES) + fun displaysQuizDetails() { + val quizId = 123L + val timeLimit = 10 + val allowedAttempts = 1 + val questionCount = 1 + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("online_quiz"), + quizId = quizId + ) + val quiz = Quiz( + id = quizId, + timeLimit = timeLimit, + allowedAttempts = allowedAttempts, + questionCount = questionCount + ) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) + loadPageWithModel(model) + assignmentDetailsRenderPage.assertQuizDescription(timeLimit.toString(), allowedAttempts.toString(), questionCount.toString()) + } + + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_QUIZZES) + fun displaysQuizDetailsNoTimeLimit() { + val quizId = 123L + val timeLimit = 0 + val allowedAttempts = 1 + val questionCount = 1 + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("online_quiz"), + quizId = quizId + ) + val quiz = Quiz( + id = quizId, + timeLimit = timeLimit, + allowedAttempts = allowedAttempts, + questionCount = questionCount + ) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) + loadPageWithModel(model) + assignmentDetailsRenderPage.assertQuizDescription(R.string.quizNoTimeLimit, allowedAttempts.toString(), questionCount.toString()) + } + + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_QUIZZES) + fun displaysQuizDetailsUnlimitedAttempts() { + val quizId = 123L + val timeLimit = 10 + val allowedAttempts = -1 + val questionCount = 1 + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("online_quiz"), + quizId = quizId + ) + val quiz = Quiz( + id = quizId, + timeLimit = timeLimit, + allowedAttempts = allowedAttempts, + questionCount = questionCount + ) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) + loadPageWithModel(model) + assignmentDetailsRenderPage.assertQuizDescription(timeLimit.toString(), R.string.unlimited, questionCount.toString()) + } + + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_QUIZZES) + fun displaysNoSubmissionTypesForQuiz() { + val quizId = 123L + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("online_quiz"), + quizId = quizId + ) + val quiz = Quiz(id = quizId) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) + loadPageWithModel(model) + assignmentDetailsRenderPage.submissionTypes.assertGone() + } + + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_QUIZZES) + fun displaysViewQuizButton() { + val quizId = 123L + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("online_quiz"), + quizId = quizId + ) + val quiz = Quiz(id = quizId) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment), quizResult = DataResult.Success(quiz)) + loadPageWithModel(model) + assignmentDetailsRenderPage.assertSubmitButton(R.string.viewQuiz) + } + + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_DISCUSSIONS) + fun displaysNoSubmissionTypesForDiscussion() { + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("discussion_topic"), + discussionTopicHeader = DiscussionTopicHeader(id = 123L, author = DiscussionParticipant(displayName = "hodor"), postedDate = Date()) + ) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) + loadPageWithModel(model) + assignmentDetailsRenderPage.submissionTypes.assertGone() + } + + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_DISCUSSIONS) + fun displaysDiscussionTopicHeader() { + val authorAvatarUrl = "pretty-hodor.com" + val authorName = "hodor" + val authoredDate = "Jul 23 at 9:59 AM" + val attachmentIconVisibility = false + val discussionMessage = "yo yo yo" + val calendar = GregorianCalendar.getInstance() + calendar.set(2019, 6, 23, 9, 59) + val discussionTopicHeader = DiscussionTopicHeader(id = 123L, message = discussionMessage, author = DiscussionParticipant(displayName = authorName, avatarImageUrl = authorAvatarUrl), postedDate = calendar.time) + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("discussion_topic"), + discussionTopicHeader = discussionTopicHeader + ) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) + loadPageWithModel(model) + assignmentDetailsRenderPage.assertDiscussionHeader(authorName, authoredDate, attachmentIconVisibility) + } + + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_DISCUSSIONS) + fun displaysDiscussionTopicHeaderWithAuthorPronouns() { + val authorAvatarUrl = "pretty-hodor.com" + val authorName = "hodor" + val authorPronouns = "Pro/Noun" + val authoredDate = "Jul 23 at 9:59 AM" + val attachmentIconVisibility = false + val discussionMessage = "yo yo yo" + val calendar = GregorianCalendar.getInstance() + calendar.set(2019, 6, 23, 9, 59) + val discussionTopicHeader = DiscussionTopicHeader( + id = 123L, + message = discussionMessage, + author = DiscussionParticipant( + displayName = authorName, + pronouns = authorPronouns, + avatarImageUrl = authorAvatarUrl + ), + postedDate = calendar.time + ) + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("discussion_topic"), + discussionTopicHeader = discussionTopicHeader + ) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) + loadPageWithModel(model) + assignmentDetailsRenderPage.assertDiscussionHeader("hodor (Pro/Noun)", authoredDate, attachmentIconVisibility) + } + + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_DISCUSSIONS) + fun displaysDiscussionTopicHeaderWithAttachments() { + val authorAvatarUrl = "pretty-hodor.com" + val authorName = "hodor" + val authoredDate = "Jul 23 at 9:59 AM" + val attachmentIconVisibility = true + val attachmentId = 12345L + val remoteFiles = mutableListOf(RemoteFile(id = attachmentId)) + val discussionMessage = "yo yo yo" + val calendar = GregorianCalendar.getInstance() + calendar.set(2019, 6, 23, 9, 59) + val discussionTopicHeader = DiscussionTopicHeader(id = 123L, attachments = remoteFiles, message = discussionMessage, author = DiscussionParticipant(displayName = authorName, avatarImageUrl = authorAvatarUrl), postedDate = calendar.time) + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("discussion_topic"), + discussionTopicHeader = discussionTopicHeader + ) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) + loadPageWithModel(model) + assignmentDetailsRenderPage.assertDiscussionHeader(authorName, authoredDate, attachmentIconVisibility) + } + + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_DISCUSSIONS) + fun displaysDiscussionDescription() { + val authorAvatarUrl = "pretty-hodor.com" + val authorName = "hodor" + val attachmentId = 12345L + val remoteFiles = mutableListOf(RemoteFile(id = attachmentId)) + val discussionMessage = "yo yo yo" + val calendar = GregorianCalendar.getInstance() + calendar.set(2019, 6, 23, 9, 59) + val discussionTopicHeader = DiscussionTopicHeader(id = 123L, attachments = remoteFiles, message = discussionMessage, author = DiscussionParticipant(displayName = authorName, avatarImageUrl = authorAvatarUrl), postedDate = calendar.time) + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("discussion_topic"), + discussionTopicHeader = discussionTopicHeader + ) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) + loadPageWithModel(model) + assignmentDetailsRenderPage.assertDisplaysDiscussionDescription(discussionMessage) + } + + @Test + @TestMetaData(Priority.COMMON, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_DISCUSSIONS) + fun displaysViewDiscussionButton() { + val assignment = Assignment( + name = "Test Assignment", + submissionTypesRaw = listOf("discussion_topic"), + discussionTopicHeader = DiscussionTopicHeader(id = 123L, author = DiscussionParticipant(displayName = "hodor"), postedDate = Date()) + ) + val model = baseModel.copy(assignmentResult = DataResult.Success(assignment)) + loadPageWithModel(model) + assignmentDetailsRenderPage.assertSubmitButton(R.string.viewDiscussion) + } + private fun mockkSubmission(failed: Boolean = false) = com.instructure.student.Submission( 123L, null, diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/DiscussionSubmissionViewRenderTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/DiscussionSubmissionViewRenderTest.kt index d936842623..36802f5853 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/DiscussionSubmissionViewRenderTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/DiscussionSubmissionViewRenderTest.kt @@ -32,21 +32,21 @@ class DiscussionSubmissionViewRenderTest : StudentRenderTest() { private val linkUrl = "https://www.google.com" @Test - @TestMetaData(Priority.P2, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysProgressBarPriorToLoading() { loadPageWithUrl(linkUrl) page.assertDisplaysProgressBar() } @Test - @TestMetaData(Priority.P2, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun showsWebViewAndHidesProgressBarAfterLoading() { loadPageWithUrl(linkUrl) page.assertDisplaysLoadedPage() } @Test - @TestMetaData(Priority.P2, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun linkOpensWebView() { loadPageWithUrl(linkUrl) page.assertUrlMatches(linkUrl) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/PickerSubmissionUploadRenderTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/PickerSubmissionUploadRenderTest.kt index 80d03fe650..bc0a772bb7 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/PickerSubmissionUploadRenderTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/PickerSubmissionUploadRenderTest.kt @@ -16,7 +16,6 @@ */ package com.instructure.student.ui.renderTests -import android.os.Build import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.ext.junit.runners.AndroidJUnit4 import com.instructure.canvasapi2.models.Assignment @@ -50,7 +49,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { private val baseVisibilities = PickerVisibilities(sources = true) @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysEmptyState() { loadPageWithViewState(PickerSubmissionUploadViewState.Empty(baseVisibilities)) page.emptyView.assertVisible() @@ -62,7 +61,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysEmptyStateWithLoading() { loadPageWithViewState(PickerSubmissionUploadViewState.Empty(baseVisibilities.copy(loading = true))) page.emptyView.assertVisible() @@ -75,7 +74,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysListState() { val fileItemStates = listOf( PickerListItemViewState(0, R.drawable.ic_media_recordings, "title", "12.3 KB") @@ -95,7 +94,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysListStateWithLoading() { val fileItemStates = listOf( PickerListItemViewState(0, R.drawable.ic_media_recordings, "title", "12.3 KB") @@ -116,7 +115,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysSourceButtons() { loadPageWithViewState( PickerSubmissionUploadViewState.Empty( @@ -135,7 +134,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun showsOnlyCameraSource() { loadPageWithViewState( PickerSubmissionUploadViewState.Empty( @@ -156,7 +155,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun showsOnlyGallerySource() { loadPageWithViewState( PickerSubmissionUploadViewState.Empty( @@ -178,7 +177,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun showsOnlyFileSource() { loadPageWithViewState( PickerSubmissionUploadViewState.Empty( @@ -199,7 +198,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysCorrectStringsForSubmissionMode() { loadPageWithViewState( PickerSubmissionUploadViewState.Empty(baseVisibilities) @@ -209,7 +208,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysCorrectStringsForCommentMode() { loadPageWithViewState( viewState = PickerSubmissionUploadViewState.Empty(baseVisibilities), @@ -220,7 +219,7 @@ class PickerSubmissionUploadRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P3, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) + @TestMetaData(Priority.NICE_TO_HAVE, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun hidesSourceButtons() { loadPageWithViewState( PickerSubmissionUploadViewState.Empty( diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SubmissionCommentsRenderTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SubmissionCommentsRenderTest.kt index 10d0042e7a..70dc9f415d 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SubmissionCommentsRenderTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SubmissionCommentsRenderTest.kt @@ -15,7 +15,6 @@ */ package com.instructure.student.ui.renderTests -import android.os.Build import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -25,6 +24,7 @@ import com.instructure.canvasapi2.models.Submission import com.instructure.canvasapi2.models.User import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority +import com.instructure.panda_annotations.SecondaryFeatureCategory import com.instructure.panda_annotations.TestCategory import com.instructure.panda_annotations.TestMetaData import com.instructure.student.PendingSubmissionComment @@ -134,7 +134,7 @@ class SubmissionCommentsRenderTest: StudentRenderTest() { } @Test - @TestMetaData(Priority.P2,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = FeatureCategory.COMMENTS) + @TestMetaData(Priority.COMMON,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_COMMENTS) fun testSingleComment() { val state = SubmissionCommentsViewState( commentStates = listOf(commentItemIsAudience), @@ -146,7 +146,7 @@ class SubmissionCommentsRenderTest: StudentRenderTest() { } @Test - @TestMetaData(Priority.P2,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = FeatureCategory.COMMENTS) + @TestMetaData(Priority.COMMON,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_COMMENTS) fun testSingleSubmission() { val state = SubmissionCommentsViewState( commentStates = listOf(submissionItem) @@ -156,7 +156,7 @@ class SubmissionCommentsRenderTest: StudentRenderTest() { } @Test - @TestMetaData(Priority.P2,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = FeatureCategory.COMMENTS) + @TestMetaData(Priority.COMMON,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_COMMENTS) fun testSinglePendingComment() { val state = SubmissionCommentsViewState( commentStates = listOf(pendingCommentItem) @@ -166,7 +166,7 @@ class SubmissionCommentsRenderTest: StudentRenderTest() { } @Test - @TestMetaData(Priority.P2,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = FeatureCategory.COMMENTS) + @TestMetaData(Priority.COMMON,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_COMMENTS) fun testSingleCommentDisplaysAuthorPronoun() { val commentItem = commentItemIsAudience.copy(authorPronouns = "Pro/Noun") val state = SubmissionCommentsViewState(commentStates = listOf(commentItem)) @@ -175,7 +175,7 @@ class SubmissionCommentsRenderTest: StudentRenderTest() { } @Test - @TestMetaData(Priority.P2,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = FeatureCategory.COMMENTS) + @TestMetaData(Priority.COMMON,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_COMMENTS) fun testSingleSubmissionDisplaysAuthorPronoun() { val commentItem = submissionItem.copy(authorPronouns = "Pro/Noun") val state = SubmissionCommentsViewState(commentStates = listOf(commentItem)) @@ -184,7 +184,7 @@ class SubmissionCommentsRenderTest: StudentRenderTest() { } @Test - @TestMetaData(Priority.P2,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = FeatureCategory.COMMENTS) + @TestMetaData(Priority.COMMON,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_COMMENTS) fun testSinglePendingCommentDisplaysAuthorPronoun() { val commentItem = pendingCommentItem.copy(authorPronouns = "Pro/Noun") val state = SubmissionCommentsViewState(commentStates = listOf(commentItem)) @@ -193,7 +193,7 @@ class SubmissionCommentsRenderTest: StudentRenderTest() { } @Test - @TestMetaData(Priority.P2,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = FeatureCategory.COMMENTS) + @TestMetaData(Priority.COMMON,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_COMMENTS) fun testEmptyState() { val state = SubmissionCommentsViewState( commentStates = listOf(CommentItemState.Empty) @@ -203,7 +203,7 @@ class SubmissionCommentsRenderTest: StudentRenderTest() { } @Test - @TestMetaData(Priority.P2,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = FeatureCategory.COMMENTS) + @TestMetaData(Priority.COMMON,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_COMMENTS) fun testFailedCommentDisplaysRetryAndDeleteOptions() { db.setCommentError(true, pendingCommentItem.pendingComment.id) val state = SubmissionCommentsViewState( @@ -215,7 +215,7 @@ class SubmissionCommentsRenderTest: StudentRenderTest() { } @Test - @TestMetaData(Priority.P2,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = FeatureCategory.COMMENTS) + @TestMetaData(Priority.COMMON,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_COMMENTS) fun testMixedCommentsAndSubmission() { val state = SubmissionCommentsViewState( commentStates = listOf(commentItemIsAudience, submissionItem, commentItemNotAudience) @@ -231,7 +231,7 @@ class SubmissionCommentsRenderTest: StudentRenderTest() { } @Test - @TestMetaData(Priority.P2,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = FeatureCategory.COMMENTS) + @TestMetaData(Priority.COMMON,FeatureCategory.ASSIGNMENTS,TestCategory.RENDER,secondaryFeature = SecondaryFeatureCategory.ASSIGNMENT_COMMENTS) fun testAudienceDistinction() { val state = SubmissionCommentsViewState( commentStates = listOf(commentItemIsAudience, commentItemNotAudience) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SyllabusRenderTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SyllabusRenderTest.kt index 6d354779c1..aa83cfa912 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SyllabusRenderTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/SyllabusRenderTest.kt @@ -17,6 +17,7 @@ package com.instructure.student.ui.renderTests import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.instructure.canvas.espresso.Stub import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.models.ScheduleItem import com.instructure.canvasapi2.utils.DataResult @@ -66,6 +67,7 @@ class SyllabusRenderTest : StudentRenderTest() { } @Test + @Stub fun displaysSyllabus() { val model = baseModel.copy() loadPageWithModel(model) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/UploadStatusSubmissionRenderTest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/UploadStatusSubmissionRenderTest.kt index f6f9d6830e..904e9a4b77 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/UploadStatusSubmissionRenderTest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/renderTests/UploadStatusSubmissionRenderTest.kt @@ -15,7 +15,6 @@ */ package com.instructure.student.ui.renderTests -import android.os.Build import androidx.test.ext.junit.runners.AndroidJUnit4 import com.instructure.panda_annotations.FeatureCategory import com.instructure.panda_annotations.Priority @@ -46,28 +45,28 @@ class UploadStatusSubmissionRenderTest : StudentRenderTest() { } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysSuccessState() { loadPageWithModel(baseModel) uploadStatusSubmissionViewRenderPage.assertSuccessVisible() } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysLoadingState() { loadPageWithModel(baseModel.copy(isLoading = true)) uploadStatusSubmissionViewRenderPage.assertLoadingVisible() } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysFailedState() { loadPageWithModel(baseModel.copy(isFailed = true)) uploadStatusSubmissionViewRenderPage.assertFailedVisible() } @Test - @TestMetaData(Priority.P2, FeatureCategory.ASSIGNMENTS, TestCategory.RENDER, secondaryFeature = FeatureCategory.SUBMISSIONS) + @TestMetaData(Priority.COMMON, FeatureCategory.SUBMISSIONS, TestCategory.RENDER) fun displaysInProgressState() { loadPageWithModel(baseModel.copy(files = listOf( FileSubmission(0, 0, null, null, null, null, null, null, false) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentActivityTestRule.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentActivityTestRule.kt index afba726dc8..bace30a97b 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentActivityTestRule.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentActivityTestRule.kt @@ -23,6 +23,7 @@ import com.instructure.student.util.StudentPrefs import com.instructure.espresso.InstructureActivityTestRule import com.instructure.loginapi.login.util.PreviousUsersUtils import com.instructure.pandautils.utils.PandaAppResetter +import com.instructure.pandautils.utils.ThemePrefs class StudentActivityTestRule(activityClass: Class) : InstructureActivityTestRule(activityClass) { @@ -31,6 +32,9 @@ class StudentActivityTestRule(activityClass: Class) : Instructu StudentPrefs.clearPrefs() CacheControlFlags.clearPrefs() PreviousUsersUtils.clear(context) + + // We need to set this true so the theme selector won't stop our tests. + ThemePrefs.themeSelectionShown = true } } 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 885a0f1c6a..1ca87195e4 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 @@ -66,7 +66,6 @@ abstract class StudentTest : CanvasTest() { val assignmentListPage = AssignmentListPage() val bookmarkPage = BookmarkPage() val calendarEventPage = CalendarEventPage() - val calendarPage = CalendarPage() val canvasWebViewPage = CanvasWebViewPage() val courseBrowserPage = CourseBrowserPage() val elementaryCoursePage = ElementaryCoursePage() @@ -81,6 +80,7 @@ abstract class StudentTest : CanvasTest() { val inboxConversationPage = InboxConversationPage() val inboxPage = InboxPage() val legalPage = LegalPage() + val aboutPage = AboutPage() val loginFindSchoolPage = LoginFindSchoolPage() val loginLandingPage = LoginLandingPage() val loginSignInPage = LoginSignInPage() diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentTestExtensions.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentTestExtensions.kt index 9399308296..6074a719b6 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentTestExtensions.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/utils/StudentTestExtensions.kt @@ -96,6 +96,7 @@ fun StudentTest.seedData( favoriteCourses: Int = 0, homeroomCourses: Int = 0, announcements: Int = 0, + locked: Boolean = false, discussions: Int = 0, syllabusBody: String? = null, gradingPeriods: Boolean = false): SeedApi.SeededDataApiModel { @@ -111,6 +112,7 @@ fun StudentTest.seedData( gradingPeriods = gradingPeriods, discussions = discussions, announcements = announcements, + locked = locked, syllabusBody = syllabusBody ) return SeedApi.seedData(request) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/utils/ViewUtils.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/utils/ViewUtils.kt new file mode 100644 index 0000000000..6eb9f98b12 --- /dev/null +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/utils/ViewUtils.kt @@ -0,0 +1,28 @@ +// +// 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.utils + +import androidx.test.espresso.Espresso + +object ViewUtils { + + fun pressBackButton(times: Int) { + for(i in 1..times) { + Espresso.pressBack() + } + } +} diff --git a/apps/student/src/main/AndroidManifest.xml b/apps/student/src/main/AndroidManifest.xml index 87783ec4cf..0a83d35912 100644 --- a/apps/student/src/main/AndroidManifest.xml +++ b/apps/student/src/main/AndroidManifest.xml @@ -47,6 +47,8 @@ + + diff --git a/apps/student/src/main/java/com/instructure/student/AnnotationComments/AnnotationCommentListFragment.kt b/apps/student/src/main/java/com/instructure/student/AnnotationComments/AnnotationCommentListFragment.kt index babe285816..e85b97f110 100644 --- a/apps/student/src/main/java/com/instructure/student/AnnotationComments/AnnotationCommentListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/AnnotationComments/AnnotationCommentListFragment.kt @@ -15,7 +15,6 @@ * */ package com.instructure.student.AnnotationComments -import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -71,7 +70,7 @@ class AnnotationCommentListFragment : ParentFragment() { override fun applyTheme() { toolbar.title = title() toolbar.setupAsCloseButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, Color.WHITE, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = @@ -137,7 +136,7 @@ class AnnotationCommentListFragment : ParentFragment() { commentInputContainer.setVisible(false) } else { sendCommentButton.imageTintList = ViewStyler.generateColorStateList( - intArrayOf(-android.R.attr.state_enabled) to ContextCompat.getColor(requireContext(), R.color.defaultTextGray), + intArrayOf(-android.R.attr.state_enabled) to ContextCompat.getColor(requireContext(), R.color.textDark), intArrayOf() to ThemePrefs.buttonColor ) 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 e250600b5b..cc5a2b290f 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 @@ -22,9 +22,11 @@ import android.content.Intent import android.net.Uri import android.os.Bundle import android.util.LayoutDirection +import android.util.TypedValue import android.view.Menu import android.view.MenuItem import android.view.View +import androidx.annotation.ColorInt import androidx.core.text.TextUtilsCompat import com.instructure.annotations.CanvasPdfMenuGrouping import com.instructure.pandautils.analytics.SCREEN_VIEW_PSPDFKIT @@ -86,6 +88,11 @@ class CandroidPSPDFActivity : PdfActivity(), ToolbarCoordinatorLayout.OnContextu override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setOnContextualToolbarLifecycleListener(this) + + val typedValue = TypedValue() + theme.resolveAttribute(R.attr.colorPrimaryDark, typedValue, true) + @ColorInt val color = typedValue.data + ViewStyler.setStatusBarDark(this, color) } override fun onPrepareOptionsMenu(menu: Menu): Boolean { diff --git a/apps/student/src/main/java/com/instructure/student/activity/InternalWebViewActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/InternalWebViewActivity.kt index 6a04f54782..6c363d3454 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/InternalWebViewActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/InternalWebViewActivity.kt @@ -18,14 +18,13 @@ package com.instructure.student.activity import android.content.Context import android.content.Intent -import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.CanvasContext.Companion.emptyCourseContext import com.instructure.pandautils.activities.BaseActionBarActivity import com.instructure.pandautils.utils.Const -import com.instructure.pandautils.utils.ViewStyler.themeToolbar +import com.instructure.pandautils.utils.ViewStyler import com.instructure.pandautils.utils.color import com.instructure.pandautils.utils.toast import com.instructure.student.R @@ -36,7 +35,7 @@ import com.instructure.student.fragment.InternalWebviewFragment.Companion.newIns class InternalWebViewActivity : BaseActionBarActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - toolbar?.let { themeToolbar(this, it, Color.WHITE, Color.BLACK, false) } + toolbar?.let { ViewStyler.themeToolbarLight(this, it) } if (savedInstanceState == null) { val bundle = intent.getBundleExtra(Const.EXTRAS) bundle?.getString(Const.ACTION_BAR_TITLE)?.let { toolbar?.title = it } 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 2ad389eb1c..579c9f20da 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 @@ -69,6 +69,7 @@ import com.instructure.loginapi.login.tasks.LogoutTask import com.instructure.pandautils.dialogs.UploadFilesDialog import com.instructure.pandautils.features.help.HelpDialogFragment import com.instructure.pandautils.features.notification.preferences.NotificationPreferencesFragment +import com.instructure.pandautils.features.themeselector.ThemeSelectorBottomSheet import com.instructure.pandautils.models.PushNotification import com.instructure.pandautils.receivers.PushExternalReceiver import com.instructure.pandautils.typeface.TypefaceBehavior @@ -102,8 +103,10 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import java.util.* import javax.inject.Inject +import kotlin.collections.ArrayList private const val BOTTOM_NAV_SCREEN = "bottomNavScreen" +private const val BOTTOM_SCREENS_BUNDLE_KEY = "bottomScreens" @AndroidEntryPoint @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") @@ -201,7 +204,6 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. from external sources. */ val visible = isBottomNavFragment(it) || supportFragmentManager.backStackEntryCount <= 1 bottomBar.setVisible(visible) - bottomBarDivider.setVisible(visible) } } @@ -223,13 +225,24 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. } } + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + if (bottomNavScreensStack.isNotEmpty()) { + val bottomScreens = ArrayList(bottomNavScreensStack.toList()) + outState.putStringArrayList(BOTTOM_SCREENS_BUNDLE_KEY, bottomScreens) + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val masqueradingUserId: Long = intent.getLongExtra(Const.QR_CODE_MASQUERADE_ID, 0L) if (masqueradingUserId != 0L) { MasqueradeHelper.startMasquerading(masqueradingUserId, ApiPrefs.domain, NavigationActivity::class.java) + finish() } + FlutterComm.updateDarkMode(this) + bottomBar.inflateMenu(navigationBehavior.bottomBarMenu) supportFragmentManager.addOnBackStackChangedListener(onBackStackChangedListener) @@ -245,6 +258,26 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. setupNavDrawerItems() checkAppUpdates() + + val savedBottomScreens = savedInstanceState?.getStringArrayList(BOTTOM_SCREENS_BUNDLE_KEY) + restoreBottomNavState(savedBottomScreens) + + if (!ThemePrefs.themeSelectionShown) { + val themeSelector = ThemeSelectorBottomSheet() + themeSelector.show(supportFragmentManager, ThemeSelectorBottomSheet::javaClass.name) + ThemePrefs.themeSelectionShown = true + } + } + + private fun restoreBottomNavState(savedBottomScreens: List?) { + if (savedBottomScreens != null && savedBottomScreens.isNotEmpty() && bottomNavScreensStack.isEmpty()) { + savedBottomScreens.reversed().forEach { bottomNavScreensStack.push(it) } + } + + currentFragment?.let { + val visible = isBottomNavFragment(it) || supportFragmentManager.backStackEntryCount <= 1 + bottomBar.setVisible(visible) + } } private fun setupNavDrawerItems() { @@ -389,7 +422,7 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. if(ProfileUtils.shouldLoadAltAvatarImage(user.avatarUrl)) { val initials = ProfileUtils.getUserInitials(user.shortName ?: "") - val color = ContextCompat.getColor(context, R.color.avatarGray) + val color = ContextCompat.getColor(context, R.color.textDark) val drawable = TextDrawable.builder() .beginConfig() .height(context.resources.getDimensionPixelSize(R.dimen.profileAvatarSize)) @@ -478,7 +511,7 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. setupUserDetails(ApiPrefs.user) - ViewStyler.themeToolbar(this, toolbar, ThemePrefs.primaryColor, ThemePrefs.primaryTextColor) + ViewStyler.themeToolbarColored(this, toolbar, ThemePrefs.primaryColor, ThemePrefs.primaryTextColor) navigationDrawerItem_startMasquerading.setVisible(!ApiPrefs.isMasquerading && ApiPrefs.canBecomeUser == true) navigationDrawerItem_stopMasquerading.setVisible(ApiPrefs.isMasquerading) @@ -534,9 +567,7 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. override fun overrideFont() { super.overrideFont() - if (navigationBehavior.shouldOverrideFont) { - typefaceBehavior.overrideFont() - } + typefaceBehavior.overrideFont(navigationBehavior.fontFamily.fontPath) } //endregion @@ -594,7 +625,7 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. private fun setupBottomNavigation() { Logger.d("NavigationActivity:setupBottomNavigation()") - bottomBar.applyTheme(ThemePrefs.brandColor, ContextCompat.getColor(this, R.color.bottomBarUnselectedItemColor)) + bottomBar.applyTheme(ThemePrefs.brandColor, ContextCompat.getColor(this, R.color.textDarkest)) bottomBar.setOnNavigationItemSelectedListener(bottomBarItemSelectedListener) bottomBar.setOnNavigationItemReselectedListener(bottomBarItemReselectedListener) updateBottomBarContentDescriptions() @@ -1048,7 +1079,7 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. .inflate(R.layout.unread_count, bottomBar, false) (badge as TextView).text = unreadCountDisplay - ColorUtils.colorIt(ContextCompat.getColor(context, R.color.electricBlueBadge), badge.background) + ColorUtils.colorIt(ContextCompat.getColor(context, R.color.backgroundInfo), badge.background) addView(badge) } } diff --git a/apps/student/src/main/java/com/instructure/student/activity/NothingToSeeHereFragment.kt b/apps/student/src/main/java/com/instructure/student/activity/NothingToSeeHereFragment.kt index 37ccd531c3..b001a7a56b 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/NothingToSeeHereFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/NothingToSeeHereFragment.kt @@ -15,7 +15,6 @@ */ package com.instructure.student.activity -import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -44,7 +43,7 @@ class NothingToSeeHereFragment : ParentFragment() { override fun applyTheme() { toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, Color.WHITE, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) } companion object { diff --git a/apps/student/src/main/java/com/instructure/student/activity/PandaAvatarActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/PandaAvatarActivity.kt index 1aba1e9bdc..caa9f1c850 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/PandaAvatarActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/PandaAvatarActivity.kt @@ -129,7 +129,7 @@ class PandaAvatarActivity : ParentActivity() { private fun setupViews() { mToolbar.setTitle(R.string.pandaAvatar) mToolbar.setupAsBackButton { finish() } - ViewStyler.themeToolbar(this, mToolbar, ThemePrefs.primaryColor, Color.WHITE) + ViewStyler.themeToolbarColored(this, mToolbar, ThemePrefs.primaryColor, getColor(R.color.white)) mToolbar.elevation = this.DP(2f) // Make the head and body all black changeHead.background = ColorKeeper.getColoredDrawable(this@PandaAvatarActivity, R.drawable.pandify_head_02, Color.BLACK) @@ -159,7 +159,7 @@ class PandaAvatarActivity : ParentActivity() { } private fun setAsAvatar() { - val file = saveImageAsPNG(false, ContextCompat.getColor(this, R.color.canvasBackgroundMedium), false) ?: return + val file = saveImageAsPNG(false, ContextCompat.getColor(this, R.color.backgroundMedium), false) ?: return val data = Intent() data.putExtra(Const.PATH, file.path) data.putExtra(Const.SIZE, file.length()) diff --git a/apps/student/src/main/java/com/instructure/student/activity/ShareFileUploadActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/ShareFileUploadActivity.kt index 10c7871031..5872617ad1 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/ShareFileUploadActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/ShareFileUploadActivity.kt @@ -80,7 +80,7 @@ class ShareFileUploadActivity : AppCompatActivity(), ShareFileDestinationDialog. public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_share_file) - ViewStyler.setStatusBarDark(this, ContextCompat.getColor(this, R.color.login_studentAppTheme)) + ViewStyler.setStatusBarDark(this, ContextCompat.getColor(this, R.color.studentDocumentSharingColor)) if (checkLoggedIn()) { revealBackground() Analytics.trackAppFlow(this) diff --git a/apps/student/src/main/java/com/instructure/student/adapter/NotificationListRecyclerAdapter.kt b/apps/student/src/main/java/com/instructure/student/adapter/NotificationListRecyclerAdapter.kt index a57e35d8c8..b6d5845683 100644 --- a/apps/student/src/main/java/com/instructure/student/adapter/NotificationListRecyclerAdapter.kt +++ b/apps/student/src/main/java/com/instructure/student/adapter/NotificationListRecyclerAdapter.kt @@ -245,9 +245,7 @@ class NotificationListRecyclerAdapter( if (!isNoNetwork) { // Double negative, only happens when there is network adapterToRecyclerViewCallback.setDisplayNoConnection(false) // We check mStreamItems here as onCallbackFinished is called prior to populating the adapter - if (streamItems != null) { - adapterToRecyclerViewCallback.setIsEmpty(isAllPagesLoaded && streamItems!!.isEmpty()) - } + adapterToRecyclerViewCallback.setIsEmpty(isAllPagesLoaded && (streamItems?.isEmpty() ?: true)) } } } diff --git a/apps/student/src/main/java/com/instructure/student/adapter/TodoListRecyclerAdapter.kt b/apps/student/src/main/java/com/instructure/student/adapter/TodoListRecyclerAdapter.kt index d9b0ac8466..6c95403977 100644 --- a/apps/student/src/main/java/com/instructure/student/adapter/TodoListRecyclerAdapter.kt +++ b/apps/student/src/main/java/com/instructure/student/adapter/TodoListRecyclerAdapter.kt @@ -163,7 +163,7 @@ open class TodoListRecyclerAdapter : ExpandableRecyclerAdapter = mutableMapOf() private val favoriteGroupMap: MutableMap = mutableMapOf() - private lateinit var courses: List + private lateinit var currentCourses: List + private lateinit var pastCourses: List + private lateinit var futureCourses: List private lateinit var groups: List - private lateinit var groupsViewData: List - private lateinit var groupHeader: EditDashboardHeaderViewModel private lateinit var courseHeader: EditDashboardHeaderViewModel private lateinit var currentCoursesViewData: List private lateinit var pastCoursesViewData: List private lateinit var futureCoursesViewData: List + private lateinit var groupsViewData: List var hasChanges = false @@ -81,15 +84,24 @@ class EditDashboardViewModel @Inject constructor(private val courseManager: Cour fun loadItems() { viewModelScope.launch { try { - courses = courseManager.getCoursesWithConcludedAsync(true).await().dataOrThrow - courses = courses.filter { it.isNotDeleted() && !it.isInvited() && !it.isEnrollmentDeleted() } - courseMap = courses.associateBy { it.id } + val (currentCoursesDeferred, pastCoursesDeferred, futureCoursesDeferred) = listOf( + courseManager.getCoursesByEnrollmentStateAsync("active", true), + courseManager.getCoursesByEnrollmentStateAsync("completed", true), + courseManager.getCoursesByEnrollmentStateAsync("invited_or_pending", true) + ) + .awaitAll() + + currentCourses = currentCoursesDeferred.dataOrThrow + pastCourses = pastCoursesDeferred.dataOrThrow + futureCourses = futureCoursesDeferred.dataOrThrow + + courseMap = (currentCourses + pastCourses + futureCourses).associateBy { it.id } groups = groupManager.getAllGroupsAsync(true).await().dataOrThrow groups = groups.filter { it.isActive(courseMap?.get(it.courseId)) } groupMap = groups.associateBy { it.id } - val items = createListItems(courses, groups) + val items = createListItems(currentCourses, pastCourses, futureCourses, groups) _data.postValue(EditDashboardViewData(items)) if (items.isEmpty()) { _state.postValue(ViewState.Empty(R.string.edit_dashboard_empty_title, R.string.edit_dashboard_empty_message, R.drawable.ic_panda_nocourses)) @@ -320,9 +332,8 @@ class EditDashboardViewModel @Inject constructor(private val courseManager: Cour private fun getCurrentCourses(courses: List): List { favoriteCourseMap.clear() - val currentCourses = courses.filter { it.hasActiveEnrollment() && it.isCurrentEnrolment() } - favoriteCourseMap.putAll(currentCourses.filter { it.isFavorite }.associateBy { it.id }) - return currentCourses.map { + favoriteCourseMap.putAll(courses.filter { it.isFavorite }.associateBy { it.id }) + return courses.map { EditDashboardCourseItemViewModel( id = it.id, name = it.name, @@ -336,12 +347,11 @@ class EditDashboardViewModel @Inject constructor(private val courseManager: Cour } private fun getPastCourses(courses: List): List { - val pastCourses = courses.filter { it.isPastEnrolment() } - return pastCourses.map { + return courses.map { EditDashboardCourseItemViewModel( id = it.id, name = it.name, - isFavorite = it.isFavorite, + isFavorite = false, favoriteable = false, openable = it.isNotDeleted() && it.isPublished(), termTitle = "${it.term?.name} | ${it.enrollments?.get(0)?.type?.apiTypeString}", @@ -351,9 +361,8 @@ class EditDashboardViewModel @Inject constructor(private val courseManager: Cour } private fun getFutureCourses(courses: List): List { - val futureCourses = courses.filter { it.isFutureEnrolment() } - favoriteCourseMap.putAll(futureCourses.filter { it.isFavorite }.associateBy { it.id }) - return futureCourses.map { + favoriteCourseMap.putAll(courses.filter { it.isFavorite }.associateBy { it.id }) + return courses.map { EditDashboardCourseItemViewModel( id = it.id, name = it.name, @@ -375,10 +384,10 @@ class EditDashboardViewModel @Inject constructor(private val courseManager: Cour } } - private fun createListItems(courses: List, groups: List, isFiltered: Boolean = false): List { - currentCoursesViewData = getCurrentCourses(courses) - pastCoursesViewData = getPastCourses(courses) - futureCoursesViewData = getFutureCourses(courses) + private fun createListItems(currentCourses: List, pastCourses: List, futureCourses: List, groups: List, isFiltered: Boolean = false): List { + currentCoursesViewData = getCurrentCourses(currentCourses) + pastCoursesViewData = getPastCourses(pastCourses) + futureCoursesViewData = getFutureCourses(futureCourses) groupsViewData = getGroups(groups) val items = mutableListOf() @@ -414,12 +423,14 @@ class EditDashboardViewModel @Inject constructor(private val courseManager: Cour fun queryItems(query: String) { val items = if (query.isBlank()) { - createListItems(courses, groups) + createListItems(currentCourses, pastCourses, futureCourses, groups) } else { - val queriedCourses = courses.filter { it.name.contains(query, true) } + val queriedCurrentCourses = currentCourses.filter { it.name.contains(query, true) } + val queriedPastCourses = pastCourses.filter { it.name.contains(query, true) } + val queriedFutureCourses = futureCourses.filter { it.name.contains(query, true) } val queriedGroups = groups.filter { it.name?.contains(query, true) ?: false || it.description?.contains(query, true) ?: false || courseMap?.get(it.courseId)?.name?.contains(query, true) ?: false } - createListItems(queriedCourses, queriedGroups, true) + createListItems(queriedCurrentCourses, queriedPastCourses, queriedFutureCourses, queriedGroups, true) } if (items.isEmpty()) { _state.postValue(ViewState.Empty(R.string.edit_dashboard_empty_title, R.string.edit_dashboard_empty_message, R.drawable.ic_panda_nocourses)) diff --git a/apps/student/src/main/java/com/instructure/student/features/documentscanning/DocumentScanningActivity.kt b/apps/student/src/main/java/com/instructure/student/features/documentscanning/DocumentScanningActivity.kt index 6868fdd770..33d25b41a2 100644 --- a/apps/student/src/main/java/com/instructure/student/features/documentscanning/DocumentScanningActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/features/documentscanning/DocumentScanningActivity.kt @@ -23,6 +23,7 @@ import androidx.activity.viewModels import androidx.core.content.ContextCompat import androidx.core.net.toUri import androidx.databinding.DataBindingUtil +import com.instructure.pandautils.utils.ViewStyler import com.instructure.student.R import com.instructure.student.databinding.ActivityDocumentScanningBinding import com.zynksoftware.documentscanner.ScanActivity @@ -96,6 +97,7 @@ class DocumentScanningActivity : ScanActivity() { setTitle(R.string.documentScanningTitle) navigationIcon = ContextCompat.getDrawable(this@DocumentScanningActivity, R.drawable.ic_back_arrow) navigationIcon?.isAutoMirrored = true + ViewStyler.themeToolbarLight(this@DocumentScanningActivity, this) setNavigationContentDescription(R.string.close) setNavigationOnClickListener { onClose() } } 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 96b1d184b3..81e15e4a42 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 @@ -30,7 +30,6 @@ import com.instructure.canvasapi2.models.Course import com.instructure.interactions.router.Route import com.instructure.pandautils.analytics.SCREEN_VIEW_ELEMENTARY_COURSE import com.instructure.pandautils.analytics.ScreenView -import com.instructure.pandautils.features.elementary.grades.GradesFragment import com.instructure.pandautils.utils.* import com.instructure.student.databinding.FragmentElementaryCourseBinding import com.instructure.student.fragment.CourseBrowserFragment @@ -108,7 +107,7 @@ class ElementaryCourseFragment : Fragment() { private fun applyTheme() { toolbar.title = canvasContext.name toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } private fun handleAction(action: ElementaryCourseAction) { diff --git a/apps/student/src/main/java/com/instructure/student/features/elementary/course/ElementaryCoursePagerAdapter.kt b/apps/student/src/main/java/com/instructure/student/features/elementary/course/ElementaryCoursePagerAdapter.kt index 37da1700fc..f86ae80d18 100644 --- a/apps/student/src/main/java/com/instructure/student/features/elementary/course/ElementaryCoursePagerAdapter.kt +++ b/apps/student/src/main/java/com/instructure/student/features/elementary/course/ElementaryCoursePagerAdapter.kt @@ -25,6 +25,7 @@ import android.widget.ProgressBar import androidx.fragment.app.FragmentActivity import androidx.viewpager.widget.PagerAdapter import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.pandautils.utils.setDarkModeSupport import com.instructure.pandautils.utils.setGone import com.instructure.pandautils.utils.setVisible import com.instructure.pandautils.views.CanvasWebView @@ -64,6 +65,7 @@ class ElementaryCoursePagerAdapter( val baseContext = (webView.context as ContextWrapper).baseContext val activity = (baseContext as? FragmentActivity) activity?.let { webView.addVideoClient(it) } + webView.setDarkModeSupport() webView.setZoomSettings(false) webView.canvasWebViewClientCallback = object : CanvasWebView.CanvasWebViewClientCallback { override fun openMediaFromWebView(mime: String, url: String, filename: String) { 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 0f33e1f33e..c7d077f074 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 @@ -68,7 +68,7 @@ class FileSearchFragment : ParentFragment(), FileSearchView { } private fun setupViews() { - ViewStyler.setStatusBarLight(requireActivity()) + ViewStyler.themeStatusBar(requireActivity()) // Set up empty state emptyPandaView.getEmptyViewImage()?.setImageResource(R.drawable.ic_panda_nofiles) diff --git a/apps/student/src/main/java/com/instructure/student/flutterChannels/FlutterComm.kt b/apps/student/src/main/java/com/instructure/student/flutterChannels/FlutterComm.kt index 50f15d5bd2..05815d590f 100644 --- a/apps/student/src/main/java/com/instructure/student/flutterChannels/FlutterComm.kt +++ b/apps/student/src/main/java/com/instructure/student/flutterChannels/FlutterComm.kt @@ -16,10 +16,10 @@ package com.instructure.student.flutterChannels +import android.app.Activity import android.content.Context +import android.content.res.Configuration import android.graphics.Color -import android.util.Log -import android.view.Window import com.google.gson.Gson import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.isValid @@ -44,6 +44,7 @@ object FlutterComm { private const val METHOD_UPDATE_LOGIN_DATA = "updateLoginData" private const val METHOD_UPDATE_SHOULD_POP = "updateShouldPop" private const val METHOD_UPDATE_THEME_DATA = "updateThemeData" + private const val METHOD_UPDATE_DARK_MODE = "updateLightOrDarkMode" private lateinit var context: Context private lateinit var channel: MethodChannel @@ -124,4 +125,13 @@ object FlutterComm { val isoDates = affectedDates.map { it.toApiString() } channel.invokeMethod(METHOD_UPDATE_CALENDAR_DATES, isoDates) } + + fun updateDarkMode(activity: Activity) { + val nightModeFlags: Int = activity.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK + val darkMode = nightModeFlags == Configuration.UI_MODE_NIGHT_YES + + val data = mutableMapOf() + data["darkMode"] = darkMode + channel.invokeMethod(METHOD_UPDATE_DARK_MODE, data) + } } 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 3733a1e983..15e0d84c0d 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 @@ -16,7 +16,6 @@ */ package com.instructure.student.fragment -import android.app.AlertDialog import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater @@ -24,6 +23,7 @@ import android.view.View import android.view.ViewGroup import android.widget.AdapterView 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 @@ -73,7 +73,7 @@ class AccountPreferencesFragment : ParentFragment() { override fun applyTheme() { toolbar.title = title() toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, Color.WHITE, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) } private fun setupViews() { @@ -100,8 +100,8 @@ class AccountPreferencesFragment : ParentFragment() { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val view: View = convertView ?: inflater.inflate(R.layout.settings_spinner, parent, false) - view.indicator.setImageDrawable(ColorKeeper.getColoredDrawable(requireContext(), R.drawable.ic_expand, Color.WHITE)) - view.indicator.setColorFilter(ContextCompat.getColor(requireContext(), R.color.defaultTextGray)) + view.indicator.setImageDrawable(ColorKeeper.getColoredDrawable(requireContext(), R.drawable.ic_expand, requireContext().getColor(R.color.white))) + view.indicator.setColorFilter(ContextCompat.getColor(requireContext(), R.color.textDark)) view.title.text = getItem(position).toString() return view } 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 index e996a3559f..dce655d913 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/ApplicationSettingsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/ApplicationSettingsFragment.kt @@ -17,7 +17,6 @@ package com.instructure.student.fragment import android.annotation.SuppressLint -import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -59,7 +58,7 @@ class ApplicationSettingsFragment : ParentFragment() { override fun applyTheme() { toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, Color.WHITE, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) } @SuppressLint("SetTextI18n") @@ -121,6 +120,8 @@ class ApplicationSettingsFragment : ParentFragment() { } } + setUpAppThemeSelector() + if (BuildConfig.DEBUG) { featureFlags.setVisible() featureFlags.onClick { @@ -137,4 +138,13 @@ class ApplicationSettingsFragment : ParentFragment() { private fun addFragment(fragment: Fragment) { (activity as? SettingsActivity)?.addFragment(fragment) } + + private fun setUpAppThemeSelector() { + val initialAppTheme = AppTheme.fromIndex(ThemePrefs.appTheme) + appThemeStatus.setText(initialAppTheme.themeNameRes) + + appThemeContainer.onClick { + AppThemeSelector.showAppThemeSelectorDialog(requireContext(), appThemeStatus) + } + } } 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 c22ddccccf..8ba9ddc1e3 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 @@ -170,7 +170,7 @@ class AssignmentBasicFragment : ParentFragment() { toolbar.let { it.title = assignment.name ?: "" it.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), it, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), it, canvasContext) } } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/AssignmentListFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/AssignmentListFragment.kt index 72229d897f..91edffab83 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/AssignmentListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/AssignmentListFragment.kt @@ -17,7 +17,6 @@ package com.instructure.student.fragment -import android.app.AlertDialog import android.content.DialogInterface import android.content.res.Configuration import android.os.Bundle @@ -26,6 +25,7 @@ import android.view.View import android.view.ViewGroup import android.widget.AdapterView import androidx.annotation.StringRes +import androidx.appcompat.app.AlertDialog import com.google.android.material.appbar.AppBarLayout import com.instructure.canvasapi2.models.Assignment import com.instructure.canvasapi2.models.CanvasContext @@ -147,7 +147,7 @@ class AssignmentListFragment : ParentFragment(), Bookmarkable { private fun setupSortByButton() { sortByButton.onClick { val checkedItemIndex = sortOrder.index - AlertDialog.Builder(context, R.style.AccentDialogTheme) + AlertDialog.Builder(requireContext(), R.style.AccentDialogTheme) .setTitle(R.string.sortByDialogTitle) .setSingleChoiceItems(R.array.assignmentsSortByOptions, checkedItemIndex, this@AssignmentListFragment::sortOrderSelected) .setNegativeButton(R.string.sortByDialogCancel) { dialog, _ -> dialog.dismiss() } @@ -181,7 +181,7 @@ class AssignmentListFragment : ParentFragment(), Bookmarkable { } recyclerAdapter.searchQuery = query } - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } private fun setupGradingPeriods(periods: List) { 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 8bcaeec925..3f7e2150f8 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 @@ -40,6 +40,7 @@ import com.instructure.pandautils.views.CanvasWebView import com.instructure.student.R import com.instructure.student.router.RouteMatcher import com.instructure.student.util.LockInfoHTMLHelper +import kotlinx.android.synthetic.main.fragment_webview.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.greenrobot.eventbus.Subscribe @@ -84,6 +85,7 @@ class BasicQuizViewFragment : InternalWebviewFragment() { // Make sure we are prepared to handle file uploads for quizzes that allow them setupFilePicker() + canvasWebView?.setDarkModeSupport() } override fun onActivityCreated(savedInstanceState: Bundle?) { 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 a23513073b..3d63be282d 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 @@ -96,7 +96,7 @@ class BookmarksFragment : ParentFragment() { } } - ViewStyler.themeToolbar(requireActivity(), toolbar, Color.WHITE, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) } private fun applyEmptyImage() { diff --git a/apps/student/src/main/java/com/instructure/student/fragment/CalendarEventFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/CalendarEventFragment.kt index 8f21a1f48b..78548c9873 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/CalendarEventFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/CalendarEventFragment.kt @@ -118,7 +118,7 @@ class CalendarEventFragment : ParentFragment() { } toolbar.setupAsBackButtonAsBackPressedOnly(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } override fun title(): String = scheduleItem?.title ?: getString(R.string.Event) @@ -236,7 +236,7 @@ class CalendarEventFragment : ParentFragment() { private fun loadCalendarHtml(html: String, contentDescription: String?) { calendarEventWebView.setVisible() - calendarEventWebView.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.canvasBackgroundLight)) + calendarEventWebView.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.backgroundLightest)) calendarEventWebView.loadHtml(html, contentDescription) } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/CalendarFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/CalendarFragment.kt index c3e1660a13..a376081f58 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/CalendarFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/CalendarFragment.kt @@ -17,12 +17,12 @@ package com.instructure.student.fragment -import android.app.AlertDialog import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.appcompat.app.AlertDialog import com.instructure.canvasapi2.models.PlannableType import com.instructure.canvasapi2.models.PlannerItem import com.instructure.canvasapi2.utils.ApiPrefs @@ -113,7 +113,7 @@ class CalendarFragment : ParentFragment() { } private fun showDialog(call: MethodCall, result: MethodChannel.Result) { - AlertDialog.Builder(activity, R.style.AccentDialogTheme) + AlertDialog.Builder(requireActivity(), R.style.AccentDialogTheme) .setTitle(call.argument("title")) .setMessage(call.argument("message")) .setPositiveButton(call.argument("positiveButtonText")) { _, _ -> result.success(true) } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/CourseBrowserFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/CourseBrowserFragment.kt index f6abc206af..b9b6639a66 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/CourseBrowserFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/CourseBrowserFragment.kt @@ -158,8 +158,8 @@ class CourseBrowserFragment : Fragment(), FragmentInteractions, AppBarLayout.OnO //region Fragment Interaction Overrides override fun applyTheme() { - ViewStyler.colorToolbarIconsAndText(requireActivity(), noOverlayToolbar, Color.WHITE) - ViewStyler.colorToolbarIconsAndText(requireActivity(), overlayToolbar, Color.WHITE) + ViewStyler.colorToolbarIconsAndText(requireActivity(), noOverlayToolbar, requireContext().getColor(R.color.white)) + ViewStyler.colorToolbarIconsAndText(requireActivity(), overlayToolbar, requireContext().getColor(R.color.white)) ViewStyler.setStatusBarDark(requireActivity(), canvasContext.color) } 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 b09fd77d04..dbea08e8b5 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 @@ -41,7 +41,7 @@ class CourseSettingsFragment : ParentFragment() { override fun applyTheme() { toolbar.title = title() toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, course) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, course) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 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 724bae0739..026a1de8cc 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 @@ -18,7 +18,6 @@ package com.instructure.student.fragment import android.app.Activity import android.content.Intent -import android.graphics.Color import android.graphics.Typeface import android.os.Bundle import android.view.LayoutInflater @@ -150,7 +149,7 @@ class CreateAnnouncementFragment : ParentFragment() { } } } - ViewStyler.themeToolbarBottomSheet(requireActivity(), isTablet, createAnnouncementToolbar, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), createAnnouncementToolbar) ViewStyler.setToolbarElevationSmall(requireContext(), createAnnouncementToolbar) if (isEditing) with(mSaveMenuButton) { setIcon(0) @@ -188,7 +187,7 @@ class CreateAnnouncementFragment : ParentFragment() { ThemePrefs.brandColor, ThemePrefs.buttonColor ) // when the RCE editor has focus we want the label to be darker so it matches the title's functionality - announcementRCEView.setLabel(announcementDescLabel, R.color.defaultTextDark, R.color.defaultTextGray) + announcementRCEView.setLabel(announcementDescLabel, R.color.textDarkest, R.color.textDark) } private fun enableUsersMustPostSwitch(enabled: Boolean) { 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 1f3e278110..b7d1d89f62 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 @@ -18,7 +18,6 @@ package com.instructure.student.fragment import android.app.Activity import android.content.Intent -import android.graphics.Color import android.graphics.Typeface import android.os.Bundle import android.view.LayoutInflater @@ -166,7 +165,7 @@ class CreateDiscussionFragment : ParentFragment() { //R.id.menuAddAttachment -> if (discussionTopicHeader == null) addAttachment() BLOCKED COMMS 868 } } - ViewStyler.themeToolbarBottomSheet(requireActivity(), isTablet, createDiscussionToolbar, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), createDiscussionToolbar) ViewStyler.setToolbarElevationSmall(requireContext(), createDiscussionToolbar) sendButton?.setTextColor(ThemePrefs.buttonColor) saveButton?.setTextColor(ThemePrefs.buttonColor) @@ -190,7 +189,7 @@ class CreateDiscussionFragment : ParentFragment() { descriptionRCEView.actionUploadImageCallback = { MediaUploadUtils.showPickImageDialog(this) } // When the RCE editor has focus we want the label to be darker so it matches the title's functionality - descriptionRCEView.setLabel(discussionDescLabel, R.color.defaultTextDark, R.color.defaultTextGray) + descriptionRCEView.setLabel(discussionDescLabel, R.color.textDarkest, R.color.textDark) if (!hasLoadedDataForEdit) discussionTopicHeader?.let { editDiscussionName.setText(it.title) diff --git a/apps/student/src/main/java/com/instructure/student/fragment/DashboardFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/DashboardFragment.kt index f32fa772cd..6acd19c5c4 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/DashboardFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/DashboardFragment.kt @@ -91,6 +91,12 @@ class DashboardFragment : ParentFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = layoutInflater.inflate(R.layout.fragment_course_grid, container, false) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + applyTheme() + } + override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) diff --git a/apps/student/src/main/java/com/instructure/student/fragment/DiscussionDetailsFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/DiscussionDetailsFragment.kt index 226ab62695..b54f39a311 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/DiscussionDetailsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/DiscussionDetailsFragment.kt @@ -17,7 +17,6 @@ package com.instructure.student.fragment import android.annotation.SuppressLint -import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -184,7 +183,7 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { toolbar.setMenu(R.menu.menu_edit_generic, menuItemCallback) } */ - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } //endregion @@ -350,7 +349,7 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { private fun updateDiscussionLikedState(discussionEntry: DiscussionEntry, methodName: String) { val likingSum = if (discussionEntry.ratingSum == 0) "" else "(${discussionEntry.ratingSum})" val likingSumAllyText = DiscussionEntryHtmlConverter.getLikeCountText(requireContext(), discussionEntry) - val likingColor = DiscussionUtils.getHexColorString(if (discussionEntry._hasRated) ThemePrefs.brandColor else ContextCompat.getColor(requireContext(), R.color.discussionLiking)) + val likingColor = DiscussionUtils.getHexColorString(if (discussionEntry._hasRated) ThemePrefs.brandColor else ContextCompat.getColor(requireContext(), R.color.textDark)) activity?.runOnUiThread { discussionRepliesWebView.loadUrl("javascript:$methodName('${discussionEntry.id}')") discussionRepliesWebView.loadUrl("javascript:updateLikedCount('${discussionEntry.id}','$likingSum','$likingColor','$likingSumAllyText')") @@ -362,9 +361,9 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { //region WebView And Javascript @SuppressLint("SetJavaScriptEnabled") - private fun setupWebView(webView: CanvasWebView) { + private fun setupWebView(webView: CanvasWebView, addDarkTheme: Boolean = false) { WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG) - webView.setBackgroundColor(Color.WHITE) + webView.setBackgroundColor(requireContext().getColor(R.color.backgroundLightest)) webView.settings.javaScriptEnabled = true webView.settings.useWideViewPort = true webView.settings.allowFileAccess = true @@ -383,8 +382,20 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { openMedia(canvasContext, url, filename) } - override fun onPageStartedCallback(webView: WebView, url: String) {} - override fun onPageFinishedCallback(webView: WebView, url: String) {} + override fun onPageStartedCallback(webView: WebView, url: String) { + // This executes a JavaScript to add the dark theme. + // It won't work exactl when the page starts to load, because the html document is not yet created, + // so we add a little delay to make sure the script can modify the document. + if (addDarkTheme) { + webView.postDelayed({ webView.addDarkThemeToHtmlDocument() }, 50) + } + } + override fun onPageFinishedCallback(webView: WebView, url: String) { + // This is just a fallback if in some cases the document wouldn't be loaded after the delay + if (addDarkTheme) { + webView.addDarkThemeToHtmlDocument() + } + } } webView.addVideoClient(requireActivity()) @@ -398,7 +409,7 @@ class DiscussionDetailsFragment : ParentFragment(), Bookmarkable { @SuppressLint("SetJavaScriptEnabled") private fun setupRepliesWebView() { - setupWebView(discussionRepliesWebView) + setupWebView(discussionRepliesWebView, addDarkTheme = true) discussionRepliesWebView.addJavascriptInterface(JSDiscussionInterface(), "accessor") } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/DiscussionListFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/DiscussionListFragment.kt index d5cc36105c..928f671281 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/DiscussionListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/DiscussionListFragment.kt @@ -26,6 +26,7 @@ import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.instructure.canvasapi2.managers.CourseManager +import com.instructure.canvasapi2.managers.FeaturesManager import com.instructure.canvasapi2.managers.GroupManager import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.models.Course @@ -33,16 +34,14 @@ import com.instructure.canvasapi2.models.DiscussionTopicHeader import com.instructure.canvasapi2.models.Group import com.instructure.canvasapi2.utils.Logger import com.instructure.canvasapi2.utils.pageview.PageView -import com.instructure.canvasapi2.utils.weave.WeaveJob -import com.instructure.canvasapi2.utils.weave.awaitApi -import com.instructure.canvasapi2.utils.weave.catch -import com.instructure.canvasapi2.utils.weave.tryWeave +import com.instructure.canvasapi2.utils.weave.* import com.instructure.interactions.bookmarks.Bookmarkable import com.instructure.interactions.bookmarks.Bookmarker import com.instructure.interactions.router.Route import com.instructure.interactions.router.RouterParams import com.instructure.pandautils.analytics.SCREEN_VIEW_DISCUSSION_LIST import com.instructure.pandautils.analytics.ScreenView +import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragment import com.instructure.pandautils.utils.* import com.instructure.student.R import com.instructure.student.adapter.DiscussionListRecyclerAdapter @@ -51,15 +50,22 @@ import com.instructure.student.events.DiscussionTopicHeaderDeletedEvent import com.instructure.student.events.DiscussionTopicHeaderEvent import com.instructure.student.events.DiscussionUpdatedEvent import com.instructure.student.router.RouteMatcher +import dagger.hilt.android.AndroidEntryPoint import kotlinx.android.synthetic.main.course_discussion_topic.* import kotlinx.coroutines.Job import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode +import javax.inject.Inject @ScreenView(SCREEN_VIEW_DISCUSSION_LIST) @PageView(url = "{canvasContext}/discussion_topics") +@AndroidEntryPoint open class DiscussionListFragment : ParentFragment(), Bookmarkable { + + @Inject + lateinit var featureFlagProvider: FeatureFlagProvider + protected var canvasContext: CanvasContext by ParcelableArg(key = Const.CANVAS_CONTEXT) private lateinit var recyclerAdapter: DiscussionListRecyclerAdapter @@ -70,6 +76,9 @@ open class DiscussionListFragment : ParentFragment(), Bookmarkable { private var permissionJob: Job? = null private var canPost: Boolean = false private var groupsJob: WeaveJob? = null + private var featureFlagsJob: WeaveJob? = null + + private var discussionRedesignEnabled = false protected open val isAnnouncement: Boolean get() = false @@ -78,6 +87,7 @@ open class DiscussionListFragment : ParentFragment(), Bookmarkable { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) checkForPermission() + checkFeatureFlags() retainInstance = true } @@ -89,12 +99,21 @@ open class DiscussionListFragment : ParentFragment(), Bookmarkable { // If the discussion/announcement hasn't been published take them back to the publish screen if (model.groupTopicChildren.isNotEmpty()) { groupsJob = tryWeave { - DiscussionDetailsFragment.getDiscussionGroup(model)?.let { - RouteMatcher.route(requireActivity(), DiscussionDetailsFragment.makeRoute(it.first, it.second, groupDiscussion = true)) - } ?: RouteMatcher.route(requireActivity(), DiscussionDetailsFragment.makeRoute(canvasContext, model)) + if (discussionRedesignEnabled) { + RouteMatcher.route(requireActivity(), DiscussionDetailsWebViewFragment.makeRoute(canvasContext, model)) + } else { + DiscussionDetailsFragment.getDiscussionGroup(model)?.let { + RouteMatcher.route(requireActivity(), DiscussionDetailsFragment.makeRoute(it.first, it.second, groupDiscussion = true)) + } + ?: RouteMatcher.route(requireActivity(), DiscussionDetailsFragment.makeRoute(canvasContext, model)) + } }.catch { } } else { - RouteMatcher.route(requireActivity(), DiscussionDetailsFragment.makeRoute(canvasContext, model)) + if (discussionRedesignEnabled) { + RouteMatcher.route(requireActivity(), DiscussionDetailsWebViewFragment.makeRoute(canvasContext, model)) + } else { + RouteMatcher.route(requireActivity(), DiscussionDetailsFragment.makeRoute(canvasContext, model)) + } } } @@ -215,6 +234,7 @@ open class DiscussionListFragment : ParentFragment(), Bookmarkable { override fun onDestroyView() { super.onDestroyView() permissionJob?.cancel() + featureFlagsJob?.cancel() recyclerAdapter.cancel() } //endregion @@ -237,7 +257,7 @@ open class DiscussionListFragment : ParentFragment(), Bookmarkable { } recyclerAdapter.searchQuery = query } - ViewStyler.themeToolbar(requireActivity(), discussionListToolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), discussionListToolbar, canvasContext) } override fun title(): String = getString(R.string.discussion) @@ -248,6 +268,20 @@ open class DiscussionListFragment : ParentFragment(), Bookmarkable { //endregion + private fun checkFeatureFlags() { + featureFlagsJob = weave { + if (canvasContext.isCourse) { + val featureFlags = FeaturesManager.getEnabledFeaturesForCourseAsync(canvasContext.id, true).await().dataOrNull + discussionRedesignEnabled = featureFlags?.contains("react_discussions_post") ?: false && featureFlagProvider.getDiscussionRedesignFeatureFlag() + } + + if (canvasContext.isGroup) { + val featureFlags = FeaturesManager.getEnabledFeaturesForCourseAsync((canvasContext as Group).courseId, true).await().dataOrNull + discussionRedesignEnabled = featureFlags?.contains("react_discussions_post") ?: false && featureFlagProvider.getDiscussionRedesignFeatureFlag() + } + } + } + private fun checkForPermission() { permissionJob = tryWeave { val permission = if(canvasContext.isCourse) { diff --git a/apps/student/src/main/java/com/instructure/student/fragment/DiscussionsReplyFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/DiscussionsReplyFragment.kt index f87ce82ba4..1fa11d9664 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/DiscussionsReplyFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/DiscussionsReplyFragment.kt @@ -18,7 +18,6 @@ package com.instructure.student.fragment import android.app.Activity import android.content.Intent -import android.graphics.Color import android.os.Bundle import android.view.* import com.instructure.canvasapi2.managers.DiscussionManager @@ -138,7 +137,7 @@ class DiscussionsReplyFragment : ParentFragment() { } else { toolbar.setMenu(R.menu.menu_discussion_reply_no_attach, menuItemCallback) } - ViewStyler.themeToolbarBottomSheet(requireActivity(), isTablet, toolbar, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) ViewStyler.setToolbarElevationSmall(requireContext(), toolbar) } //endregion diff --git a/apps/student/src/main/java/com/instructure/student/fragment/DiscussionsUpdateFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/DiscussionsUpdateFragment.kt index 129f1498c4..7cb31be38b 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/DiscussionsUpdateFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/DiscussionsUpdateFragment.kt @@ -16,7 +16,6 @@ */ package com.instructure.student.fragment -import android.graphics.Color import android.os.Bundle import android.view.* import android.widget.Toast @@ -101,7 +100,7 @@ class DiscussionsUpdateFragment : ParentFragment() { } } toolbar.setMenu(R.menu.menu_discussion_update, menuItemCallback) - ViewStyler.themeToolbarBottomSheet(requireActivity(), isTablet, toolbar, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) ViewStyler.setToolbarElevationSmall(requireContext(), toolbar) } //endregion 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 a46e95bbfd..1943616e0d 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 @@ -19,7 +19,6 @@ package com.instructure.student.fragment import android.app.Activity import android.content.Intent -import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.MenuItem @@ -123,7 +122,7 @@ class EditPageDetailsFragment : ParentFragment() { ThemePrefs.brandColor, ThemePrefs.buttonColor ) // when the RCE editor has focus we want the label to be darker so it matches the title's functionality - pageRCEView.setLabel(pageDescLabel, R.color.defaultTextDark, R.color.defaultTextGray) + pageRCEView.setLabel(pageDescLabel, R.color.textDarkest, R.color.textDark) } private fun savePage() { @@ -175,7 +174,7 @@ class EditPageDetailsFragment : ParentFragment() { } toolbar.title = page.title setupToolbarMenu(toolbar, R.menu.menu_edit_page) - ViewStyler.themeToolbarBottomSheet(requireActivity(), isTablet, toolbar, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) ViewStyler.setToolbarElevationSmall(requireContext(), toolbar) with(saveMenuButton) { setIcon(0) diff --git a/apps/student/src/main/java/com/instructure/student/fragment/FileDetailsFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/FileDetailsFragment.kt index d9dfd67a88..fd294e1e48 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/FileDetailsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/FileDetailsFragment.kt @@ -102,7 +102,7 @@ class FileDetailsFragment : ParentFragment() { override fun applyTheme() { setupToolbarMenu(toolbar) toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) ViewStyler.themeButton(openButton) ViewStyler.themeButton(downloadButton) } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/FileListFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/FileListFragment.kt index 577ffb4660..198877c353 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/FileListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/FileListFragment.kt @@ -16,10 +16,8 @@ */ package com.instructure.student.fragment -import android.app.AlertDialog import android.content.DialogInterface import android.content.res.Configuration -import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.MenuItem @@ -28,6 +26,7 @@ import android.view.ViewGroup import android.view.ViewGroup.MarginLayoutParams import android.view.animation.AnimationUtils import android.widget.Toast +import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.PopupMenu import androidx.fragment.app.DialogFragment import com.instructure.canvasapi2.managers.FileFolderManager @@ -236,11 +235,11 @@ class FileListFragment : ParentFragment(), Bookmarkable { private fun themeToolbar() { // We style the toolbar white for user files if (canvasContext.type == CanvasContext.Type.USER) { - ViewStyler.themeProgressBar(fileLoadingProgressBar, Color.BLACK) - ViewStyler.themeToolbar(requireActivity(), toolbar, Color.WHITE, Color.BLACK, false) + ViewStyler.themeProgressBar(fileLoadingProgressBar, requireContext().getColor(R.color.textDarkest)) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) } else { - ViewStyler.themeProgressBar(fileLoadingProgressBar, Color.WHITE) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeProgressBar(fileLoadingProgressBar, requireContext().getColor(R.color.white)) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/GradesListFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/GradesListFragment.kt index 153557067a..1dc47c199e 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/GradesListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/GradesListFragment.kt @@ -120,7 +120,7 @@ class GradesListFragment : ParentFragment(), Bookmarkable { setupToolbarMenu(toolbar) toolbar.title = title() toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, course) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, course) } override fun onConfigurationChanged(newConfig: Configuration) { @@ -131,7 +131,7 @@ class GradesListFragment : ParentFragment(), Bookmarkable { 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.canvasTextDark)) + val lockDrawable = ColorKeeper.getColoredDrawable(requireContext(), R.drawable.ic_lock, ContextCompat.getColor(requireContext(), R.color.textDarkest)) lockedGradeImage.setImageDrawable(lockDrawable) setupListeners() diff --git a/apps/student/src/main/java/com/instructure/student/fragment/InboxComposeMessageFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/InboxComposeMessageFragment.kt index 96856a23c8..2af3db8363 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/InboxComposeMessageFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/InboxComposeMessageFragment.kt @@ -15,7 +15,6 @@ */ package com.instructure.student.fragment -import android.graphics.Color import android.os.Bundle import android.text.TextUtils import android.view.LayoutInflater @@ -95,8 +94,8 @@ class InboxComposeMessageFragment : ParentFragment() { override fun applyTheme() { ColorUtils.colorIt(ThemePrefs.buttonColor, contactsImageButton) ViewStyler.themeSwitch(requireContext(), sendIndividualSwitch, ThemePrefs.brandColor) - ViewStyler.themeToolbarBottomSheet(requireActivity(), isTablet, toolbar, Color.BLACK, false) - ViewStyler.themeProgressBar(savingProgressBar, Color.BLACK) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) + ViewStyler.themeProgressBar(savingProgressBar, requireContext().getColor(R.color.textDarkest)) } private fun validateMessage() = when { 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 9189148ba7..97412d4cdf 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 @@ -197,7 +197,7 @@ class InboxConversationFragment : ParentFragment() { } override fun applyTheme() { - ViewStyler.themeToolbar(requireActivity(), toolbar, ThemePrefs.primaryColor, ThemePrefs.primaryTextColor) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, ThemePrefs.primaryColor, ThemePrefs.primaryTextColor) } private fun setupViews() { diff --git a/apps/student/src/main/java/com/instructure/student/fragment/InboxFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/InboxFragment.kt index c4219a0daa..2721d36458 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/InboxFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/InboxFragment.kt @@ -241,7 +241,7 @@ class InboxFragment : ParentFragment() { override fun applyTheme() { setupToolbarMenu(toolbar, R.menu.menu_filter_inbox) - ViewStyler.themeToolbar(requireActivity(), toolbar, ThemePrefs.primaryColor, ThemePrefs.primaryTextColor) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, ThemePrefs.primaryColor, ThemePrefs.primaryTextColor) addMessage.backgroundTintList = ViewStyler.makeColorStateListForButton() } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/InboxRecipientsFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/InboxRecipientsFragment.kt index b8b62e2498..f9dc8353c6 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/InboxRecipientsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/InboxRecipientsFragment.kt @@ -15,7 +15,6 @@ */ package com.instructure.student.fragment -import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -46,7 +45,7 @@ class InboxRecipientsFragment : ParentFragment() { override fun applyTheme() { (view?.findViewById(R.id.menu_done) as? TextView)?.setTextColor(ThemePrefs.buttonColor) - ViewStyler.themeToolbarBottomSheet(requireActivity(), isTablet, toolbar, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) } private val adapter: InboxRecipientAdapter by lazy { 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 1b28415c83..87cfc2e54e 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 @@ -43,7 +43,6 @@ import com.instructure.interactions.router.Route import com.instructure.pandautils.utils.* import com.instructure.pandautils.views.CanvasWebView import com.instructure.student.R -import com.instructure.student.activity.InternalWebViewActivity import com.instructure.student.router.RouteMatcher import com.instructure.student.util.FileDownloadJobIntentService import kotlinx.android.synthetic.main.fragment_webview.* @@ -104,6 +103,7 @@ open class InternalWebviewFragment : ParentFragment() { originalUserAgentString = canvasWebView.settings.userAgentString canvasWebView.settings.userAgentString = ApiPrefs.userAgent canvasWebView.setInitialScale(100) + canvasWebView.setDarkModeSupport(webThemeDarkeningOnly = true) webViewLoading?.setVisible(true) canvasWebView.canvasWebChromeClientCallback = object : CanvasWebView.CanvasWebChromeClientCallback { @@ -255,7 +255,7 @@ open class InternalWebviewFragment : ParentFragment() { override fun applyTheme() { toolbar.title = title() toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } override fun title(): String = title ?: canvasContext.name ?: "" @@ -324,13 +324,6 @@ open class InternalWebviewFragment : ParentFragment() { } } - // BaseURL is set as Referer. Referer needed for some vimeo videos to play - fun loadHtml(html: String) { - canvasWebView?.loadDataWithBaseURL(ApiPrefs.fullDomain, - FileUtils.getAssetsFile(requireContext(), "html_wrapper.html").replace("{\$CONTENT$}", html, ignoreCase = false), - "text/html", "UTF-8", null) - } - fun loadHtml(data: String, mimeType: String, encoding: String, historyUrl: String?) { // BaseURL is set as Referer. Referer needed for some vimeo videos to play canvasWebView?.loadDataWithBaseURL(CanvasWebView.getReferrer(), data, mimeType, encoding, historyUrl) @@ -338,7 +331,7 @@ open class InternalWebviewFragment : ParentFragment() { fun loadUrl(targetUrl: String?) { if (!html.isNullOrBlank()) { - loadHtml(html!!) + canvasWebView?.loadHtml(html!!, title ?: "") return } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/MasteryPathSelectionFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/MasteryPathSelectionFragment.kt index aa121dcb91..8decfefc31 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/MasteryPathSelectionFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/MasteryPathSelectionFragment.kt @@ -133,7 +133,7 @@ class MasteryPathSelectionFragment : ParentFragment() { toolbar.let { it.title = getString(R.string.chooseAssignmentPath) it.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), it, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), it, canvasContext) } } @@ -143,7 +143,7 @@ class MasteryPathSelectionFragment : ParentFragment() { private fun setupTabLayoutColors() { val color = ColorKeeper.getOrGenerateColor(canvasContext) tabLayout.setBackgroundColor(color) - tabLayout.setTabTextColors(ContextCompat.getColor(requireContext(), R.color.glassWhite), Color.WHITE) + tabLayout.setTabTextColors(ContextCompat.getColor(requireContext(), R.color.transparentWhite), requireContext().getColor(R.color.white)) } //endregion diff --git a/apps/student/src/main/java/com/instructure/student/fragment/ModuleListFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/ModuleListFragment.kt index c6d9ebe875..64695443af 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/ModuleListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/ModuleListFragment.kt @@ -121,7 +121,7 @@ class ModuleListFragment : ParentFragment(), Bookmarkable { toolbar.title = title() toolbar.setupAsBackButton(this) setupToolbarMenu(toolbar) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } //endregion diff --git a/apps/student/src/main/java/com/instructure/student/fragment/ModuleQuizDecider.kt b/apps/student/src/main/java/com/instructure/student/fragment/ModuleQuizDecider.kt index c4ad10c96f..3572c4ab65 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/ModuleQuizDecider.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/ModuleQuizDecider.kt @@ -101,7 +101,7 @@ class ModuleQuizDecider : ParentFragment() { override fun applyTheme() { toolbar.title = if (this::quiz.isInitialized) quiz.title else getString(R.string.quizzes) toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } private fun obtainQuiz() { 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 5696214ff9..a0fd308b16 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 @@ -117,6 +117,8 @@ class NotificationListFragment : ParentFragment(), Bookmarkable { cancelButton.text = getString(R.string.cancel) cancelButton.setOnClickListener { recyclerAdapter.cancelButtonClicked() } + + applyTheme() } override fun onDestroyView() { @@ -133,7 +135,7 @@ class NotificationListFragment : ParentFragment(), Bookmarkable { val canvasContext = canvasContext if (canvasContext is Course || canvasContext is Group) { toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } else { val navigation = navigation navigation?.attachNavigationDrawer(this, toolbar!!) diff --git a/apps/student/src/main/java/com/instructure/student/fragment/PageDetailsFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/PageDetailsFragment.kt index c909cf5821..a5633d7aaa 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/PageDetailsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/PageDetailsFragment.kt @@ -280,7 +280,7 @@ class PageDetailsFragment : InternalWebviewFragment(), Bookmarkable { it.menu.findItem(R.id.menu_edit).isVisible = false checkCanEdit() - ViewStyler.themeToolbar(requireActivity(), it, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), it, canvasContext) } } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/PageListFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/PageListFragment.kt index 3897bd2fea..a8bde86224 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/PageListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/PageListFragment.kt @@ -148,7 +148,7 @@ class PageListFragment : ParentFragment(), Bookmarkable { } recyclerAdapter.searchQuery = query } - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } override fun handleBackPressed() = toolbar.closeSearch() diff --git a/apps/student/src/main/java/com/instructure/student/fragment/PeopleListFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/PeopleListFragment.kt index 34d6a74314..469095174a 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/PeopleListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/PeopleListFragment.kt @@ -80,7 +80,7 @@ class PeopleListFragment : ParentFragment(), Bookmarkable { toolbar.title = title() toolbar.setupAsBackButton(this) setupToolbarMenu(toolbar) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } override val bookmark: Bookmarker diff --git a/apps/student/src/main/java/com/instructure/student/fragment/ProfileSettingsFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/ProfileSettingsFragment.kt index 92b5083497..f8c8973690 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/ProfileSettingsFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/ProfileSettingsFragment.kt @@ -21,7 +21,6 @@ import android.app.Activity import android.content.ContentValues import android.content.Context import android.content.Intent -import android.graphics.Color import android.net.Uri import android.os.Bundle import android.provider.MediaStore @@ -85,7 +84,7 @@ class ProfileSettingsFragment : ParentFragment(), LoaderManager.LoaderCallbacks< override fun applyTheme() { toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, Color.WHITE, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) } private fun setupViews() { diff --git a/apps/student/src/main/java/com/instructure/student/fragment/QuizListFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/QuizListFragment.kt index 22170385fa..a7b5f4b567 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/QuizListFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/QuizListFragment.kt @@ -87,7 +87,7 @@ class QuizListFragment : ParentFragment(), Bookmarkable { } recyclerAdapter?.searchQuery = query } - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } override fun onConfigurationChanged(newConfig: Configuration) { 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 8b5fdd8ec2..9d986319f8 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 @@ -50,6 +50,7 @@ class StudioWebViewFragment : InternalWebviewFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + getCanvasWebView()?.setDarkModeSupport() getCanvasWebView()?.addJavascriptInterface(JSInterface(), "HtmlViewer") getCanvasWebView()?.canvasWebViewClientCallback = object : CanvasWebView.CanvasWebViewClientCallback { 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 967842b34d..f1b8402c63 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 @@ -124,7 +124,7 @@ class ToDoListFragment : ParentFragment() { override fun applyTheme() { setupToolbarMenu(toolbar) - ViewStyler.themeToolbar(requireActivity(), toolbar, ThemePrefs.primaryColor, ThemePrefs.primaryTextColor) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, ThemePrefs.primaryColor, ThemePrefs.primaryTextColor) } override fun onConfigurationChanged(newConfig: Configuration) { 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 9b0ab47df8..4a67fe75e7 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 @@ -44,7 +44,7 @@ class UnknownItemFragment : ParentFragment() { override fun applyTheme() { toolbar.title = streamItem.getTitle(requireContext())?.toString().validOrNull() ?: getString(R.string.message) toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = layoutInflater.inflate(R.layout.unknown_item, container, false) diff --git a/apps/student/src/main/java/com/instructure/student/fragment/UnsupportedFeatureFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/UnsupportedFeatureFragment.kt index a199e6de56..f0ce443044 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/UnsupportedFeatureFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/UnsupportedFeatureFragment.kt @@ -47,7 +47,7 @@ open class UnsupportedFeatureFragment : ParentFragment() { override fun applyTheme() { toolbar.title = title() toolbar.setupAsBackButton(this) - ViewStyler.themeToolbar(requireActivity(), toolbar, canvasContext) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, canvasContext) initViews() } diff --git a/apps/student/src/main/java/com/instructure/student/fragment/ViewHtmlFragment.kt b/apps/student/src/main/java/com/instructure/student/fragment/ViewHtmlFragment.kt index 9437f7ab80..6afd6cb09c 100644 --- a/apps/student/src/main/java/com/instructure/student/fragment/ViewHtmlFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/fragment/ViewHtmlFragment.kt @@ -80,7 +80,7 @@ class ViewHtmlFragment : InternalWebviewFragment() { toolbar?.title = it.file.displayName } - ViewStyler.themeToolbar(requireActivity(), toolbar!!, mToolbarColor, Color.WHITE) + ViewStyler.themeToolbarColored(requireActivity(), toolbar!!, mToolbarColor, requireContext().getColor(R.color.white)) } override fun onDestroy() { 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 6715f8efe8..a1a1691432 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 @@ -77,12 +77,12 @@ class ViewImageFragment : Fragment(), ShareableFile { } if (isTablet && mToolbarColor != 0) { - ViewStyler.themeToolbar(requireActivity(), toolbar, mToolbarColor, Color.WHITE) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, mToolbarColor, requireContext().getColor(R.color.white)) } else { toolbar.setupAsBackButton { requireActivity().onBackPressed() } - ViewStyler.themeToolbar(requireActivity(), toolbar, Color.WHITE, Color.BLACK) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) ViewStyler.setToolbarElevationSmall(requireContext(), toolbar) } } @@ -123,7 +123,7 @@ class ViewImageFragment : Fragment(), ShareableFile { fun colorBackground(bitmap: Bitmap) { // Generate palette asynchronously Palette.from(bitmap).generate { palette -> - palette?.let { viewImageRootView.setBackgroundColor(it.getDarkMutedColor(Color.WHITE)) } + palette?.let { viewImageRootView.setBackgroundColor(it.getDarkMutedColor(requireContext().getColor(R.color.backgroundLightest))) } } } 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 dd3262b191..8fb74e3dd3 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 @@ -16,7 +16,6 @@ package com.instructure.student.fragment * along with this program. If not, see . */ -import android.graphics.Color import android.net.Uri import android.os.Bundle import android.view.LayoutInflater @@ -73,12 +72,12 @@ class ViewUnsupportedFileFragment : Fragment() { } if(isTablet && mToolbarColor != 0) { - ViewStyler.themeToolbar(requireActivity(), toolbar, mToolbarColor, Color.WHITE) + ViewStyler.themeToolbarColored(requireActivity(), toolbar, mToolbarColor, requireContext().getColor(R.color.white)) } else { toolbar.setupAsBackButton { requireActivity().onBackPressed() } - ViewStyler.themeToolbar(requireActivity(), toolbar, Color.WHITE, Color.BLACK) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) ViewStyler.setToolbarElevationSmall(requireContext(), toolbar) } } diff --git a/apps/student/src/main/java/com/instructure/student/holders/AssignmentViewHolder.kt b/apps/student/src/main/java/com/instructure/student/holders/AssignmentViewHolder.kt index 8a9414378e..29de8a2b17 100644 --- a/apps/student/src/main/java/com/instructure/student/holders/AssignmentViewHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/holders/AssignmentViewHolder.kt @@ -67,10 +67,8 @@ class AssignmentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val descriptionText: String? // Set description to assignment description or excused if (submission != null && submission.excused) { descriptionText = context.getString(R.string.excusedAssignment) - description.setTypeface(null, Typeface.BOLD) } else { descriptionText = BinderUtils.getHtmlAsText(assignment.description ?: "") - description.setTypeface(null, Typeface.NORMAL) } description.setTextForVisibility(descriptionText) diff --git a/apps/student/src/main/java/com/instructure/student/holders/CanvasContextViewHolder.kt b/apps/student/src/main/java/com/instructure/student/holders/CanvasContextViewHolder.kt index 8f8c272eda..b51c0df07a 100644 --- a/apps/student/src/main/java/com/instructure/student/holders/CanvasContextViewHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/holders/CanvasContextViewHolder.kt @@ -37,10 +37,10 @@ class CanvasContextViewHolder(view: View) : RecyclerView.ViewHolder(view) { if (canvasContext.id == -1L) { // This is a header, so we want it a gray color title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f) - title.setTextColor(ContextCompat.getColor(context, R.color.defaultTextGray)) + title.setTextColor(ContextCompat.getColor(context, R.color.textDark)) } else { title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f) - title.setTextColor(ContextCompat.getColor(context, R.color.defaultTextDark)) + title.setTextColor(ContextCompat.getColor(context, R.color.textDarkest)) } onClick { diff --git a/apps/student/src/main/java/com/instructure/student/holders/DiscussionListHolder.kt b/apps/student/src/main/java/com/instructure/student/holders/DiscussionListHolder.kt index 0bc3a57a86..494dbc831a 100644 --- a/apps/student/src/main/java/com/instructure/student/holders/DiscussionListHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/holders/DiscussionListHolder.kt @@ -73,7 +73,7 @@ class DiscussionListHolder(view: View) : RecyclerView.ViewHolder(view) { } if(discussionTopicHeader.lockedForUser) { - discussionIcon.setNestedIcon(R.drawable.ic_lock, ContextCompat.getColor(context, R.color.lockedDiscussionColor)) + discussionIcon.setNestedIcon(R.drawable.ic_lock, ContextCompat.getColor(context, R.color.textDark)) discussionIcon.setNestedIconContentDescription(context.getString(R.string.locked)) } else { discussionIcon.hideNestedIcon() diff --git a/apps/student/src/main/java/com/instructure/student/holders/GradeViewHolder.kt b/apps/student/src/main/java/com/instructure/student/holders/GradeViewHolder.kt index 1bd598ab01..96fb694e24 100644 --- a/apps/student/src/main/java/com/instructure/student/holders/GradeViewHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/holders/GradeViewHolder.kt @@ -76,7 +76,7 @@ class GradeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { // Configures whatIf editing boxes and listener for dialog edit.setVisible(isEdit) if (isEdit) { - edit.setImageDrawable(ColorKeeper.getColoredDrawable(context, R.drawable.ic_edit, ContextCompat.getColor(context, R.color.defaultTextDark))) + edit.setImageDrawable(ColorKeeper.getColoredDrawable(context, R.drawable.ic_edit, ContextCompat.getColor(context, R.color.textDarkest))) edit.setOnClickListener { whatIfDialogCallback.onClick(assignment, adapterPosition) } } @@ -89,11 +89,11 @@ class GradeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { if (assignment.isMissing() && !isEdit && assignment.submission?.grade == null) { submissionState.text = context.getString(R.string.missingAssignment) - submissionState.setTextColor(ContextCompat.getColor(context, R.color.canvasRed)) + submissionState.setTextColor(ContextCompat.getColor(context, R.color.textDanger)) submissionState.setVisible() } else if (!assignment.isSubmitted && !isEdit) { submissionState.text = context.getString(R.string.notSubmitted) - submissionState.setTextColor(ContextCompat.getColor(context, R.color.defaultTextGray)) + submissionState.setTextColor(ContextCompat.getColor(context, R.color.textDark)) submissionState.setVisible() } else { submissionState.setGone() diff --git a/apps/student/src/main/java/com/instructure/student/holders/InboxViewHolder.kt b/apps/student/src/main/java/com/instructure/student/holders/InboxViewHolder.kt index f5f73ea8fb..631f14c7d0 100644 --- a/apps/student/src/main/java/com/instructure/student/holders/InboxViewHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/holders/InboxViewHolder.kt @@ -43,7 +43,7 @@ class InboxViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { message.setVisible(message.text.isNotBlank()) if (conversation.hasAttachments() || conversation.hasMedia()) { - attachment.setImageDrawable(ColorUtils.colorIt(ContextCompat.getColor(context, R.color.canvasTextMedium), attachment.drawable)) + attachment.setImageDrawable(ColorUtils.colorIt(ContextCompat.getColor(context, R.color.textDark), attachment.drawable)) attachment.setVisible() } else { attachment.setGone() diff --git a/apps/student/src/main/java/com/instructure/student/holders/ModuleHeaderViewHolder.kt b/apps/student/src/main/java/com/instructure/student/holders/ModuleHeaderViewHolder.kt index 072e20808f..ad09eae5f0 100644 --- a/apps/student/src/main/java/com/instructure/student/holders/ModuleHeaderViewHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/holders/ModuleHeaderViewHolder.kt @@ -43,7 +43,7 @@ class ModuleHeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) isExpanded = expanded expandCollapse.rotation = if (isExpanded) 180f else 0f divider.setVisible(!isExpanded) - val color = ContextCompat.getColor(context, R.color.canvasTextMedium) + val color = ContextCompat.getColor(context, R.color.textDark) itemView.setOnClickListener { v -> viewHolderHeaderClicked.viewClicked(v, moduleObject) val animationType: Int diff --git a/apps/student/src/main/java/com/instructure/student/holders/ModuleViewHolder.kt b/apps/student/src/main/java/com/instructure/student/holders/ModuleViewHolder.kt index 802c58ad03..4ee969b14a 100644 --- a/apps/student/src/main/java/com/instructure/student/holders/ModuleViewHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/holders/ModuleViewHolder.kt @@ -60,10 +60,10 @@ class ModuleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { || ModuleItem.Type.ChooseAssignmentGroup.toString().equals(moduleItem.type, ignoreCase = true) ) { title.setTypeface(null, Typeface.ITALIC) - title.setTextColor(ContextCompat.getColor(context, R.color.secondaryText)) + title.setTextColor(ContextCompat.getColor(context, R.color.textDark)) } else { title.setTypeface(null, Typeface.NORMAL) - title.setTextColor(ContextCompat.getColor(context, R.color.primaryText)) + title.setTextColor(ContextCompat.getColor(context, R.color.textDarkest)) } // Description @@ -71,7 +71,7 @@ class ModuleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val requirement = moduleItem.completionRequirement!! val complete = requirement.completed description.setVisible() - description.setTextColor(ContextCompat.getColor(context, R.color.canvasTextMedium)) + description.setTextColor(ContextCompat.getColor(context, R.color.textDark)) val text: String? = when (ModuleObject.State.values().firstOrNull { it.apiString == requirement.type }) { ModuleObject.State.MustSubmit -> { if (complete) description.setTextColor(courseColor) diff --git a/apps/student/src/main/java/com/instructure/student/holders/NotificationViewHolder.kt b/apps/student/src/main/java/com/instructure/student/holders/NotificationViewHolder.kt index 04ac95e963..10c978c857 100644 --- a/apps/student/src/main/java/com/instructure/student/holders/NotificationViewHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/holders/NotificationViewHolder.kt @@ -81,9 +81,9 @@ class NotificationViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) } if (item.isChecked) { - setBackgroundColor(ContextCompat.getColor(context, R.color.lightGray)) + setBackgroundColor(ContextCompat.getColor(context, R.color.backgroundMedium)) } else { - setBackgroundColor(ContextCompat.getColor(context, R.color.canvasBackgroundWhite)) + setBackgroundColor(ContextCompat.getColor(context, R.color.backgroundLightest)) } // Icon diff --git a/apps/student/src/main/java/com/instructure/student/holders/TodoViewHolder.kt b/apps/student/src/main/java/com/instructure/student/holders/TodoViewHolder.kt index 1a68e2db98..d63156f529 100644 --- a/apps/student/src/main/java/com/instructure/student/holders/TodoViewHolder.kt +++ b/apps/student/src/main/java/com/instructure/student/holders/TodoViewHolder.kt @@ -55,12 +55,12 @@ class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { } // Get courseColor - val courseColor = item.canvasContext?.color ?: ContextCompat.getColor(context, R.color.defaultPrimary) + val courseColor = item.canvasContext?.color ?: ContextCompat.getColor(context, R.color.textDarkest) if (item.isChecked) { - setBackgroundColor(ContextCompat.getColor(context, R.color.lightGray)) + setBackgroundColor(ContextCompat.getColor(context, R.color.backgroundMedium)) } else { - setBackgroundColor(ContextCompat.getColor(context, R.color.canvasBackgroundWhite)) + setBackgroundColor(ContextCompat.getColor(context, R.color.backgroundLightest)) } var todoDetails: String? = "" diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/AssignmentDetailsPresenter.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/AssignmentDetailsPresenter.kt index 9f457ca93d..fef59aa445 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/AssignmentDetailsPresenter.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/AssignmentDetailsPresenter.kt @@ -87,7 +87,7 @@ object AssignmentDetailsPresenter : Presenter { var icon: Int - var color: Int = R.color.defaultActionColor + var color: Int = R.color.textInfo var canDelete = false return model.files.mapIndexed { index, file -> if (file.errorFlag && failedIcon != null) { icon = failedIcon - color = R.color.destructive + color = R.color.textDanger canDelete = deletableIfError } else { icon = FileUtils.getFileIcon(file.name ?: "", file.contentType ?: "") diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/file/ui/UploadStatusSubmissionView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/file/ui/UploadStatusSubmissionView.kt index 217b98014c..cd108291f1 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/file/ui/UploadStatusSubmissionView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/file/ui/UploadStatusSubmissionView.kt @@ -17,12 +17,11 @@ package com.instructure.student.mobius.assignmentDetails.submission.file.ui import android.app.Activity -import android.app.AlertDialog import android.content.res.ColorStateList -import android.graphics.Color import android.view.LayoutInflater import android.view.ViewGroup import android.widget.Toast +import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.recyclerview.widget.LinearLayoutManager import com.instructure.pandautils.utils.* @@ -59,7 +58,7 @@ class UploadStatusSubmissionView(inflater: LayoutInflater, parent: ViewGroup) : override fun onDispose() = Unit override fun applyTheme() { - ViewStyler.themeToolbarBottomSheet(context as Activity, false, toolbar, Color.BLACK, false) + ViewStyler.themeToolbarLight(context as Activity, toolbar) } override fun onConnect(output: Consumer) { @@ -148,8 +147,8 @@ class UploadStatusSubmissionView(inflater: LayoutInflater, parent: ViewGroup) : .setNegativeButton(R.string.no, null) .create() dialog?.setOnShowListener { - dialog?.getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(ContextCompat.getColor(context, R.color.destructive)) - dialog?.getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(ContextCompat.getColor(context, R.color.gray)) + dialog?.getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(ContextCompat.getColor(context, R.color.textDanger)) + dialog?.getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(ContextCompat.getColor(context, R.color.textDark)) } dialog?.setOnCancelListener { dialog = null diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/picker/ui/PickerSubmissionUploadView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/picker/ui/PickerSubmissionUploadView.kt index e3f25bffb8..c3f6868eba 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/picker/ui/PickerSubmissionUploadView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/picker/ui/PickerSubmissionUploadView.kt @@ -18,7 +18,6 @@ package com.instructure.student.mobius.assignmentDetails.submission.picker.ui import android.app.Activity import android.content.Intent -import android.graphics.Color import android.net.Uri import android.provider.MediaStore import android.view.LayoutInflater @@ -79,7 +78,7 @@ class PickerSubmissionUploadView(inflater: LayoutInflater, parent: ViewGroup, va override fun onDispose() = Unit override fun applyTheme() { - ViewStyler.themeToolbarBottomSheet(context as Activity, false, toolbar, Color.BLACK, false) + ViewStyler.themeToolbarLight(context as Activity, toolbar) } override fun render(state: PickerSubmissionUploadViewState) { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/text/ui/TextSubmissionUploadView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/text/ui/TextSubmissionUploadView.kt index da44e42f6f..e91fb711af 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/text/ui/TextSubmissionUploadView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/text/ui/TextSubmissionUploadView.kt @@ -17,7 +17,6 @@ package com.instructure.student.mobius.assignmentDetails.submission.text.ui import android.app.Activity -import android.graphics.Color import android.net.Uri import android.view.LayoutInflater import android.view.ViewGroup @@ -96,7 +95,7 @@ class TextSubmissionUploadView(inflater: LayoutInflater, parent: ViewGroup) : override fun onDispose() { } override fun applyTheme() { - ViewStyler.themeToolbarBottomSheet(context as Activity, false, toolbar, Color.BLACK, false) + ViewStyler.themeToolbarLight(context as Activity, toolbar) } fun setInitialSubmissionText(text: String?) { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/url/ui/UrlSubmissionUploadView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/url/ui/UrlSubmissionUploadView.kt index bebd6767b4..6c39eeab80 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/url/ui/UrlSubmissionUploadView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submission/url/ui/UrlSubmissionUploadView.kt @@ -69,6 +69,7 @@ class UrlSubmissionUploadView(inflater: LayoutInflater, parent: ViewGroup) : Mob override fun applyTheme() {} fun showPreviewUrl(url: String) { + urlPreviewWebView?.setVisible() urlPreviewWebView.loadUrl(url) } @@ -84,6 +85,6 @@ class UrlSubmissionUploadView(inflater: LayoutInflater, parent: ViewGroup) : Mob companion object { private const val DELAY = 400L - private const val URL_MINIMUM_LENGTH = 0 + private const val URL_MINIMUM_LENGTH = 3 } } \ No newline at end of file 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 461dc0421d..01c45a4c24 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 @@ -29,6 +29,7 @@ import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.weave.StatusCallbackError import com.instructure.canvasapi2.utils.weave.awaitApi import com.instructure.pandautils.utils.StringArg +import com.instructure.pandautils.utils.setDarkModeSupport import com.instructure.pandautils.utils.setGone import com.instructure.pandautils.utils.setVisible import com.instructure.pandautils.views.CanvasWebView @@ -57,6 +58,7 @@ class DiscussionSubmissionViewFragment : Fragment() { override fun onStart() { super.onStart() progressBar.announceForAccessibility(getString(R.string.loading)) + discussionSubmissionWebView.setDarkModeSupport() discussionSubmissionWebView.webChromeClient = object : WebChromeClient() { override fun onProgressChanged(view: WebView?, newProgress: Int) { super.onProgressChanged(view, newProgress) 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 f62cd4d44e..ac48f263c5 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 @@ -176,7 +176,14 @@ class PdfStudentSubmissionView( @SuppressLint("CommitTransaction") override fun setFragment(fragment: Fragment) { - if (isAttachedToWindow) supportFragmentManager.beginTransaction().replace(content.id, fragment).commitNowAllowingStateLoss() + if (isAttachedToWindow) supportFragmentManager.beginTransaction().replace(R.id.content, fragment).commitNowAllowingStateLoss() + } + + override fun removeContentFragment() { + val contentFragment = supportFragmentManager.findFragmentById(R.id.content) + if (contentFragment != null) { + supportFragmentManager.beginTransaction().remove(contentFragment).commitAllowingStateLoss() + } } @Subscribe(threadMode = ThreadMode.MAIN) diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/QuizSubmissionViewFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/QuizSubmissionViewFragment.kt index e0f68c096f..32f36a5687 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/QuizSubmissionViewFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/content/QuizSubmissionViewFragment.kt @@ -22,6 +22,7 @@ import android.webkit.WebView import com.instructure.pandautils.analytics.SCREEN_VIEW_QUIZ_SUBMISSION_VIEW import com.instructure.pandautils.analytics.ScreenView import com.instructure.pandautils.utils.Const +import com.instructure.pandautils.utils.setDarkModeSupport import com.instructure.pandautils.utils.setGone import com.instructure.pandautils.utils.setInvisible import com.instructure.pandautils.utils.setVisible @@ -33,7 +34,7 @@ import kotlinx.android.synthetic.main.fragment_webview.* class QuizSubmissionViewFragment : InternalWebviewFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { getCanvasLoading()?.setVisible() // Set visible so we can test it - + canvasWebView?.setDarkModeSupport() canvasWebView.setInitialScale(100) canvasWebView.setInvisible() // Set invisible so we can test it canvasWebView.webChromeClient = object : WebChromeClient() { 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 7f3f75bff1..7b2ea3a03d 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 @@ -16,7 +16,6 @@ package com.instructure.student.mobius.assignmentDetails.submissionDetails.content.emptySubmission.ui import android.app.Activity -import android.app.AlertDialog import android.app.Dialog import android.content.Intent import android.content.res.ColorStateList @@ -25,6 +24,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.appcompat.app.AlertDialog import com.instructure.canvasapi2.models.* import com.instructure.canvasapi2.utils.AnalyticsEventConstants import com.instructure.canvasapi2.utils.ApiPrefs diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/comments/ui/PendingCommentBinder.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/comments/ui/PendingCommentBinder.kt index 1b9b7e3949..10fba7785b 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/comments/ui/PendingCommentBinder.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/comments/ui/PendingCommentBinder.kt @@ -84,7 +84,7 @@ class PendingCommentBinder : BasicItemBinder { - setCommentBubbleColor(ContextCompat.getColor(context, R.color.commentBubbleIncoming)) - ContextCompat.getColor(context, R.color.defaultTextDark) + setCommentBubbleColor(ContextCompat.getColor(context, R.color.backgroundLight)) + ContextCompat.getColor(context, R.color.textDarkest) } CommentDirection.OUTGOING -> { - setCommentBubbleColor(ContextCompat.getColor(context, R.color.commentBubbleOutgoing)) - Color.WHITE + setCommentBubbleColor(ContextCompat.getColor(context, R.color.backgroundInfo)) + context.getColor(R.color.white) } } } diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/rubric/ui/CriterionRatingButton.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/rubric/ui/CriterionRatingButton.kt index cb5fc483b1..24a3982367 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/rubric/ui/CriterionRatingButton.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/submissionDetails/drawer/rubric/ui/CriterionRatingButton.kt @@ -66,7 +66,7 @@ class CriterionRatingButton(context: Context, data: RatingData, val tint: Int) : intArrayOf(android.R.attr.state_activated) to Color.WHITE, intArrayOf(android.R.attr.state_selected) to tint, intArrayOf(android.R.attr.state_pressed) to tint, - intArrayOf() to ContextCompat.getColor(context, R.color.defaultTextGray) + intArrayOf() to ContextCompat.getColor(context, R.color.textDark) ) ) @@ -139,7 +139,7 @@ class RatingButtonDrawable(context: Context, val tint: Int) : Drawable() { intArrayOf() to AnimState( padding = context.DP(2), backgroundColor = Color.TRANSPARENT, - strokeColor = ContextCompat.getColor(context, R.color.defaultTrackColor) + strokeColor = ContextCompat.getColor(context, R.color.backgroundMedium) ) ) 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 fcf67e0d1a..91f244f235 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 @@ -16,7 +16,6 @@ */ package com.instructure.student.mobius.assignmentDetails.submissionDetails.drawer.rubric.ui -import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -49,7 +48,7 @@ class SubmissionRubricDescriptionFragment : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { toolbar.title = title toolbar.setupAsBackButton(this) - ViewStyler.themeToolbarBottomSheet(requireActivity(), resources.getBoolean(R.bool.isDeviceTablet), toolbar, Color.BLACK, false) + ViewStyler.themeToolbarLight(requireActivity(), toolbar) // Show progress bar while loading description progressBar.setVisible() 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 825724e16d..ce7174fac7 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 @@ -107,7 +107,7 @@ class SubmissionDetailsView( // Tint the tab with the course color val tint = canvasContext.color drawerTabLayout.setSelectedTabIndicatorColor(tint) - drawerTabLayout.setTabTextColors(ContextCompat.getColor(context, R.color.defaultTextDark), tint) + drawerTabLayout.setTabTextColors(ContextCompat.getColor(context, R.color.textDarkest), tint) // Use 90% luminance to ensure a 'light' ripple effect that doesn't overpower the tab text val rippleTint = tint.withLuminance(0.90f).asStateList() @@ -164,7 +164,7 @@ class SubmissionDetailsView( } override fun applyTheme() { - ViewStyler.themeToolbar(context as Activity, toolbar, canvasContext) + ViewStyler.themeToolbarColored(context as Activity, toolbar, canvasContext) } override fun onConnect(output: Consumer) { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/AssignmentDetailsView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/AssignmentDetailsView.kt index d2389b6610..737bf19719 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/AssignmentDetailsView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/AssignmentDetailsView.kt @@ -17,7 +17,6 @@ package com.instructure.student.mobius.assignmentDetails.ui import android.app.Activity -import android.app.AlertDialog import android.app.Dialog import android.content.Intent import android.content.res.ColorStateList @@ -28,6 +27,7 @@ import android.view.View import android.view.ViewGroup import android.webkit.WebView import android.widget.Toast +import androidx.appcompat.app.AlertDialog import androidx.constraintlayout.widget.ConstraintSet import androidx.fragment.app.FragmentActivity import com.instructure.canvasapi2.models.* @@ -108,7 +108,7 @@ class AssignmentDetailsView( } override fun applyTheme() { - ViewStyler.themeToolbar(context as Activity, toolbar, canvasContext) + ViewStyler.themeToolbarColored(context as Activity, toolbar, canvasContext) } override fun onConnect(output: Consumer) { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/DonutChartView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/DonutChartView.kt index 0eaece4041..0a601995d4 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/DonutChartView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/DonutChartView.kt @@ -53,7 +53,7 @@ class DonutChartView(context: Context, attrs: AttributeSet) : View(context, attr /** The color of the background arc */ private val bgColor: Int = ContextCompat.getColor( context, - R.color.defaultThumbColor + R.color.textLight ) /** The animator used to animated the foreground arc from its current progress value to a new progress value. */ @@ -65,7 +65,7 @@ class DonutChartView(context: Context, attrs: AttributeSet) : View(context, attr progress = 0.65f color = ContextCompat.getColor( context, - R.color.canvasDefaultAccent + R.color.backgroundInfo ) } } diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/GradeCellViewState.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/GradeCellViewState.kt index c4ca61c27f..a2dcbf71f3 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/GradeCellViewState.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/GradeCellViewState.kt @@ -107,7 +107,7 @@ sealed class GradeCellViewState { showCompleteIcon = isComplete, showIncompleteIcon = !isComplete, grade = context.getString(if (isComplete) R.string.gradeComplete else R.string.gradeIncomplete), - accentColor = if (isComplete) accentColor else ContextCompat.getColor(context, R.color.defaultTextGray), + accentColor = if (isComplete) accentColor else ContextCompat.getColor(context, R.color.textDark), outOf = outOfText, outOfContentDescription = outOfContentDescriptionText, graphPercent = 1.0f diff --git a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/GradeStatisticsView.kt b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/GradeStatisticsView.kt index 2346becf07..d50e5ff43e 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/GradeStatisticsView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/assignmentDetails/ui/gradeCell/GradeStatisticsView.kt @@ -25,7 +25,7 @@ class GradeStatisticsView(context: Context, attrs: AttributeSet) : View(context, strokeCap = Paint.Cap.ROUND isAntiAlias = true strokeWidth = context.DP(2) - color = ContextCompat.getColor(context, R.color.defaultTrackColor) + color = ContextCompat.getColor(context, R.color.backgroundMedium) } private val darkLinePaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { @@ -33,7 +33,7 @@ class GradeStatisticsView(context: Context, attrs: AttributeSet) : View(context, strokeCap = Paint.Cap.ROUND isAntiAlias = true strokeWidth = context.DP(3) - color = ContextCompat.getColor(context, R.color.gray) + color = ContextCompat.getColor(context, R.color.textDark) } private val meanLinePaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { @@ -41,11 +41,11 @@ class GradeStatisticsView(context: Context, attrs: AttributeSet) : View(context, strokeCap = Paint.Cap.ROUND isAntiAlias = true strokeWidth = context.DP(3) - color = ContextCompat.getColor(context, R.color.darkerGray) + color = ContextCompat.getColor(context, R.color.textDarkest) } private val circlePaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = ContextCompat.getColor(context, R.color.canvasDefaultAccent) + color = ContextCompat.getColor(context, R.color.backgroundInfo) style = Paint.Style.FILL } diff --git a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsView.kt b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsView.kt index 5d34bb0033..5034590688 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_details/ui/ConferenceDetailsView.kt @@ -19,7 +19,6 @@ package com.instructure.student.mobius.conferences.conference_details.ui import android.annotation.SuppressLint import android.app.Activity import android.net.Uri -import android.os.Build import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -48,7 +47,7 @@ class ConferenceDetailsView(val canvasContext: CanvasContext, inflater: LayoutIn } override fun applyTheme() { - ViewStyler.themeToolbar(context as Activity, toolbar, canvasContext) + ViewStyler.themeToolbarColored(context as Activity, toolbar, canvasContext) } override fun onConnect(output: Consumer) { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ConferenceListPresenter.kt b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ConferenceListPresenter.kt index b6f2fb868b..6dff778f60 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ConferenceListPresenter.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ConferenceListPresenter.kt @@ -104,16 +104,16 @@ object ConferenceListPresenter : Presenter { isJoinable = true label = context.getString(R.string.inProgress) - labelTint = ContextCompat.getColor(context, R.color.publishedGreen) + labelTint = ContextCompat.getColor(context, R.color.textSuccess) } else -> { label = context.getString(R.string.notStarted) - labelTint = ContextCompat.getColor(context, R.color.defaultTextGray) + labelTint = ContextCompat.getColor(context, R.color.textDark) } } diff --git a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListView.kt b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListView.kt index 9c012970b0..df10daed03 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/conferences/conference_list/ui/ConferenceListView.kt @@ -57,7 +57,7 @@ class ConferenceListView(val canvasContext: CanvasContext, inflater: LayoutInfla } override fun applyTheme() { - ViewStyler.themeToolbar(context as Activity, toolbar, canvasContext) + ViewStyler.themeToolbarColored(context as Activity, toolbar, canvasContext) } override fun onConnect(output: Consumer) { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/elementary/ElementaryDashboardFragment.kt b/apps/student/src/main/java/com/instructure/student/mobius/elementary/ElementaryDashboardFragment.kt index 840d3a763e..52b7e27fc3 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/elementary/ElementaryDashboardFragment.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/elementary/ElementaryDashboardFragment.kt @@ -105,6 +105,8 @@ class ElementaryDashboardFragment : ParentFragment() { .add(R.id.importantDates, importantDatesFragment) .commit() } ?: addImportantDatesFragment() + + applyTheme() } private fun addImportantDatesFragment() { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/settings/pairobserver/ui/PairObserverView.kt b/apps/student/src/main/java/com/instructure/student/mobius/settings/pairobserver/ui/PairObserverView.kt index 770d7ace9b..b410e9c3e7 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/settings/pairobserver/ui/PairObserverView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/settings/pairobserver/ui/PairObserverView.kt @@ -18,7 +18,6 @@ package com.instructure.student.mobius.settings.pairobserver.ui import android.app.Activity import android.graphics.Bitmap -import android.graphics.Color import android.view.LayoutInflater import android.view.ViewGroup import androidx.fragment.app.FragmentActivity @@ -45,7 +44,7 @@ class PairObserverView(inflater: LayoutInflater, parent: ViewGroup) : } override fun applyTheme() { - ViewStyler.themeToolbar(context as Activity, toolbar, Color.WHITE, Color.BLACK, false) + ViewStyler.themeToolbarLight(context as Activity, toolbar) } override fun onConnect(output: Consumer) { diff --git a/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusView.kt b/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusView.kt index 3a120fad4b..50899ac591 100644 --- a/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusView.kt +++ b/apps/student/src/main/java/com/instructure/student/mobius/syllabus/ui/SyllabusView.kt @@ -63,7 +63,7 @@ class SyllabusView(val canvasContext: CanvasContext, inflater: LayoutInflater, p } override fun applyTheme() { - ViewStyler.themeToolbar(context as Activity, toolbar, canvasContext) + ViewStyler.themeToolbarColored(context as Activity, toolbar, canvasContext) syllabusTabLayout.setBackgroundColor(ColorKeeper.getOrGenerateColor(canvasContext)) } diff --git a/apps/student/src/main/java/com/instructure/student/navigation/DefaultNavigationBehavior.kt b/apps/student/src/main/java/com/instructure/student/navigation/DefaultNavigationBehavior.kt index 9229b7757e..7f1e4e2139 100644 --- a/apps/student/src/main/java/com/instructure/student/navigation/DefaultNavigationBehavior.kt +++ b/apps/student/src/main/java/com/instructure/student/navigation/DefaultNavigationBehavior.kt @@ -19,17 +19,22 @@ package com.instructure.student.navigation import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.interactions.router.Route +import com.instructure.pandautils.utils.FontFamily import com.instructure.student.R -import com.instructure.student.fragment.* +import com.instructure.student.fragment.CalendarFragment +import com.instructure.student.fragment.DashboardFragment +import com.instructure.student.fragment.NotificationListFragment +import com.instructure.student.fragment.ParentFragment +import com.instructure.student.fragment.ToDoListFragment -class DefaultNavigationBehavior() : NavigationBehavior { +class DefaultNavigationBehavior(private val apiPrefs: ApiPrefs) : NavigationBehavior { override val bottomNavBarFragments: List> = listOf( DashboardFragment::class.java, CalendarFragment::class.java, ToDoListFragment::class.java, NotificationListFragment::class.java, - InboxFragment::class.java + getInboxBottomBarFragment(apiPrefs) ) override val homeFragmentClass: Class = DashboardFragment::class.java @@ -40,8 +45,8 @@ class DefaultNavigationBehavior() : NavigationBehavior { override val visibleAccountMenuItems: Set = setOf(AccountMenuItem.HELP, AccountMenuItem.CHANGE_USER, AccountMenuItem.LOGOUT) - override val shouldOverrideFont: Boolean - get() = false + override val fontFamily: FontFamily + get() = FontFamily.REGULAR override val bottomBarMenu: Int = R.menu.bottom_bar_menu diff --git a/apps/student/src/main/java/com/instructure/student/navigation/ElementaryNavigationBehavior.kt b/apps/student/src/main/java/com/instructure/student/navigation/ElementaryNavigationBehavior.kt index 8e3291174c..84008582ba 100644 --- a/apps/student/src/main/java/com/instructure/student/navigation/ElementaryNavigationBehavior.kt +++ b/apps/student/src/main/java/com/instructure/student/navigation/ElementaryNavigationBehavior.kt @@ -19,18 +19,22 @@ package com.instructure.student.navigation import com.instructure.canvasapi2.models.CanvasContext import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.interactions.router.Route +import com.instructure.pandautils.utils.FontFamily import com.instructure.student.R -import com.instructure.student.fragment.* +import com.instructure.student.fragment.CalendarFragment +import com.instructure.student.fragment.NotificationListFragment +import com.instructure.student.fragment.ParentFragment +import com.instructure.student.fragment.ToDoListFragment import com.instructure.student.mobius.elementary.ElementaryDashboardFragment -class ElementaryNavigationBehavior() : NavigationBehavior { +class ElementaryNavigationBehavior(private val apiPrefs: ApiPrefs) : NavigationBehavior { override val bottomNavBarFragments: List> = listOf( ElementaryDashboardFragment::class.java, CalendarFragment::class.java, ToDoListFragment::class.java, NotificationListFragment::class.java, - InboxFragment::class.java + getInboxBottomBarFragment(apiPrefs) ) override val homeFragmentClass: Class = ElementaryDashboardFragment::class.java @@ -41,8 +45,8 @@ class ElementaryNavigationBehavior() : NavigationBehavior { override val visibleAccountMenuItems: Set = setOf(AccountMenuItem.HELP, AccountMenuItem.CHANGE_USER, AccountMenuItem.LOGOUT) - override val shouldOverrideFont: Boolean - get() = true + override val fontFamily: FontFamily + get() = FontFamily.K5 override val bottomBarMenu: Int = R.menu.bottom_bar_menu_elementary diff --git a/apps/student/src/main/java/com/instructure/student/navigation/NavigationBehavior.kt b/apps/student/src/main/java/com/instructure/student/navigation/NavigationBehavior.kt index 1c84ada09c..5cac83b310 100644 --- a/apps/student/src/main/java/com/instructure/student/navigation/NavigationBehavior.kt +++ b/apps/student/src/main/java/com/instructure/student/navigation/NavigationBehavior.kt @@ -18,7 +18,11 @@ package com.instructure.student.navigation import androidx.annotation.MenuRes import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.interactions.router.Route +import com.instructure.pandautils.utils.FontFamily +import com.instructure.student.activity.NothingToSeeHereFragment +import com.instructure.student.fragment.InboxFragment import com.instructure.student.fragment.ParentFragment interface NavigationBehavior { @@ -34,7 +38,7 @@ interface NavigationBehavior { val visibleAccountMenuItems: Set - val shouldOverrideFont: Boolean + val fontFamily: FontFamily @get:MenuRes val bottomBarMenu: Int @@ -42,6 +46,14 @@ interface NavigationBehavior { fun createHomeFragmentRoute(canvasContext: CanvasContext?): Route fun createHomeFragment(route: Route): ParentFragment + + fun getInboxBottomBarFragment(apiPrefs: ApiPrefs): Class { + return if (apiPrefs.isStudentView) { + NothingToSeeHereFragment::class.java + } else { + InboxFragment::class.java + } + } } enum class NavigationMenuItem { 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 634e3baa55..6eb681b270 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 @@ -23,8 +23,8 @@ import com.instructure.student.router.RouteMatcher class StudentWebViewRouter(val activity: FragmentActivity) : WebViewRouter { - override fun canRouteInternally(url: String): Boolean { - return RouteMatcher.canRouteInternally(activity, url, ApiPrefs.domain, routeIfPossible = false, allowUnsupported = false) + override fun canRouteInternally(url: String, routeIfPossible: Boolean): Boolean { + return RouteMatcher.canRouteInternally(activity, url, ApiPrefs.domain, routeIfPossible = routeIfPossible, allowUnsupported = false) } override fun routeInternally(url: String) { 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 71a441027c..96a48a6a7c 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 @@ -37,12 +37,12 @@ import com.instructure.canvasapi2.utils.LinkHeaders import com.instructure.canvasapi2.utils.Logger import com.instructure.interactions.router.* import com.instructure.pandautils.activities.BaseViewMediaActivity +import com.instructure.pandautils.features.discussion.details.DiscussionDetailsWebViewFragment import com.instructure.pandautils.loaders.OpenMediaAsyncTaskLoader import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.LoaderUtils import com.instructure.pandautils.utils.RouteUtils import com.instructure.pandautils.utils.nonNullArgs -import com.instructure.student.BuildConfig import com.instructure.student.R import com.instructure.student.activity.* import com.instructure.student.features.elementary.course.ElementaryCourseFragment @@ -81,7 +81,7 @@ object RouteMatcher : BaseRouteMatcher() { ////////////////////////// routes.add(Route(courseOrGroup("/"), DashboardFragment::class.java)) routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}"), CourseBrowserFragment::class.java, NotificationListFragment::class.java, Arrays.asList(":${RouterParams.RECENT_ACTIVITY}"))) // Recent Activity - if (ApiPrefs.canvasForElementary && ApiPrefs.elementaryDashboardEnabledOverride) { + if (ApiPrefs.showElementaryView) { routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}"), ElementaryCourseFragment::class.java)) } else { routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}"), CourseBrowserFragment::class.java)) @@ -95,7 +95,7 @@ object RouteMatcher : BaseRouteMatcher() { ! CAUTION: Order matters, these are purposely placed above the pages, quizzes, disscussions, assignments, and files so they are matched if query params exist and routed to Modules !!!!!!!!!!!! */ - if (ApiPrefs.canvasForElementary && ApiPrefs.elementaryDashboardEnabledOverride) { + if (ApiPrefs.showElementaryView) { routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/modules"), ElementaryCourseFragment::class.java, tabId = Tab.MODULES_ID)) } else { routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/modules"), ModuleListFragment::class.java)) @@ -114,7 +114,7 @@ object RouteMatcher : BaseRouteMatcher() { routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/notifications"), NotificationListFragment::class.java)) // Grades - if (ApiPrefs.canvasForElementary && ApiPrefs.elementaryDashboardEnabledOverride) { + if (ApiPrefs.showElementaryView) { routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/grades"), ElementaryCourseFragment::class.java, tabId = Tab.GRADES_ID)) } else { routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/grades"), GradesListFragment::class.java)) @@ -137,7 +137,7 @@ object RouteMatcher : BaseRouteMatcher() { // Discussions routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/discussion_topics"), DiscussionListFragment::class.java)) routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/discussion_topics/:${RouterParams.MESSAGE_ID}"), DiscussionListFragment::class.java, CourseModuleProgressionFragment::class.java)) - routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/discussion_topics/:${RouterParams.MESSAGE_ID}"), DiscussionListFragment::class.java, DiscussionDetailsFragment::class.java)) + routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/discussion_topics/:${RouterParams.MESSAGE_ID}"), DiscussionListFragment::class.java, DiscussionDetailsWebViewFragment::class.java)) // Pages routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/pages"), PageListFragment::class.java)) @@ -150,8 +150,10 @@ object RouteMatcher : BaseRouteMatcher() { routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/announcements"), AnnouncementListFragment::class.java)) // :message_id because it shares with discussions routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/announcements/:${RouterParams.MESSAGE_ID}"), AnnouncementListFragment::class.java, DiscussionDetailsFragment::class.java)) + routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/announcements/:${RouterParams.MESSAGE_ID}"), AnnouncementListFragment::class.java, DiscussionDetailsWebViewFragment::class.java)) // Announcements from the notifications tab routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/announcements/:${RouterParams.MESSAGE_ID}"), NotificationListFragment::class.java, DiscussionDetailsFragment::class.java)) + routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/announcements/:${RouterParams.MESSAGE_ID}"), NotificationListFragment::class.java, DiscussionDetailsWebViewFragment::class.java)) // Quiz routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/quizzes"), QuizListFragment::class.java)) 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 a4354b81a2..0fabd50ace 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.discussion.details.DiscussionDetailsWebViewFragment import com.instructure.pandautils.features.notification.preferences.NotificationPreferencesFragment import com.instructure.pandautils.utils.Const import com.instructure.student.AnnotationComments.AnnotationCommentListFragment @@ -121,6 +122,7 @@ object RouteResolver { cls.isA() -> NothingToSeeHereFragment.newInstance() cls.isA() -> AnnotationSubmissionUploadFragment.newInstance(route) cls.isA() -> NotificationPreferencesFragment.newInstance() + cls.isA() -> DiscussionDetailsWebViewFragment.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/util/BaseAppManager.kt b/apps/student/src/main/java/com/instructure/student/util/BaseAppManager.kt index fbe973da56..17cb0fbe34 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 @@ -18,6 +18,7 @@ package com.instructure.student.util import android.os.Build import android.webkit.WebView +import androidx.appcompat.app.AppCompatDelegate import androidx.core.content.ContextCompat import com.google.android.gms.analytics.GoogleAnalytics import com.google.android.gms.analytics.HitBuilders @@ -29,7 +30,9 @@ import com.instructure.canvasapi2.utils.Analytics import com.instructure.canvasapi2.utils.pageview.PageViewUploadService import com.instructure.loginapi.login.tasks.LogoutTask import com.instructure.pandautils.typeface.TypefaceBehavior +import com.instructure.pandautils.utils.AppTheme 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.flutterChannels.FlutterComm @@ -63,6 +66,9 @@ open class BaseAppManager : com.instructure.canvasapi2.AppManager(), AnalyticsEv } super.onCreate() + val appTheme = AppTheme.fromIndex(ThemePrefs.appTheme) + AppCompatDelegate.setDefaultNightMode(appTheme.nightModeType) + // Call it superstition, but I don't trust BuildConfig flags to be set correctly // in library builds. IS_TESTING, for example, does not percolate down to libraries // correctly. So I'm reading/setting these user properties here instead of canvasapi2/AppManager. @@ -82,7 +88,7 @@ open class BaseAppManager : com.instructure.canvasapi2.AppManager(), AnalyticsEv FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true) } - ColorKeeper.defaultColor = ContextCompat.getColor(this, R.color.defaultPrimary) + ColorKeeper.defaultColor = ContextCompat.getColor(this, R.color.textDarkest) // There appears to be a bug when the user is installing/updating the android webview stuff. // http://code.google.com/p/android/issues/detail?id=175124 diff --git a/apps/student/src/main/java/com/instructure/student/view/AttachmentDogEarLayout.kt b/apps/student/src/main/java/com/instructure/student/view/AttachmentDogEarLayout.kt index 1abbcd0b97..ae0e03dd3f 100644 --- a/apps/student/src/main/java/com/instructure/student/view/AttachmentDogEarLayout.kt +++ b/apps/student/src/main/java/com/instructure/student/view/AttachmentDogEarLayout.kt @@ -39,7 +39,7 @@ class AttachmentDogEarLayout @JvmOverloads constructor( } private val dogEarPaint: Paint by lazy { - Paint(Paint.ANTI_ALIAS_FLAG).apply { color = ContextCompat.getColor(context, R.color.lightGray) } + Paint(Paint.ANTI_ALIAS_FLAG).apply { color = ContextCompat.getColor(context, R.color.backgroundMedium) } } private val dogEarShadowPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = 0x33000000 } diff --git a/apps/student/src/main/java/com/instructure/student/widget/BaseRemoteViewsService.kt b/apps/student/src/main/java/com/instructure/student/widget/BaseRemoteViewsService.kt index 0ca81fdfe9..1863b747ee 100644 --- a/apps/student/src/main/java/com/instructure/student/widget/BaseRemoteViewsService.kt +++ b/apps/student/src/main/java/com/instructure/student/widget/BaseRemoteViewsService.kt @@ -32,7 +32,7 @@ abstract class BaseRemoteViewsService : RemoteViewsService() { fun getWidgetTextColor(widgetId: Int, context: Context): Int { val widgetBackgroundPref = getWidgetBackgroundPref(widgetId) return if (widgetBackgroundPref.equals(WidgetSetupActivity.WIDGET_BACKGROUND_COLOR_LIGHT, ignoreCase = true)) - ContextCompat.getColor(context, R.color.canvasTextDark) else ContextCompat.getColor(context, R.color.white) + ContextCompat.getColor(context, R.color.textDarkest) else ContextCompat.getColor(context, R.color.textLightest) } fun getWidgetBackgroundResourceId(widgetId: Int): Int { diff --git a/apps/student/src/main/java/com/instructure/student/widget/NotificationViewWidgetService.kt b/apps/student/src/main/java/com/instructure/student/widget/NotificationViewWidgetService.kt index 033dc29c81..6c63b27a39 100644 --- a/apps/student/src/main/java/com/instructure/student/widget/NotificationViewWidgetService.kt +++ b/apps/student/src/main/java/com/instructure/student/widget/NotificationViewWidgetService.kt @@ -82,7 +82,7 @@ class NotificationViewWidgetService : BaseRemoteViewsService(), Serializable { row.setInt(R.id.icon, "setColorFilter", color) } else { val color = if(streamItem.canvasContext != null) ColorKeeper.getOrGenerateColor(streamItem.canvasContext) - else ContextCompat.getColor(applicationContext, R.color.canvasRed) + else ContextCompat.getColor(applicationContext, R.color.textDanger) row.setInt(R.id.icon, "setColorFilter", color) } diff --git a/apps/student/src/main/java/com/instructure/student/widget/TodoViewWidgetService.kt b/apps/student/src/main/java/com/instructure/student/widget/TodoViewWidgetService.kt index e442ae0088..0e5eb57d5f 100644 --- a/apps/student/src/main/java/com/instructure/student/widget/TodoViewWidgetService.kt +++ b/apps/student/src/main/java/com/instructure/student/widget/TodoViewWidgetService.kt @@ -32,6 +32,7 @@ import com.instructure.canvasapi2.managers.CourseManager import com.instructure.canvasapi2.managers.GroupManager import com.instructure.canvasapi2.managers.ToDoManager import com.instructure.canvasapi2.models.CanvasContext +import com.instructure.canvasapi2.models.ScheduleItem import com.instructure.canvasapi2.models.ToDo import com.instructure.canvasapi2.utils.* import com.instructure.pandautils.utils.ColorKeeper @@ -72,7 +73,7 @@ class TodoViewWidgetService : BaseRemoteViewsService(), Serializable { if (streamItem.canvasContext != null && streamItem.canvasContext!!.type != CanvasContext.Type.USER) { row.setInt(R.id.icon, "setColorFilter", ColorKeeper.getOrGenerateColor(streamItem.canvasContext)) } else { - row.setInt(R.id.icon, "setColorFilter", R.color.canvasRed) + row.setInt(R.id.icon, "setColorFilter", R.color.textDanger) } val appWidgetId = BaseRemoteViewsService.getAppWidgetId(intent) @@ -160,14 +161,15 @@ class TodoViewWidgetService : BaseRemoteViewsService(), Serializable { .filter { it.isFavorite && !it.accessRestrictedByDate && !it.isInvited() } val groups = GroupManager.getFavoriteGroupsSynchronous(true) val todos = ToDoManager.getTodosSynchronous(ApiPrefs.user!!, true) - val events = CalendarEventManager.getUpcomingEventsSynchronous(true) + val scheduleItems = CalendarEventManager.getUpcomingEventsSynchronous(true) val courseMap = CourseManager.createCourseMap(courses) val groupMap = GroupManager.createGroupMap(groups) - val upcomingTodos = ArrayList(100) - events.forEach { upcomingTodos.add(ToDo.toDoWithScheduleItem(it)) } - val dataStream = ToDoManager.mergeToDoUpcoming(todos, upcomingTodos) + val eventTodos = scheduleItems + .filter { it.type == ScheduleItem.TYPE_EVENT } + .map { ToDo.toDoWithScheduleItem(it) } + val dataStream = mergeToDosWithEvents(todos, eventTodos) dataStream.forEach { ToDo.setContextInfo(it, courseMap, groupMap) } setData(dataStream.filter { it.canvasContext != null }) @@ -176,6 +178,15 @@ class TodoViewWidgetService : BaseRemoteViewsService(), Serializable { } } } + + private fun mergeToDosWithEvents(todoList: List?, eventList: List?): List { + val todos = todoList ?: emptyList() + val events = eventList ?: emptyList() + + // Return combined list, sorted by date + val defaultDate = Date(0) + return (todos + events).sortedBy { it.comparisonDate ?: defaultDate } + } } companion object { diff --git a/apps/student/src/main/res/drawable/bg_comment_attachment.xml b/apps/student/src/main/res/drawable/bg_comment_attachment.xml index ae81aa7482..e7e8ada3c6 100644 --- a/apps/student/src/main/res/drawable/bg_comment_attachment.xml +++ b/apps/student/src/main/res/drawable/bg_comment_attachment.xml @@ -29,7 +29,7 @@ - + diff --git a/apps/student/src/main/res/drawable/divider.xml b/apps/student/src/main/res/drawable/divider.xml index e18caf1939..cbe8447dd4 100644 --- a/apps/student/src/main/res/drawable/divider.xml +++ b/apps/student/src/main/res/drawable/divider.xml @@ -16,5 +16,5 @@ --> - + diff --git a/apps/student/src/main/res/drawable/favoriting_icon_background.xml b/apps/student/src/main/res/drawable/favoriting_icon_background.xml index 3a59ed57c2..9d476dd50b 100644 --- a/apps/student/src/main/res/drawable/favoriting_icon_background.xml +++ b/apps/student/src/main/res/drawable/favoriting_icon_background.xml @@ -18,6 +18,6 @@ - + \ No newline at end of file diff --git a/apps/student/src/main/res/drawable/grade_background.xml b/apps/student/src/main/res/drawable/grade_background.xml index 9c04b03d7f..6d1e5721f7 100644 --- a/apps/student/src/main/res/drawable/grade_background.xml +++ b/apps/student/src/main/res/drawable/grade_background.xml @@ -18,7 +18,7 @@ - + \ No newline at end of file diff --git a/apps/student/src/main/res/drawable/ic_circle.xml b/apps/student/src/main/res/drawable/ic_circle.xml index 999d04d385..219dc59fdf 100644 --- a/apps/student/src/main/res/drawable/ic_circle.xml +++ b/apps/student/src/main/res/drawable/ic_circle.xml @@ -17,6 +17,6 @@ - + diff --git a/apps/student/src/main/res/drawable/item_decorator_gray.xml b/apps/student/src/main/res/drawable/item_decorator_gray.xml index f5c2c27659..c4d1f10d9f 100644 --- a/apps/student/src/main/res/drawable/item_decorator_gray.xml +++ b/apps/student/src/main/res/drawable/item_decorator_gray.xml @@ -17,5 +17,5 @@ - + diff --git a/apps/student/src/main/res/drawable/line_divider.xml b/apps/student/src/main/res/drawable/line_divider.xml index e4ec0780e3..4728c4ff12 100644 --- a/apps/student/src/main/res/drawable/line_divider.xml +++ b/apps/student/src/main/res/drawable/line_divider.xml @@ -23,6 +23,6 @@ android:width="1dp" android:height=".5dp" /> - + \ No newline at end of file diff --git a/apps/student/src/main/res/drawable/listview_states.xml b/apps/student/src/main/res/drawable/listview_states.xml index 972a319b53..b35261769c 100644 --- a/apps/student/src/main/res/drawable/listview_states.xml +++ b/apps/student/src/main/res/drawable/listview_states.xml @@ -19,12 +19,12 @@ + android:drawable="@color/backgroundMedium"/> + android:drawable="@color/transparent"/> - + \ No newline at end of file diff --git a/apps/student/src/main/res/drawable/rounded_corner_tiara_bg.xml b/apps/student/src/main/res/drawable/rounded_corner_tiara_bg.xml index ea3ad5e7bd..7dd49c5522 100644 --- a/apps/student/src/main/res/drawable/rounded_corner_tiara_bg.xml +++ b/apps/student/src/main/res/drawable/rounded_corner_tiara_bg.xml @@ -21,7 +21,7 @@ android:shape="rectangle"> + android:color="@color/backgroundLightest" > + android:color="@color/backgroundLightest" > + android:drawable="@color/backgroundMedium" /> + android:drawable="@color/backgroundLightest" /> \ No newline at end of file diff --git a/apps/student/src/main/res/drawable/status_indicator_blue.xml b/apps/student/src/main/res/drawable/status_indicator_blue.xml index 22714ef204..dde03e4013 100644 --- a/apps/student/src/main/res/drawable/status_indicator_blue.xml +++ b/apps/student/src/main/res/drawable/status_indicator_blue.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/apps/student/src/main/res/drawable/upload_file_bg.xml b/apps/student/src/main/res/drawable/upload_file_bg.xml index 0c4c02c4c5..3c40ee20a1 100644 --- a/apps/student/src/main/res/drawable/upload_file_bg.xml +++ b/apps/student/src/main/res/drawable/upload_file_bg.xml @@ -22,7 +22,7 @@ + android:color="@color/uploadFileDialogBackground" > - + - + diff --git a/apps/student/src/main/res/layout-sw720dp/fragment_elementary_course.xml b/apps/student/src/main/res/layout-sw720dp/fragment_elementary_course.xml index bb96ab95bc..997415dc81 100644 --- a/apps/student/src/main/res/layout-sw720dp/fragment_elementary_course.xml +++ b/apps/student/src/main/res/layout-sw720dp/fragment_elementary_course.xml @@ -36,7 +36,7 @@ android:id="@+id/elementaryCoursePage" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/white"> + android:background="@color/backgroundLightest"> @@ -56,29 +56,29 @@ android:id="@+id/courseTabLayout" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="@color/white" + android:background="@color/backgroundLightest" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/toolbar" app:tabContentStart="16dp" app:tabIconTint="@color/tab_layout_icon_tint" app:tabIndicator="@drawable/tab_bar_indicator" - app:tabIndicatorColor="@color/blueAnnotation" + app:tabIndicatorColor="@color/textInfo" app:tabIndicatorFullWidth="false" app:tabIndicatorHeight="3dp" app:tabInlineLabel="true" app:tabMode="scrollable" app:tabPaddingEnd="12dp" app:tabPaddingStart="8dp" - app:tabSelectedTextColor="@color/blueAnnotation" + app:tabSelectedTextColor="@color/textInfo" app:tabTextAppearance="@android:style/TextAppearance.Widget.TabWidget" - app:tabTextColor="@color/defaultTextDark" + app:tabTextColor="@color/textDarkest" app:tabs="@{viewModel.data.tabs}" /> + tools:background="@color/backgroundWarning" /> @@ -58,23 +58,23 @@ android:id="@+id/dashboardTabLayout" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="@color/white" + android:background="@color/backgroundLightest" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/toolbar" app:tabContentStart="8dp" app:tabIconTint="@color/tab_layout_icon_tint" app:tabIndicator="@drawable/tab_bar_indicator" - app:tabIndicatorColor="@color/blueAnnotation" + app:tabIndicatorColor="@color/textInfo" app:tabIndicatorFullWidth="false" app:tabIndicatorHeight="3dp" app:tabInlineLabel="true" app:tabMode="scrollable" app:tabPaddingEnd="12dp" app:tabPaddingStart="8dp" - app:tabSelectedTextColor="@color/blueAnnotation" + app:tabSelectedTextColor="@color/textInfo" app:tabTextAppearance="@android:style/TextAppearance.Widget.TabWidget" - app:tabTextColor="@color/defaultTextDark"> + app:tabTextColor="@color/textDarkest"> + app:titleTextColor="@color/textDarkest"> @@ -64,7 +64,7 @@ android:id="@+id/imageView" android:layout_width="0dp" android:layout_height="0dp" - android:background="@color/canvasBackgroundMedium" + android:background="@color/backgroundMedium" app:bitmap="@{viewModel.data.selectedBitmap}" app:layout_constraintBottom_toTopOf="@+id/filters" app:layout_constraintEnd_toEndOf="parent" @@ -75,7 +75,7 @@ android:id="@+id/filters" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@color/white" + android:background="@color/backgroundLightest" android:orientation="horizontal" app:itemViewModels="@{viewModel.data.filterItemViewModels}" app:layout_constraintBottom_toBottomOf="parent" /> diff --git a/apps/student/src/main/res/layout/activity_navigation.xml b/apps/student/src/main/res/layout/activity_navigation.xml index 6423d17983..40ac2489bc 100644 --- a/apps/student/src/main/res/layout/activity_navigation.xml +++ b/apps/student/src/main/res/layout/activity_navigation.xml @@ -21,7 +21,7 @@ android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/canvasBackgroundWhite"> + android:background="@color/backgroundLightest"> - - diff --git a/apps/student/src/main/res/layout/activity_settings.xml b/apps/student/src/main/res/layout/activity_settings.xml index 7fb4e6b362..0a10a2ed51 100644 --- a/apps/student/src/main/res/layout/activity_settings.xml +++ b/apps/student/src/main/res/layout/activity_settings.xml @@ -19,7 +19,7 @@ android:id="@+id/fragmentContainer" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/canvasBackgroundWhite"> + android:background="@color/backgroundLightest"> + android:background="@color/studentDocumentSharingColor"/> 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 d906aea209..ce779a49cb 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 @@ -21,13 +21,13 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:background="@color/white"> + android:background="@color/backgroundLightest"> + app:clv_override_color="@color/backgroundDarkest"/> \ No newline at end of file diff --git a/apps/student/src/main/res/layout/activity_video_view.xml b/apps/student/src/main/res/layout/activity_video_view.xml index 09e6b37be6..9a8ba4b2da 100644 --- a/apps/student/src/main/res/layout/activity_video_view.xml +++ b/apps/student/src/main/res/layout/activity_video_view.xml @@ -18,7 +18,7 @@ + android:background="@color/black"> @@ -63,7 +63,7 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/light" - android:textColor="@color/black" /> + android:textColor="@color/textDarkest" /> @@ -73,7 +73,7 @@ android:layout_height="wrap_content" android:layout_weight="1" android:foreground="?android:attr/selectableItemBackground" - app:cardBackgroundColor="@color/widgetDarkColor" + app:cardBackgroundColor="@color/backgroundDarkest" app:cardElevation="8dp" app:cardUseCompatPadding="true" app:contentPadding="8dp"> @@ -83,7 +83,7 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/dark" - android:textColor="@color/widgetLightColor" /> + android:textColor="@color/backgroundLightest" /> @@ -95,7 +95,7 @@ android:layout_height="wrap_content" android:checked="false" android:text="@string/widgetMinimumStyle" - app:backgroundTint="@color/widgetDarkColor" /> + app:backgroundTint="@color/backgroundDarkest" /> diff --git a/apps/student/src/main/res/layout/adapter_conference_header.xml b/apps/student/src/main/res/layout/adapter_conference_header.xml index db54bf374e..1b3e831814 100644 --- a/apps/student/src/main/res/layout/adapter_conference_header.xml +++ b/apps/student/src/main/res/layout/adapter_conference_header.xml @@ -30,7 +30,7 @@ android:ellipsize="end" android:maxLines="2" android:textSize="12sp" - android:textColor="@color/defaultTextGray" + android:textColor="@color/textDark" tools:text="New Conferences" /> diff --git a/apps/student/src/main/res/layout/adapter_conference_item.xml b/apps/student/src/main/res/layout/adapter_conference_item.xml index efe5d03b74..1f60cadb02 100644 --- a/apps/student/src/main/res/layout/adapter_conference_item.xml +++ b/apps/student/src/main/res/layout/adapter_conference_item.xml @@ -50,7 +50,7 @@ style="@style/TextFont.Regular" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textColor="@color/defaultTextGray" + android:textColor="@color/textDark" tools:text="Not Started" /> diff --git a/apps/student/src/main/res/layout/adapter_conference_list_empty.xml b/apps/student/src/main/res/layout/adapter_conference_list_empty.xml index f8bb3b74d0..187078251f 100644 --- a/apps/student/src/main/res/layout/adapter_conference_list_empty.xml +++ b/apps/student/src/main/res/layout/adapter_conference_list_empty.xml @@ -37,7 +37,7 @@ android:layout_marginTop="32dp" android:gravity="center" android:text="@string/noConferencesTitle" - android:textColor="@color/defaultTextDark" + android:textColor="@color/textDarkest" android:textSize="20sp" android:textStyle="bold"/> @@ -48,7 +48,7 @@ android:layout_marginTop="8dp" android:gravity="center" android:text="@string/noConferencesMessage" - android:textColor="@color/defaultTextGray" + android:textColor="@color/textDark" android:textSize="16sp"/> diff --git a/apps/student/src/main/res/layout/adapter_conference_list_error.xml b/apps/student/src/main/res/layout/adapter_conference_list_error.xml index 83af673105..b9e4327bb1 100644 --- a/apps/student/src/main/res/layout/adapter_conference_list_error.xml +++ b/apps/student/src/main/res/layout/adapter_conference_list_error.xml @@ -27,7 +27,7 @@ android:layout_gravity="center_horizontal" android:importantForAccessibility="no" android:src="@drawable/ic_warning" - android:tint="@color/alertRed" /> + android:tint="@color/textDanger" />