Skip to content

Commit

Permalink
[Student][Hotfix-6.7.1] Cherry pick student view unsupported feature …
Browse files Browse the repository at this point in the history
…screen (#798)
  • Loading branch information
StephenBrough authored May 13, 2020
1 parent 911a080 commit b49b9e7
Show file tree
Hide file tree
Showing 11 changed files with 566 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,14 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog.
addFragment(NotificationListFragment.newInstance(route), route)
}
AppShortcutManager.APP_SHORTCUT_INBOX -> {
val route = InboxFragment.makeRoute()
addFragment(InboxFragment.newInstance(route), route)
if (ApiPrefs.isStudentView) {
// Inbox not available in Student View
val route = NothingToSeeHereFragment.makeRoute()
addFragment(NothingToSeeHereFragment.newInstance(), route)
} else {
val route = InboxFragment.makeRoute()
addFragment(InboxFragment.newInstance(route), route)
}
}
}
}
Expand Down Expand Up @@ -487,15 +493,21 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog.
addFragment(NotificationListFragment.newInstance(route), route)
}
R.id.bottomNavigationInbox -> {
val route = InboxFragment.makeRoute()
addFragment(InboxFragment.newInstance(route), route)
if (ApiPrefs.isStudentView) {
// Inbox not available in Student View
val route = NothingToSeeHereFragment.makeRoute()
addFragment(NothingToSeeHereFragment.newInstance(), route)
} else {
val route = InboxFragment.makeRoute()
addFragment(InboxFragment.newInstance(route), route)
}
}
}
true
}

private val bottomBarItemReselectedListener = BottomNavigationView.OnNavigationItemReselectedListener { item: MenuItem ->
//if the top fragment != courses, calendar, to-do, notifications, inbox then load the item
// If the top fragment != courses, calendar, to-do, notifications, inbox then load the item

var abortReselect = true
topFragment?.let {
Expand All @@ -522,8 +534,14 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog.
addFragment(NotificationListFragment.newInstance(route), route)
}
R.id.bottomNavigationInbox -> {
val route = InboxFragment.makeRoute()
addFragment(InboxFragment.newInstance(route), route)
if (ApiPrefs.isStudentView) {
// Inbox not available in Student View
val route = NothingToSeeHereFragment.makeRoute()
addFragment(NothingToSeeHereFragment.newInstance(), route)
} else {
val route = InboxFragment.makeRoute()
addFragment(InboxFragment.newInstance(route), route)
}
}
}
}
Expand Down Expand Up @@ -629,7 +647,7 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog.
}

