Skip to content

Commit c393f18

Browse files
kristofnemereclaude
andcommitted
[MBL-19842][Parent] Always show Front Page tab if it has content
The parent app was only showing the Front Page tab when the course home was set to Wiki/Front Page. For Canvas for Elementary courses, the home setting can't be changed back once modified, so the Front Page tab was never shown even though a front page existed. Fix: fetch the front page and show the tab whenever it has content, regardless of the course home setting. Also decouple syllabus visibility from front page visibility so both tabs can appear independently. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 489552c commit c393f18

5 files changed

Lines changed: 140 additions & 9 deletions

File tree

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package com.instructure.parentapp.di.feature
1919

2020
import com.instructure.canvasapi2.apis.CourseAPI
21+
import com.instructure.canvasapi2.apis.PageAPI
2122
import com.instructure.canvasapi2.apis.TabAPI
2223
import com.instructure.parentapp.features.courses.details.CourseDetailsRepository
2324
import dagger.Module
@@ -33,8 +34,9 @@ class CourseDetailsModule {
3334
@Provides
3435
fun provideCourseDetailsRepository(
3536
courseApi: CourseAPI.CoursesInterface,
36-
tabsInterface: TabAPI.TabsInterface
37+
tabsInterface: TabAPI.TabsInterface,
38+
pageApi: PageAPI.PagesInterface
3739
): CourseDetailsRepository {
38-
return CourseDetailsRepository(courseApi, tabsInterface)
40+
return CourseDetailsRepository(courseApi, tabsInterface, pageApi)
3941
}
4042
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,19 @@
1818
package com.instructure.parentapp.features.courses.details
1919

2020
import com.instructure.canvasapi2.apis.CourseAPI
21+
import com.instructure.canvasapi2.apis.PageAPI
2122
import com.instructure.canvasapi2.apis.TabAPI
2223
import com.instructure.canvasapi2.builders.RestParams
2324
import com.instructure.canvasapi2.models.CanvasContext
2425
import com.instructure.canvasapi2.models.Course
26+
import com.instructure.canvasapi2.models.Page
2527
import com.instructure.canvasapi2.models.Tab
2628

2729

2830
class CourseDetailsRepository(
2931
private val courseApi: CourseAPI.CoursesInterface,
30-
private val tabApi: TabAPI.TabsInterface
32+
private val tabApi: TabAPI.TabsInterface,
33+
private val pageApi: PageAPI.PagesInterface
3134
) {
3235

3336
suspend fun getCourse(id: Long, forceRefresh: Boolean): Course {
@@ -39,4 +42,9 @@ class CourseDetailsRepository(
3942
val params = RestParams(isForceReadFromNetwork = forceRefresh)
4043
return tabApi.getTabs(id, CanvasContext.Type.COURSE.apiString, params).dataOrThrow
4144
}
45+
46+
suspend fun getFrontPage(courseId: Long, forceRefresh: Boolean): Page? {
47+
val params = RestParams(isForceReadFromNetwork = forceRefresh)
48+
return pageApi.getFrontPage(CanvasContext.Type.COURSE.apiString, courseId, params).dataOrNull
49+
}
4250
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,18 @@ class CourseDetailsViewModel @Inject constructor(
7979

8080
val course = repository.getCourse(courseId, forceRefresh)
8181
val tabs = repository.getCourseTabs(courseId, forceRefresh)
82+
val frontPage = repository.getFrontPage(courseId, forceRefresh)
8283

83-
val hasHomePageAsFrontPage = course.homePage == Course.HomePage.HOME_WIKI
84+
val showFrontPageTab = !frontPage?.body.isNullOrEmpty()
8485

8586
val showSyllabusTab = !course.syllabusBody.isNullOrEmpty() &&
86-
(course.homePage == Course.HomePage.HOME_SYLLABUS ||
87-
(!hasHomePageAsFrontPage && tabs.any { it.tabId == Tab.SYLLABUS_ID }))
87+
(course.homePage == Course.HomePage.HOME_SYLLABUS || tabs.any { it.tabId == Tab.SYLLABUS_ID })
8888

8989
val showSummary = showSyllabusTab && course.settings?.courseSummary.orDefault()
9090

9191
val tabTypes = buildList {
9292
add(TabType.GRADES)
93-
if (hasHomePageAsFrontPage) add(TabType.FRONT_PAGE)
93+
if (showFrontPageTab) add(TabType.FRONT_PAGE)
9494
if (showSyllabusTab) add(TabType.SYLLABUS)
9595
if (showSummary) add(TabType.SUMMARY)
9696
}

apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/CourseDetailsRepositoryTest.kt

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
package com.instructure.parentapp.features.courses.details
1919

2020
import com.instructure.canvasapi2.apis.CourseAPI
21+
import com.instructure.canvasapi2.apis.PageAPI
2122
import com.instructure.canvasapi2.apis.TabAPI
2223
import com.instructure.canvasapi2.builders.RestParams
2324
import com.instructure.canvasapi2.models.CanvasContext
2425
import com.instructure.canvasapi2.models.Course
26+
import com.instructure.canvasapi2.models.Page
2527
import com.instructure.canvasapi2.models.Tab
2628
import com.instructure.canvasapi2.utils.DataResult
2729
import io.mockk.coEvery
@@ -35,8 +37,9 @@ class CourseDetailsRepositoryTest {
3537

3638
private val courseApi: CourseAPI.CoursesInterface = mockk(relaxed = true)
3739
private val tabApi: TabAPI.TabsInterface = mockk(relaxed = true)
40+
private val pageApi: PageAPI.PagesInterface = mockk(relaxed = true)
3841

39-
private val repository = CourseDetailsRepository(courseApi, tabApi)
42+
private val repository = CourseDetailsRepository(courseApi, tabApi, pageApi)
4043

4144
@Test
4245
fun `Get course details successfully returns data`() = runTest {
@@ -85,4 +88,34 @@ class CourseDetailsRepositoryTest {
8588

8689
repository.getCourseTabs(1L, true)
8790
}
91+
92+
@Test
93+
fun `Get front page successfully returns page`() = runTest {
94+
val expected = Page(body = "Front page content")
95+
96+
coEvery {
97+
pageApi.getFrontPage(
98+
CanvasContext.Type.COURSE.apiString,
99+
1L,
100+
RestParams(isForceReadFromNetwork = false)
101+
)
102+
} returns DataResult.Success(expected)
103+
104+
val result = repository.getFrontPage(1L, false)
105+
Assert.assertEquals(expected, result)
106+
}
107+
108+
@Test
109+
fun `Get front page returns null when fails`() = runTest {
110+
coEvery {
111+
pageApi.getFrontPage(
112+
CanvasContext.Type.COURSE.apiString,
113+
1L,
114+
RestParams(isForceReadFromNetwork = false)
115+
)
116+
} returns DataResult.Fail()
117+
118+
val result = repository.getFrontPage(1L, false)
119+
Assert.assertNull(result)
120+
}
88121
}

apps/parent/src/test/java/com/instructure/parentapp/features/courses/details/CourseDetailsViewModelTest.kt

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import androidx.lifecycle.LifecycleRegistry
2525
import androidx.lifecycle.SavedStateHandle
2626
import com.instructure.canvasapi2.models.Course
2727
import com.instructure.canvasapi2.models.CourseSettings
28+
import com.instructure.canvasapi2.models.Page
2829
import com.instructure.canvasapi2.models.Tab
2930
import com.instructure.canvasapi2.models.User
3031
import com.instructure.canvasapi2.type.EnrollmentType
@@ -98,8 +99,9 @@ class CourseDetailsViewModelTest {
9899

99100
@Test
100101
fun `Load course details with front page tab`() = runTest {
101-
coEvery { repository.getCourse(1, any()) } returns Course(id = 1, name = "Course 1", homePage = Course.HomePage.HOME_WIKI)
102+
coEvery { repository.getCourse(1, any()) } returns Course(id = 1, name = "Course 1")
102103
coEvery { repository.getCourseTabs(1, any()) } returns listOf(Tab("tab1"))
104+
coEvery { repository.getFrontPage(1, any()) } returns Page(body = "Front page content")
103105

104106
createViewModel()
105107

@@ -115,6 +117,92 @@ class CourseDetailsViewModelTest {
115117
Assert.assertEquals(expected, viewModel.uiState.value)
116118
}
117119

120+
@Test
121+
fun `Front page tab not shown when front page body is empty`() = runTest {
122+
coEvery { repository.getCourse(1, any()) } returns Course(id = 1, name = "Course 1")
123+
coEvery { repository.getCourseTabs(1, any()) } returns listOf(Tab("tab1"))
124+
coEvery { repository.getFrontPage(1, any()) } returns Page(body = "")
125+
126+
createViewModel()
127+
128+
val expected = CourseDetailsUiState(
129+
courseName = "Course 1",
130+
studentColor = 1,
131+
isLoading = false,
132+
isError = false,
133+
tabs = listOf(TabType.GRADES),
134+
baseUrl = "domain/courses/1"
135+
)
136+
137+
Assert.assertEquals(expected, viewModel.uiState.value)
138+
}
139+
140+
@Test
141+
fun `Front page tab not shown when no front page`() = runTest {
142+
coEvery { repository.getCourse(1, any()) } returns Course(id = 1, name = "Course 1")
143+
coEvery { repository.getCourseTabs(1, any()) } returns listOf(Tab("tab1"))
144+
coEvery { repository.getFrontPage(1, any()) } returns null
145+
146+
createViewModel()
147+
148+
val expected = CourseDetailsUiState(
149+
courseName = "Course 1",
150+
studentColor = 1,
151+
isLoading = false,
152+
isError = false,
153+
tabs = listOf(TabType.GRADES),
154+
baseUrl = "domain/courses/1"
155+
)
156+
157+
Assert.assertEquals(expected, viewModel.uiState.value)
158+
}
159+
160+
@Test
161+
fun `Front page tab shown when default view is not front page`() = runTest {
162+
coEvery { repository.getCourse(1, any()) } returns Course(id = 1, name = "Course 1", homePage = Course.HomePage.HOME_ASSIGNMENTS)
163+
coEvery { repository.getCourseTabs(1, any()) } returns listOf(Tab("tab1"))
164+
coEvery { repository.getFrontPage(1, any()) } returns Page(body = "Front page content")
165+
166+
createViewModel()
167+
168+
val expected = CourseDetailsUiState(
169+
courseName = "Course 1",
170+
studentColor = 1,
171+
isLoading = false,
172+
isError = false,
173+
tabs = listOf(TabType.GRADES, TabType.FRONT_PAGE),
174+
baseUrl = "domain/courses/1"
175+
)
176+
177+
Assert.assertEquals(expected, viewModel.uiState.value)
178+
}
179+
180+
@Test
181+
fun `Front page tab shown alongside syllabus tab`() = runTest {
182+
coEvery { repository.getCourse(1, any()) } returns Course(
183+
id = 1,
184+
name = "Course 1",
185+
homePage = Course.HomePage.HOME_SYLLABUS,
186+
syllabusBody = "Syllabus body"
187+
)
188+
coEvery { repository.getCourseTabs(1, any()) } returns listOf(Tab(Tab.SYLLABUS_ID))
189+
coEvery { repository.getFrontPage(1, any()) } returns Page(body = "Front page content")
190+
191+
createViewModel()
192+
193+
val expected = CourseDetailsUiState(
194+
courseName = "Course 1",
195+
studentColor = 1,
196+
isLoading = false,
197+
isError = false,
198+
tabs = listOf(TabType.GRADES, TabType.FRONT_PAGE, TabType.SYLLABUS),
199+
syllabus = "Syllabus body",
200+
baseUrl = "domain/courses/1"
201+
)
202+
203+
Assert.assertEquals(expected, viewModel.uiState.value)
204+
}
205+
118206
@Test
119207
fun `Load course details with syllabus tab`() = runTest {
120208
coEvery { repository.getCourse(1, any()) } returns Course(

0 commit comments

Comments
 (0)