From 48d04e204032ebcde7fe0f8d1617623d3e89722a Mon Sep 17 00:00:00 2001 From: omerhabib26 Date: Sat, 27 Jan 2024 03:08:59 +0500 Subject: [PATCH 1/8] feat: added PLS banner for shift dates on Course Dashboard - Banner added on course dashboard if its type is RESET_DATES and course is still available. --- .../org/openedx/core/data/api/CourseApi.kt | 3 + .../openedx/core/data/model/CourseDates.kt | 18 ++-- .../domain/model/CourseDatesBannerInfo.kt | 4 + core/src/main/res/values/strings.xml | 7 +- .../data/repository/CourseRepository.kt | 3 + .../domain/interactor/CourseInteractor.kt | 2 + .../container/CourseContainerAdapter.kt | 2 + .../container/CourseContainerFragment.kt | 25 ++++++ .../presentation/dates/CourseDatesFragment.kt | 4 + .../presentation/info/CourseInfoFragment.kt | 4 +- .../outline/CourseOutlineFragment.kt | 90 ++++++++++++++++--- .../outline/CourseOutlineUIState.kt | 4 +- .../outline/CourseOutlineViewModel.kt | 33 ++++++- .../course/presentation/ui/CourseUI.kt | 83 ++++++++++++++--- .../presentation/program/ProgramFragment.kt | 4 +- 15 files changed, 247 insertions(+), 39 deletions(-) diff --git a/core/src/main/java/org/openedx/core/data/api/CourseApi.kt b/core/src/main/java/org/openedx/core/data/api/CourseApi.kt index 365bfbc6e..5a0b9445a 100644 --- a/core/src/main/java/org/openedx/core/data/api/CourseApi.kt +++ b/core/src/main/java/org/openedx/core/data/api/CourseApi.kt @@ -71,6 +71,9 @@ interface CourseApi { @POST("/api/course_experience/v1/reset_course_deadlines") suspend fun resetCourseDates(@Body courseBody: Map): ResetCourseDates + @GET("/api/course_experience/v1/course_deadlines_info/{course_id}") + suspend fun getDatesBannerInfo(@Path("course_id") courseId: String): CourseDates + @GET("/api/mobile/v1/course_info/{course_id}/handouts") suspend fun getHandouts(@Path("course_id") courseId: String): HandoutsModel diff --git a/core/src/main/java/org/openedx/core/data/model/CourseDates.kt b/core/src/main/java/org/openedx/core/data/model/CourseDates.kt index 3b31ccd77..49448cdbc 100644 --- a/core/src/main/java/org/openedx/core/data/model/CourseDates.kt +++ b/core/src/main/java/org/openedx/core/data/model/CourseDates.kt @@ -22,13 +22,17 @@ data class CourseDates( fun getCourseDatesResult(): CourseDatesResult { return CourseDatesResult( datesSection = getStructuredCourseDates(), - courseBanner = CourseDatesBannerInfo( - missedDeadlines = datesBannerInfo?.missedDeadlines ?: false, - missedGatedContent = datesBannerInfo?.missedGatedContent ?: false, - verifiedUpgradeLink = datesBannerInfo?.verifiedUpgradeLink ?: "", - contentTypeGatingEnabled = datesBannerInfo?.contentTypeGatingEnabled ?: false, - hasEnded = hasEnded, - ) + courseBanner = getDatesBannerInfo(), + ) + } + + fun getDatesBannerInfo(): CourseDatesBannerInfo { + return CourseDatesBannerInfo( + missedDeadlines = datesBannerInfo?.missedDeadlines ?: false, + missedGatedContent = datesBannerInfo?.missedGatedContent ?: false, + verifiedUpgradeLink = datesBannerInfo?.verifiedUpgradeLink ?: "", + contentTypeGatingEnabled = datesBannerInfo?.contentTypeGatingEnabled ?: false, + hasEnded = hasEnded, ) } diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt b/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt index ffcecd02b..7020e3e16 100644 --- a/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt +++ b/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt @@ -25,6 +25,10 @@ data class CourseDatesBannerInfo( return selfPacedAvailable || instructorPacedAvailable } + fun isBannerAvailableForDashboard(): Boolean { + return hasEnded.not() && bannerType == RESET_DATES + } + private fun getCourseBannerType(): CourseBannerType = when { canUpgradeToGraded() -> UPGRADE_TO_GRADED canUpgradeToReset() -> UPGRADE_TO_RESET diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 4592272ff..6b77b5b11 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -72,8 +72,8 @@ Continue Leaving the app You are now leaving the %s app and opening a browser. - Enrollment Error - We are unable to enroll you in this course at this time using the %s mobile application. Please try again on your web browser. + Enrollment Error + We are unable to enroll you in this course at this time using the %s mobile application. Please try again on your web browser. @@ -100,6 +100,9 @@ We built a suggested schedule to help you stay on track. But don’t worry – it’s flexible so you can learn at your own pace. If you happen to fall behind, you’ll be able to adjust the dates to keep yourself on track. To complete graded assignments as part of this course, you can upgrade today. You are auditing this course, which means that you are unable to participate in graded assignments. It looks like you missed some important deadlines based on our suggested schedule. To complete graded assignments as part of this course and shift the past due assignments into the future, you can upgrade today. + Your due dates have been successfully shifted to help you stay on track. + Your dates could not be shifted. Please try again. + View all dates Register Sign in diff --git a/course/src/main/java/org/openedx/course/data/repository/CourseRepository.kt b/course/src/main/java/org/openedx/course/data/repository/CourseRepository.kt index a3157fc1e..a608c2945 100644 --- a/course/src/main/java/org/openedx/course/data/repository/CourseRepository.kt +++ b/course/src/main/java/org/openedx/course/data/repository/CourseRepository.kt @@ -106,6 +106,9 @@ class CourseRepository( suspend fun resetCourseDates(courseId: String) = api.resetCourseDates(mapOf(ApiConstants.COURSE_KEY to courseId)).mapToDomain() + suspend fun getDatesBannerInfo(courseId: String) = + api.getDatesBannerInfo(courseId).getDatesBannerInfo() + suspend fun getHandouts(courseId: String) = api.getHandouts(courseId).mapToDomain() suspend fun getAnnouncements(courseId: String) = diff --git a/course/src/main/java/org/openedx/course/domain/interactor/CourseInteractor.kt b/course/src/main/java/org/openedx/course/domain/interactor/CourseInteractor.kt index d3c640831..8b0fb0f03 100644 --- a/course/src/main/java/org/openedx/course/domain/interactor/CourseInteractor.kt +++ b/course/src/main/java/org/openedx/course/domain/interactor/CourseInteractor.kt @@ -76,6 +76,8 @@ class CourseInteractor( suspend fun resetCourseDates(courseId: String) = repository.resetCourseDates(courseId) + suspend fun getDatesBannerInfo(courseId: String) = repository.getDatesBannerInfo(courseId) + suspend fun getHandouts(courseId: String) = repository.getHandouts(courseId) suspend fun getAnnouncements(courseId: String) = repository.getAnnouncements(courseId) diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt index 80a383143..14f1daf96 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt @@ -14,4 +14,6 @@ class CourseContainerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment fun addFragment(fragment: Fragment) { fragments.add(fragment) } + + fun getFragment(position: Int): Fragment = fragments[position] } \ No newline at end of file diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt index d681de59d..68d638058 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt @@ -21,6 +21,7 @@ import org.openedx.course.presentation.outline.CourseOutlineFragment import org.openedx.course.presentation.ui.CourseToolbar import org.openedx.course.presentation.videos.CourseVideosFragment import org.openedx.discussion.presentation.topics.DiscussionTopicsFragment +import org.openedx.core.R as coreR class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { @@ -155,6 +156,30 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { viewModel.updateData(withSwipeRefresh) } + fun showDatesUpdateSnackbar(isSuccess: Boolean) { + val message = if (isSuccess) { + getString(coreR.string.core_dates_shift_dates_successfully_msg) + } else { + getString(coreR.string.core_dates_shift_dates_unsuccessful_msg) + } + val duration = if (isSuccess) { + Snackbar.LENGTH_INDEFINITE + } else { + Snackbar.LENGTH_LONG + } + snackBar = Snackbar.make(binding.root, message, duration).also { + if (isSuccess) { + it.setAction(coreR.string.core_dates_view_all_dates) { + binding.viewPager.setCurrentItem(3, true) + adapter?.getFragment(3)?.let { fragment -> + (fragment as CourseDatesFragment).updateData() + } + } + } + } + snackBar?.show() + } + companion object { private const val ARG_COURSE_ID = "courseId" private const val ARG_TITLE = "title" diff --git a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt index 0f1bfd324..2d7bca572 100644 --- a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt @@ -163,6 +163,10 @@ class CourseDatesFragment : Fragment() { } } + fun updateData() { + viewModel.getCourseDates() + } + companion object { private const val ARG_COURSE_ID = "courseId" private const val ARG_IS_SELF_PACED = "selfPaced" diff --git a/course/src/main/java/org/openedx/course/presentation/info/CourseInfoFragment.kt b/course/src/main/java/org/openedx/course/presentation/info/CourseInfoFragment.kt index 0f84d2143..852b3a5ca 100644 --- a/course/src/main/java/org/openedx/course/presentation/info/CourseInfoFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/info/CourseInfoFragment.kt @@ -82,9 +82,9 @@ class CourseInfoFragment : Fragment() { LaunchedEffect(showAlert) { if (showAlert) { InfoDialogFragment.newInstance( - title = context.getString(CoreR.string.course_enrollment_error), + title = context.getString(CoreR.string.core_enrollment_error), message = context.getString( - CoreR.string.course_enrollment_error_message, + CoreR.string.core_enrollment_error_message, getString(CoreR.string.platform_name) ) ).show( diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt index e025f083f..7d442727a 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt @@ -6,16 +6,41 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material.* +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Divider +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Surface +import androidx.compose.material.Text import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState -import androidx.compose.runtime.* +import androidx.compose.material.rememberScaffoldState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView @@ -37,16 +62,27 @@ import org.openedx.core.R import org.openedx.core.UIMessage import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.BlockCounts +import org.openedx.core.domain.model.CourseDatesBannerInfo import org.openedx.core.domain.model.CourseStructure import org.openedx.core.domain.model.CoursewareAccess import org.openedx.core.presentation.course.CourseViewMode -import org.openedx.core.ui.* +import org.openedx.core.ui.HandleUIMessage +import org.openedx.core.ui.OfflineModeDialog +import org.openedx.core.ui.OpenEdXButton +import org.openedx.core.ui.TextIcon +import org.openedx.core.ui.WindowSize +import org.openedx.core.ui.WindowType +import org.openedx.core.ui.displayCutoutForLandscape +import org.openedx.core.ui.rememberWindowSize import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors import org.openedx.core.ui.theme.appTypography +import org.openedx.core.ui.windowSizeValue import org.openedx.course.presentation.CourseRouter import org.openedx.course.presentation.container.CourseContainerFragment import org.openedx.course.presentation.outline.CourseOutlineFragment.Companion.getUnitBlockIcon +import org.openedx.course.presentation.ui.CourseDatesBanner +import org.openedx.course.presentation.ui.CourseDatesBannerTablet import org.openedx.course.presentation.ui.CourseExpandableChapterCard import org.openedx.course.presentation.ui.CourseImageHeader import org.openedx.course.presentation.ui.CourseSectionCard @@ -153,6 +189,11 @@ class CourseOutlineFragment : Fragment() { .replace(Regex("\\s"), "_"), it.id ) } + }, + onResetDatesClick = { + viewModel.resetCourseDatesBanner(onResetDates = { + (parentFragment as CourseContainerFragment).showDatesUpdateSnackbar(it) + }) } ) } @@ -204,7 +245,8 @@ internal fun CourseOutlineScreen( onExpandClick: (Block) -> Unit, onSubSectionClick: (Block) -> Unit, onResumeClick: (String) -> Unit, - onDownloadClick: (Block) -> Unit + onDownloadClick: (Block) -> Unit, + onResetDatesClick: () -> Unit, ) { val scaffoldState = rememberScaffoldState() val pullRefreshState = @@ -291,6 +333,30 @@ internal fun CourseOutlineScreen( ) } } + uiState.datesBannerInfo?.let { + if (it.isBannerAvailableForDashboard()) { + item { + Box( + modifier = Modifier + .padding(all = 6.dp) + ) { + if (windowSize.isTablet) { + CourseDatesBannerTablet( + modifier = Modifier.padding(bottom = 16.dp), + banner = it, + resetDates = onResetDatesClick, + ) + } else { + CourseDatesBanner( + modifier = Modifier.padding(bottom = 16.dp), + banner = it, + resetDates = onResetDatesClick, + ) + } + } + } + } + } if (uiState.resumeComponent != null) { item { Spacer(Modifier.height(28.dp)) @@ -503,7 +569,7 @@ private fun ResumeCourseTablet( } } OpenEdXButton( - width = Modifier.width(194.dp), + width = Modifier.width(210.dp), text = stringResource(id = org.openedx.course.R.string.course_resume), onClick = { onResumeClick(block.id) @@ -533,7 +599,8 @@ private fun CourseOutlineScreenPreview() { mockChapterBlock, mapOf(), mapOf(), - mapOf() + mapOf(), + CourseDatesBannerInfo(false, false, "", false, false) ), apiHostUrl = "", isCourseNestedListEnabled = true, @@ -547,7 +614,8 @@ private fun CourseOutlineScreenPreview() { onSubSectionClick = {}, onResumeClick = {}, onReloadClick = {}, - onDownloadClick = {} + onDownloadClick = {}, + onResetDatesClick = {}, ) } } @@ -565,7 +633,8 @@ private fun CourseOutlineScreenTabletPreview() { mockChapterBlock, mapOf(), mapOf(), - mapOf() + mapOf(), + CourseDatesBannerInfo(false, false, "", false, false) ), apiHostUrl = "", isCourseNestedListEnabled = true, @@ -579,7 +648,8 @@ private fun CourseOutlineScreenTabletPreview() { onSubSectionClick = {}, onResumeClick = {}, onReloadClick = {}, - onDownloadClick = {} + onDownloadClick = {}, + onResetDatesClick = {}, ) } } diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineUIState.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineUIState.kt index ac35057bb..b4be4c4ee 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineUIState.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineUIState.kt @@ -1,6 +1,7 @@ package org.openedx.course.presentation.outline import org.openedx.core.domain.model.Block +import org.openedx.core.domain.model.CourseDatesBannerInfo import org.openedx.core.domain.model.CourseStructure import org.openedx.core.module.db.DownloadedState @@ -11,7 +12,8 @@ sealed class CourseOutlineUIState { val resumeComponent: Block?, val courseSubSections: Map>, val courseSectionsState: Map, - val subSectionsDownloadsCount: Map + val subSectionsDownloadsCount: Map, + val datesBannerInfo: CourseDatesBannerInfo?, ) : CourseOutlineUIState() object Loading : CourseOutlineUIState() diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt index ee3105968..3f26c9ef8 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt @@ -94,7 +94,8 @@ class CourseOutlineViewModel( resumeComponent = state.resumeComponent, courseSubSections = courseSubSections, courseSectionsState = state.courseSectionsState, - subSectionsDownloadsCount = subSectionsDownloadsCount + subSectionsDownloadsCount = subSectionsDownloadsCount, + datesBannerInfo = state.datesBannerInfo, ) } } @@ -144,7 +145,8 @@ class CourseOutlineViewModel( resumeComponent = state.resumeComponent, courseSubSections = courseSubSections, courseSectionsState = courseSectionsState, - subSectionsDownloadsCount = subSectionsDownloadsCount + subSectionsDownloadsCount = subSectionsDownloadsCount, + datesBannerInfo = state.datesBannerInfo, ) courseSectionsState[blockId] ?: false @@ -165,6 +167,12 @@ class CourseOutlineViewModel( } else { CourseComponentStatus("") } + + val datesBannerInfo = if (networkConnection.isOnline()) { + interactor.getDatesBannerInfo(courseId) + } else { + null + } setBlocks(blocks) courseSubSections.clear() courseSubSectionUnit.clear() @@ -180,7 +188,8 @@ class CourseOutlineViewModel( resumeComponent = getResumeBlock(blocks, courseStatus.lastVisitedBlockId), courseSubSections = courseSubSections, courseSectionsState = courseSectionsState, - subSectionsDownloadsCount = subSectionsDownloadsCount + subSectionsDownloadsCount = subSectionsDownloadsCount, + datesBannerInfo = datesBannerInfo, ) } catch (e: Exception) { if (e.isInternetError()) { @@ -236,6 +245,24 @@ class CourseOutlineViewModel( return resumeBlock } + fun resetCourseDatesBanner(onResetDates: (Boolean) -> Unit) { + viewModelScope.launch { + try { + interactor.resetCourseDates(courseId = courseId) + onResetDates(true) + } catch (e: Exception) { + if (e.isInternetError()) { + _uiMessage.value = + UIMessage.SnackBarMessage(resourceManager.getString(R.string.core_error_no_connection)) + } else { + _uiMessage.value = + UIMessage.SnackBarMessage(resourceManager.getString(R.string.core_error_unknown_error)) + } + onResetDates(false) + } + } + } + fun resumeCourseTappedEvent(blockId: String) { val currentState = uiState.value if (currentState is CourseOutlineUIState.CourseData) { diff --git a/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt b/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt index 98b463ed5..d64997ceb 100644 --- a/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt +++ b/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt @@ -66,6 +66,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -87,6 +88,7 @@ import org.openedx.core.extension.nonZero import org.openedx.core.module.db.DownloadedState import org.openedx.core.ui.BackBtn import org.openedx.core.ui.IconText +import org.openedx.core.ui.OpenEdXButton import org.openedx.core.ui.OpenEdXOutlinedButton import org.openedx.core.ui.WindowSize import org.openedx.core.ui.WindowType @@ -996,6 +998,7 @@ fun CourseDatesBanner( banner.bannerType.bodyResId.nonZero()?.let { Text( + modifier = Modifier.padding(bottom = 8.dp), text = stringResource(id = it), style = MaterialTheme.appTypography.bodyMedium, color = MaterialTheme.appColors.textDark @@ -1003,24 +1006,67 @@ fun CourseDatesBanner( } banner.bannerType.buttonResId.nonZero()?.let { - Button( - modifier = Modifier - .fillMaxWidth() - .padding(top = 8.dp) - .height(36.dp), - shape = MaterialTheme.appShapes.buttonShape, + OpenEdXButton( + text = stringResource(id = it), onClick = resetDates, - colors = ButtonDefaults.buttonColors( - backgroundColor = MaterialTheme.appColors.buttonBackground - ), - ) { + ) + } + } +} + +@Composable +fun CourseDatesBannerTablet( + modifier: Modifier, + banner: CourseDatesBannerInfo, + resetDates: () -> Unit, +) { + val cardModifier = modifier + .background( + MaterialTheme.appColors.cardViewBackground, + MaterialTheme.appShapes.material.medium + ) + .border( + 1.dp, + MaterialTheme.appColors.cardViewBorder, + MaterialTheme.appShapes.material.medium + ) + .padding(16.dp) + + Row( + modifier = cardModifier. + fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Column( + modifier = Modifier + .weight(1f) + .padding(end = 16.dp) + ) { + banner.bannerType.headerResId.nonZero()?.let { Text( + modifier = Modifier.padding(bottom = 8.dp), text = stringResource(id = it), - color = MaterialTheme.appColors.buttonText, - style = MaterialTheme.appTypography.labelLarge + style = MaterialTheme.appTypography.titleMedium, + color = MaterialTheme.appColors.textDark + ) + } + + banner.bannerType.bodyResId.nonZero()?.let { + Text( + text = stringResource(id = it), + style = MaterialTheme.appTypography.bodyMedium, + color = MaterialTheme.appColors.textDark ) } } +// banner.bannerType.buttonResId.nonZero()?.let { + OpenEdXButton( + width = Modifier.width(210.dp), + text = stringResource(id = org.openedx.core.R.string.core_dates_reset_dates_banner_button), + onClick = resetDates, + ) +// } } } @@ -1144,6 +1190,19 @@ private fun CourseDatesBannerPreview() { } } +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, device = Devices.NEXUS_9) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.NEXUS_9) +@Composable +private fun CourseDatesBannerTabletPreview() { + OpenEdXTheme { + CourseDatesBannerTablet( + modifier = Modifier, + banner = mockedCourseBannerInfo, + resetDates = {} + ) + } +} + private val mockCourse = EnrolledCourse( auditAccessExpires = Date(), created = "created", diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/program/ProgramFragment.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/program/ProgramFragment.kt index 70d805e26..00da95a6e 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/program/ProgramFragment.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/program/ProgramFragment.kt @@ -99,8 +99,8 @@ class ProgramFragment(private val myPrograms: Boolean = false) : Fragment() { context.toastMessage(getString(R.string.dashboard_enrolled_successfully)) } else { InfoDialogFragment.newInstance( - title = getString(coreR.string.course_enrollment_error), - message = getString(coreR.string.course_enrollment_error_message) + title = getString(coreR.string.core_enrollment_error), + message = getString(coreR.string.core_enrollment_error_message) ).show( requireActivity().supportFragmentManager, InfoDialogFragment::class.simpleName From ad3c91c68a0029233c9106c470db1dae5a6fa8e4 Mon Sep 17 00:00:00 2001 From: omerhabib26 Date: Sun, 28 Jan 2024 03:35:18 +0500 Subject: [PATCH 2/8] fix: Address PR comments --- .../container/CourseContainerAdapter.kt | 23 +++++++++++---- .../container/CourseContainerFragment.kt | 29 ++++++++++++++----- .../course/presentation/ui/CourseUI.kt | 9 +++--- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt index 14f1daf96..599dd46e0 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt @@ -5,15 +5,26 @@ import androidx.viewpager2.adapter.FragmentStateAdapter class CourseContainerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { - private val fragments = ArrayList() + private val fragments = HashMap() override fun getItemCount(): Int = fragments.size - override fun createFragment(position: Int): Fragment = fragments[position] + override fun createFragment(position: Int): Fragment { + val tab = CourseContainerTab.values().find { it.position == position } + return fragments[tab] ?: throw IllegalStateException("Fragment not found for tab $tab") + } - fun addFragment(fragment: Fragment) { - fragments.add(fragment) + fun addFragment(tab: CourseContainerTab, fragment: Fragment) { + fragments[tab] = fragment } - fun getFragment(position: Int): Fragment = fragments[position] -} \ No newline at end of file + fun getFragment(tab: CourseContainerTab): Fragment? = fragments[tab] +} + +enum class CourseContainerTab(val position: Int) { + OUTLINE(0), + VIDEOS(1), + DISCUSSION(2), + DATES(3), + HANDOUTS(4), +} diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt index 68d638058..f30501a38 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt @@ -94,11 +94,26 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { binding.viewPager.isVisible = true binding.viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL adapter = CourseContainerAdapter(this).apply { - addFragment(CourseOutlineFragment.newInstance(viewModel.courseId, viewModel.courseName)) - addFragment(CourseVideosFragment.newInstance(viewModel.courseId, viewModel.courseName)) - addFragment(DiscussionTopicsFragment.newInstance(viewModel.courseId, viewModel.courseName)) - addFragment(CourseDatesFragment.newInstance(viewModel.courseId, viewModel.isSelfPaced)) - addFragment(HandoutsFragment.newInstance(viewModel.courseId)) + addFragment( + CourseContainerTab.OUTLINE, + CourseOutlineFragment.newInstance(viewModel.courseId, viewModel.courseName) + ) + addFragment( + CourseContainerTab.VIDEOS, + CourseVideosFragment.newInstance(viewModel.courseId, viewModel.courseName) + ) + addFragment( + CourseContainerTab.DISCUSSION, + DiscussionTopicsFragment.newInstance(viewModel.courseId, viewModel.courseName) + ) + addFragment( + CourseContainerTab.DATES, + CourseDatesFragment.newInstance(viewModel.courseId, viewModel.isSelfPaced) + ) + addFragment( + CourseContainerTab.HANDOUTS, + HandoutsFragment.newInstance(viewModel.courseId) + ) } binding.viewPager.offscreenPageLimit = adapter?.itemCount ?: 1 binding.viewPager.adapter = adapter @@ -170,8 +185,8 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { snackBar = Snackbar.make(binding.root, message, duration).also { if (isSuccess) { it.setAction(coreR.string.core_dates_view_all_dates) { - binding.viewPager.setCurrentItem(3, true) - adapter?.getFragment(3)?.let { fragment -> + adapter?.getFragment(CourseContainerTab.DATES)?.let { fragment -> + binding.viewPager.setCurrentItem(CourseContainerTab.DATES.position, true) (fragment as CourseDatesFragment).updateData() } } diff --git a/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt b/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt index d64997ceb..1e6f81361 100644 --- a/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt +++ b/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt @@ -1033,8 +1033,7 @@ fun CourseDatesBannerTablet( .padding(16.dp) Row( - modifier = cardModifier. - fillMaxWidth(), + modifier = cardModifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { @@ -1060,13 +1059,13 @@ fun CourseDatesBannerTablet( ) } } -// banner.bannerType.buttonResId.nonZero()?.let { + banner.bannerType.buttonResId.nonZero()?.let { OpenEdXButton( width = Modifier.width(210.dp), - text = stringResource(id = org.openedx.core.R.string.core_dates_reset_dates_banner_button), + text = stringResource(id = it), onClick = resetDates, ) -// } + } } } From f49f80990190c243761260307bbb4e87f63143c6 Mon Sep 17 00:00:00 2001 From: omerhabib26 Date: Sun, 28 Jan 2024 04:32:07 +0500 Subject: [PATCH 3/8] fix: failed test cases --- .../outline/CourseOutlineViewModelTest.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/course/src/test/java/org/openedx/course/presentation/outline/CourseOutlineViewModelTest.kt b/course/src/test/java/org/openedx/course/presentation/outline/CourseOutlineViewModelTest.kt index c98524c3d..e26cb019f 100644 --- a/course/src/test/java/org/openedx/course/presentation/outline/CourseOutlineViewModelTest.kt +++ b/course/src/test/java/org/openedx/course/presentation/outline/CourseOutlineViewModelTest.kt @@ -130,6 +130,14 @@ class CourseOutlineViewModelTest { isSelfPaced = false ) + private val mockCourseDatesBannerInfo = CourseDatesBannerInfo( + missedDeadlines = true, + missedGatedContent = false, + verifiedUpgradeLink = "", + contentTypeGatingEnabled = false, + hasEnded = true, + ) + private val downloadModel = DownloadModel( "id", "title", @@ -229,6 +237,7 @@ class CourseOutlineViewModelTest { } coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") every { config.isCourseNestedListEnabled() } returns false + coEvery { interactor.getDatesBannerInfo(any()) } returns mockCourseDatesBannerInfo val viewModel = CourseOutlineViewModel( "", @@ -307,6 +316,7 @@ class CourseOutlineViewModelTest { } coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") every { config.isCourseNestedListEnabled() } returns false + coEvery { interactor.getDatesBannerInfo(any()) } returns mockCourseDatesBannerInfo val viewModel = CourseOutlineViewModel( "", @@ -379,6 +389,7 @@ class CourseOutlineViewModelTest { coEvery { interactor.getCourseStatus(any()) } returns CourseComponentStatus("id") coEvery { downloadDao.readAllData() } returns flow { emit(emptyList()) } every { config.isCourseNestedListEnabled() } returns false + coEvery { interactor.getDatesBannerInfo(any()) } returns mockCourseDatesBannerInfo val viewModel = CourseOutlineViewModel( "", @@ -410,6 +421,7 @@ class CourseOutlineViewModelTest { coEvery { workerController.saveModels(*anyVararg()) } returns Unit coEvery { downloadDao.readAllData() } returns flow { emit(emptyList()) } every { config.isCourseNestedListEnabled() } returns false + coEvery { interactor.getDatesBannerInfo(any()) } returns mockCourseDatesBannerInfo val viewModel = CourseOutlineViewModel( "", From 27d43e7ba5151f5c035857385b430a7794349253 Mon Sep 17 00:00:00 2001 From: omerhabib26 Date: Sun, 28 Jan 2024 15:05:39 +0500 Subject: [PATCH 4/8] fix: optimise code --- .../container/CourseContainerAdapter.kt | 21 +++++++--- .../container/CourseContainerFragment.kt | 39 +++---------------- .../container/CourseContainerViewModel.kt | 20 +++++++--- 3 files changed, 36 insertions(+), 44 deletions(-) diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt index 599dd46e0..2291331c1 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt @@ -2,6 +2,7 @@ package org.openedx.course.presentation.container import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.FragmentStateAdapter +import org.openedx.course.R class CourseContainerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { @@ -21,10 +22,18 @@ class CourseContainerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment fun getFragment(tab: CourseContainerTab): Fragment? = fragments[tab] } -enum class CourseContainerTab(val position: Int) { - OUTLINE(0), - VIDEOS(1), - DISCUSSION(2), - DATES(3), - HANDOUTS(4), +enum class CourseContainerTab(val itemId: Int, val position: Int, val titleResId: Int) { + OUTLINE(itemId = R.id.outline, position = 0, titleResId = R.string.course_navigation_course), + VIDEOS(itemId = R.id.videos, position = 1, titleResId = R.string.course_navigation_video), + DISCUSSION( + itemId = R.id.discussions, + position = 2, + titleResId = R.string.course_navigation_discussion + ), + DATES(itemId = R.id.dates, position = 3, titleResId = R.string.course_navigation_dates), + HANDOUTS( + itemId = R.id.resources, + position = 4, + titleResId = R.string.course_navigation_handouts + ), } diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt index f30501a38..7deb3375b 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt @@ -121,45 +121,18 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { if (viewModel.isCourseTopTabBarEnabled) { TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position -> tab.text = getString( - when (position) { - 0 -> R.string.course_navigation_course - 1 -> R.string.course_navigation_video - 2 -> R.string.course_navigation_discussion - 3 -> R.string.course_navigation_dates - else -> R.string.course_navigation_handouts - } + CourseContainerTab.values().find { it.position == position }?.titleResId + ?: R.string.course_navigation_course ) }.attach() binding.tabLayout.isVisible = true } else { binding.viewPager.isUserInputEnabled = false - binding.bottomNavView.setOnItemSelectedListener { - when (it.itemId) { - R.id.outline -> { - viewModel.courseTabClickedEvent() - binding.viewPager.setCurrentItem(0, false) - } - - R.id.videos -> { - viewModel.videoTabClickedEvent() - binding.viewPager.setCurrentItem(1, false) - } - - R.id.discussions -> { - viewModel.discussionTabClickedEvent() - binding.viewPager.setCurrentItem(2, false) - } - - R.id.dates -> { - viewModel.datesTabClickedEvent() - binding.viewPager.setCurrentItem(3, false) - } - - R.id.resources -> { - viewModel.handoutsTabClickedEvent() - binding.viewPager.setCurrentItem(4, false) - } + binding.bottomNavView.setOnItemSelectedListener { menuItem -> + CourseContainerTab.values().find { menuItem.itemId == it.itemId }?.let { tab -> + viewModel.courseTabClickedEvent(tab) + binding.viewPager.setCurrentItem(tab.position, false) } true } diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerViewModel.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerViewModel.kt index e9256799f..3a614d29f 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerViewModel.kt @@ -109,23 +109,33 @@ class CourseContainerViewModel( } } - fun courseTabClickedEvent() { + fun courseTabClickedEvent(tab: CourseContainerTab) { + when (tab) { + CourseContainerTab.OUTLINE -> courseTabClickedEvent() + CourseContainerTab.VIDEOS -> videoTabClickedEvent() + CourseContainerTab.DISCUSSION -> discussionTabClickedEvent() + CourseContainerTab.DATES -> datesTabClickedEvent() + CourseContainerTab.HANDOUTS -> handoutsTabClickedEvent() + } + } + + private fun courseTabClickedEvent() { analytics.courseTabClickedEvent(courseId, courseName) } - fun videoTabClickedEvent() { + private fun videoTabClickedEvent() { analytics.videoTabClickedEvent(courseId, courseName) } - fun discussionTabClickedEvent() { + private fun discussionTabClickedEvent() { analytics.discussionTabClickedEvent(courseId, courseName) } - fun datesTabClickedEvent() { + private fun datesTabClickedEvent() { analytics.datesTabClickedEvent(courseId, courseName) } - fun handoutsTabClickedEvent() { + private fun handoutsTabClickedEvent() { analytics.handoutsTabClickedEvent(courseId, courseName) } } From f9c6a81a6970fa85a4f9f5b638d7bba0a8fda98d Mon Sep 17 00:00:00 2001 From: omerhabib26 Date: Sun, 28 Jan 2024 15:26:12 +0500 Subject: [PATCH 5/8] fix: tab position replaced with ordinal --- .../container/CourseContainerAdapter.kt | 22 ++++++------------- .../container/CourseContainerFragment.kt | 21 +++++++++--------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt index 2291331c1..2896588ca 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt @@ -11,7 +11,7 @@ class CourseContainerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment override fun getItemCount(): Int = fragments.size override fun createFragment(position: Int): Fragment { - val tab = CourseContainerTab.values().find { it.position == position } + val tab = CourseContainerTab.values().find { it.ordinal == position } return fragments[tab] ?: throw IllegalStateException("Fragment not found for tab $tab") } @@ -22,18 +22,10 @@ class CourseContainerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment fun getFragment(tab: CourseContainerTab): Fragment? = fragments[tab] } -enum class CourseContainerTab(val itemId: Int, val position: Int, val titleResId: Int) { - OUTLINE(itemId = R.id.outline, position = 0, titleResId = R.string.course_navigation_course), - VIDEOS(itemId = R.id.videos, position = 1, titleResId = R.string.course_navigation_video), - DISCUSSION( - itemId = R.id.discussions, - position = 2, - titleResId = R.string.course_navigation_discussion - ), - DATES(itemId = R.id.dates, position = 3, titleResId = R.string.course_navigation_dates), - HANDOUTS( - itemId = R.id.resources, - position = 4, - titleResId = R.string.course_navigation_handouts - ), +enum class CourseContainerTab(val itemId: Int, val titleResId: Int) { + OUTLINE(itemId = R.id.outline, titleResId = R.string.course_navigation_course), + VIDEOS(itemId = R.id.videos, titleResId = R.string.course_navigation_video), + DISCUSSION(itemId = R.id.discussions, titleResId = R.string.course_navigation_discussion), + DATES(itemId = R.id.dates, titleResId = R.string.course_navigation_dates), + HANDOUTS(itemId = R.id.resources, titleResId = R.string.course_navigation_handouts), } diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt index 7deb3375b..8390f7110 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt @@ -22,6 +22,7 @@ import org.openedx.course.presentation.ui.CourseToolbar import org.openedx.course.presentation.videos.CourseVideosFragment import org.openedx.discussion.presentation.topics.DiscussionTopicsFragment import org.openedx.core.R as coreR +import org.openedx.course.presentation.container.CourseContainerTab as Tabs class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { @@ -95,23 +96,23 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { binding.viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL adapter = CourseContainerAdapter(this).apply { addFragment( - CourseContainerTab.OUTLINE, + Tabs.OUTLINE, CourseOutlineFragment.newInstance(viewModel.courseId, viewModel.courseName) ) addFragment( - CourseContainerTab.VIDEOS, + Tabs.VIDEOS, CourseVideosFragment.newInstance(viewModel.courseId, viewModel.courseName) ) addFragment( - CourseContainerTab.DISCUSSION, + Tabs.DISCUSSION, DiscussionTopicsFragment.newInstance(viewModel.courseId, viewModel.courseName) ) addFragment( - CourseContainerTab.DATES, + Tabs.DATES, CourseDatesFragment.newInstance(viewModel.courseId, viewModel.isSelfPaced) ) addFragment( - CourseContainerTab.HANDOUTS, + Tabs.HANDOUTS, HandoutsFragment.newInstance(viewModel.courseId) ) } @@ -121,7 +122,7 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { if (viewModel.isCourseTopTabBarEnabled) { TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position -> tab.text = getString( - CourseContainerTab.values().find { it.position == position }?.titleResId + Tabs.values().find { it.ordinal == position }?.titleResId ?: R.string.course_navigation_course ) }.attach() @@ -130,9 +131,9 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { } else { binding.viewPager.isUserInputEnabled = false binding.bottomNavView.setOnItemSelectedListener { menuItem -> - CourseContainerTab.values().find { menuItem.itemId == it.itemId }?.let { tab -> + Tabs.values().find { menuItem.itemId == it.itemId }?.let { tab -> viewModel.courseTabClickedEvent(tab) - binding.viewPager.setCurrentItem(tab.position, false) + binding.viewPager.setCurrentItem(tab.ordinal, false) } true } @@ -158,8 +159,8 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { snackBar = Snackbar.make(binding.root, message, duration).also { if (isSuccess) { it.setAction(coreR.string.core_dates_view_all_dates) { - adapter?.getFragment(CourseContainerTab.DATES)?.let { fragment -> - binding.viewPager.setCurrentItem(CourseContainerTab.DATES.position, true) + adapter?.getFragment(Tabs.DATES)?.let { fragment -> + binding.viewPager.setCurrentItem(Tabs.DATES.ordinal, true) (fragment as CourseDatesFragment).updateData() } } From 3d98024a78ca8db0f34b9f45f491a65efa84b051 Mon Sep 17 00:00:00 2001 From: omerhabib26 Date: Fri, 2 Feb 2024 01:55:34 +0500 Subject: [PATCH 6/8] fix: Address PR comments + missed cases --- .../org/openedx/core/data/api/CourseApi.kt | 2 +- .../core/data/model/CourseDatesBannerInfo.kt | 21 ++++++++++ .../domain/model/CourseDatesBannerInfo.kt | 10 ++--- .../data/repository/CourseRepository.kt | 2 +- .../container/CourseContainerAdapter.kt | 2 +- .../container/CourseContainerFragment.kt | 35 ++++++---------- .../container/CourseContainerViewModel.kt | 4 +- .../outline/CourseOutlineFragment.kt | 40 ++++++++++++++++--- .../outline/CourseOutlineViewModel.kt | 4 +- .../res/menu/bottom_course_container_menu.xml | 2 +- 10 files changed, 81 insertions(+), 41 deletions(-) create mode 100644 core/src/main/java/org/openedx/core/data/model/CourseDatesBannerInfo.kt diff --git a/core/src/main/java/org/openedx/core/data/api/CourseApi.kt b/core/src/main/java/org/openedx/core/data/api/CourseApi.kt index 5a0b9445a..64e749a26 100644 --- a/core/src/main/java/org/openedx/core/data/api/CourseApi.kt +++ b/core/src/main/java/org/openedx/core/data/api/CourseApi.kt @@ -72,7 +72,7 @@ interface CourseApi { suspend fun resetCourseDates(@Body courseBody: Map): ResetCourseDates @GET("/api/course_experience/v1/course_deadlines_info/{course_id}") - suspend fun getDatesBannerInfo(@Path("course_id") courseId: String): CourseDates + suspend fun getDatesBannerInfo(@Path("course_id") courseId: String): CourseDatesBannerInfo @GET("/api/mobile/v1/course_info/{course_id}/handouts") suspend fun getHandouts(@Path("course_id") courseId: String): HandoutsModel diff --git a/core/src/main/java/org/openedx/core/data/model/CourseDatesBannerInfo.kt b/core/src/main/java/org/openedx/core/data/model/CourseDatesBannerInfo.kt new file mode 100644 index 000000000..1c4fdac90 --- /dev/null +++ b/core/src/main/java/org/openedx/core/data/model/CourseDatesBannerInfo.kt @@ -0,0 +1,21 @@ +package org.openedx.core.data.model + +import com.google.gson.annotations.SerializedName +import org.openedx.core.domain.model.CourseDatesBannerInfo + +data class CourseDatesBannerInfo( + @SerializedName("dates_banner_info") + val datesBannerInfo: DatesBannerInfo?, + @SerializedName("has_ended") + val hasEnded: Boolean, +) { + fun mapToDomain(): CourseDatesBannerInfo { + return CourseDatesBannerInfo( + missedDeadlines = datesBannerInfo?.missedDeadlines ?: false, + missedGatedContent = datesBannerInfo?.missedGatedContent ?: false, + verifiedUpgradeLink = datesBannerInfo?.verifiedUpgradeLink ?: "", + contentTypeGatingEnabled = datesBannerInfo?.contentTypeGatingEnabled ?: false, + hasEnded = hasEnded, + ) + } +} diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt b/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt index 7020e3e16..58431744d 100644 --- a/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt +++ b/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt @@ -8,11 +8,11 @@ import org.openedx.core.domain.model.CourseBannerType.UPGRADE_TO_GRADED import org.openedx.core.domain.model.CourseBannerType.UPGRADE_TO_RESET data class CourseDatesBannerInfo( - private val missedDeadlines: Boolean, - private val missedGatedContent: Boolean, - private val verifiedUpgradeLink: String, - private val contentTypeGatingEnabled: Boolean, - private val hasEnded: Boolean + private val missedDeadlines: Boolean = false, + private val missedGatedContent: Boolean = false, + private val verifiedUpgradeLink: String = "", + private val contentTypeGatingEnabled: Boolean = false, + private val hasEnded: Boolean = false, ) { val bannerType by lazy { getCourseBannerType() } diff --git a/course/src/main/java/org/openedx/course/data/repository/CourseRepository.kt b/course/src/main/java/org/openedx/course/data/repository/CourseRepository.kt index a608c2945..5ddec50c0 100644 --- a/course/src/main/java/org/openedx/course/data/repository/CourseRepository.kt +++ b/course/src/main/java/org/openedx/course/data/repository/CourseRepository.kt @@ -107,7 +107,7 @@ class CourseRepository( api.resetCourseDates(mapOf(ApiConstants.COURSE_KEY to courseId)).mapToDomain() suspend fun getDatesBannerInfo(courseId: String) = - api.getDatesBannerInfo(courseId).getDatesBannerInfo() + api.getDatesBannerInfo(courseId).mapToDomain() suspend fun getHandouts(courseId: String) = api.getHandouts(courseId).mapToDomain() diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt index 2896588ca..cb9ca5930 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerAdapter.kt @@ -23,7 +23,7 @@ class CourseContainerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment } enum class CourseContainerTab(val itemId: Int, val titleResId: Int) { - OUTLINE(itemId = R.id.outline, titleResId = R.string.course_navigation_course), + COURSE(itemId = R.id.course, titleResId = R.string.course_navigation_course), VIDEOS(itemId = R.id.videos, titleResId = R.string.course_navigation_video), DISCUSSION(itemId = R.id.discussions, titleResId = R.string.course_navigation_discussion), DATES(itemId = R.id.dates, titleResId = R.string.course_navigation_dates), diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt index 8390f7110..2dfea43b1 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt @@ -15,13 +15,13 @@ import org.openedx.core.presentation.global.viewBinding import org.openedx.course.R import org.openedx.course.databinding.FragmentCourseContainerBinding import org.openedx.course.presentation.CourseRouter +import org.openedx.course.presentation.container.CourseContainerTab import org.openedx.course.presentation.dates.CourseDatesFragment import org.openedx.course.presentation.handouts.HandoutsFragment import org.openedx.course.presentation.outline.CourseOutlineFragment import org.openedx.course.presentation.ui.CourseToolbar import org.openedx.course.presentation.videos.CourseVideosFragment import org.openedx.discussion.presentation.topics.DiscussionTopicsFragment -import org.openedx.core.R as coreR import org.openedx.course.presentation.container.CourseContainerTab as Tabs class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { @@ -96,7 +96,7 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { binding.viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL adapter = CourseContainerAdapter(this).apply { addFragment( - Tabs.OUTLINE, + Tabs.COURSE, CourseOutlineFragment.newInstance(viewModel.courseId, viewModel.courseName) ) addFragment( @@ -132,7 +132,7 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { binding.viewPager.isUserInputEnabled = false binding.bottomNavView.setOnItemSelectedListener { menuItem -> Tabs.values().find { menuItem.itemId == it.itemId }?.let { tab -> - viewModel.courseTabClickedEvent(tab) + viewModel.courseContainerTabClickedEvent(tab) binding.viewPager.setCurrentItem(tab.ordinal, false) } true @@ -145,30 +145,19 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { viewModel.updateData(withSwipeRefresh) } - fun showDatesUpdateSnackbar(isSuccess: Boolean) { - val message = if (isSuccess) { - getString(coreR.string.core_dates_shift_dates_successfully_msg) - } else { - getString(coreR.string.core_dates_shift_dates_unsuccessful_msg) - } - val duration = if (isSuccess) { - Snackbar.LENGTH_INDEFINITE - } else { - Snackbar.LENGTH_LONG + fun updateCourseDates() { + adapter?.getFragment(Tabs.DATES)?.let { + (it as CourseDatesFragment).updateData() } - snackBar = Snackbar.make(binding.root, message, duration).also { - if (isSuccess) { - it.setAction(coreR.string.core_dates_view_all_dates) { - adapter?.getFragment(Tabs.DATES)?.let { fragment -> - binding.viewPager.setCurrentItem(Tabs.DATES.ordinal, true) - (fragment as CourseDatesFragment).updateData() - } - } - } + } + + fun navigateToTab(tab: CourseContainerTab) { + adapter?.getFragment(tab)?.let { + binding.viewPager.setCurrentItem(tab.ordinal, true) } - snackBar?.show() } + companion object { private const val ARG_COURSE_ID = "courseId" private const val ARG_TITLE = "title" diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerViewModel.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerViewModel.kt index 3a614d29f..f0d9a9507 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerViewModel.kt @@ -109,9 +109,9 @@ class CourseContainerViewModel( } } - fun courseTabClickedEvent(tab: CourseContainerTab) { + fun courseContainerTabClickedEvent(tab: CourseContainerTab) { when (tab) { - CourseContainerTab.OUTLINE -> courseTabClickedEvent() + CourseContainerTab.COURSE -> courseTabClickedEvent() CourseContainerTab.VIDEOS -> videoTabClickedEvent() CourseContainerTab.DISCUSSION -> discussionTabClickedEvent() CourseContainerTab.DATES -> datesTabClickedEvent() diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt index 7d442727a..e74d50cf9 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt @@ -54,6 +54,7 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.core.os.bundleOf import androidx.fragment.app.Fragment +import com.google.android.material.snackbar.Snackbar import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf @@ -80,6 +81,7 @@ import org.openedx.core.ui.theme.appTypography import org.openedx.core.ui.windowSizeValue import org.openedx.course.presentation.CourseRouter import org.openedx.course.presentation.container.CourseContainerFragment +import org.openedx.course.presentation.container.CourseContainerTab import org.openedx.course.presentation.outline.CourseOutlineFragment.Companion.getUnitBlockIcon import org.openedx.course.presentation.ui.CourseDatesBanner import org.openedx.course.presentation.ui.CourseDatesBannerTablet @@ -97,6 +99,8 @@ class CourseOutlineFragment : Fragment() { } private val router by inject() + private var snackBar: Snackbar? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycle.addObserver(viewModel) @@ -192,7 +196,8 @@ class CourseOutlineFragment : Fragment() { }, onResetDatesClick = { viewModel.resetCourseDatesBanner(onResetDates = { - (parentFragment as CourseContainerFragment).showDatesUpdateSnackbar(it) + (parentFragment as CourseContainerFragment).updateCourseDates() + showDatesUpdateSnackbar(it) }) } ) @@ -200,6 +205,29 @@ class CourseOutlineFragment : Fragment() { } } + override fun onDestroyView() { + snackBar?.dismiss() + super.onDestroyView() + } + + private fun showDatesUpdateSnackbar(isSuccess: Boolean) { + val message = if (isSuccess) { + getString(R.string.core_dates_shift_dates_successfully_msg) + } else { + getString(R.string.core_dates_shift_dates_unsuccessful_msg) + } + snackBar = view?.let { + Snackbar.make(it, message, Snackbar.LENGTH_LONG).apply { + if (isSuccess) { + setAction(R.string.core_dates_view_all_dates) { + (parentFragment as CourseContainerFragment).navigateToTab(CourseContainerTab.DATES) + } + } + } + } + snackBar?.show() + } + companion object { private const val ARG_COURSE_ID = "courseId" @@ -333,8 +361,9 @@ internal fun CourseOutlineScreen( ) } } - uiState.datesBannerInfo?.let { - if (it.isBannerAvailableForDashboard()) { + item { Spacer(Modifier.height(28.dp)) } + uiState.datesBannerInfo?.let { banner -> + if (banner.isBannerAvailableForDashboard()) { item { Box( modifier = Modifier @@ -343,13 +372,13 @@ internal fun CourseOutlineScreen( if (windowSize.isTablet) { CourseDatesBannerTablet( modifier = Modifier.padding(bottom = 16.dp), - banner = it, + banner = banner, resetDates = onResetDatesClick, ) } else { CourseDatesBanner( modifier = Modifier.padding(bottom = 16.dp), - banner = it, + banner = banner, resetDates = onResetDatesClick, ) } @@ -359,7 +388,6 @@ internal fun CourseOutlineScreen( } if (uiState.resumeComponent != null) { item { - Spacer(Modifier.height(28.dp)) Box(listPadding) { if (windowSize.isTablet) { ResumeCourseTablet( diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt index 3f26c9ef8..69d9b1c3f 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt @@ -13,6 +13,7 @@ import org.openedx.core.config.Config import org.openedx.core.data.storage.CorePreferences import org.openedx.core.domain.model.Block import org.openedx.core.domain.model.CourseComponentStatus +import org.openedx.core.domain.model.CourseDatesBannerInfo import org.openedx.core.extension.getSequentialBlocks import org.openedx.core.extension.getVerticalBlocks import org.openedx.core.extension.isInternetError @@ -171,7 +172,7 @@ class CourseOutlineViewModel( val datesBannerInfo = if (networkConnection.isOnline()) { interactor.getDatesBannerInfo(courseId) } else { - null + CourseDatesBannerInfo() } setBlocks(blocks) courseSubSections.clear() @@ -249,6 +250,7 @@ class CourseOutlineViewModel( viewModelScope.launch { try { interactor.resetCourseDates(courseId = courseId) + updateCourseData(false) onResetDates(true) } catch (e: Exception) { if (e.isInternetError()) { diff --git a/course/src/main/res/menu/bottom_course_container_menu.xml b/course/src/main/res/menu/bottom_course_container_menu.xml index e65c6ea5e..da9eee1b9 100644 --- a/course/src/main/res/menu/bottom_course_container_menu.xml +++ b/course/src/main/res/menu/bottom_course_container_menu.xml @@ -2,7 +2,7 @@ From 5942d0d60395d8b2019d238f8bf253a25fdd62f1 Mon Sep 17 00:00:00 2001 From: omerhabib26 Date: Sun, 4 Feb 2024 21:26:41 +0500 Subject: [PATCH 7/8] fix: Address PR comments 2 --- .../openedx/core/data/model/CourseDates.kt | 6 +-- .../core/data/model/CourseDatesBannerInfo.kt | 4 +- .../domain/model/CourseDatesBannerInfo.kt | 10 ++-- .../container/CourseContainerFragment.kt | 1 - .../presentation/dates/CourseDatesFragment.kt | 19 +++++-- .../outline/CourseOutlineFragment.kt | 54 +++++++++++-------- .../outline/CourseOutlineUIState.kt | 2 +- .../outline/CourseOutlineViewModel.kt | 10 +++- 8 files changed, 65 insertions(+), 41 deletions(-) diff --git a/core/src/main/java/org/openedx/core/data/model/CourseDates.kt b/core/src/main/java/org/openedx/core/data/model/CourseDates.kt index 49448cdbc..97fc3180f 100644 --- a/core/src/main/java/org/openedx/core/data/model/CourseDates.kt +++ b/core/src/main/java/org/openedx/core/data/model/CourseDates.kt @@ -17,7 +17,7 @@ data class CourseDates( @SerializedName("dates_banner_info") val datesBannerInfo: DatesBannerInfo?, @SerializedName("has_ended") - val hasEnded: Boolean, + val hasEnded: Boolean?, ) { fun getCourseDatesResult(): CourseDatesResult { return CourseDatesResult( @@ -26,13 +26,13 @@ data class CourseDates( ) } - fun getDatesBannerInfo(): CourseDatesBannerInfo { + private fun getDatesBannerInfo(): CourseDatesBannerInfo { return CourseDatesBannerInfo( missedDeadlines = datesBannerInfo?.missedDeadlines ?: false, missedGatedContent = datesBannerInfo?.missedGatedContent ?: false, verifiedUpgradeLink = datesBannerInfo?.verifiedUpgradeLink ?: "", contentTypeGatingEnabled = datesBannerInfo?.contentTypeGatingEnabled ?: false, - hasEnded = hasEnded, + hasEnded = hasEnded ?: false, ) } diff --git a/core/src/main/java/org/openedx/core/data/model/CourseDatesBannerInfo.kt b/core/src/main/java/org/openedx/core/data/model/CourseDatesBannerInfo.kt index 1c4fdac90..09e2d39cb 100644 --- a/core/src/main/java/org/openedx/core/data/model/CourseDatesBannerInfo.kt +++ b/core/src/main/java/org/openedx/core/data/model/CourseDatesBannerInfo.kt @@ -7,7 +7,7 @@ data class CourseDatesBannerInfo( @SerializedName("dates_banner_info") val datesBannerInfo: DatesBannerInfo?, @SerializedName("has_ended") - val hasEnded: Boolean, + val hasEnded: Boolean?, ) { fun mapToDomain(): CourseDatesBannerInfo { return CourseDatesBannerInfo( @@ -15,7 +15,7 @@ data class CourseDatesBannerInfo( missedGatedContent = datesBannerInfo?.missedGatedContent ?: false, verifiedUpgradeLink = datesBannerInfo?.verifiedUpgradeLink ?: "", contentTypeGatingEnabled = datesBannerInfo?.contentTypeGatingEnabled ?: false, - hasEnded = hasEnded, + hasEnded = hasEnded ?: false, ) } } diff --git a/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt b/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt index 58431744d..3281ca045 100644 --- a/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt +++ b/core/src/main/java/org/openedx/core/domain/model/CourseDatesBannerInfo.kt @@ -8,11 +8,11 @@ import org.openedx.core.domain.model.CourseBannerType.UPGRADE_TO_GRADED import org.openedx.core.domain.model.CourseBannerType.UPGRADE_TO_RESET data class CourseDatesBannerInfo( - private val missedDeadlines: Boolean = false, - private val missedGatedContent: Boolean = false, - private val verifiedUpgradeLink: String = "", - private val contentTypeGatingEnabled: Boolean = false, - private val hasEnded: Boolean = false, + private val missedDeadlines: Boolean, + private val missedGatedContent: Boolean, + private val verifiedUpgradeLink: String, + private val contentTypeGatingEnabled: Boolean, + private val hasEnded: Boolean, ) { val bannerType by lazy { getCourseBannerType() } diff --git a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt index 2dfea43b1..f2a27d510 100644 --- a/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/container/CourseContainerFragment.kt @@ -157,7 +157,6 @@ class CourseContainerFragment : Fragment(R.layout.fragment_course_container) { } } - companion object { private const val ARG_COURSE_ID = "courseId" private const val ARG_TITLE = "title" diff --git a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt index 2d7bca572..7e67a6c90 100644 --- a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt @@ -101,6 +101,7 @@ import org.openedx.core.utils.clearTime import org.openedx.course.R import org.openedx.course.presentation.CourseRouter import org.openedx.course.presentation.ui.CourseDatesBanner +import org.openedx.course.presentation.ui.CourseDatesBannerTablet import org.openedx.core.R as coreR class CourseDatesFragment : Fragment() { @@ -271,11 +272,19 @@ internal fun CourseDatesScreen( if (courseBanner.isBannerAvailableForUserType(isSelfPaced)) { item { - CourseDatesBanner( - modifier = Modifier.padding(bottom = 16.dp), - banner = courseBanner, - resetDates = onSyncDates - ) + if (windowSize.isTablet) { + CourseDatesBannerTablet( + modifier = Modifier.padding(bottom = 16.dp), + banner = courseBanner, + resetDates = onSyncDates, + ) + } else { + CourseDatesBanner( + modifier = Modifier.padding(bottom = 16.dp), + banner = courseBanner, + resetDates = onSyncDates + ) + } } } diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt index e74d50cf9..e760400e9 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineFragment.kt @@ -362,26 +362,24 @@ internal fun CourseOutlineScreen( } } item { Spacer(Modifier.height(28.dp)) } - uiState.datesBannerInfo?.let { banner -> - if (banner.isBannerAvailableForDashboard()) { - item { - Box( - modifier = Modifier - .padding(all = 6.dp) - ) { - if (windowSize.isTablet) { - CourseDatesBannerTablet( - modifier = Modifier.padding(bottom = 16.dp), - banner = banner, - resetDates = onResetDatesClick, - ) - } else { - CourseDatesBanner( - modifier = Modifier.padding(bottom = 16.dp), - banner = banner, - resetDates = onResetDatesClick, - ) - } + if (uiState.datesBannerInfo.isBannerAvailableForDashboard()) { + item { + Box( + modifier = Modifier + .padding(all = 8.dp) + ) { + if (windowSize.isTablet) { + CourseDatesBannerTablet( + modifier = Modifier.padding(bottom = 16.dp), + banner = uiState.datesBannerInfo, + resetDates = onResetDatesClick, + ) + } else { + CourseDatesBanner( + modifier = Modifier.padding(bottom = 16.dp), + banner = uiState.datesBannerInfo, + resetDates = onResetDatesClick, + ) } } } @@ -628,7 +626,13 @@ private fun CourseOutlineScreenPreview() { mapOf(), mapOf(), mapOf(), - CourseDatesBannerInfo(false, false, "", false, false) + CourseDatesBannerInfo( + missedDeadlines = false, + missedGatedContent = false, + verifiedUpgradeLink = "", + contentTypeGatingEnabled = false, + hasEnded = false + ) ), apiHostUrl = "", isCourseNestedListEnabled = true, @@ -662,7 +666,13 @@ private fun CourseOutlineScreenTabletPreview() { mapOf(), mapOf(), mapOf(), - CourseDatesBannerInfo(false, false, "", false, false) + CourseDatesBannerInfo( + missedDeadlines = false, + missedGatedContent = false, + verifiedUpgradeLink = "", + contentTypeGatingEnabled = false, + hasEnded = false + ) ), apiHostUrl = "", isCourseNestedListEnabled = true, diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineUIState.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineUIState.kt index b4be4c4ee..8b29be31e 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineUIState.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineUIState.kt @@ -13,7 +13,7 @@ sealed class CourseOutlineUIState { val courseSubSections: Map>, val courseSectionsState: Map, val subSectionsDownloadsCount: Map, - val datesBannerInfo: CourseDatesBannerInfo?, + val datesBannerInfo: CourseDatesBannerInfo, ) : CourseOutlineUIState() object Loading : CourseOutlineUIState() diff --git a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt index 69d9b1c3f..361e04be0 100644 --- a/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/outline/CourseOutlineViewModel.kt @@ -129,7 +129,7 @@ class CourseOutlineViewModel( getCourseDataInternal() } - fun getCourseData() { + private fun getCourseData() { _uiState.value = CourseOutlineUIState.Loading getCourseDataInternal() } @@ -172,7 +172,13 @@ class CourseOutlineViewModel( val datesBannerInfo = if (networkConnection.isOnline()) { interactor.getDatesBannerInfo(courseId) } else { - CourseDatesBannerInfo() + CourseDatesBannerInfo( + missedDeadlines = false, + missedGatedContent = false, + verifiedUpgradeLink = "", + contentTypeGatingEnabled = false, + hasEnded = false + ) } setBlocks(blocks) courseSubSections.clear() From c9ff25fddb14af525cf115e68e997db78747c6e1 Mon Sep 17 00:00:00 2001 From: omerhabib26 Date: Tue, 6 Feb 2024 00:49:50 +0500 Subject: [PATCH 8/8] fix: Update banner on Course Outline --- .../course/presentation/dates/CourseDatesFragment.kt | 8 +++++++- .../course/presentation/dates/CourseDatesViewModel.kt | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt index 7e67a6c90..d93d170ae 100644 --- a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt +++ b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesFragment.kt @@ -100,6 +100,7 @@ import org.openedx.core.utils.TimeUtils import org.openedx.core.utils.clearTime import org.openedx.course.R import org.openedx.course.presentation.CourseRouter +import org.openedx.course.presentation.container.CourseContainerFragment import org.openedx.course.presentation.ui.CourseDatesBanner import org.openedx.course.presentation.ui.CourseDatesBannerTablet import org.openedx.core.R as coreR @@ -157,7 +158,12 @@ class CourseDatesFragment : Fragment() { } }, onSyncDates = { - viewModel.resetCourseDatesBanner() + viewModel.resetCourseDatesBanner { + if (it) { + (parentFragment as CourseContainerFragment) + .updateCourseStructure(false) + } + } }, ) } diff --git a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesViewModel.kt b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesViewModel.kt index d66b2366c..8d643de9d 100644 --- a/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesViewModel.kt +++ b/course/src/main/java/org/openedx/course/presentation/dates/CourseDatesViewModel.kt @@ -73,11 +73,12 @@ class CourseDatesViewModel( } } - fun resetCourseDatesBanner() { + fun resetCourseDatesBanner(onResetDates: (Boolean) -> Unit) { viewModelScope.launch { try { interactor.resetCourseDates(courseId = courseId) getCourseDates() + onResetDates(true) } catch (e: Exception) { if (e.isInternetError()) { _uiMessage.value = @@ -86,6 +87,7 @@ class CourseDatesViewModel( _uiMessage.value = UIMessage.SnackBarMessage(resourceManager.getString(R.string.core_error_unknown_error)) } + onResetDates(false) } } }