override fun handleRoute(route: Route) {
if(routeJob?.isActive == true) return
if (routeJob?.isActive == true) return

routeJob = tryWeave {
if(route.routeContext == RouteContext.EXTERNAL) showLoadingIndicator()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* 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.activity

import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.instructure.interactions.router.Route
import com.instructure.pandautils.utils.ViewStyler
import com.instructure.pandautils.utils.setupAsBackButton
import com.instructure.student.R
import com.instructure.student.fragment.ParentFragment
import kotlinx.android.synthetic.main.fragment_nothing_to_see_here.*

class NothingToSeeHereFragment : ParentFragment() {

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
inflater.inflate(R.layout.fragment_nothing_to_see_here, container, false)

override fun title() = "" // Don't need this

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
applyTheme()
}

override fun applyTheme() {
toolbar.setupAsBackButton(this)
ViewStyler.themeToolbar(requireActivity(), toolbar, Color.WHITE, Color.BLACK, false)
}

companion object {
fun newInstance(): NothingToSeeHereFragment {
return NothingToSeeHereFragment()
}

@JvmStatic
fun makeRoute() = Route(NothingToSeeHereFragment::class.java, null)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class CourseBrowserViewHolder(view: View, val color: Int) : RecyclerView.ViewHol
Tab.COLLABORATIONS_ID -> R.drawable.vd_collaborations
Tab.SETTINGS_ID -> R.drawable.vd_settings
else -> {
// Determine if its the attendance tool
// Determine if it's the attendance tool
if (tab.type == Tab.TYPE_EXTERNAL) {
R.drawable.vd_lti
} else R.drawable.vd_canvas_logo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.instructure.pandautils.fragments.RemoteConfigParamsFragment
import com.instructure.pandautils.utils.*
import com.instructure.student.BuildConfig
import com.instructure.student.R
import com.instructure.student.activity.NothingToSeeHereFragment
import com.instructure.student.activity.NotificationPreferencesActivity
import com.instructure.student.activity.SettingsActivity
import com.instructure.student.dialog.HelpDialogStyled
Expand Down Expand Up @@ -70,7 +71,16 @@ class ApplicationSettingsFragment : ParentFragment() {

@SuppressLint("SetTextI18n")
private fun setupViews() {
profileSettings.onClick { addFragment(ProfileSettingsFragment.newInstance()) }
profileSettings.onClick {
val frag = if (ApiPrefs.isStudentView) {
// Profile settings not available in Student View
NothingToSeeHereFragment.newInstance()
} else {
ProfileSettingsFragment.newInstance()
}

addFragment(frag)
}
accountPreferences.onClick { addFragment(AccountPreferencesFragment.newInstance()) }
legal.onClick { LegalDialogStyled().show(requireFragmentManager(), LegalDialogStyled.TAG) }
help.onClick { HelpDialogStyled.show(requireActivity()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ object RouteMatcher : BaseRouteMatcher() {
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/modules/items/:${RouterParams.MODULE_ITEM_ID}"), ModuleListFragment::class.java)) // Just route to modules list. API does not have a way to fetch a module item without knowing the module id (even though web canvas can do it)
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/modules/:${RouterParams.MODULE_ID}"), ModuleListFragment::class.java))

routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/pages/:${RouterParams.PAGE_ID}"), ModuleListFragment::class.java, CourseModuleProgressionFragment::class.java, Arrays.asList(":${RouterParams.MODULE_ITEM_ID}")))
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/quizzes/:${RouterParams.QUIZ_ID}"), ModuleListFragment::class.java, CourseModuleProgressionFragment::class.java, Arrays.asList(":${RouterParams.MODULE_ITEM_ID}")))
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/discussion_topics/:${RouterParams.MESSAGE_ID}"), ModuleListFragment::class.java, CourseModuleProgressionFragment::class.java, Arrays.asList(":${RouterParams.MODULE_ITEM_ID}")))
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/assignments/:${RouterParams.ASSIGNMENT_ID}"), ModuleListFragment::class.java, CourseModuleProgressionFragment::class.java, Arrays.asList(":${RouterParams.MODULE_ITEM_ID}")))
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/files/:${RouterParams.FILE_ID}"), ModuleListFragment::class.java, CourseModuleProgressionFragment::class.java, Arrays.asList(":${RouterParams.MODULE_ITEM_ID}"))) // TODO TEST
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/pages/:${RouterParams.PAGE_ID}"), ModuleListFragment::class.java, CourseModuleProgressionFragment::class.java, listOf(":${RouterParams.MODULE_ITEM_ID}")))
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/quizzes/:${RouterParams.QUIZ_ID}"), ModuleListFragment::class.java, CourseModuleProgressionFragment::class.java, listOf(":${RouterParams.MODULE_ITEM_ID}")))
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/discussion_topics/:${RouterParams.MESSAGE_ID}"), ModuleListFragment::class.java, CourseModuleProgressionFragment::class.java, listOf(":${RouterParams.MODULE_ITEM_ID}")))
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/assignments/:${RouterParams.ASSIGNMENT_ID}"), ModuleListFragment::class.java, CourseModuleProgressionFragment::class.java, listOf(":${RouterParams.MODULE_ITEM_ID}")))
routes.add(Route(courseOrGroup("/:${RouterParams.COURSE_ID}/files/:${RouterParams.FILE_ID}"), ModuleListFragment::class.java, CourseModuleProgressionFragment::class.java, listOf(":${RouterParams.MODULE_ITEM_ID}"))) // TODO TEST
// endregion

// Notifications
Expand Down Expand Up @@ -218,6 +218,14 @@ object RouteMatcher : BaseRouteMatcher() {
//One or two classes? (F, or M/D)

val route = getInternalRoute(url, domain)

// Prevent routing to unsupported features while in student view
if (ApiPrefs.isStudentView &&
(route?.primaryClass == InboxFragment::class.java ||
route?.tabId == Tab.CONFERENCES_ID || route?.tabId == Tab.COLLABORATIONS_ID)) {
route.primaryClass = NothingToSeeHereFragment::class.java
}

extras?.let { route?.arguments?.putAll(it) }

// The Group API will not load an individual user's details, so we route to the List fragment by default
Expand All @@ -235,7 +243,7 @@ object RouteMatcher : BaseRouteMatcher() {

if (route == null || route.routeContext == RouteContext.DO_NOT_ROUTE) {
if (route?.uri != null) {
//No route, no problem
// No route, no problem
handleWebViewUrl(context, route.uri.toString())
}
} else if (route.routeContext == RouteContext.FILE || route.primaryClass?.isAssignableFrom(FileListFragment::class.java) == true && route.queryParamsHash.containsKey(RouterParams.PREVIEW)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.instructure.canvasapi2.models.CanvasContext
import com.instructure.interactions.router.Route
import com.instructure.pandautils.utils.Const
import com.instructure.student.AnnotationComments.AnnotationCommentListFragment
import com.instructure.student.activity.NothingToSeeHereFragment
import com.instructure.student.features.files.search.FileSearchFragment
import com.instructure.student.fragment.*
import com.instructure.student.mobius.assignmentDetails.submission.file.ui.UploadStatusSubmissionFragment
Expand Down Expand Up @@ -116,6 +117,7 @@ object RouteResolver {
cls.isA<PickerSubmissionUploadFragment>() -> PickerSubmissionUploadFragment.newInstance(route)
cls.isA<UploadStatusSubmissionFragment>() -> UploadStatusSubmissionFragment.newInstance(route)
cls.isA<AnnotationCommentListFragment>() -> AnnotationCommentListFragment.newInstance(route)
cls.isA<NothingToSeeHereFragment>() -> NothingToSeeHereFragment.newInstance()
cls.isA<InternalWebviewFragment>() -> InternalWebviewFragment.newInstance(route) // Keep this at the end
else -> null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ import com.instructure.canvasapi2.models.CanvasContext
import com.instructure.canvasapi2.models.Course
import com.instructure.canvasapi2.models.Page
import com.instructure.canvasapi2.models.Tab
import com.instructure.canvasapi2.utils.ApiPrefs
import com.instructure.canvasapi2.utils.ContextKeeper
import com.instructure.canvasapi2.utils.validOrNull
import com.instructure.interactions.router.Route
import com.instructure.student.R
import com.instructure.student.activity.NothingToSeeHereFragment
import com.instructure.student.fragment.*
import com.instructure.student.mobius.conferences.conference_list.ui.ConferenceListFragment
import com.instructure.student.mobius.syllabus.ui.SyllabusFragment
Expand Down Expand Up @@ -62,6 +64,14 @@ object TabHelper {
fun getRouteByTabId(tabb: Tab?, canvasContext: CanvasContext): Route? {
val tab = tabb ?: Tab(Tab.HOME_ID, "")

// Student view doesn't support groups, collaborations, or external LTIs from the Course Browser
if (ApiPrefs.isStudentView) {
if (tab.tabId == Tab.CONFERENCES_ID || tab.tabId == Tab.COLLABORATIONS_ID ||
tab.type == Tab.TYPE_EXTERNAL) {
return NothingToSeeHereFragment.makeRoute()
}
}

val isCourse = canvasContext is Course
var tabId = tab.tabId.validOrNull() ?: (canvasContext as Course).homePageID

Expand Down Expand Up @@ -91,7 +101,7 @@ object TabHelper {
Tab.SETTINGS_ID -> CourseSettingsFragment.makeRoute(canvasContext)
Tab.NOTIFICATIONS_ID -> NotificationListFragment.makeRoute(canvasContext)
else -> when {
// We just care if it's external, some external tabs (Attendance) have an id after "external"
// We just care if it's external, some external tabs (Attendance) have an id after "external"
tabId.contains(Tab.TYPE_EXTERNAL) -> LTIWebViewFragment.makeRoute(canvasContext, tab)
else -> null
}
Expand Down
87 changes: 87 additions & 0 deletions apps/student/src/main/res/layout/fragment_nothing_to_see_here.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2020 - present Instructure, Inc.
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, version 3 of the License.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
~
-->

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/canvasBackgroundWhite">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="@android:color/white"
android:elevation="6dp"
app:popupTheme="@style/ToolBarPopupStyle"
app:theme="@style/ToolBarStyle"
app:title="@string/unsupportedFeature"
app:titleTextColor="@color/defaultTextDark" />


<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="32dp">

<ImageView
android:id="@+id/iconImageView"
android:layout_width="234dp"
android:layout_height="200dp"
android:layout_marginBottom="32dp"
android:importantForAccessibility="no"
android:scaleType="fitCenter"
app:layout_constraintBottom_toTopOf="@+id/titleTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
app:srcCompat="@drawable/vd_panda_nothing_to_see" />

<TextView
android:id="@+id/titleTextView"
style="@style/TextFont.Medium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nothingToSeeHere"
android:textColor="#2D3B45"
android:textSize="24sp"
app:layout_constraintBottom_toTopOf="@+id/messageTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/iconImageView" />

<TextView
android:id="@+id/messageTextView"
style="@style/TextFont.Regular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/featureNotAllowedInStudentView"
android:textColor="@color/defaultTextDark"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/titleTextView" />

</androidx.constraintlayout.widget.ConstraintLayout>


</FrameLayout>
Loading

0 comments on commit b49b9e7

Please sign in to comment.